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