~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
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
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"
1 by brian
clean slate
59
1775.4.4 by Brian Aker
Cleanup my_thread_var usage.
60
#include "drizzled/session.h"
61
#include "drizzled/current_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
622.1.1 by Brian Aker
32bit fixes around vars
92
uint64_t max_write_lock_count= ~(uint64_t) 0L;
1 by brian
clean slate
93
94
/*
95
** For the future (now the thread specific cond is alloced by my_pthread.c)
96
*/
97
146 by Brian Aker
my_bool cleanup.
98
static inline bool
1 by brian
clean slate
99
thr_lock_owner_equal(THR_LOCK_OWNER *rhs, THR_LOCK_OWNER *lhs)
100
{
101
  return rhs == lhs;
102
}
103
104
105
	/* Initialize a lock */
106
107
void thr_lock_init(THR_LOCK *lock)
108
{
1689.2.11 by Brian Aker
Encapsulate more of the thr lock.
109
  lock->init();
1 by brian
clean slate
110
  lock->read.last= &lock->read.data;
111
  lock->read_wait.last= &lock->read_wait.data;
112
  lock->write_wait.last= &lock->write_wait.data;
113
  lock->write.last= &lock->write.data;
114
}
115
116
1689.2.12 by Brian Aker
THR_LOCK_INFO::init() <-- encapsulation
117
void THR_LOCK_INFO::init()
1 by brian
clean slate
118
{
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
119
  internal::st_my_thread_var *tmp= my_thread_var;
1689.2.12 by Brian Aker
THR_LOCK_INFO::init() <-- encapsulation
120
  thread= tmp->pthread_self;
121
  thread_id= tmp->id;
122
  n_cursors= 0;
1 by brian
clean slate
123
}
124
125
	/* Initialize a lock instance */
126
1689.2.13 by Brian Aker
More encapsulation of thr_lock
127
void THR_LOCK_DATA::init(THR_LOCK *lock_arg, void *param_arg)
1 by brian
clean slate
128
{
1689.2.13 by Brian Aker
More encapsulation of thr_lock
129
  lock= lock_arg;
130
  type= TL_UNLOCK;
131
  owner= NULL;                               /* no owner yet */
132
  status_param= param_arg;
133
  cond= NULL;
1 by brian
clean slate
134
}
135
136
146 by Brian Aker
my_bool cleanup.
137
static inline bool
1 by brian
clean slate
138
have_old_read_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner)
139
{
140
  for ( ; data ; data=data->next)
141
  {
142
    if (thr_lock_owner_equal(data->owner, owner))
1054.1.4 by Brian Aker
Formatting.
143
      return true;					/* Already locked by thread */
1 by brian
clean slate
144
  }
1054.1.4 by Brian Aker
Formatting.
145
  return false;
1 by brian
clean slate
146
}
147
148
static void wake_up_waiters(THR_LOCK *lock);
149
150
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
151
static enum enum_thr_lock_result wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data, bool in_wait_list)
1 by brian
clean slate
152
{
1775.4.4 by Brian Aker
Cleanup my_thread_var usage.
153
  Session *session= current_session;
154
  internal::st_my_thread_var *thread_var= session->getThreadVar();
155
1786.2.1 by Brian Aker
Current boost work (more conversion).
156
  boost::condition_variable *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
  if (!in_wait_list)
161
  {
162
    (*wait->last)=data;				/* Wait for lock */
163
    data->prev= wait->last;
164
    wait->last= &data->next;
165
  }
166
1689.5.1 by Joseph Daly
remove increment calls
167
  current_global_counters.locks_waited++;
1 by brian
clean slate
168
169
  /* Set up control struct to allow others to abort locks */
1689.2.11 by Brian Aker
Encapsulate more of the thr lock.
170
  thread_var->current_mutex= data->lock->native_handle();
1786.2.1 by Brian Aker
Current boost work (more conversion).
171
  thread_var->current_cond=  &thread_var->suspend;
172
  data->cond= &thread_var->suspend;;
1 by brian
clean slate
173
174
  while (!thread_var->abort || in_wait_list)
175
  {
1798.3.7 by Brian Aker
This allows us to use boost for the condition wait (though really.. not
176
    boost::mutex::scoped_lock scoped(*data->lock->native_handle(), boost::adopt_lock_t());
177
178
    if (can_deadlock)
179
    {
180
      boost::xtime xt; 
181
      xtime_get(&xt, boost::TIME_UTC); 
182
      xt.sec += table_lock_wait_timeout; 
183
      if (not cond->timed_wait(scoped, xt))
184
      {
185
        result= THR_LOCK_WAIT_TIMEOUT;
186
        scoped.release();
187
        break;
188
      }
189
    }
190
    else
191
    {
192
      cond->wait(scoped);
193
    }
1 by brian
clean slate
194
    /*
195
      We must break the wait if one of the following occurs:
196
      - the connection has been aborted (!thread_var->abort), but
197
        this is not a delayed insert thread (in_wait_list). For a delayed
198
        insert thread the proper action at shutdown is, apparently, to
199
        acquire the lock and complete the insert.
200
      - the lock has been granted (data->cond is set to NULL by the granter),
201
        or the waiting has been aborted (additionally data->type is set to
202
        TL_UNLOCK).
203
      - the wait has timed out (rc == ETIMEDOUT)
204
      Order of checks below is important to not report about timeout
205
      if the predicate is true.
206
    */
1786.2.1 by Brian Aker
Current boost work (more conversion).
207
    if (data->cond == NULL)
1 by brian
clean slate
208
    {
1798.3.7 by Brian Aker
This allows us to use boost for the condition wait (though really.. not
209
      scoped.release();
210
      break;
211
    }
212
    scoped.release();
1 by brian
clean slate
213
  }
214
  if (data->cond || data->type == TL_UNLOCK)
215
  {
216
    if (data->cond)                             /* aborted or timed out */
217
    {
218
      if (((*data->prev)=data->next))		/* remove from wait-list */
219
	data->next->prev= data->prev;
220
      else
221
	wait->last=data->prev;
222
      data->type= TL_UNLOCK;                    /* No lock */
223
      wake_up_waiters(data->lock);
224
    }
225
  }
226
  else
227
  {
228
    result= THR_LOCK_SUCCESS;
229
  }
1689.2.11 by Brian Aker
Encapsulate more of the thr lock.
230
  data->lock->unlock();
1 by brian
clean slate
231
232
  /* The following must be done after unlock of lock->mutex */
1786.2.1 by Brian Aker
Current boost work (more conversion).
233
  boost::mutex::scoped_lock scopedLock(thread_var->mutex);
1054.1.4 by Brian Aker
Formatting.
234
  thread_var->current_mutex= NULL;
235
  thread_var->current_cond= NULL;
51.3.14 by Jay Pipes
Phase 2 removal of DBUG in mysys
236
  return(result);
1 by brian
clean slate
237
}
238
239
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
240
static enum enum_thr_lock_result thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner, enum thr_lock_type lock_type)
1 by brian
clean slate
241
{
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
242
  THR_LOCK *lock= data->lock;
1 by brian
clean slate
243
  enum enum_thr_lock_result result= THR_LOCK_SUCCESS;
244
  struct st_lock_list *wait_queue;
245
  THR_LOCK_DATA *lock_owner;
246
247
  data->next=0;
248
  data->cond=0;					/* safety */
249
  data->type=lock_type;
250
  data->owner= owner;                           /* Must be reset ! */
1689.2.11 by Brian Aker
Encapsulate more of the thr lock.
251
  lock->lock();
1 by brian
clean slate
252
  if ((int) lock_type <= (int) TL_READ_NO_INSERT)
253
  {
254
    /* Request for READ lock */
255
    if (lock->write.data)
256
    {
257
      /* We can allow a read lock even if there is already a write lock
258
	 on the table in one the following cases:
259
	 - This thread alread have a write lock on the table
260
	 - The write lock is TL_WRITE_ALLOW_READ or TL_WRITE_DELAYED
261
           and the read lock is TL_READ_HIGH_PRIORITY or TL_READ
262
         - The write lock is TL_WRITE_CONCURRENT_INSERT or TL_WRITE_ALLOW_WRITE
263
	   and the read lock is not TL_READ_NO_INSERT
264
      */
265
266
      if (thr_lock_owner_equal(data->owner, lock->write.data->owner) ||
1008.1.1 by Brian Aker
Remove dead lock code around delayed INSERT.
267
	  (lock->write.data->type <= TL_WRITE_CONCURRENT_INSERT &&
1008.1.4 by Brian Aker
Removed TL_READ_HIGH_PRIORITY
268
	   (((int) lock_type <= (int) TL_READ_WITH_SHARED_LOCKS) ||
1 by brian
clean slate
269
	    (lock->write.data->type != TL_WRITE_CONCURRENT_INSERT &&
270
	     lock->write.data->type != TL_WRITE_ALLOW_READ))))
271
      {						/* Already got a write lock */
272
	(*lock->read.last)=data;		/* Add to running FIFO */
273
	data->prev=lock->read.last;
274
	lock->read.last= &data->next;
275
	if (lock_type == TL_READ_NO_INSERT)
276
	  lock->read_no_write_count++;
1689.5.1 by Joseph Daly
remove increment calls
277
        current_global_counters.locks_immediate++;
1 by brian
clean slate
278
	goto end;
279
      }
280
      if (lock->write.data->type == TL_WRITE_ONLY)
281
      {
282
	/* We are not allowed to get a READ lock in this case */
283
	data->type=TL_UNLOCK;
284
        result= THR_LOCK_ABORTED;               /* Can't wait for this one */
285
	goto end;
286
      }
287
    }
288
    else if (!lock->write_wait.data ||
1008.1.2 by Brian Aker
Removed old DELAYED keyword from parser (plus cleaned up tests). Also
289
	     lock->write_wait.data->type <= TL_WRITE_DEFAULT ||
1 by brian
clean slate
290
	     have_old_read_lock(lock->read.data, data->owner))
291
    {						/* No important write-locks */
292
      (*lock->read.last)=data;			/* Add to running FIFO */
293
      data->prev=lock->read.last;
294
      lock->read.last= &data->next;
295
      if (lock_type == TL_READ_NO_INSERT)
296
	lock->read_no_write_count++;
1689.5.1 by Joseph Daly
remove increment calls
297
      current_global_counters.locks_immediate++;
1 by brian
clean slate
298
      goto end;
299
    }
300
    /*
301
      We're here if there is an active write lock or no write
302
      lock but a high priority write waiting in the write_wait queue.
303
      In the latter case we should yield the lock to the writer.
304
    */
305
    wait_queue= &lock->read_wait;
306
  }
307
  else						/* Request for WRITE lock */
308
  {
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
309
    if (lock_type == TL_WRITE_CONCURRENT_INSERT)
1 by brian
clean slate
310
      data->type=lock_type= thr_upgraded_concurrent_insert_lock;
311
312
    if (lock->write.data)			/* If there is a write lock */
313
    {
314
      if (lock->write.data->type == TL_WRITE_ONLY)
315
      {
316
        /* Allow lock owner to bypass TL_WRITE_ONLY. */
317
        if (!thr_lock_owner_equal(data->owner, lock->write.data->owner))
318
        {
319
          /* We are not allowed to get a lock in this case */
320
          data->type=TL_UNLOCK;
321
          result= THR_LOCK_ABORTED;               /* Can't wait for this one */
322
          goto end;
323
        }
324
      }
325
326
      /*
327
	The following test will not work if the old lock was a
328
	TL_WRITE_ALLOW_WRITE, TL_WRITE_ALLOW_READ or TL_WRITE_DELAYED in
329
	the same thread, but this will never happen within MySQL.
330
      */
331
      if (thr_lock_owner_equal(data->owner, lock->write.data->owner) ||
332
	  (lock_type == TL_WRITE_ALLOW_WRITE &&
333
	   !lock->write_wait.data &&
334
	   lock->write.data->type == TL_WRITE_ALLOW_WRITE))
335
      {
336
	/*
337
          We have already got a write lock or all locks are
338
          TL_WRITE_ALLOW_WRITE
339
        */
340
341
	(*lock->write.last)=data;	/* Add to running fifo */
342
	data->prev=lock->write.last;
343
	lock->write.last= &data->next;
1689.5.1 by Joseph Daly
remove increment calls
344
        current_global_counters.locks_immediate++;
1 by brian
clean slate
345
	goto end;
346
      }
347
    }
348
    else
349
    {
350
      if (!lock->write_wait.data)
351
      {						/* no scheduled write locks */
146 by Brian Aker
my_bool cleanup.
352
        bool concurrent_insert= 0;
1 by brian
clean slate
353
	if (lock_type == TL_WRITE_CONCURRENT_INSERT)
354
        {
355
          concurrent_insert= 1;
356
        }
357
358
	if (!lock->read.data ||
1008.1.1 by Brian Aker
Remove dead lock code around delayed INSERT.
359
	    (lock_type <= TL_WRITE_CONCURRENT_INSERT &&
1 by brian
clean slate
360
	     ((lock_type != TL_WRITE_CONCURRENT_INSERT &&
361
	       lock_type != TL_WRITE_ALLOW_WRITE) ||
362
	      !lock->read_no_write_count)))
363
	{
364
	  (*lock->write.last)=data;		/* Add as current write lock */
365
	  data->prev=lock->write.last;
366
	  lock->write.last= &data->next;
1689.5.1 by Joseph Daly
remove increment calls
367
          current_global_counters.locks_immediate++;
1 by brian
clean slate
368
	  goto end;
369
	}
370
      }
371
    }
372
    wait_queue= &lock->write_wait;
373
  }
374
  /*
375
    Try to detect a trivial deadlock when using cursors: attempt to
376
    lock a table that is already locked by an open cursor within the
377
    same connection. lock_owner can be zero if we succumbed to a high
378
    priority writer in the write_wait queue.
379
  */
380
  lock_owner= lock->read.data ? lock->read.data : lock->write.data;
381
  if (lock_owner && lock_owner->owner->info == owner->info)
382
  {
383
    result= THR_LOCK_DEADLOCK;
384
    goto end;
385
  }
1689.2.11 by Brian Aker
Encapsulate more of the thr lock.
386
1 by brian
clean slate
387
  /* Can't get lock yet;  Wait for it */
51.3.14 by Jay Pipes
Phase 2 removal of DBUG in mysys
388
  return(wait_for_lock(wait_queue, data, 0));
1 by brian
clean slate
389
end:
1689.2.11 by Brian Aker
Encapsulate more of the thr lock.
390
  lock->unlock();
391
51.3.14 by Jay Pipes
Phase 2 removal of DBUG in mysys
392
  return(result);
1 by brian
clean slate
393
}
394
395
1022.2.29 by Monty Taylor
Fixed some no-inline warnings.
396
static void free_all_read_locks(THR_LOCK *lock, bool using_concurrent_insert)
1 by brian
clean slate
397
{
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
398
  THR_LOCK_DATA *data= lock->read_wait.data;
1 by brian
clean slate
399
400
  /* move all locks from read_wait list to read list */
401
  (*lock->read.last)=data;
402
  data->prev=lock->read.last;
403
  lock->read.last=lock->read_wait.last;
404
405
  /* Clear read_wait list */
406
  lock->read_wait.last= &lock->read_wait.data;
407
408
  do
409
  {
1786.2.1 by Brian Aker
Current boost work (more conversion).
410
    boost::condition_variable *cond= data->cond;
1 by brian
clean slate
411
    if ((int) data->type == (int) TL_READ_NO_INSERT)
412
    {
413
      if (using_concurrent_insert)
414
      {
415
	/*
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
416
	  We can't free this lock;
1 by brian
clean slate
417
	  Link lock away from read chain back into read_wait chain
418
	*/
419
	if (((*data->prev)=data->next))
420
	  data->next->prev=data->prev;
421
	else
422
	  lock->read.last=data->prev;
423
	*lock->read_wait.last= data;
424
	data->prev= lock->read_wait.last;
425
	lock->read_wait.last= &data->next;
426
	continue;
427
      }
428
      lock->read_no_write_count++;
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
429
    }
1786.2.1 by Brian Aker
Current boost work (more conversion).
430
    data->cond= NULL;				/* Mark thread free */
431
    cond->notify_one();
1 by brian
clean slate
432
  } while ((data=data->next));
433
  *lock->read_wait.last=0;
434
  if (!lock->read_wait.data)
435
    lock->write_lock_count=0;
436
}
437
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
438
/* Unlock lock and free next thread on same lock */
1 by brian
clean slate
439
1165.1.89 by Stewart Smith
make thr_unlock() static to mysys/thr_lock.cc
440
static void thr_unlock(THR_LOCK_DATA *data)
1 by brian
clean slate
441
{
442
  THR_LOCK *lock=data->lock;
443
  enum thr_lock_type lock_type=data->type;
1689.2.11 by Brian Aker
Encapsulate more of the thr lock.
444
  lock->lock();
1 by brian
clean slate
445
446
  if (((*data->prev)=data->next))		/* remove from lock-list */
447
    data->next->prev= data->prev;
448
  else if (lock_type <= TL_READ_NO_INSERT)
449
    lock->read.last=data->prev;
450
  else
451
    lock->write.last=data->prev;
452
  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
453
  { }
1 by brian
clean slate
454
  else
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
455
  { }
1 by brian
clean slate
456
  if (lock_type == TL_READ_NO_INSERT)
457
    lock->read_no_write_count--;
458
  data->type=TL_UNLOCK;				/* Mark unlocked */
459
  wake_up_waiters(lock);
1689.2.11 by Brian Aker
Encapsulate more of the thr lock.
460
  lock->unlock();
1 by brian
clean slate
461
}
462
463
464
/**
465
  @brief  Wake up all threads which pending requests for the lock
466
          can be satisfied.
467
468
  @param  lock  Lock for which threads should be woken up
469
470
*/
471
472
static void wake_up_waiters(THR_LOCK *lock)
473
{
474
  THR_LOCK_DATA *data;
475
  enum thr_lock_type lock_type;
476
477
  if (!lock->write.data)			/* If no active write locks */
478
  {
479
    data=lock->write_wait.data;
480
    if (!lock->read.data)			/* If no more locks in use */
481
    {
482
      /* Release write-locks with TL_WRITE or TL_WRITE_ONLY priority first */
483
      if (data &&
1008.1.4 by Brian Aker
Removed TL_READ_HIGH_PRIORITY
484
	  (!lock->read_wait.data || lock->read_wait.data->type <= TL_READ_WITH_SHARED_LOCKS))
1 by brian
clean slate
485
      {
486
	if (lock->write_lock_count++ > max_write_lock_count)
487
	{
488
	  /* Too many write locks in a row;  Release all waiting read locks */
489
	  lock->write_lock_count=0;
490
	  if (lock->read_wait.data)
491
	  {
492
	    free_all_read_locks(lock,0);
493
	    goto end;
494
	  }
495
	}
496
	for (;;)
497
	{
498
	  if (((*data->prev)=data->next))	/* remove from wait-list */
499
	    data->next->prev= data->prev;
500
	  else
501
	    lock->write_wait.last=data->prev;
502
	  (*lock->write.last)=data;		/* Put in execute list */
503
	  data->prev=lock->write.last;
504
	  data->next=0;
505
	  lock->write.last= &data->next;
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
506
1 by brian
clean slate
507
	  {
1786.2.1 by Brian Aker
Current boost work (more conversion).
508
            boost::condition_variable *cond= data->cond;
509
	    data->cond= NULL;				/* Mark thread free */
510
            cond->notify_one(); /* Start waiting thred */
1 by brian
clean slate
511
	  }
512
	  if (data->type != TL_WRITE_ALLOW_WRITE ||
513
	      !lock->write_wait.data ||
514
	      lock->write_wait.data->type != TL_WRITE_ALLOW_WRITE)
515
	    break;
516
	  data=lock->write_wait.data;		/* Free this too */
517
	}
1008.1.2 by Brian Aker
Removed old DELAYED keyword from parser (plus cleaned up tests). Also
518
	if (data->type >= TL_WRITE)
1 by brian
clean slate
519
          goto end;
520
	/* Release possible read locks together with the write lock */
521
      }
522
      if (lock->read_wait.data)
523
	free_all_read_locks(lock,
524
			    data &&
525
			    (data->type == TL_WRITE_CONCURRENT_INSERT ||
526
			     data->type == TL_WRITE_ALLOW_WRITE));
527
    }
528
    else if (data &&
1008.1.1 by Brian Aker
Remove dead lock code around delayed INSERT.
529
	     (lock_type=data->type) <= TL_WRITE_CONCURRENT_INSERT &&
1 by brian
clean slate
530
	     ((lock_type != TL_WRITE_CONCURRENT_INSERT &&
531
	       lock_type != TL_WRITE_ALLOW_WRITE) ||
532
	      !lock->read_no_write_count))
533
    {
534
      do {
1786.2.1 by Brian Aker
Current boost work (more conversion).
535
        boost::condition_variable *cond= data->cond;
1 by brian
clean slate
536
	if (((*data->prev)=data->next))		/* remove from wait-list */
537
	  data->next->prev= data->prev;
538
	else
539
	  lock->write_wait.last=data->prev;
540
	(*lock->write.last)=data;		/* Put in execute list */
541
	data->prev=lock->write.last;
542
	lock->write.last= &data->next;
543
	data->next=0;				/* Only one write lock */
1786.2.1 by Brian Aker
Current boost work (more conversion).
544
	data->cond= NULL;				/* Mark thread free */
545
        cond->notify_one(); /* Start waiting thread */
1 by brian
clean slate
546
      } while (lock_type == TL_WRITE_ALLOW_WRITE &&
547
	       (data=lock->write_wait.data) &&
548
	       data->type == TL_WRITE_ALLOW_WRITE);
549
      if (lock->read_wait.data)
550
	free_all_read_locks(lock,
551
			    (lock_type == TL_WRITE_CONCURRENT_INSERT ||
552
			     lock_type == TL_WRITE_ALLOW_WRITE));
553
    }
554
    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
555
    {
1 by brian
clean slate
556
      free_all_read_locks(lock,0);
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
557
    }
1 by brian
clean slate
558
  }
559
end:
51.3.14 by Jay Pipes
Phase 2 removal of DBUG in mysys
560
  return;
1 by brian
clean slate
561
}
562
563
564
/*
565
** Get all locks in a specific order to avoid dead-locks
566
** Sort acording to lock position and put write_locks before read_locks if
567
** lock on same lock.
568
*/
569
570
895 by Brian Aker
Completion (?) of uint conversion.
571
#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
572
482 by Brian Aker
Remove uint.
573
static void sort_locks(THR_LOCK_DATA **data,uint32_t count)
1 by brian
clean slate
574
{
575
  THR_LOCK_DATA **pos,**end,**prev,*tmp;
576
577
  /* Sort locks with insertion sort (fast because almost always few locks) */
578
579
  for (pos=data+1,end=data+count; pos < end ; pos++)
580
  {
581
    tmp= *pos;
582
    if (LOCK_CMP(tmp,pos[-1]))
583
    {
584
      prev=pos;
585
      do {
586
	prev[0]=prev[-1];
587
      } while (--prev != data && LOCK_CMP(tmp,prev[-1]));
588
      prev[0]=tmp;
589
    }
590
  }
591
}
592
593
594
enum enum_thr_lock_result
482 by Brian Aker
Remove uint.
595
thr_multi_lock(THR_LOCK_DATA **data, uint32_t count, THR_LOCK_OWNER *owner)
1 by brian
clean slate
596
{
597
  THR_LOCK_DATA **pos,**end;
598
  if (count > 1)
599
    sort_locks(data,count);
600
  /* lock everything */
601
  for (pos=data,end=data+count; pos < end ; pos++)
602
  {
603
    enum enum_thr_lock_result result= thr_lock(*pos, owner, (*pos)->type);
604
    if (result != THR_LOCK_SUCCESS)
605
    {						/* Aborted */
895 by Brian Aker
Completion (?) of uint conversion.
606
      thr_multi_unlock(data,(uint32_t) (pos-data));
51.3.14 by Jay Pipes
Phase 2 removal of DBUG in mysys
607
      return(result);
1 by brian
clean slate
608
    }
609
  }
610
  /*
611
    Ensure that all get_locks() have the same status
612
    If we lock the same table multiple times, we must use the same
613
    status_param!
614
  */
615
#if !defined(DONT_USE_RW_LOCKS)
616
  if (count > 1)
617
  {
618
    THR_LOCK_DATA *last_lock= end[-1];
619
    pos=end-1;
620
    do
621
    {
622
      pos--;
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
623
      last_lock=(*pos);
1 by brian
clean slate
624
    } while (pos != data);
625
  }
626
#endif
51.3.14 by Jay Pipes
Phase 2 removal of DBUG in mysys
627
  return(THR_LOCK_SUCCESS);
1 by brian
clean slate
628
}
629
630
  /* free all locks */
631
482 by Brian Aker
Remove uint.
632
void thr_multi_unlock(THR_LOCK_DATA **data,uint32_t count)
1 by brian
clean slate
633
{
634
  THR_LOCK_DATA **pos,**end;
635
636
  for (pos=data,end=data+count; pos < end ; pos++)
637
  {
638
    if ((*pos)->type != TL_UNLOCK)
639
      thr_unlock(*pos);
640
  }
51.3.14 by Jay Pipes
Phase 2 removal of DBUG in mysys
641
  return;
1 by brian
clean slate
642
}
643
644
/*
645
  Abort all threads waiting for a lock. The lock will be upgraded to
646
  TL_WRITE_ONLY to abort any new accesses to the lock
647
*/
648
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
649
void THR_LOCK::abort_locks()
1 by brian
clean slate
650
{
1786.2.1 by Brian Aker
Current boost work (more conversion).
651
  boost::mutex::scoped_lock scopedLock(mutex);
1 by brian
clean slate
652
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
653
  for (THR_LOCK_DATA *local_data= read_wait.data; local_data ; local_data= local_data->next)
1 by brian
clean slate
654
  {
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
655
    local_data->type= TL_UNLOCK;			/* Mark killed */
1 by brian
clean slate
656
    /* 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).
657
    local_data->cond->notify_one();
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
658
    local_data->cond= NULL;				/* Removed from list */
1 by brian
clean slate
659
  }
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
660
  for (THR_LOCK_DATA *local_data= write_wait.data; local_data ; local_data= local_data->next)
1 by brian
clean slate
661
  {
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
662
    local_data->type= TL_UNLOCK;
1786.2.1 by Brian Aker
Current boost work (more conversion).
663
    local_data->cond->notify_one();
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
664
    local_data->cond= NULL;
1 by brian
clean slate
665
  }
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
666
  read_wait.last= &read_wait.data;
667
  write_wait.last= &write_wait.data;
668
  read_wait.data= write_wait.data=0;
669
  if (write.data)
670
    write.data->type=TL_WRITE_ONLY;
1 by brian
clean slate
671
}
672
673
674
/*
675
  Abort all locks for specific table/thread combination
676
677
  This is used to abort all locks for a specific thread
678
*/
679
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
680
bool THR_LOCK::abort_locks_for_thread(uint64_t thread_id_arg)
1 by brian
clean slate
681
{
163 by Brian Aker
Merge Monty's code.
682
  bool found= false;
1 by brian
clean slate
683
1786.2.1 by Brian Aker
Current boost work (more conversion).
684
  boost::mutex::scoped_lock scopedLock(mutex);
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
685
  for (THR_LOCK_DATA *local_data= read_wait.data; local_data ; local_data= local_data->next)
1 by brian
clean slate
686
  {
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
687
    if (local_data->owner->info->thread_id == thread_id_arg)
1 by brian
clean slate
688
    {
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
689
      local_data->type= TL_UNLOCK;			/* Mark killed */
1 by brian
clean slate
690
      /* It's safe to signal the cond first: we're still holding the mutex. */
163 by Brian Aker
Merge Monty's code.
691
      found= true;
1786.2.1 by Brian Aker
Current boost work (more conversion).
692
      local_data->cond->notify_one();
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
693
      local_data->cond= 0;				/* Removed from list */
1 by brian
clean slate
694
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
695
      if (((*local_data->prev)= local_data->next))
696
	local_data->next->prev= local_data->prev;
1 by brian
clean slate
697
      else
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
698
	read_wait.last= local_data->prev;
1 by brian
clean slate
699
    }
700
  }
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
701
  for (THR_LOCK_DATA *local_data= write_wait.data; local_data ; local_data= local_data->next)
1 by brian
clean slate
702
  {
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
703
    if (local_data->owner->info->thread_id == thread_id_arg)
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
      local_data->type= TL_UNLOCK;
163 by Brian Aker
Merge Monty's code.
706
      found= true;
1786.2.1 by Brian Aker
Current boost work (more conversion).
707
      local_data->cond->notify_one();
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
708
      local_data->cond= NULL;
1 by brian
clean slate
709
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
710
      if (((*local_data->prev)= local_data->next))
711
	local_data->next->prev= local_data->prev;
1 by brian
clean slate
712
      else
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
713
	write_wait.last= local_data->prev;
1 by brian
clean slate
714
    }
715
  }
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
716
  wake_up_waiters(this);
717
718
  return found;
1 by brian
clean slate
719
}
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
720
721
} /* namespace drizzled */