~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/table/cache.cc

  • Committer: lbieber
  • Date: 2010-10-02 19:48:35 UTC
  • mfrom: (1730.6.19 drizzle-make-lcov)
  • Revision ID: lbieber@orisndriz08-20101002194835-q5zd9qc4lvx1xnfo
Merge Hartmut - clean up lex, now require flex to build, also "make lcov" improvements

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
 
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3
 
 *
4
 
 *  Copyright (C) 2010 Brian Aker
5
 
 *
6
 
 *  This program is free software; you can redistribute it and/or modify
7
 
 *  it under the terms of the GNU General Public License as published by
8
 
 *  the Free Software Foundation; either version 2 of the License, or
9
 
 *  (at your option) any later version.
10
 
 *
11
 
 *  This program is distributed in the hope that it will be useful,
12
 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 
 *  GNU General Public License for more details.
15
 
 *
16
 
 *  You should have received a copy of the GNU General Public License
17
 
 *  along with this program; if not, write to the Free Software
18
 
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19
 
 */
20
 
 
21
 
#include "config.h"
22
 
 
23
 
#include <sys/types.h>
24
 
#include <sys/stat.h>
25
 
#include <fcntl.h>
26
 
 
27
 
 
28
 
#include "drizzled/identifier.h"
29
 
#include "drizzled/table.h"
30
 
#include "drizzled/session.h"
31
 
#include "drizzled/table/concurrent.h"
32
 
 
33
 
#include "drizzled/table/cache.h"
34
 
#include "drizzled/table/unused.h"
35
 
 
36
 
#include "drizzled/pthread_globals.h"
37
 
 
38
 
namespace drizzled
39
 
{
40
 
 
41
 
class Session;
42
 
 
43
 
namespace table
44
 
{
45
 
 
46
 
CacheMap &getCache(void)
47
 
{
48
 
  return Cache::singleton().getCache();
49
 
}
50
 
 
51
 
/*
52
 
  Remove table from the open table cache
53
 
 
54
 
  SYNOPSIS
55
 
  free_cache_entry()
56
 
  entry         Table to remove
57
 
 
58
 
  NOTE
59
 
  We need to have a lock on table::Cache::singleton().mutex() when calling this
60
 
*/
61
 
 
62
 
static void free_cache_entry(table::Concurrent *table)
63
 
{
64
 
  table->intern_close_table();
65
 
  if (not table->in_use)
66
 
  {
67
 
    getUnused().unlink(table);
68
 
  }
69
 
 
70
 
  boost::checked_delete(table);
71
 
}
72
 
 
73
 
void remove_table(table::Concurrent *arg)
74
 
{
75
 
  CacheRange ppp;
76
 
  ppp= getCache().equal_range(arg->getShare()->getCacheKey());
77
 
 
78
 
  for (CacheMap::const_iterator iter= ppp.first;
79
 
         iter != ppp.second; ++iter)
80
 
  {
81
 
    table::Concurrent *found_table= (*iter).second;
82
 
 
83
 
    if (found_table == arg)
84
 
    {
85
 
      free_cache_entry(arg);
86
 
      getCache().erase(iter);
87
 
      return;
88
 
    }
89
 
  }
90
 
}
91
 
 
92
 
/*
93
 
  Wait until all threads has closed the tables in the list
94
 
  We have also to wait if there is thread that has a lock on this table even
95
 
  if the table is closed
96
 
*/
97
 
 
98
 
bool Cache::areTablesUsed(Table *table, bool wait_for_name_lock)
99
 
{
100
 
  do
101
 
  {
102
 
    const identifier::Table::Key &key(table->getShare()->getCacheKey());
103
 
 
104
 
    table::CacheRange ppp= table::getCache().equal_range(key);
105
 
 
106
 
    for (table::CacheMap::const_iterator iter= ppp.first; iter != ppp.second; ++iter)
107
 
    {
108
 
      Table *search= (*iter).second;
109
 
      if (search->in_use == table->in_use)
110
 
        continue;                               // Name locked by this thread
111
 
      /*
112
 
        We can't use the table under any of the following conditions:
113
 
        - There is an name lock on it (Table is to be deleted or altered)
114
 
        - If we are in flush table and we didn't execute the flush
115
 
        - If the table engine is open and it's an old version
116
 
        (We must wait until all engines are shut down to use the table)
117
 
      */
118
 
      if ( (search->locked_by_name && wait_for_name_lock) ||
119
 
           (search->is_name_opened() && search->needs_reopen_or_name_lock()))
120
 
        return 1;
121
 
    }
122
 
  } while ((table=table->getNext()));
123
 
  return 0;
124
 
}
125
 
 
126
 
/*
127
 
  Invalidate any cache entries that are for some DB
128
 
 
129
 
  SYNOPSIS
130
 
  removeSchema()
131
 
  db            Database name. This will be in lower case if
132
 
  lower_case_table_name is set
133
 
 
134
 
NOTE:
135
 
We can't use hash_delete when looping hash_elements. We mark them first
136
 
and afterwards delete those marked unused.
137
 
*/
138
 
 
139
 
void Cache::removeSchema(const identifier::Schema &schema_identifier)
140
 
{
141
 
  boost::mutex::scoped_lock scopedLock(_mutex);
142
 
 
143
 
  for (table::CacheMap::const_iterator iter= table::getCache().begin();
144
 
       iter != table::getCache().end();
145
 
       iter++)
146
 
  {
147
 
    table::Concurrent *table= (*iter).second;
148
 
 
149
 
    if (not schema_identifier.getPath().compare(table->getShare()->getSchemaName()))
150
 
    {
151
 
      table->getMutableShare()->resetVersion();                 /* Free when thread is ready */
152
 
      if (not table->in_use)
153
 
        table::getUnused().relink(table);
154
 
    }
155
 
  }
156
 
 
157
 
  table::getUnused().cullByVersion();
158
 
}
159
 
 
160
 
/*
161
 
  Mark all entries with the table as deleted to force an reopen of the table
162
 
 
163
 
  The table will be closed (not stored in cache) by the current thread when
164
 
  close_thread_tables() is called.
165
 
 
166
 
  PREREQUISITES
167
 
  Lock on table::Cache::singleton().mutex()()
168
 
 
169
 
  RETURN
170
 
  0  This thread now have exclusive access to this table and no other thread
171
 
  can access the table until close_thread_tables() is called.
172
 
  1  Table is in use by another thread
173
 
*/
174
 
 
175
 
bool Cache::removeTable(Session *session, identifier::Table &identifier, uint32_t flags)
176
 
{
177
 
  const identifier::Table::Key &key(identifier.getKey());
178
 
  bool result= false; 
179
 
  bool signalled= false;
180
 
 
181
 
  for (;;)
182
 
  {
183
 
    result= signalled= false;
184
 
 
185
 
    table::CacheRange ppp;
186
 
    ppp= table::getCache().equal_range(key);
187
 
 
188
 
    for (table::CacheMap::const_iterator iter= ppp.first;
189
 
         iter != ppp.second; ++iter)
190
 
    {
191
 
      table::Concurrent *table= (*iter).second;
192
 
      Session *in_use;
193
 
 
194
 
      table->getMutableShare()->resetVersion();         /* Free when thread is ready */
195
 
      if (not (in_use= table->in_use))
196
 
      {
197
 
        table::getUnused().relink(table);
198
 
      }
199
 
      else if (in_use != session)
200
 
      {
201
 
        /*
202
 
          Mark that table is going to be deleted from cache. This will
203
 
          force threads that are in lockTables() (but not yet
204
 
          in thr_multi_lock()) to abort it's locks, close all tables and retry
205
 
        */
206
 
        in_use->some_tables_deleted= true;
207
 
        if (table->is_name_opened())
208
 
        {
209
 
          result= true;
210
 
        }
211
 
        /*
212
 
          Now we must abort all tables locks used by this thread
213
 
          as the thread may be waiting to get a lock for another table.
214
 
          Note that we need to hold table::Cache::singleton().mutex() while going through the
215
 
          list. So that the other thread cannot change it. The other
216
 
          thread must also hold table::Cache::singleton().mutex() whenever changing the
217
 
          open_tables list. Aborting the MERGE lock after a child was
218
 
          closed and before the parent is closed would be fatal.
219
 
        */
220
 
        for (Table *session_table= in_use->open_tables;
221
 
             session_table ;
222
 
             session_table= session_table->getNext())
223
 
        {
224
 
          /* Do not handle locks of MERGE children. */
225
 
          if (session_table->db_stat)   // If table is open
226
 
            signalled|= session->abortLockForThread(session_table);
227
 
        }
228
 
      }
229
 
      else
230
 
      {
231
 
        result= result || (flags & RTFC_OWNED_BY_Session_FLAG);
232
 
      }
233
 
    }
234
 
 
235
 
    table::getUnused().cullByVersion();
236
 
 
237
 
    /* Remove table from table definition cache if it's not in use */
238
 
    table::instance::release(identifier);
239
 
 
240
 
    if (result && (flags & RTFC_WAIT_OTHER_THREAD_FLAG))
241
 
    {
242
 
      /*
243
 
        Signal any thread waiting for tables to be freed to
244
 
        reopen their tables
245
 
      */
246
 
      locking::broadcast_refresh();
247
 
      if (not (flags & RTFC_CHECK_KILLED_FLAG) || not session->getKilled())
248
 
      {
249
 
        dropping_tables++;
250
 
        if (likely(signalled))
251
 
        {
252
 
          boost_unique_lock_t scoped(table::Cache::singleton().mutex(), boost::adopt_lock_t());
253
 
          COND_refresh.wait(scoped);
254
 
          scoped.release();
255
 
        }
256
 
        else
257
 
        {
258
 
          /*
259
 
            It can happen that another thread has opened the
260
 
            table but has not yet locked any table at all. Since
261
 
            it can be locked waiting for a table that our thread
262
 
            has done LOCK Table x WRITE on previously, we need to
263
 
            ensure that the thread actually hears our signal
264
 
            before we go to sleep. Thus we wait for a short time
265
 
            and then we retry another loop in the
266
 
            table::Cache::singleton().removeTable routine.
267
 
          */
268
 
          boost::xtime xt; 
269
 
          xtime_get(&xt, boost::TIME_UTC); 
270
 
          xt.sec += 10; 
271
 
          boost_unique_lock_t scoped(table::Cache::singleton().mutex(), boost::adopt_lock_t());
272
 
          COND_refresh.timed_wait(scoped, xt);
273
 
          scoped.release();
274
 
        }
275
 
        dropping_tables--;
276
 
        continue;
277
 
      }
278
 
    }
279
 
    break;
280
 
  }
281
 
 
282
 
  return result;
283
 
}
284
 
 
285
 
 
286
 
bool Cache::insert(table::Concurrent *arg)
287
 
{
288
 
  CacheMap::iterator returnable= cache.insert(std::make_pair(arg->getShare()->getCacheKey(), arg));
289
 
 
290
 
  return not (returnable == cache.end());
291
 
}
292
 
 
293
 
} /* namespace table */
294
 
} /* namespace drizzled */