~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/locking/global.cc

  • Committer: Brian Aker
  • Date: 2010-11-26 22:40:33 UTC
  • mto: This revision was merged to the branch mainline in revision 1958.
  • Revision ID: brian@tangent.org-20101126224033-yt9a3o82w2rhaihp
Adding select for update test with flush locks engaged.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* 
2
 
    Copyright (C) 2011 Brian Aker
3
 
    Copyright (C) 2000-2006 MySQL AB
 
1
/* Copyright (C) 2000-2006 MySQL AB
4
2
 
5
3
   This program is free software; you can redistribute it and/or modify
6
4
   it under the terms of the GNU General Public License as published by
19
17
/**
20
18
  @file
21
19
 
22
 
  @note this is out of date, just for historical reference 
23
 
 
24
 
  Locking functions for drizzled.
 
20
  Locking functions for mysql.
25
21
 
26
22
  Because of the new concurrent inserts, we must first get external locks
27
23
  before getting internal locks.  If we do it in the other order, the status
34
30
  - For each SQL statement lockTables() is called for all involved
35
31
    tables.
36
32
    - lockTables() will call
37
 
      cursor->external_lock(session,locktype) for each table.
 
33
      table_handler->external_lock(session,locktype) for each table.
38
34
      This is followed by a call to thr_multi_lock() for all tables.
39
35
 
40
36
  - When statement is done, we call unlockTables().
76
72
  Change to use malloc() ONLY when using LOCK TABLES command or when
77
73
  we are forced to use mysql_lock_merge.
78
74
*/
79
 
#include <config.h>
80
 
 
 
75
#include "config.h"
81
76
#include <fcntl.h>
82
 
 
83
77
#include <drizzled/error.h>
84
78
#include <drizzled/my_hash.h>
85
79
#include <drizzled/thr_lock.h>
86
80
#include <drizzled/session.h>
87
81
#include <drizzled/sql_base.h>
88
82
#include <drizzled/lock.h>
89
 
#include <drizzled/pthread_globals.h>
90
 
#include <drizzled/internal/my_sys.h>
91
 
#include <drizzled/pthread_globals.h>
92
 
#include <drizzled/refresh_version.h>
93
 
#include <drizzled/plugin/storage_engine.h>
 
83
#include "drizzled/pthread_globals.h"
 
84
#include "drizzled/internal/my_sys.h"
 
85
#include "drizzled/pthread_globals.h"
94
86
 
95
87
#include <set>
96
88
#include <vector>
130
122
                                              lockTables() should
131
123
                                              notify upper level and rely
132
124
                                              on caller doing this.
 
125
    need_reopen                 Out parameter, TRUE if some tables were altered
 
126
                                or deleted and should be reopened by caller.
133
127
 
134
128
  RETURN
135
129
    A lock structure pointer on success.
137
131
*/
138
132
 
139
133
/* Map the return value of thr_lock to an error from errmsg.txt */
140
 
static drizzled::error_t thr_lock_errno_to_mysql[]=
141
 
{ EE_OK, EE_ERROR_FIRST, ER_LOCK_WAIT_TIMEOUT, ER_LOCK_DEADLOCK };
 
134
static int thr_lock_errno_to_mysql[]=
 
135
{ 0, 1, ER_LOCK_WAIT_TIMEOUT, ER_LOCK_DEADLOCK };
142
136
 
143
137
 
144
138
/**
169
163
  *mysql_lock= 0;
170
164
}
171
165
 
172
 
DrizzleLock *Session::lockTables(Table **tables, uint32_t count, uint32_t flags)
 
166
void DrizzleLock::reset(void)
 
167
{
 
168
  for (std::vector<THR_LOCK_DATA *>::iterator iter= locks.begin(); iter != locks.end(); iter++)
 
169
  {
 
170
    (*iter)->type= TL_UNLOCK;
 
171
  }
 
172
}
 
173
 
 
174
 
 
175
DrizzleLock *Session::lockTables(Table **tables, uint32_t count, uint32_t flags, bool *need_reopen)
173
176
{
174
177
  DrizzleLock *sql_lock;
175
178
  Table *write_lock_used;
176
179
  vector<plugin::StorageEngine *> involved_engines;
177
 
 
178
 
  do
 
180
  int rc;
 
181
 
 
182
  *need_reopen= false;
 
183
 
 
184
  for (;;)
179
185
  {
180
 
    if (! (sql_lock= get_lock_data(tables, count, true, &write_lock_used)))
 
186
    if (! (sql_lock= get_lock_data(tables, count, true,
 
187
                                   &write_lock_used)))
181
188
      break;
182
189
 
183
 
    if (global_read_lock && write_lock_used and (not (flags & DRIZZLE_LOCK_IGNORE_GLOBAL_READ_LOCK)))
 
190
    if (global_read_lock && write_lock_used &&
 
191
        ! (flags & DRIZZLE_LOCK_IGNORE_GLOBAL_READ_LOCK))
184
192
    {
185
193
      /*
186
194
        Someone has issued LOCK ALL TABLES FOR READ and we want a write lock
192
200
        reset_lock_data_and_free(&sql_lock);
193
201
        break;
194
202
      }
195
 
 
196
203
      if (version != refresh_version)
197
204
      {
198
205
        /* Clear the lock type of all lock data to avoid reusage. */
199
206
        reset_lock_data_and_free(&sql_lock);
200
 
        break;
 
207
        goto retry;
201
208
      }
202
209
    }
203
210
    
210
217
    {
211
218
      size_t num_tables= sql_lock->sizeTable();
212
219
      plugin::StorageEngine *engine;
213
 
      std::set<size_t> involved_slots;
214
 
 
 
220
      set<size_t> involved_slots;
215
221
      for (size_t x= 1; x <= num_tables; x++, tables++)
216
222
      {
217
223
        engine= (*tables)->cursor->getEngine();
218
 
 
219
224
        if (involved_slots.count(engine->getId()) > 0)
220
225
          continue; /* already added to involved engines */
221
 
 
222
226
        involved_engines.push_back(engine);
223
227
        involved_slots.insert(engine->getId());
224
228
      }
246
250
    memcpy(sql_lock->getLocks() + sql_lock->sizeLock(),
247
251
           sql_lock->getLocks(),
248
252
           sql_lock->sizeLock() * sizeof(*sql_lock->getLocks()));
249
 
 
250
253
    /* Lock on the copied half of the lock data array. */
251
 
    drizzled::error_t rc;
252
 
    rc= thr_lock_errno_to_mysql[(int) thr_multi_lock(*this,
253
 
                                                     sql_lock->getLocks() +
 
254
    rc= thr_lock_errno_to_mysql[(int) thr_multi_lock(sql_lock->getLocks() +
254
255
                                                     sql_lock->sizeLock(),
255
256
                                                     sql_lock->sizeLock(),
256
257
                                                     this->lock_id)];
257
 
    if (rc)                                 /* a timeout or a deadlock */
 
258
    if (rc > 1)                                 /* a timeout or a deadlock */
258
259
    {
259
260
      if (sql_lock->sizeTable())
260
261
        unlock_external(sql_lock->getTable(), sql_lock->sizeTable());
261
262
      reset_lock_data_and_free(&sql_lock);
262
263
      my_error(rc, MYF(0));
263
 
    }
264
 
  } while(0);
 
264
      break;
 
265
    }
 
266
    else if (rc == 1)                           /* aborted */
 
267
    {
 
268
      some_tables_deleted= true;                // Try again
 
269
      sql_lock->setLock(0);                  // Locks are already freed
 
270
      // Fall through: unlock, reset lock data, free and retry
 
271
    }
 
272
    else if (not some_tables_deleted || (flags & DRIZZLE_LOCK_IGNORE_FLUSH))
 
273
    {
 
274
      /*
 
275
        Thread was killed or lock aborted. Let upper level close all
 
276
        used tables and retry or give error.
 
277
      */
 
278
      break;
 
279
    }
 
280
    else if (not open_tables)
 
281
    {
 
282
      // Only using temporary tables, no need to unlock
 
283
      some_tables_deleted= false;
 
284
      break;
 
285
    }
 
286
    set_proc_info(0);
 
287
 
 
288
    /* going to retry, unlock all tables */
 
289
    if (sql_lock->sizeLock())
 
290
        sql_lock->unlock(sql_lock->sizeLock());
 
291
 
 
292
    if (sql_lock->sizeTable())
 
293
      unlock_external(sql_lock->getTable(), sql_lock->sizeTable());
 
294
 
 
295
    /*
 
296
      If thr_multi_lock fails it resets lock type for tables, which
 
297
      were locked before (and including) one that caused error. Lock
 
298
      type for other tables preserved.
 
299
    */
 
300
    reset_lock_data_and_free(&sql_lock);
 
301
 
 
302
    /*
 
303
     * Notify all involved engines that the
 
304
     * SQL statement has ended
 
305
     */
 
306
    for_each(involved_engines.begin(),
 
307
             involved_engines.end(),
 
308
             bind2nd(mem_fun(&plugin::StorageEngine::endStatement), this));
 
309
retry:
 
310
    if (flags & DRIZZLE_LOCK_NOTIFY_IF_NEED_REOPEN)
 
311
    {
 
312
      *need_reopen= true;
 
313
      break;
 
314
    }
 
315
 
 
316
    if (wait_for_tables(this))
 
317
    {
 
318
      break;                                    // Couldn't open tables
 
319
    }
 
320
  }
265
321
 
266
322
  set_proc_info(0);
267
323
  if (getKilled())
273
329
      sql_lock= NULL;
274
330
    }
275
331
  }
276
 
 
277
332
  set_time_after_lock();
278
 
 
279
333
  return (sql_lock);
280
334
}
281
335
 
620
674
 
621
675
int Session::lock_table_name(TableList *table_list)
622
676
{
623
 
  identifier::Table identifier(table_list->getSchemaName(), table_list->getTableName());
624
 
  const identifier::Table::Key &key(identifier.getKey());
 
677
  TableIdentifier identifier(table_list->getSchemaName(), table_list->getTableName());
 
678
  const TableIdentifier::Key &key(identifier.getKey());
625
679
 
626
680
  {
627
681
    /* Only insert the table if we haven't insert it already */
828
882
 
829
883
static void print_lock_error(int error, const char *table)
830
884
{
831
 
  drizzled::error_t textno;
 
885
  int textno;
832
886
 
833
887
  switch (error) {
834
888
  case HA_ERR_LOCK_WAIT_TIMEOUT:
976
1030
{
977
1031
  uint32_t tmp;
978
1032
 
979
 
  if (not isGlobalReadLock()) // If we have no personal stake in the global lock, just return
980
 
    return;
981
 
 
982
1033
  {
983
1034
    boost_unique_lock_t scopedLock(LOCK_global_read_lock);
984
1035
    tmp= --global_read_lock;
1041
1092
    if (getKilled())
1042
1093
      result=1;
1043
1094
  }
1044
 
 
1045
1095
  if (not abort_on_refresh && not result)
1046
1096
    protect_against_global_read_lock++;
1047
1097