Drizzled Public API Documentation

cache.cc
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  */
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  (void)(returnable);
287  assert(returnable != cache.end());
288 }
289 
290 } /* namespace table */
291 } /* namespace drizzled */
void broadcast_refresh(void)
Definition: global.cc:1112
TODO: Rename this file - func.h is stupid.