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