~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/sql_base.cc

  • Committer: Brian Aker
  • Date: 2010-10-28 17:12:01 UTC
  • mfrom: (1887.1.3 merge)
  • Revision ID: brian@tangent.org-20101028171201-baj6l1bnntn1s4ad
Merge in POTFILES changes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
55
55
#include "drizzled/plugin/authorization.h"
56
56
#include "drizzled/table/temporary.h"
57
57
#include "drizzled/table/placeholder.h"
 
58
#include "drizzled/table/unused.h"
58
59
 
59
60
using namespace std;
60
61
 
63
64
 
64
65
extern bool volatile shutdown_in_progress;
65
66
 
66
 
TableOpenCache &get_open_cache()
67
 
{
68
 
  static TableOpenCache open_cache;                             /* Used by mysql_test */
69
 
 
70
 
  return open_cache;
71
 
}
72
 
 
73
 
static void free_cache_entry(table::Concurrent *entry);
74
 
 
75
 
void remove_table(table::Concurrent *arg)
76
 
{
77
 
  TableOpenCacheRange ppp;
78
 
  ppp= get_open_cache().equal_range(arg->getShare()->getCacheKey());
79
 
 
80
 
  for (TableOpenCache::const_iterator iter= ppp.first;
81
 
         iter != ppp.second; ++iter)
82
 
  {
83
 
    table::Concurrent *found_table= (*iter).second;
84
 
 
85
 
    if (found_table == arg)
86
 
    {
87
 
      free_cache_entry(arg);
88
 
      get_open_cache().erase(iter);
89
 
      return;
90
 
    }
91
 
  }
92
 
}
93
 
 
94
67
static bool add_table(table::Concurrent *arg)
95
68
{
96
 
  TableOpenCache &open_cache(get_open_cache());
 
69
  table::CacheMap &open_cache(table::getCache());
97
70
 
98
 
  TableOpenCache::iterator returnable= open_cache.insert(make_pair(arg->getShare()->getCacheKey(), arg));
 
71
  table::CacheMap::iterator returnable= open_cache.insert(make_pair(arg->getShare()->getCacheKey(), arg));
99
72
 
100
73
  return not (returnable == open_cache.end());
101
74
}
102
75
 
103
 
class UnusedTables {
104
 
  table::Concurrent *tables;                            /* Used by mysql_test */
105
 
 
106
 
  table::Concurrent *getTable() const
107
 
  {
108
 
    return tables;
109
 
  }
110
 
 
111
 
  table::Concurrent *setTable(Table *arg)
112
 
  {
113
 
    return tables= static_cast<table::Concurrent *>(arg);
114
 
  }
115
 
 
116
 
public:
117
 
 
118
 
  void cull()
119
 
  {
120
 
    /* Free cache if too big */
121
 
    while (cached_open_tables() > table_cache_size && getTable())
122
 
      remove_table(getTable());
123
 
  }
124
 
 
125
 
  void cullByVersion()
126
 
  {
127
 
    while (getTable() && not getTable()->getShare()->getVersion())
128
 
      remove_table(getTable());
129
 
  }
130
 
  
131
 
  void link(table::Concurrent *table)
132
 
  {
133
 
    if (getTable())
134
 
    {
135
 
      table->setNext(getTable());               /* Link in last */
136
 
      table->setPrev(getTable()->getPrev());
137
 
      getTable()->setPrev(table);
138
 
      table->getPrev()->setNext(table);
139
 
    }
140
 
    else
141
 
    {
142
 
      table->setPrev(setTable(table));
143
 
      table->setNext(table->getPrev());
144
 
      assert(table->getNext() == table && table->getPrev() == table);
145
 
    }
146
 
  }
147
 
 
148
 
 
149
 
  void unlink(table::Concurrent *table)
150
 
  {
151
 
    table->unlink();
152
 
 
153
 
    /* Unlink the table from "unused_tables" list. */
154
 
    if (table == getTable())
155
 
    {  // First unused
156
 
      setTable(getTable()->getNext()); // Remove from link
157
 
      if (table == getTable())
158
 
        setTable(NULL);
159
 
    }
160
 
  }
161
 
 
162
 
/* move table first in unused links */
163
 
 
164
 
  void relink(table::Concurrent *table)
165
 
  {
166
 
    if (table != getTable())
167
 
    {
168
 
      table->unlink();
169
 
 
170
 
      table->setNext(getTable());                       /* Link in unused tables */
171
 
      table->setPrev(getTable()->getPrev());
172
 
      getTable()->getPrev()->setNext(table);
173
 
      getTable()->setPrev(table);
174
 
      setTable(table);
175
 
    }
176
 
  }
177
 
 
178
 
 
179
 
  void clear()
180
 
  {
181
 
    while (getTable())
182
 
      remove_table(getTable());
183
 
  }
184
 
 
185
 
  UnusedTables():
186
 
    tables(NULL)
187
 
  { }
188
 
 
189
 
  ~UnusedTables()
190
 
  { 
191
 
  }
192
 
};
193
 
 
194
 
static UnusedTables unused_tables;
195
 
 
196
76
bool table_cache_init(void)
197
77
{
198
78
  return false;
200
80
 
201
81
uint32_t cached_open_tables(void)
202
82
{
203
 
  return get_open_cache().size();
 
83
  return table::getCache().size();
204
84
}
205
85
 
206
86
void table_cache_free(void)
207
87
{
208
88
  refresh_version++;                            // Force close of open tables
209
89
 
210
 
  unused_tables.clear();
211
 
  get_open_cache().clear();
 
90
  table::getUnused().clear();
 
91
  table::getCache().clear();
212
92
}
213
93
 
214
94
/*
266
146
  }
267
147
}
268
148
 
269
 
/*
270
 
  Remove table from the open table cache
271
 
 
272
 
  SYNOPSIS
273
 
  free_cache_entry()
274
 
  entry         Table to remove
275
 
 
276
 
  NOTE
277
 
  We need to have a lock on LOCK_open when calling this
278
 
*/
279
 
 
280
 
void free_cache_entry(table::Concurrent *table)
281
 
{
282
 
  table->intern_close_table();
283
 
  if (not table->in_use)
284
 
  {
285
 
    unused_tables.unlink(table);
286
 
  }
287
 
 
288
 
  delete table;
289
 
}
290
 
 
291
149
/* Free resources allocated by filesort() and read_record() */
292
150
 
293
151
void Table::free_io_cache()
328
186
    {
329
187
      refresh_version++;                                // Force close of open tables
330
188
 
331
 
      unused_tables.clear();
 
189
      table::getUnused().clear();
332
190
 
333
191
      if (wait_for_refresh)
334
192
      {
359
217
          again. There they will wait until we update all tables version
360
218
          below.
361
219
 
362
 
          Setting some_tables_deleted is done by remove_table_from_cache()
 
220
          Setting some_tables_deleted is done by table::Cache::singleton().removeTable()
363
221
          in the other branch.
364
222
 
365
223
          In other words (reviewer suggestion): You need this setting of
369
227
          after the call to Session::close_old_data_files() i.e. after removal of
370
228
          current thread locks.
371
229
        */
372
 
        for (TableOpenCache::const_iterator iter= get_open_cache().begin();
373
 
             iter != get_open_cache().end();
 
230
        for (table::CacheMap::const_iterator iter= table::getCache().begin();
 
231
             iter != table::getCache().end();
374
232
             iter++)
375
233
        {
376
234
          Table *table= (*iter).second;
385
243
      for (TableList *table= tables; table; table= table->next_local)
386
244
      {
387
245
        TableIdentifier identifier(table->getSchemaName(), table->getTableName());
388
 
        if (remove_table_from_cache(session, identifier,
 
246
        if (table::Cache::singleton().removeTable(session, identifier,
389
247
                                    RTFC_OWNED_BY_Session_FLAG))
390
248
        {
391
249
          found= true;
412
270
      while (found && ! session->killed)
413
271
      {
414
272
        found= false;
415
 
        for (TableOpenCache::const_iterator iter= get_open_cache().begin();
416
 
             iter != get_open_cache().end();
 
273
        for (table::CacheMap::const_iterator iter= table::getCache().begin();
 
274
             iter != table::getCache().end();
417
275
             iter++)
418
276
        {
419
277
          Table *table= (*iter).second;
497
355
  if (table->needs_reopen_or_name_lock() ||
498
356
      version != refresh_version || !table->db_stat)
499
357
  {
500
 
    remove_table(table);
 
358
    table::remove_table(table);
501
359
    found_old_table= true;
502
360
  }
503
361
  else
512
370
    table->cursor->ha_reset();
513
371
    table->in_use= false;
514
372
 
515
 
    unused_tables.link(table);
 
373
    table::getUnused().link(table);
516
374
  }
517
375
 
518
376
  return found_old_table;
820
678
  /*
821
679
    Note that we need to hold LOCK_open while changing the
822
680
    open_tables list. Another thread may work on it.
823
 
    (See: remove_table_from_cache(), mysql_wait_completed_table())
 
681
    (See: table::Cache::singleton().removeTable(), mysql_wait_completed_table())
824
682
    Closing a MERGE child before the parent would be fatal if the
825
683
    other thread tries to abort the MERGE lock in between.
826
684
  */
834
692
      *prev= list->getNext();
835
693
 
836
694
      /* Close table. */
837
 
      remove_table(static_cast<table::Concurrent *>(list));
 
695
      table::remove_table(static_cast<table::Concurrent *>(list));
838
696
    }
839
697
    else
840
698
    {
942
800
  case of failure.
943
801
*/
944
802
 
945
 
Table *Session::table_cache_insert_placeholder(const drizzled::TableIdentifier &arg)
 
803
table::Placeholder *Session::table_cache_insert_placeholder(const drizzled::TableIdentifier &arg)
946
804
{
947
805
  safe_mutex_assert_owner(LOCK_open.native_handle());
948
806
 
990
848
 
991
849
  boost_unique_lock_t scope_lock(LOCK_open); /* Obtain a name lock even though table is not in cache (like for create table)  */
992
850
 
993
 
  TableOpenCache::iterator iter;
994
 
 
995
 
  iter= get_open_cache().find(key);
996
 
 
997
 
  if (iter != get_open_cache().end())
 
851
  table::CacheMap::iterator iter;
 
852
 
 
853
  iter= table::getCache().find(key);
 
854
 
 
855
  if (iter != table::getCache().end())
998
856
  {
999
857
    *table= 0;
1000
858
    return false;
1065
923
 
1066
924
  TableIdentifier identifier(table_list->getSchemaName(), table_list->getTableName());
1067
925
  const TableIdentifier::Key &key(identifier.getKey());
1068
 
  TableOpenCacheRange ppp;
 
926
  table::CacheRange ppp;
1069
927
 
1070
928
  /*
1071
929
    Unless requested otherwise, try to resolve this table in the list
1163
1021
        an implicit "pending locks queue" - see
1164
1022
        wait_for_locked_table_names for details.
1165
1023
      */
1166
 
      ppp= get_open_cache().equal_range(key);
 
1024
      ppp= table::getCache().equal_range(key);
1167
1025
 
1168
1026
      table= NULL;
1169
 
      for (TableOpenCache::const_iterator iter= ppp.first;
 
1027
      for (table::CacheMap::const_iterator iter= ppp.first;
1170
1028
           iter != ppp.second; ++iter, table= NULL)
1171
1029
      {
1172
1030
        table= (*iter).second;
1254
1112
      }
1255
1113
      if (table)
1256
1114
      {
1257
 
        unused_tables.unlink(static_cast<table::Concurrent *>(table));
 
1115
        table::getUnused().unlink(static_cast<table::Concurrent *>(table));
1258
1116
        table->in_use= this;
1259
1117
      }
1260
1118
      else
1262
1120
        /* Insert a new Table instance into the open cache */
1263
1121
        int error;
1264
1122
        /* Free cache if too big */
1265
 
        unused_tables.cull();
 
1123
        table::getUnused().cull();
1266
1124
 
1267
1125
        if (table_list->isCreate())
1268
1126
        {
1462
1320
    next= table->getNext();
1463
1321
 
1464
1322
    my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->getAlias());
1465
 
    remove_table(static_cast<table::Concurrent *>(table));
 
1323
    table::remove_table(static_cast<table::Concurrent *>(table));
1466
1324
    error= 1;
1467
1325
  }
1468
1326
  *prev=0;
1588
1446
}
1589
1447
 
1590
1448
 
1591
 
/*
1592
 
  Wait until all threads has closed the tables in the list
1593
 
  We have also to wait if there is thread that has a lock on this table even
1594
 
  if the table is closed
1595
 
*/
1596
 
 
1597
 
bool table_is_used(Table *table, bool wait_for_name_lock)
1598
 
{
1599
 
  do
1600
 
  {
1601
 
    const TableIdentifier::Key &key(table->getShare()->getCacheKey());
1602
 
 
1603
 
    TableOpenCacheRange ppp;
1604
 
    ppp= get_open_cache().equal_range(key);
1605
 
 
1606
 
    for (TableOpenCache::const_iterator iter= ppp.first;
1607
 
         iter != ppp.second; ++iter)
1608
 
    {
1609
 
      Table *search= (*iter).second;
1610
 
      if (search->in_use == table->in_use)
1611
 
        continue;                               // Name locked by this thread
1612
 
      /*
1613
 
        We can't use the table under any of the following conditions:
1614
 
        - There is an name lock on it (Table is to be deleted or altered)
1615
 
        - If we are in flush table and we didn't execute the flush
1616
 
        - If the table engine is open and it's an old version
1617
 
        (We must wait until all engines are shut down to use the table)
1618
 
      */
1619
 
      if ( (search->locked_by_name && wait_for_name_lock) ||
1620
 
           (search->is_name_opened() && search->needs_reopen_or_name_lock()))
1621
 
        return 1;
1622
 
    }
1623
 
  } while ((table=table->getNext()));
1624
 
  return 0;
1625
 
}
1626
 
 
1627
 
 
1628
1449
/* Wait until all used tables are refreshed */
1629
1450
 
1630
1451
bool wait_for_tables(Session *session)
1638
1459
    {
1639
1460
      session->some_tables_deleted= false;
1640
1461
      session->close_old_data_files(false, dropping_tables != 0);
1641
 
      if (!table_is_used(session->open_tables, 1))
 
1462
      if (not table::Cache::singleton().areTablesUsed(session->open_tables, 1))
 
1463
      {
1642
1464
        break;
 
1465
      }
1643
1466
      COND_refresh.wait(lock);
1644
1467
    }
1645
1468
    if (session->killed)
1690
1513
  /*
1691
1514
    Note that we need to hold LOCK_open while changing the
1692
1515
    open_tables list. Another thread may work on it.
1693
 
    (See: remove_table_from_cache(), mysql_wait_completed_table())
 
1516
    (See: table::Cache::singleton().removeTable(), mysql_wait_completed_table())
1694
1517
    Closing a MERGE child before the parent would be fatal if the
1695
1518
    other thread tries to abort the MERGE lock in between.
1696
1519
  */
1714
1537
      else
1715
1538
      {
1716
1539
        /* We already have a name lock, remove copy */
1717
 
        remove_table(static_cast<table::Concurrent *>(table));
 
1540
        table::remove_table(static_cast<table::Concurrent *>(table));
1718
1541
      }
1719
1542
    }
1720
1543
    else
4146
3969
  unireg support functions
4147
3970
 *****************************************************************************/
4148
3971
 
4149
 
/*
4150
 
  Invalidate any cache entries that are for some DB
4151
 
 
4152
 
  SYNOPSIS
4153
 
  remove_db_from_cache()
4154
 
  db            Database name. This will be in lower case if
4155
 
  lower_case_table_name is set
4156
 
 
4157
 
NOTE:
4158
 
We can't use hash_delete when looping hash_elements. We mark them first
4159
 
and afterwards delete those marked unused.
4160
 
*/
4161
 
 
4162
 
void remove_db_from_cache(const SchemaIdentifier &schema_identifier)
4163
 
{
4164
 
  safe_mutex_assert_owner(LOCK_open.native_handle());
4165
 
 
4166
 
  for (TableOpenCache::const_iterator iter= get_open_cache().begin();
4167
 
       iter != get_open_cache().end();
4168
 
       iter++)
4169
 
  {
4170
 
    table::Concurrent *table= (*iter).second;
4171
 
 
4172
 
    if (not schema_identifier.getPath().compare(table->getShare()->getSchemaName()))
4173
 
    {
4174
 
      table->getMutableShare()->resetVersion();                 /* Free when thread is ready */
4175
 
      if (not table->in_use)
4176
 
        unused_tables.relink(table);
4177
 
    }
4178
 
  }
4179
 
 
4180
 
  unused_tables.cullByVersion();
4181
 
}
4182
 
 
4183
 
 
4184
 
/*
4185
 
  Mark all entries with the table as deleted to force an reopen of the table
4186
 
 
4187
 
  The table will be closed (not stored in cache) by the current thread when
4188
 
  close_thread_tables() is called.
4189
 
 
4190
 
  PREREQUISITES
4191
 
  Lock on LOCK_open()
4192
 
 
4193
 
  RETURN
4194
 
  0  This thread now have exclusive access to this table and no other thread
4195
 
  can access the table until close_thread_tables() is called.
4196
 
  1  Table is in use by another thread
4197
 
*/
4198
 
 
4199
 
bool remove_table_from_cache(Session *session, TableIdentifier &identifier, uint32_t flags)
4200
 
{
4201
 
  const TableIdentifier::Key &key(identifier.getKey());
4202
 
  bool result= false; 
4203
 
  bool signalled= false;
4204
 
 
4205
 
  for (;;)
4206
 
  {
4207
 
    result= signalled= false;
4208
 
 
4209
 
    TableOpenCacheRange ppp;
4210
 
    ppp= get_open_cache().equal_range(key);
4211
 
 
4212
 
    for (TableOpenCache::const_iterator iter= ppp.first;
4213
 
         iter != ppp.second; ++iter)
4214
 
    {
4215
 
      table::Concurrent *table= (*iter).second;
4216
 
      Session *in_use;
4217
 
 
4218
 
      table->getMutableShare()->resetVersion();         /* Free when thread is ready */
4219
 
      if (not (in_use= table->in_use))
4220
 
      {
4221
 
        unused_tables.relink(table);
4222
 
      }
4223
 
      else if (in_use != session)
4224
 
      {
4225
 
        /*
4226
 
          Mark that table is going to be deleted from cache. This will
4227
 
          force threads that are in mysql_lock_tables() (but not yet
4228
 
          in thr_multi_lock()) to abort it's locks, close all tables and retry
4229
 
        */
4230
 
        in_use->some_tables_deleted= true;
4231
 
        if (table->is_name_opened())
4232
 
        {
4233
 
          result= true;
4234
 
        }
4235
 
        /*
4236
 
          Now we must abort all tables locks used by this thread
4237
 
          as the thread may be waiting to get a lock for another table.
4238
 
          Note that we need to hold LOCK_open while going through the
4239
 
          list. So that the other thread cannot change it. The other
4240
 
          thread must also hold LOCK_open whenever changing the
4241
 
          open_tables list. Aborting the MERGE lock after a child was
4242
 
          closed and before the parent is closed would be fatal.
4243
 
        */
4244
 
        for (Table *session_table= in_use->open_tables;
4245
 
             session_table ;
4246
 
             session_table= session_table->getNext())
4247
 
        {
4248
 
          /* Do not handle locks of MERGE children. */
4249
 
          if (session_table->db_stat)   // If table is open
4250
 
            signalled|= mysql_lock_abort_for_thread(session, session_table);
4251
 
        }
4252
 
      }
4253
 
      else
4254
 
      {
4255
 
        result= result || (flags & RTFC_OWNED_BY_Session_FLAG);
4256
 
      }
4257
 
    }
4258
 
 
4259
 
    unused_tables.cullByVersion();
4260
 
 
4261
 
    /* Remove table from table definition cache if it's not in use */
4262
 
    TableShare::release(identifier);
4263
 
 
4264
 
    if (result && (flags & RTFC_WAIT_OTHER_THREAD_FLAG))
4265
 
    {
4266
 
      /*
4267
 
        Signal any thread waiting for tables to be freed to
4268
 
        reopen their tables
4269
 
      */
4270
 
      broadcast_refresh();
4271
 
      if (!(flags & RTFC_CHECK_KILLED_FLAG) || !session->killed)
4272
 
      {
4273
 
        dropping_tables++;
4274
 
        if (likely(signalled))
4275
 
        {
4276
 
          boost_unique_lock_t scoped(LOCK_open, boost::adopt_lock_t());
4277
 
          COND_refresh.wait(scoped);
4278
 
          scoped.release();
4279
 
        }
4280
 
        else
4281
 
        {
4282
 
          /*
4283
 
            It can happen that another thread has opened the
4284
 
            table but has not yet locked any table at all. Since
4285
 
            it can be locked waiting for a table that our thread
4286
 
            has done LOCK Table x WRITE on previously, we need to
4287
 
            ensure that the thread actually hears our signal
4288
 
            before we go to sleep. Thus we wait for a short time
4289
 
            and then we retry another loop in the
4290
 
            remove_table_from_cache routine.
4291
 
          */
4292
 
          boost::xtime xt; 
4293
 
          xtime_get(&xt, boost::TIME_UTC); 
4294
 
          xt.sec += 10; 
4295
 
          boost_unique_lock_t scoped(LOCK_open, boost::adopt_lock_t());
4296
 
          COND_refresh.timed_wait(scoped, xt);
4297
 
          scoped.release();
4298
 
        }
4299
 
        dropping_tables--;
4300
 
        continue;
4301
 
      }
4302
 
    }
4303
 
    break;
4304
 
  }
4305
 
 
4306
 
  return result;
4307
 
}
 
3972
 
4308
3973
 
4309
3974
 
4310
3975
/**