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