~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/table/cache.cc

  • Committer: Brian Aker
  • Date: 2010-10-28 17:12:01 UTC
  • mfrom: (1887.1.3 merge)
  • Revision ID: brian@tangent.org-20101028171201-baj6l1bnntn1s4ad
Merge in POTFILES changes.

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/table.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 LOCK_open 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
  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 TableIdentifier::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 SchemaIdentifier &schema_identifier)
 
140
{
 
141
  //safe_mutex_assert_owner(LOCK_open.native_handle());
 
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 LOCK_open()
 
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, TableIdentifier &identifier, uint32_t flags)
 
176
{
 
177
  const TableIdentifier::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 mysql_lock_tables() (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 LOCK_open while going through the
 
215
          list. So that the other thread cannot change it. The other
 
216
          thread must also hold LOCK_open 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|= mysql_lock_abort_for_thread(session, 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
    TableShare::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
      broadcast_refresh();
 
247
      if (!(flags & RTFC_CHECK_KILLED_FLAG) || !session->killed)
 
248
      {
 
249
        dropping_tables++;
 
250
        if (likely(signalled))
 
251
        {
 
252
          boost_unique_lock_t scoped(LOCK_open, 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(LOCK_open, 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
} /* namespace table */
 
286
} /* namespace drizzled */