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