1877.2.6
by Brian Aker
Fixed header/etc. |
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" |
|
1877.2.8
by Brian Aker
Additional encapsulation |
30 |
#include "drizzled/session.h" |
1877.2.6
by Brian Aker
Fixed header/etc. |
31 |
#include "drizzled/table/concurrent.h" |
32 |
||
33 |
#include "drizzled/table/cache.h" |
|
34 |
#include "drizzled/table/unused.h" |
|
35 |
||
1877.2.8
by Brian Aker
Additional encapsulation |
36 |
#include "drizzled/pthread_globals.h" |
37 |
||
1877.2.6
by Brian Aker
Fixed header/etc. |
38 |
namespace drizzled |
39 |
{
|
|
1877.2.8
by Brian Aker
Additional encapsulation |
40 |
|
41 |
class Session; |
|
42 |
||
1877.2.6
by Brian Aker
Fixed header/etc. |
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
|
|
1938.4.10
by Brian Aker
Convert LOCK_open to lock in mutex |
59 |
We need to have a lock on table::Cache::singleton().mutex() when calling this
|
1877.2.6
by Brian Aker
Fixed header/etc. |
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 |
||
1877.2.7
by Brian Aker
Encapsulate more of the table cache. |
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 |
||
1877.2.8
by Brian Aker
Additional encapsulation |
126 |
/*
|
127 |
Invalidate any cache entries that are for some DB
|
|
128 |
||
129 |
SYNOPSIS
|
|
1887.2.5
by Brian Aker
OSX found a reference to a function that was no longer declared. |
130 |
removeSchema()
|
1877.2.8
by Brian Aker
Additional encapsulation |
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 |
{
|
|
1938.4.11
by Brian Aker
Scoped locks a bit better. |
141 |
boost::mutex::scoped_lock scopedLock(_mutex); |
1877.2.8
by Brian Aker
Additional encapsulation |
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
|
|
1938.4.10
by Brian Aker
Convert LOCK_open to lock in mutex |
167 |
Lock on table::Cache::singleton().mutex()()
|
1877.2.8
by Brian Aker
Additional encapsulation |
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
|
|
1910.2.7
by Brian Aker
Rename lock methods to be style + well make sense. |
203 |
force threads that are in lockTables() (but not yet
|
1877.2.8
by Brian Aker
Additional encapsulation |
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.
|
|
1938.4.10
by Brian Aker
Convert LOCK_open to lock in mutex |
214 |
Note that we need to hold table::Cache::singleton().mutex() while going through the
|
1877.2.8
by Brian Aker
Additional encapsulation |
215 |
list. So that the other thread cannot change it. The other
|
1938.4.10
by Brian Aker
Convert LOCK_open to lock in mutex |
216 |
thread must also hold table::Cache::singleton().mutex() whenever changing the
|
1877.2.8
by Brian Aker
Additional encapsulation |
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 |
|
1910.2.7
by Brian Aker
Rename lock methods to be style + well make sense. |
226 |
signalled|= session->abortLockForThread(session_table); |
1877.2.8
by Brian Aker
Additional encapsulation |
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 |
*/
|
|
1910.2.5
by Brian Aker
Merge in changes such that lock is now broken out into its own directory. |
246 |
locking::broadcast_refresh(); |
1910.2.8
by Brian Aker
Enapsulate Kill. |
247 |
if (not (flags & RTFC_CHECK_KILLED_FLAG) || not session->getKilled()) |
1877.2.8
by Brian Aker
Additional encapsulation |
248 |
{
|
249 |
dropping_tables++; |
|
250 |
if (likely(signalled)) |
|
251 |
{
|
|
1938.4.10
by Brian Aker
Convert LOCK_open to lock in mutex |
252 |
boost_unique_lock_t scoped(table::Cache::singleton().mutex(), boost::adopt_lock_t()); |
1877.2.8
by Brian Aker
Additional encapsulation |
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
|
|
1887.2.5
by Brian Aker
OSX found a reference to a function that was no longer declared. |
266 |
table::Cache::singleton().removeTable routine.
|
1877.2.8
by Brian Aker
Additional encapsulation |
267 |
*/
|
268 |
boost::xtime xt; |
|
269 |
xtime_get(&xt, boost::TIME_UTC); |
|
270 |
xt.sec += 10; |
|
1938.4.10
by Brian Aker
Convert LOCK_open to lock in mutex |
271 |
boost_unique_lock_t scoped(table::Cache::singleton().mutex(), boost::adopt_lock_t()); |
1877.2.8
by Brian Aker
Additional encapsulation |
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 |
||
1903.1.1
by Brian Aker
Merge of partial set of patches for locks. |
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 |
||
1877.2.6
by Brian Aker
Fixed header/etc. |
293 |
} /* namespace table */ |
294 |
} /* namespace drizzled */ |