1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4
* Copyright (C) 2010 Brian Aker
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.
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.
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
22
#include <drizzled/table/cache.h>
24
#include <sys/types.h>
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>
41
CacheMap Cache::cache;
42
boost::mutex Cache::_mutex;
46
return Cache::getCache();
50
Remove table from the open table cache
57
We need to have a lock on table::Cache::mutex() when calling this
60
static void free_cache_entry(table::Concurrent *table)
62
table->intern_close_table();
63
if (not table->in_use)
65
getUnused().unlink(table);
68
boost::checked_delete(table);
71
void remove_table(table::Concurrent *arg)
74
ppp= getCache().equal_range(arg->getShare()->getCacheKey());
76
for (CacheMap::const_iterator iter= ppp.first;
77
iter != ppp.second; ++iter)
79
table::Concurrent *found_table= iter->second;
81
if (found_table == arg)
83
free_cache_entry(arg);
84
getCache().erase(iter);
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
96
bool Cache::areTablesUsed(Table *table, bool wait_for_name_lock)
100
const identifier::Table::Key &key(table->getShare()->getCacheKey());
102
table::CacheRange ppp= table::getCache().equal_range(key);
104
for (table::CacheMap::const_iterator iter= ppp.first; iter != ppp.second; ++iter)
106
Table *search= iter->second;
107
if (search->in_use == table->in_use)
108
continue; // Name locked by this thread
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)
116
if ( (search->locked_by_name && wait_for_name_lock) ||
117
(search->is_name_opened() && search->needs_reopen_or_name_lock()))
120
} while ((table=table->getNext()));
125
Invalidate any cache entries that are for some DB
129
db Database name. This will be in lower case if
130
lower_case_table_name is set
133
We can't use hash_delete when looping hash_elements. We mark them first
134
and afterwards delete those marked unused.
137
void Cache::removeSchema(const identifier::Schema &schema_identifier)
139
boost::mutex::scoped_lock scopedLock(_mutex);
141
for (table::CacheMap::const_iterator iter= table::getCache().begin();
142
iter != table::getCache().end();
145
table::Concurrent *table= iter->second;
147
if (not schema_identifier.getPath().compare(table->getShare()->getSchemaName()))
149
table->getMutableShare()->resetVersion(); /* Free when thread is ready */
150
if (not table->in_use)
151
table::getUnused().relink(table);
155
table::getUnused().cullByVersion();
159
Mark all entries with the table as deleted to force an reopen of the table
161
The table will be closed (not stored in cache) by the current thread when
162
close_thread_tables() is called.
165
Lock on table::Cache::mutex()()
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
173
bool Cache::removeTable(Session& session, const identifier::Table &identifier, uint32_t flags)
175
const identifier::Table::Key &key(identifier.getKey());
177
bool signalled= false;
181
result= signalled= false;
183
table::CacheRange ppp;
184
ppp= table::getCache().equal_range(key);
186
for (table::CacheMap::const_iterator iter= ppp.first;
187
iter != ppp.second; ++iter)
189
table::Concurrent *table= iter->second;
192
table->getMutableShare()->resetVersion(); /* Free when thread is ready */
193
if (not (in_use= table->in_use))
195
table::getUnused().relink(table);
197
else if (in_use != &session)
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
204
if (table->is_name_opened())
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.
217
for (Table *session_table= in_use->open_tables.open_tables_;
219
session_table= session_table->getNext())
221
/* Do not handle locks of MERGE children. */
222
if (session_table->db_stat) // If table is open
223
signalled|= session.abortLockForThread(session_table);
228
result= result || (flags & RTFC_OWNED_BY_Session_FLAG);
232
table::getUnused().cullByVersion();
234
/* Remove table from table definition cache if it's not in use */
235
table::instance::release(identifier);
237
if (result && (flags & RTFC_WAIT_OTHER_THREAD_FLAG))
240
Signal any thread waiting for tables to be freed to
243
locking::broadcast_refresh();
244
if (not (flags & RTFC_CHECK_KILLED_FLAG) || not session.getKilled())
247
if (likely(signalled))
249
boost::mutex::scoped_lock scoped(table::Cache::mutex(), boost::adopt_lock_t());
250
COND_refresh.wait(scoped);
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.
266
xtime_get(&xt, boost::TIME_UTC);
268
boost::mutex::scoped_lock scoped(table::Cache::mutex(), boost::adopt_lock_t());
269
COND_refresh.timed_wait(scoped, xt);
283
void Cache::insert(table::Concurrent* arg)
285
CacheMap::iterator returnable= cache.insert(std::make_pair(arg->getShare()->getCacheKey(), arg));
286
assert(returnable != cache.end());
289
} /* namespace table */
290
} /* namespace drizzled */