~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/table/cache.cc

  • Committer: Daniel Nichter
  • Date: 2011-10-23 16:01:37 UTC
  • mto: This revision was merged to the branch mainline in revision 2448.
  • Revision ID: daniel@percona.com-20111023160137-7ac3blgz8z4tf8za
Add Administration Getting Started and Logging.  Capitalize SQL clause keywords.

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