~drizzle-trunk/drizzle/development

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
2173.2.1 by Monty Taylor
Fixes incorrect usage of include
21
#include <config.h>
2275.3.2 by Olaf van der Spek
Session Cache
22
#include <drizzled/table/cache.h>
1877.2.6 by Brian Aker
Fixed header/etc.
23
24
#include <sys/types.h>
25
#include <sys/stat.h>
26
#include <fcntl.h>
27
2318.6.116 by Olaf van der Spek
Add copyright
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>
1877.2.8 by Brian Aker
Additional encapsulation
37
2241.2.14 by Olaf van der Spek
Refactor
38
namespace drizzled {
39
namespace table {
1877.2.6 by Brian Aker
Fixed header/etc.
40
2272.1.3 by Olaf van der Spek
Table Cache
41
CacheMap Cache::cache;
42
boost::mutex Cache::_mutex;
43
44
CacheMap& getCache()
1877.2.6 by Brian Aker
Fixed header/etc.
45
{
2275.3.1 by Olaf van der Spek
Remove table::Cache::singleton()
46
  return Cache::getCache();
1877.2.6 by Brian Aker
Fixed header/etc.
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
2275.3.1 by Olaf van der Spek
Remove table::Cache::singleton()
57
  We need to have a lock on table::Cache::mutex() when calling this
1877.2.6 by Brian Aker
Fixed header/etc.
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
2069.4.1 by Brian Aker
A little on the paranoid side, but not the worst plan ever to check our
68
  boost::checked_delete(table);
1877.2.6 by Brian Aker
Fixed header/etc.
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
  {
2192.4.7 by Olaf van der Spek
Use "iter->" instead of "(*iter)."
79
    table::Concurrent *found_table= iter->second;
1877.2.6 by Brian Aker
Fixed header/etc.
80
81
    if (found_table == arg)
82
    {
83
      free_cache_entry(arg);
84
      getCache().erase(iter);
85
      return;
86
    }
87
  }
88
}
89
1877.2.7 by Brian Aker
Encapsulate more of the table cache.
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
  {
2087.4.2 by Brian Aker
Modify TableIdentifier to fit with the rest of the identifiers.
100
    const identifier::Table::Key &key(table->getShare()->getCacheKey());
1877.2.7 by Brian Aker
Encapsulate more of the table cache.
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
    {
2192.4.7 by Olaf van der Spek
Use "iter->" instead of "(*iter)."
106
      Table *search= iter->second;
1877.2.7 by Brian Aker
Encapsulate more of the table cache.
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
1877.2.8 by Brian Aker
Additional encapsulation
124
/*
125
  Invalidate any cache entries that are for some DB
126
127
  SYNOPSIS
1887.2.5 by Brian Aker
OSX found a reference to a function that was no longer declared.
128
  removeSchema()
1877.2.8 by Brian Aker
Additional encapsulation
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
2087.4.1 by Brian Aker
Merge in schema identifier.
137
void Cache::removeSchema(const identifier::Schema &schema_identifier)
1877.2.8 by Brian Aker
Additional encapsulation
138
{
1938.4.11 by Brian Aker
Scoped locks a bit better.
139
  boost::mutex::scoped_lock scopedLock(_mutex);
1877.2.8 by Brian Aker
Additional encapsulation
140
141
  for (table::CacheMap::const_iterator iter= table::getCache().begin();
142
       iter != table::getCache().end();
143
       iter++)
144
  {
2192.4.7 by Olaf van der Spek
Use "iter->" instead of "(*iter)."
145
    table::Concurrent *table= iter->second;
1877.2.8 by Brian Aker
Additional encapsulation
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
2275.3.1 by Olaf van der Spek
Remove table::Cache::singleton()
165
  Lock on table::Cache::mutex()()
1877.2.8 by Brian Aker
Additional encapsulation
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
2272.1.2 by Olaf van der Spek
Table Cache
173
bool Cache::removeTable(Session& session, const identifier::Table &identifier, uint32_t flags)
1877.2.8 by Brian Aker
Additional encapsulation
174
{
2087.4.2 by Brian Aker
Modify TableIdentifier to fit with the rest of the identifiers.
175
  const identifier::Table::Key &key(identifier.getKey());
2227.4.3 by Olaf van der Spek
Remove unnecessary statement.h include
176
  bool result= false;
1877.2.8 by Brian Aker
Additional encapsulation
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
    {
2192.4.7 by Olaf van der Spek
Use "iter->" instead of "(*iter)."
189
      table::Concurrent *table= iter->second;
1877.2.8 by Brian Aker
Additional encapsulation
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
      }
2272.1.2 by Olaf van der Spek
Table Cache
197
      else if (in_use != &session)
1877.2.8 by Brian Aker
Additional encapsulation
198
      {
199
        /*
200
          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.
201
          force threads that are in lockTables() (but not yet
1877.2.8 by Brian Aker
Additional encapsulation
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.
2275.3.1 by Olaf van der Spek
Remove table::Cache::singleton()
211
          Note that we need to hold table::Cache::mutex() while going through the
1877.2.8 by Brian Aker
Additional encapsulation
212
          list. So that the other thread cannot change it. The other
2275.3.1 by Olaf van der Spek
Remove table::Cache::singleton()
213
          thread must also hold table::Cache::mutex() whenever changing the
1877.2.8 by Brian Aker
Additional encapsulation
214
          open_tables list. Aborting the MERGE lock after a child was
215
          closed and before the parent is closed would be fatal.
216
        */
2263.3.3 by Olaf van der Spek
Use open_tables
217
        for (Table *session_table= in_use->open_tables.open_tables_;
1877.2.8 by Brian Aker
Additional encapsulation
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
2272.1.2 by Olaf van der Spek
Table Cache
223
            signalled|= session.abortLockForThread(session_table);
1877.2.8 by Brian Aker
Additional encapsulation
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 */
2069.4.4 by Brian Aker
Create a shared form of the instance which is a bit more heavier weight then
235
    table::instance::release(identifier);
1877.2.8 by Brian Aker
Additional encapsulation
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
      */
1910.2.5 by Brian Aker
Merge in changes such that lock is now broken out into its own directory.
243
      locking::broadcast_refresh();
2272.1.2 by Olaf van der Spek
Table Cache
244
      if (not (flags & RTFC_CHECK_KILLED_FLAG) || not session.getKilled())
1877.2.8 by Brian Aker
Additional encapsulation
245
      {
246
        dropping_tables++;
247
        if (likely(signalled))
248
        {
2275.3.4 by Olaf van der Spek
Thread
249
          boost::mutex::scoped_lock scoped(table::Cache::mutex(), boost::adopt_lock_t());
1877.2.8 by Brian Aker
Additional encapsulation
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
2275.3.1 by Olaf van der Spek
Remove table::Cache::singleton()
263
            table::Cache::removeTable routine.
1877.2.8 by Brian Aker
Additional encapsulation
264
          */
2227.4.3 by Olaf van der Spek
Remove unnecessary statement.h include
265
          boost::xtime xt;
266
          xtime_get(&xt, boost::TIME_UTC);
267
          xt.sec += 10;
2275.3.4 by Olaf van der Spek
Thread
268
          boost::mutex::scoped_lock scoped(table::Cache::mutex(), boost::adopt_lock_t());
1877.2.8 by Brian Aker
Additional encapsulation
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
1903.1.1 by Brian Aker
Merge of partial set of patches for locks.
282
2263.3.12 by Olaf van der Spek
Refactor constant return
283
void Cache::insert(table::Concurrent* arg)
1903.1.1 by Brian Aker
Merge of partial set of patches for locks.
284
{
285
  CacheMap::iterator returnable= cache.insert(std::make_pair(arg->getShare()->getCacheKey(), arg));
2241.3.12 by Olaf van der Spek
Refactor Session
286
	assert(returnable != cache.end());
1903.1.1 by Brian Aker
Merge of partial set of patches for locks.
287
}
288
1877.2.6 by Brian Aker
Fixed header/etc.
289
} /* namespace table */
290
} /* namespace drizzled */