~drizzle-trunk/drizzle/development

1 by brian
clean slate
1
/* Copyright (C) 2000 MySQL AB
2
3
   This program is free software; you can redistribute it and/or modify
4
   it under the terms of the GNU General Public License as published by
5
   the Free Software Foundation; version 2 of the License.
6
7
   This program is distributed in the hope that it will be useful,
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
   GNU General Public License for more details.
11
12
   You should have received a copy of the GNU General Public License
13
   along with this program; if not, write to the Free Software
1802.10.2 by Monty Taylor
Update all of the copyright headers to include the correct address.
14
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
1 by brian
clean slate
15
16
/*
17
Read and write locks for Posix threads. All tread must acquire
18
all locks it needs through thr_multi_lock() to avoid dead-locks.
19
A lock consists of a master lock (THR_LOCK), and lock instances
20
(THR_LOCK_DATA).
21
Any thread can have any number of lock instances (read and write:s) on
22
any lock. All lock instances must be freed.
23
Locks are prioritized according to:
24
25
The current lock types are:
26
27
TL_READ	 		# Low priority read
28
TL_READ_WITH_SHARED_LOCKS
29
TL_READ_NO_INSERT	# Read without concurrent inserts
30
TL_WRITE_ALLOW_WRITE	# Write lock that allows other writers
31
TL_WRITE_ALLOW_READ	# Write lock, but allow reading
32
TL_WRITE_CONCURRENT_INSERT
33
			# Insert that can be mixed when selects
34
TL_WRITE		# High priority write
35
TL_WRITE_ONLY		# High priority write
36
			# Abort all new lock request with an error
37
38
Locks are prioritized according to:
39
40
WRITE_ALLOW_WRITE, WRITE_ALLOW_READ, WRITE_CONCURRENT_INSERT, WRITE_DELAYED,
41
WRITE_LOW_PRIORITY, READ, WRITE, READ_HIGH_PRIORITY and WRITE_ONLY
42
43
Locks in the same privilege level are scheduled in first-in-first-out order.
44
45
To allow concurrent read/writes locks, with 'WRITE_CONCURRENT_INSERT' one
46
should put a pointer to the following functions in the lock structure:
47
(If the pointer is zero (default), the function is not called)
48
49
50
The lock algorithm allows one to have one TL_WRITE_ALLOW_READ,
1008.1.1 by Brian Aker
Remove dead lock code around delayed INSERT.
51
TL_WRITE_CONCURRENT_INSERT lock at the same time as multiple read locks.
1 by brian
clean slate
52
53
*/
54
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
55
#include "config.h"
56
#include "drizzled/internal/my_sys.h"
1689.2.10 by Brian Aker
Move thread_var out to its own include file.
57
#include "drizzled/internal/thread_var.h"
1537.2.1 by Joe Daly
add statistics_variables.h
58
#include "drizzled/statistics_variables.h"
1812.3.7 by Brian Aker
Typdef our lock type.
59
#include "drizzled/pthread_globals.h"
1 by brian
clean slate
60
1775.4.4 by Brian Aker
Cleanup my_thread_var usage.
61
#include "drizzled/session.h"
62
1 by brian
clean slate
63
#include "thr_lock.h"
1241.9.64 by Monty Taylor
Moved remaining non-public portions of mysys and mystrings to drizzled/internal.
64
#include "drizzled/internal/m_string.h"
1 by brian
clean slate
65
#include <errno.h>
916.1.9 by Padraig O'Sullivan
Removing an instance of the custom list structure from thr_lock.
66
#include <list>
1 by brian
clean slate
67
481.1.15 by Monty Taylor
Removed time.h and sys/time.h from global.h.
68
#if TIME_WITH_SYS_TIME
69
# include <sys/time.h>
70
# include <time.h>
71
#else
72
# if HAVE_SYS_TIME_H
73
#  include <sys/time.h>
74
# else
75
#  include <time.h>
76
# endif
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
77
#endif
481.1.15 by Monty Taylor
Removed time.h and sys/time.h from global.h.
78
492.1.7 by Monty Taylor
Moved test() to its own file.
79
#include <drizzled/util/test.h>
481.1.15 by Monty Taylor
Removed time.h and sys/time.h from global.h.
80
1798.3.7 by Brian Aker
This allows us to use boost for the condition wait (though really.. not
81
#include <boost/interprocess/sync/lock_options.hpp>
82
916.1.9 by Padraig O'Sullivan
Removing an instance of the custom list structure from thr_lock.
83
using namespace std;
84
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
85
namespace drizzled
86
{
87
622.1.1 by Brian Aker
32bit fixes around vars
88
uint64_t table_lock_wait_timeout;
1165.1.90 by Stewart Smith
make thr_upgraded_concurrent_insert_lock static to mysys/thr_lock.cc
89
static enum thr_lock_type thr_upgraded_concurrent_insert_lock = TL_WRITE;
1 by brian
clean slate
90
91
1813.2.9 by Monty Taylor
Made data_home be fs::path natively.
92
uint64_t max_write_lock_count= UINT64_MAX;
1 by brian
clean slate
93
1948.2.1 by Brian Aker
Fix for 680028, crash on SELECT FOR UPDATE afer FLUSH TABLES WITH READ LOCKS
94
void thr_multi_unlock(THR_LOCK_DATA **data,uint32_t count);
1859.2.4 by Brian Aker
A few cleanups.
95
1 by brian
clean slate
96
/*
97
** For the future (now the thread specific cond is alloced by my_pthread.c)
98
*/
99
146 by Brian Aker
my_bool cleanup.
100
static inline bool
1 by brian
clean slate
101
thr_lock_owner_equal(THR_LOCK_OWNER *rhs, THR_LOCK_OWNER *lhs)
102
{
103
  return rhs == lhs;
104
}
105
106
107
	/* Initialize a lock */
108
109
void thr_lock_init(THR_LOCK *lock)
110
{
1689.2.11 by Brian Aker
Encapsulate more of the thr lock.
111
  lock->init();
1 by brian
clean slate
112
  lock->read.last= &lock->read.data;
113
  lock->read_wait.last= &lock->read_wait.data;
114
  lock->write_wait.last= &lock->write_wait.data;
115
  lock->write.last= &lock->write.data;
116
}
117
118
1689.2.12 by Brian Aker
THR_LOCK_INFO::init() <-- encapsulation
119
void THR_LOCK_INFO::init()
1 by brian
clean slate
120
{
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
121
  internal::st_my_thread_var *tmp= my_thread_var;
1689.2.12 by Brian Aker
THR_LOCK_INFO::init() <-- encapsulation
122
  thread_id= tmp->id;
123
  n_cursors= 0;
1 by brian
clean slate
124
}
125
126
	/* Initialize a lock instance */
127
1689.2.13 by Brian Aker
More encapsulation of thr_lock
128
void THR_LOCK_DATA::init(THR_LOCK *lock_arg, void *param_arg)
1 by brian
clean slate
129
{
1689.2.13 by Brian Aker
More encapsulation of thr_lock
130
  lock= lock_arg;
131
  type= TL_UNLOCK;
132
  owner= NULL;                               /* no owner yet */
133
  status_param= param_arg;
134
  cond= NULL;
1 by brian
clean slate
135
}
136
137
146 by Brian Aker
my_bool cleanup.
138
static inline bool
1 by brian
clean slate
139
have_old_read_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner)
140
{
141
  for ( ; data ; data=data->next)
142
  {
143
    if (thr_lock_owner_equal(data->owner, owner))
1054.1.4 by Brian Aker
Formatting.
144
      return true;					/* Already locked by thread */
1 by brian
clean slate
145
  }
1054.1.4 by Brian Aker
Formatting.
146
  return false;
1 by brian
clean slate
147
}
148
149
static void wake_up_waiters(THR_LOCK *lock);
150
151
1960.1.1 by Brian Aker
Remove dead code in wait, pass session.
152
static enum enum_thr_lock_result wait_for_lock(Session &session, struct st_lock_list *wait, THR_LOCK_DATA *data)
1 by brian
clean slate
153
{
1960.1.1 by Brian Aker
Remove dead code in wait, pass session.
154
  internal::st_my_thread_var *thread_var= session.getThreadVar();
1775.4.4 by Brian Aker
Cleanup my_thread_var usage.
155
1812.3.5 by Brian Aker
Move to boost condition_any
156
  boost::condition_variable_any *cond= &thread_var->suspend;
1 by brian
clean slate
157
  enum enum_thr_lock_result result= THR_LOCK_ABORTED;
146 by Brian Aker
my_bool cleanup.
158
  bool can_deadlock= test(data->owner->info->n_cursors);
1 by brian
clean slate
159
160
  {
161
    (*wait->last)=data;				/* Wait for lock */
162
    data->prev= wait->last;
163
    wait->last= &data->next;
164
  }
165
1689.5.1 by Joseph Daly
remove increment calls
166
  current_global_counters.locks_waited++;
1 by brian
clean slate
167
168
  /* Set up control struct to allow others to abort locks */
1689.2.11 by Brian Aker
Encapsulate more of the thr lock.
169
  thread_var->current_mutex= data->lock->native_handle();
1786.2.1 by Brian Aker
Current boost work (more conversion).
170
  thread_var->current_cond=  &thread_var->suspend;
171
  data->cond= &thread_var->suspend;;
1 by brian
clean slate
172
1960.1.1 by Brian Aker
Remove dead code in wait, pass session.
173
  while (not thread_var->abort)
1 by brian
clean slate
174
  {
1812.3.7 by Brian Aker
Typdef our lock type.
175
    boost_unique_lock_t scoped(*data->lock->native_handle(), boost::adopt_lock_t());
1798.3.7 by Brian Aker
This allows us to use boost for the condition wait (though really.. not
176
177
    if (can_deadlock)
178
    {
179
      boost::xtime xt; 
180
      xtime_get(&xt, boost::TIME_UTC); 
181
      xt.sec += table_lock_wait_timeout; 
182
      if (not cond->timed_wait(scoped, xt))
183
      {
184
        result= THR_LOCK_WAIT_TIMEOUT;
185
        scoped.release();
186
        break;
187
      }
188
    }
189
    else
190
    {
191
      cond->wait(scoped);
192
    }
1 by brian
clean slate
193
    /*
194
      We must break the wait if one of the following occurs:
195
      - the connection has been aborted (!thread_var->abort), but
196
        this is not a delayed insert thread (in_wait_list). For a delayed
197
        insert thread the proper action at shutdown is, apparently, to
198
        acquire the lock and complete the insert.
199
      - the lock has been granted (data->cond is set to NULL by the granter),
200
        or the waiting has been aborted (additionally data->type is set to
201
        TL_UNLOCK).
202
      - the wait has timed out (rc == ETIMEDOUT)
203
      Order of checks below is important to not report about timeout
204
      if the predicate is true.
205
    */
1786.2.1 by Brian Aker
Current boost work (more conversion).
206
    if (data->cond == NULL)
1 by brian
clean slate
207
    {
1798.3.7 by Brian Aker
This allows us to use boost for the condition wait (though really.. not
208
      scoped.release();
209
      break;
210
    }
211
    scoped.release();
1 by brian
clean slate
212
  }
213
  if (data->cond || data->type == TL_UNLOCK)
214
  {
215
    if (data->cond)                             /* aborted or timed out */
216
    {
217
      if (((*data->prev)=data->next))		/* remove from wait-list */
218
	data->next->prev= data->prev;
219
      else
220
	wait->last=data->prev;
221
      data->type= TL_UNLOCK;                    /* No lock */
222
      wake_up_waiters(data->lock);
223
    }
224
  }
225
  else
226
  {
227
    result= THR_LOCK_SUCCESS;
228
  }
1689.2.11 by Brian Aker
Encapsulate more of the thr lock.
229
  data->lock->unlock();
1 by brian
clean slate
230
231
  /* The following must be done after unlock of lock->mutex */
1812.3.7 by Brian Aker
Typdef our lock type.
232
  boost_unique_lock_t scopedLock(thread_var->mutex);
1054.1.4 by Brian Aker
Formatting.
233
  thread_var->current_mutex= NULL;
234
  thread_var->current_cond= NULL;
51.3.14 by Jay Pipes
Phase 2 removal of DBUG in mysys
235
  return(result);
1 by brian
clean slate
236
}
237
238
1960.1.1 by Brian Aker
Remove dead code in wait, pass session.
239
static enum enum_thr_lock_result thr_lock(Session &session, THR_LOCK_DATA *data, THR_LOCK_OWNER *owner, enum thr_lock_type lock_type)
1 by brian
clean slate
240
{
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
241
  THR_LOCK *lock= data->lock;
1 by brian
clean slate
242
  enum enum_thr_lock_result result= THR_LOCK_SUCCESS;
243
  struct st_lock_list *wait_queue;
244
  THR_LOCK_DATA *lock_owner;
245
246
  data->next=0;
247
  data->cond=0;					/* safety */
248
  data->type=lock_type;
249
  data->owner= owner;                           /* Must be reset ! */
1689.2.11 by Brian Aker
Encapsulate more of the thr lock.
250
  lock->lock();
1 by brian
clean slate
251
  if ((int) lock_type <= (int) TL_READ_NO_INSERT)
252
  {
253
    /* Request for READ lock */
254
    if (lock->write.data)
255
    {
256
      /* We can allow a read lock even if there is already a write lock
257
	 on the table in one the following cases:
258
	 - This thread alread have a write lock on the table
259
	 - The write lock is TL_WRITE_ALLOW_READ or TL_WRITE_DELAYED
260
           and the read lock is TL_READ_HIGH_PRIORITY or TL_READ
261
         - The write lock is TL_WRITE_CONCURRENT_INSERT or TL_WRITE_ALLOW_WRITE
262
	   and the read lock is not TL_READ_NO_INSERT
263
      */
264
265
      if (thr_lock_owner_equal(data->owner, lock->write.data->owner) ||
1008.1.1 by Brian Aker
Remove dead lock code around delayed INSERT.
266
	  (lock->write.data->type <= TL_WRITE_CONCURRENT_INSERT &&
1008.1.4 by Brian Aker
Removed TL_READ_HIGH_PRIORITY
267
	   (((int) lock_type <= (int) TL_READ_WITH_SHARED_LOCKS) ||
1 by brian
clean slate
268
	    (lock->write.data->type != TL_WRITE_CONCURRENT_INSERT &&
269
	     lock->write.data->type != TL_WRITE_ALLOW_READ))))
270
      {						/* Already got a write lock */
271
	(*lock->read.last)=data;		/* Add to running FIFO */
272
	data->prev=lock->read.last;
273
	lock->read.last= &data->next;
274
	if (lock_type == TL_READ_NO_INSERT)
275
	  lock->read_no_write_count++;
1689.5.1 by Joseph Daly
remove increment calls
276
        current_global_counters.locks_immediate++;
1 by brian
clean slate
277
	goto end;
278
      }
279
      if (lock->write.data->type == TL_WRITE_ONLY)
280
      {
281
	/* We are not allowed to get a READ lock in this case */
282
	data->type=TL_UNLOCK;
283
        result= THR_LOCK_ABORTED;               /* Can't wait for this one */
284
	goto end;
285
      }
286
    }
287
    else if (!lock->write_wait.data ||
1008.1.2 by Brian Aker
Removed old DELAYED keyword from parser (plus cleaned up tests). Also
288
	     lock->write_wait.data->type <= TL_WRITE_DEFAULT ||
1 by brian
clean slate
289
	     have_old_read_lock(lock->read.data, data->owner))
290
    {						/* No important write-locks */
291
      (*lock->read.last)=data;			/* Add to running FIFO */
292
      data->prev=lock->read.last;
293
      lock->read.last= &data->next;
294
      if (lock_type == TL_READ_NO_INSERT)
295
	lock->read_no_write_count++;
1689.5.1 by Joseph Daly
remove increment calls
296
      current_global_counters.locks_immediate++;
1 by brian
clean slate
297
      goto end;
298
    }
299
    /*
300
      We're here if there is an active write lock or no write
301
      lock but a high priority write waiting in the write_wait queue.
302
      In the latter case we should yield the lock to the writer.
303
    */
304
    wait_queue= &lock->read_wait;
305
  }
306
  else						/* Request for WRITE lock */
307
  {
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
308
    if (lock_type == TL_WRITE_CONCURRENT_INSERT)
1 by brian
clean slate
309
      data->type=lock_type= thr_upgraded_concurrent_insert_lock;
310
311
    if (lock->write.data)			/* If there is a write lock */
312
    {
313
      if (lock->write.data->type == TL_WRITE_ONLY)
314
      {
315
        /* Allow lock owner to bypass TL_WRITE_ONLY. */
316
        if (!thr_lock_owner_equal(data->owner, lock->write.data->owner))
317
        {
318
          /* We are not allowed to get a lock in this case */
319
          data->type=TL_UNLOCK;
320
          result= THR_LOCK_ABORTED;               /* Can't wait for this one */
321
          goto end;
322
        }
323
      }
324
325
      /*
326
	The following test will not work if the old lock was a
327
	TL_WRITE_ALLOW_WRITE, TL_WRITE_ALLOW_READ or TL_WRITE_DELAYED in
328
	the same thread, but this will never happen within MySQL.
329
      */
330
      if (thr_lock_owner_equal(data->owner, lock->write.data->owner) ||
331
	  (lock_type == TL_WRITE_ALLOW_WRITE &&
332
	   !lock->write_wait.data &&
333
	   lock->write.data->type == TL_WRITE_ALLOW_WRITE))
334
      {
335
	/*
336
          We have already got a write lock or all locks are
337
          TL_WRITE_ALLOW_WRITE
338
        */
339
340
	(*lock->write.last)=data;	/* Add to running fifo */
341
	data->prev=lock->write.last;
342
	lock->write.last= &data->next;
1689.5.1 by Joseph Daly
remove increment calls
343
        current_global_counters.locks_immediate++;
1 by brian
clean slate
344
	goto end;
345
      }
346
    }
347
    else
348
    {
349
      if (!lock->write_wait.data)
350
      {						/* no scheduled write locks */
146 by Brian Aker
my_bool cleanup.
351
        bool concurrent_insert= 0;
1 by brian
clean slate
352
	if (lock_type == TL_WRITE_CONCURRENT_INSERT)
353
        {
354
          concurrent_insert= 1;
355
        }
356
357
	if (!lock->read.data ||
1008.1.1 by Brian Aker
Remove dead lock code around delayed INSERT.
358
	    (lock_type <= TL_WRITE_CONCURRENT_INSERT &&
1 by brian
clean slate
359
	     ((lock_type != TL_WRITE_CONCURRENT_INSERT &&
360
	       lock_type != TL_WRITE_ALLOW_WRITE) ||
361
	      !lock->read_no_write_count)))
362
	{
363
	  (*lock->write.last)=data;		/* Add as current write lock */
364
	  data->prev=lock->write.last;
365
	  lock->write.last= &data->next;
1689.5.1 by Joseph Daly
remove increment calls
366
          current_global_counters.locks_immediate++;
1 by brian
clean slate
367
	  goto end;
368
	}
369
      }
370
    }
371
    wait_queue= &lock->write_wait;
372
  }
373
  /*
374
    Try to detect a trivial deadlock when using cursors: attempt to
375
    lock a table that is already locked by an open cursor within the
376
    same connection. lock_owner can be zero if we succumbed to a high
377
    priority writer in the write_wait queue.
378
  */
379
  lock_owner= lock->read.data ? lock->read.data : lock->write.data;
380
  if (lock_owner && lock_owner->owner->info == owner->info)
381
  {
382
    result= THR_LOCK_DEADLOCK;
383
    goto end;
384
  }
1689.2.11 by Brian Aker
Encapsulate more of the thr lock.
385
1 by brian
clean slate
386
  /* Can't get lock yet;  Wait for it */
1960.1.1 by Brian Aker
Remove dead code in wait, pass session.
387
  return(wait_for_lock(session, wait_queue, data));
1 by brian
clean slate
388
end:
1689.2.11 by Brian Aker
Encapsulate more of the thr lock.
389
  lock->unlock();
390
51.3.14 by Jay Pipes
Phase 2 removal of DBUG in mysys
391
  return(result);
1 by brian
clean slate
392
}
393
394
1022.2.29 by Monty Taylor
Fixed some no-inline warnings.
395
static void free_all_read_locks(THR_LOCK *lock, bool using_concurrent_insert)
1 by brian
clean slate
396
{
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
397
  THR_LOCK_DATA *data= lock->read_wait.data;
1 by brian
clean slate
398
399
  /* move all locks from read_wait list to read list */
400
  (*lock->read.last)=data;
401
  data->prev=lock->read.last;
402
  lock->read.last=lock->read_wait.last;
403
404
  /* Clear read_wait list */
405
  lock->read_wait.last= &lock->read_wait.data;
406
407
  do
408
  {
1812.3.5 by Brian Aker
Move to boost condition_any
409
    boost::condition_variable_any *cond= data->cond;
1 by brian
clean slate
410
    if ((int) data->type == (int) TL_READ_NO_INSERT)
411
    {
412
      if (using_concurrent_insert)
413
      {
414
	/*
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
415
	  We can't free this lock;
1 by brian
clean slate
416
	  Link lock away from read chain back into read_wait chain
417
	*/
418
	if (((*data->prev)=data->next))
419
	  data->next->prev=data->prev;
420
	else
421
	  lock->read.last=data->prev;
422
	*lock->read_wait.last= data;
423
	data->prev= lock->read_wait.last;
424
	lock->read_wait.last= &data->next;
425
	continue;
426
      }
427
      lock->read_no_write_count++;
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
428
    }
1786.2.1 by Brian Aker
Current boost work (more conversion).
429
    data->cond= NULL;				/* Mark thread free */
430
    cond->notify_one();
1 by brian
clean slate
431
  } while ((data=data->next));
432
  *lock->read_wait.last=0;
433
  if (!lock->read_wait.data)
434
    lock->write_lock_count=0;
435
}
436
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
437
/* Unlock lock and free next thread on same lock */
1 by brian
clean slate
438
1165.1.89 by Stewart Smith
make thr_unlock() static to mysys/thr_lock.cc
439
static void thr_unlock(THR_LOCK_DATA *data)
1 by brian
clean slate
440
{
441
  THR_LOCK *lock=data->lock;
442
  enum thr_lock_type lock_type=data->type;
1689.2.11 by Brian Aker
Encapsulate more of the thr lock.
443
  lock->lock();
1 by brian
clean slate
444
445
  if (((*data->prev)=data->next))		/* remove from lock-list */
446
    data->next->prev= data->prev;
447
  else if (lock_type <= TL_READ_NO_INSERT)
448
    lock->read.last=data->prev;
449
  else
450
    lock->write.last=data->prev;
451
  if (lock_type >= TL_WRITE_CONCURRENT_INSERT)
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
452
  { }
1 by brian
clean slate
453
  else
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
454
  { }
1 by brian
clean slate
455
  if (lock_type == TL_READ_NO_INSERT)
456
    lock->read_no_write_count--;
457
  data->type=TL_UNLOCK;				/* Mark unlocked */
458
  wake_up_waiters(lock);
1689.2.11 by Brian Aker
Encapsulate more of the thr lock.
459
  lock->unlock();
1 by brian
clean slate
460
}
461
462
463
/**
464
  @brief  Wake up all threads which pending requests for the lock
465
          can be satisfied.
466
467
  @param  lock  Lock for which threads should be woken up
468
469
*/
470
471
static void wake_up_waiters(THR_LOCK *lock)
472
{
473
  THR_LOCK_DATA *data;
474
  enum thr_lock_type lock_type;
475
476
  if (!lock->write.data)			/* If no active write locks */
477
  {
478
    data=lock->write_wait.data;
479
    if (!lock->read.data)			/* If no more locks in use */
480
    {
481
      /* Release write-locks with TL_WRITE or TL_WRITE_ONLY priority first */
482
      if (data &&
1008.1.4 by Brian Aker
Removed TL_READ_HIGH_PRIORITY
483
	  (!lock->read_wait.data || lock->read_wait.data->type <= TL_READ_WITH_SHARED_LOCKS))
1 by brian
clean slate
484
      {
485
	if (lock->write_lock_count++ > max_write_lock_count)
486
	{
487
	  /* Too many write locks in a row;  Release all waiting read locks */
488
	  lock->write_lock_count=0;
489
	  if (lock->read_wait.data)
490
	  {
491
	    free_all_read_locks(lock,0);
492
	    goto end;
493
	  }
494
	}
495
	for (;;)
496
	{
497
	  if (((*data->prev)=data->next))	/* remove from wait-list */
498
	    data->next->prev= data->prev;
499
	  else
500
	    lock->write_wait.last=data->prev;
501
	  (*lock->write.last)=data;		/* Put in execute list */
502
	  data->prev=lock->write.last;
503
	  data->next=0;
504
	  lock->write.last= &data->next;
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
505
1 by brian
clean slate
506
	  {
1812.3.5 by Brian Aker
Move to boost condition_any
507
            boost::condition_variable_any *cond= data->cond;
1786.2.1 by Brian Aker
Current boost work (more conversion).
508
	    data->cond= NULL;				/* Mark thread free */
509
            cond->notify_one(); /* Start waiting thred */
1 by brian
clean slate
510
	  }
511
	  if (data->type != TL_WRITE_ALLOW_WRITE ||
512
	      !lock->write_wait.data ||
513
	      lock->write_wait.data->type != TL_WRITE_ALLOW_WRITE)
514
	    break;
515
	  data=lock->write_wait.data;		/* Free this too */
516
	}
1008.1.2 by Brian Aker
Removed old DELAYED keyword from parser (plus cleaned up tests). Also
517
	if (data->type >= TL_WRITE)
1 by brian
clean slate
518
          goto end;
519
	/* Release possible read locks together with the write lock */
520
      }
521
      if (lock->read_wait.data)
522
	free_all_read_locks(lock,
523
			    data &&
524
			    (data->type == TL_WRITE_CONCURRENT_INSERT ||
525
			     data->type == TL_WRITE_ALLOW_WRITE));
526
    }
527
    else if (data &&
1008.1.1 by Brian Aker
Remove dead lock code around delayed INSERT.
528
	     (lock_type=data->type) <= TL_WRITE_CONCURRENT_INSERT &&
1 by brian
clean slate
529
	     ((lock_type != TL_WRITE_CONCURRENT_INSERT &&
530
	       lock_type != TL_WRITE_ALLOW_WRITE) ||
531
	      !lock->read_no_write_count))
532
    {
533
      do {
1812.3.5 by Brian Aker
Move to boost condition_any
534
        boost::condition_variable_any *cond= data->cond;
1 by brian
clean slate
535
	if (((*data->prev)=data->next))		/* remove from wait-list */
536
	  data->next->prev= data->prev;
537
	else
538
	  lock->write_wait.last=data->prev;
539
	(*lock->write.last)=data;		/* Put in execute list */
540
	data->prev=lock->write.last;
541
	lock->write.last= &data->next;
542
	data->next=0;				/* Only one write lock */
1786.2.1 by Brian Aker
Current boost work (more conversion).
543
	data->cond= NULL;				/* Mark thread free */
544
        cond->notify_one(); /* Start waiting thread */
1 by brian
clean slate
545
      } while (lock_type == TL_WRITE_ALLOW_WRITE &&
546
	       (data=lock->write_wait.data) &&
547
	       data->type == TL_WRITE_ALLOW_WRITE);
548
      if (lock->read_wait.data)
549
	free_all_read_locks(lock,
550
			    (lock_type == TL_WRITE_CONCURRENT_INSERT ||
551
			     lock_type == TL_WRITE_ALLOW_WRITE));
552
    }
553
    else if (!data && lock->read_wait.data)
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
554
    {
1 by brian
clean slate
555
      free_all_read_locks(lock,0);
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
556
    }
1 by brian
clean slate
557
  }
558
end:
51.3.14 by Jay Pipes
Phase 2 removal of DBUG in mysys
559
  return;
1 by brian
clean slate
560
}
561
562
563
/*
564
** Get all locks in a specific order to avoid dead-locks
565
** Sort acording to lock position and put write_locks before read_locks if
566
** lock on same lock.
567
*/
568
569
895 by Brian Aker
Completion (?) of uint conversion.
570
#define LOCK_CMP(A,B) ((unsigned char*) (A->lock) - (uint32_t) ((A)->type) < (unsigned char*) (B->lock)- (uint32_t) ((B)->type))
1 by brian
clean slate
571
482 by Brian Aker
Remove uint.
572
static void sort_locks(THR_LOCK_DATA **data,uint32_t count)
1 by brian
clean slate
573
{
574
  THR_LOCK_DATA **pos,**end,**prev,*tmp;
575
576
  /* Sort locks with insertion sort (fast because almost always few locks) */
577
578
  for (pos=data+1,end=data+count; pos < end ; pos++)
579
  {
580
    tmp= *pos;
581
    if (LOCK_CMP(tmp,pos[-1]))
582
    {
583
      prev=pos;
584
      do {
585
	prev[0]=prev[-1];
586
      } while (--prev != data && LOCK_CMP(tmp,prev[-1]));
587
      prev[0]=tmp;
588
    }
589
  }
590
}
591
592
593
enum enum_thr_lock_result
1960.1.1 by Brian Aker
Remove dead code in wait, pass session.
594
thr_multi_lock(Session &session, THR_LOCK_DATA **data, uint32_t count, THR_LOCK_OWNER *owner)
1 by brian
clean slate
595
{
596
  THR_LOCK_DATA **pos,**end;
597
  if (count > 1)
598
    sort_locks(data,count);
599
  /* lock everything */
600
  for (pos=data,end=data+count; pos < end ; pos++)
601
  {
1960.1.1 by Brian Aker
Remove dead code in wait, pass session.
602
    enum enum_thr_lock_result result= thr_lock(session, *pos, owner, (*pos)->type);
1 by brian
clean slate
603
    if (result != THR_LOCK_SUCCESS)
604
    {						/* Aborted */
895 by Brian Aker
Completion (?) of uint conversion.
605
      thr_multi_unlock(data,(uint32_t) (pos-data));
51.3.14 by Jay Pipes
Phase 2 removal of DBUG in mysys
606
      return(result);
1 by brian
clean slate
607
    }
608
  }
609
  /*
610
    Ensure that all get_locks() have the same status
611
    If we lock the same table multiple times, we must use the same
612
    status_param!
613
  */
614
#if !defined(DONT_USE_RW_LOCKS)
615
  if (count > 1)
616
  {
617
    THR_LOCK_DATA *last_lock= end[-1];
618
    pos=end-1;
619
    do
620
    {
621
      pos--;
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
622
      last_lock=(*pos);
1 by brian
clean slate
623
    } while (pos != data);
624
  }
625
#endif
51.3.14 by Jay Pipes
Phase 2 removal of DBUG in mysys
626
  return(THR_LOCK_SUCCESS);
1 by brian
clean slate
627
}
628
629
  /* free all locks */
630
1948.2.1 by Brian Aker
Fix for 680028, crash on SELECT FOR UPDATE afer FLUSH TABLES WITH READ LOCKS
631
void thr_multi_unlock(THR_LOCK_DATA **data,uint32_t count)
1 by brian
clean slate
632
{
633
  THR_LOCK_DATA **pos,**end;
634
635
  for (pos=data,end=data+count; pos < end ; pos++)
636
  {
637
    if ((*pos)->type != TL_UNLOCK)
638
      thr_unlock(*pos);
639
  }
51.3.14 by Jay Pipes
Phase 2 removal of DBUG in mysys
640
  return;
1 by brian
clean slate
641
}
642
1859.2.4 by Brian Aker
A few cleanups.
643
void DrizzleLock::unlock(uint32_t count)
644
{
645
  THR_LOCK_DATA **pos,**end;
646
647
  for (pos= getLocks(),end= getLocks()+count; pos < end ; pos++)
648
  {
649
    if ((*pos)->type != TL_UNLOCK)
650
      thr_unlock(*pos);
651
  }
652
}
653
1 by brian
clean slate
654
/*
655
  Abort all threads waiting for a lock. The lock will be upgraded to
656
  TL_WRITE_ONLY to abort any new accesses to the lock
657
*/
658
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
659
void THR_LOCK::abort_locks()
1 by brian
clean slate
660
{
1812.3.7 by Brian Aker
Typdef our lock type.
661
  boost_unique_lock_t scopedLock(mutex);
1 by brian
clean slate
662
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
663
  for (THR_LOCK_DATA *local_data= read_wait.data; local_data ; local_data= local_data->next)
1 by brian
clean slate
664
  {
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
665
    local_data->type= TL_UNLOCK;			/* Mark killed */
1 by brian
clean slate
666
    /* It's safe to signal the cond first: we're still holding the mutex. */
1786.2.1 by Brian Aker
Current boost work (more conversion).
667
    local_data->cond->notify_one();
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
668
    local_data->cond= NULL;				/* Removed from list */
1 by brian
clean slate
669
  }
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
670
  for (THR_LOCK_DATA *local_data= write_wait.data; local_data ; local_data= local_data->next)
1 by brian
clean slate
671
  {
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
672
    local_data->type= TL_UNLOCK;
1786.2.1 by Brian Aker
Current boost work (more conversion).
673
    local_data->cond->notify_one();
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
674
    local_data->cond= NULL;
1 by brian
clean slate
675
  }
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
676
  read_wait.last= &read_wait.data;
677
  write_wait.last= &write_wait.data;
678
  read_wait.data= write_wait.data=0;
679
  if (write.data)
680
    write.data->type=TL_WRITE_ONLY;
1 by brian
clean slate
681
}
682
683
684
/*
685
  Abort all locks for specific table/thread combination
686
687
  This is used to abort all locks for a specific thread
688
*/
689
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
690
bool THR_LOCK::abort_locks_for_thread(uint64_t thread_id_arg)
1 by brian
clean slate
691
{
163 by Brian Aker
Merge Monty's code.
692
  bool found= false;
1 by brian
clean slate
693
1812.3.7 by Brian Aker
Typdef our lock type.
694
  boost_unique_lock_t scopedLock(mutex);
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
695
  for (THR_LOCK_DATA *local_data= read_wait.data; local_data ; local_data= local_data->next)
1 by brian
clean slate
696
  {
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
697
    if (local_data->owner->info->thread_id == thread_id_arg)
1 by brian
clean slate
698
    {
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
699
      local_data->type= TL_UNLOCK;			/* Mark killed */
1 by brian
clean slate
700
      /* It's safe to signal the cond first: we're still holding the mutex. */
163 by Brian Aker
Merge Monty's code.
701
      found= true;
1786.2.1 by Brian Aker
Current boost work (more conversion).
702
      local_data->cond->notify_one();
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
703
      local_data->cond= 0;				/* Removed from list */
1 by brian
clean slate
704
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
705
      if (((*local_data->prev)= local_data->next))
706
	local_data->next->prev= local_data->prev;
1 by brian
clean slate
707
      else
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
708
	read_wait.last= local_data->prev;
1 by brian
clean slate
709
    }
710
  }
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
711
  for (THR_LOCK_DATA *local_data= write_wait.data; local_data ; local_data= local_data->next)
1 by brian
clean slate
712
  {
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
713
    if (local_data->owner->info->thread_id == thread_id_arg)
1 by brian
clean slate
714
    {
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
715
      local_data->type= TL_UNLOCK;
163 by Brian Aker
Merge Monty's code.
716
      found= true;
1786.2.1 by Brian Aker
Current boost work (more conversion).
717
      local_data->cond->notify_one();
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
718
      local_data->cond= NULL;
1 by brian
clean slate
719
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
720
      if (((*local_data->prev)= local_data->next))
721
	local_data->next->prev= local_data->prev;
1 by brian
clean slate
722
      else
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
723
	write_wait.last= local_data->prev;
1 by brian
clean slate
724
    }
725
  }
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
726
  wake_up_waiters(this);
727
728
  return found;
1 by brian
clean slate
729
}
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
730
731
} /* namespace drizzled */