~drizzle-trunk/drizzle/development

1 by brian
clean slate
1
/* Copyright (C) 2000 MySQL AB
2
3
   This program is free software; you can redistribute it and/or modify
4
   it under the terms of the GNU General Public License as published by
5
   the Free Software Foundation; version 2 of the License.
6
7
   This program is distributed in the hope that it will be useful,
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
   GNU General Public License for more details.
11
12
   You should have received a copy of the GNU General Public License
13
   along with this program; if not, write to the Free Software
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
16
/*
17
Read and write locks for Posix threads. All tread must acquire
18
all locks it needs through thr_multi_lock() to avoid dead-locks.
19
A lock consists of a master lock (THR_LOCK), and lock instances
20
(THR_LOCK_DATA).
21
Any thread can have any number of lock instances (read and write:s) on
22
any lock. All lock instances must be freed.
23
Locks are prioritized according to:
24
25
The current lock types are:
26
27
TL_READ	 		# Low priority read
28
TL_READ_WITH_SHARED_LOCKS
29
TL_READ_NO_INSERT	# Read without concurrent inserts
30
TL_WRITE_ALLOW_WRITE	# Write lock that allows other writers
31
TL_WRITE_ALLOW_READ	# Write lock, but allow reading
32
TL_WRITE_CONCURRENT_INSERT
33
			# Insert that can be mixed when selects
34
TL_WRITE		# High priority write
35
TL_WRITE_ONLY		# High priority write
36
			# Abort all new lock request with an error
37
38
Locks are prioritized according to:
39
40
WRITE_ALLOW_WRITE, WRITE_ALLOW_READ, WRITE_CONCURRENT_INSERT, WRITE_DELAYED,
41
WRITE_LOW_PRIORITY, READ, WRITE, READ_HIGH_PRIORITY and WRITE_ONLY
42
43
Locks in the same privilege level are scheduled in first-in-first-out order.
44
45
To allow concurrent read/writes locks, with 'WRITE_CONCURRENT_INSERT' one
46
should put a pointer to the following functions in the lock structure:
47
(If the pointer is zero (default), the function is not called)
48
49
50
The lock algorithm allows one to have one TL_WRITE_ALLOW_READ,
1008.1.1 by Brian Aker
Remove dead lock code around delayed INSERT.
51
TL_WRITE_CONCURRENT_INSERT lock at the same time as multiple read locks.
1 by brian
clean slate
52
53
*/
54
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
55
#include "config.h"
56
#include "drizzled/internal/my_sys.h"
1689.2.10 by Brian Aker
Move thread_var out to its own include file.
57
#include "drizzled/internal/thread_var.h"
1537.2.1 by Joe Daly
add statistics_variables.h
58
#include "drizzled/statistics_variables.h"
1 by brian
clean slate
59
60
#include "thr_lock.h"
1241.9.64 by Monty Taylor
Moved remaining non-public portions of mysys and mystrings to drizzled/internal.
61
#include "drizzled/internal/m_string.h"
1 by brian
clean slate
62
#include <errno.h>
916.1.9 by Padraig O'Sullivan
Removing an instance of the custom list structure from thr_lock.
63
#include <list>
1 by brian
clean slate
64
481.1.15 by Monty Taylor
Removed time.h and sys/time.h from global.h.
65
#if TIME_WITH_SYS_TIME
66
# include <sys/time.h>
67
# include <time.h>
68
#else
69
# if HAVE_SYS_TIME_H
70
#  include <sys/time.h>
71
# else
72
#  include <time.h>
73
# endif
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
74
#endif
481.1.15 by Monty Taylor
Removed time.h and sys/time.h from global.h.
75
492.1.7 by Monty Taylor
Moved test() to its own file.
76
#include <drizzled/util/test.h>
481.1.15 by Monty Taylor
Removed time.h and sys/time.h from global.h.
77
916.1.9 by Padraig O'Sullivan
Removing an instance of the custom list structure from thr_lock.
78
using namespace std;
79
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
80
namespace drizzled
81
{
82
622.1.1 by Brian Aker
32bit fixes around vars
83
uint64_t table_lock_wait_timeout;
1165.1.90 by Stewart Smith
make thr_upgraded_concurrent_insert_lock static to mysys/thr_lock.cc
84
static enum thr_lock_type thr_upgraded_concurrent_insert_lock = TL_WRITE;
1 by brian
clean slate
85
86
622.1.1 by Brian Aker
32bit fixes around vars
87
uint64_t max_write_lock_count= ~(uint64_t) 0L;
1 by brian
clean slate
88
89
static inline pthread_cond_t *get_cond(void)
90
{
91
  return &my_thread_var->suspend;
92
}
93
94
/*
95
** For the future (now the thread specific cond is alloced by my_pthread.c)
96
*/
97
146 by Brian Aker
my_bool cleanup.
98
static inline bool
1 by brian
clean slate
99
thr_lock_owner_equal(THR_LOCK_OWNER *rhs, THR_LOCK_OWNER *lhs)
100
{
101
  return rhs == lhs;
102
}
103
104
105
	/* Initialize a lock */
106
107
void thr_lock_init(THR_LOCK *lock)
108
{
1689.2.11 by Brian Aker
Encapsulate more of the thr lock.
109
  lock->init();
1 by brian
clean slate
110
  lock->read.last= &lock->read.data;
111
  lock->read_wait.last= &lock->read_wait.data;
112
  lock->write_wait.last= &lock->write_wait.data;
113
  lock->write.last= &lock->write.data;
114
}
115
116
1689.2.12 by Brian Aker
THR_LOCK_INFO::init() <-- encapsulation
117
void THR_LOCK_INFO::init()
1 by brian
clean slate
118
{
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
119
  internal::st_my_thread_var *tmp= my_thread_var;
1689.2.12 by Brian Aker
THR_LOCK_INFO::init() <-- encapsulation
120
  thread= tmp->pthread_self;
121
  thread_id= tmp->id;
122
  n_cursors= 0;
1 by brian
clean slate
123
}
124
125
	/* Initialize a lock instance */
126
1689.2.13 by Brian Aker
More encapsulation of thr_lock
127
void THR_LOCK_DATA::init(THR_LOCK *lock_arg, void *param_arg)
1 by brian
clean slate
128
{
1689.2.13 by Brian Aker
More encapsulation of thr_lock
129
  lock= lock_arg;
130
  type= TL_UNLOCK;
131
  owner= NULL;                               /* no owner yet */
132
  status_param= param_arg;
133
  cond= NULL;
1 by brian
clean slate
134
}
135
136
146 by Brian Aker
my_bool cleanup.
137
static inline bool
1 by brian
clean slate
138
have_old_read_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner)
139
{
140
  for ( ; data ; data=data->next)
141
  {
142
    if (thr_lock_owner_equal(data->owner, owner))
1054.1.4 by Brian Aker
Formatting.
143
      return true;					/* Already locked by thread */
1 by brian
clean slate
144
  }
1054.1.4 by Brian Aker
Formatting.
145
  return false;
1 by brian
clean slate
146
}
147
148
static void wake_up_waiters(THR_LOCK *lock);
149
150
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
151
static enum enum_thr_lock_result wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data, bool in_wait_list)
1 by brian
clean slate
152
{
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
153
  internal::st_my_thread_var *thread_var= my_thread_var;
1 by brian
clean slate
154
  pthread_cond_t *cond= &thread_var->suspend;
155
  struct timespec wait_timeout;
156
  enum enum_thr_lock_result result= THR_LOCK_ABORTED;
146 by Brian Aker
my_bool cleanup.
157
  bool can_deadlock= test(data->owner->info->n_cursors);
1 by brian
clean slate
158
159
  if (!in_wait_list)
160
  {
161
    (*wait->last)=data;				/* Wait for lock */
162
    data->prev= wait->last;
163
    wait->last= &data->next;
164
  }
165
1537.2.1 by Joe Daly
add statistics_variables.h
166
  status_var_increment(current_global_counters.locks_waited);
1 by brian
clean slate
167
168
  /* Set up control struct to allow others to abort locks */
1689.2.11 by Brian Aker
Encapsulate more of the thr lock.
169
  thread_var->current_mutex= data->lock->native_handle();
1 by brian
clean slate
170
  thread_var->current_cond=  cond;
171
  data->cond= cond;
172
173
  if (can_deadlock)
174
    set_timespec(wait_timeout, table_lock_wait_timeout);
175
  while (!thread_var->abort || in_wait_list)
176
  {
177
    int rc= (can_deadlock ?
1689.2.11 by Brian Aker
Encapsulate more of the thr lock.
178
             pthread_cond_timedwait(cond, data->lock->native_handle(),
1 by brian
clean slate
179
                                    &wait_timeout) :
1689.2.11 by Brian Aker
Encapsulate more of the thr lock.
180
             pthread_cond_wait(cond, data->lock->native_handle()));
1 by brian
clean slate
181
    /*
182
      We must break the wait if one of the following occurs:
183
      - the connection has been aborted (!thread_var->abort), but
184
        this is not a delayed insert thread (in_wait_list). For a delayed
185
        insert thread the proper action at shutdown is, apparently, to
186
        acquire the lock and complete the insert.
187
      - the lock has been granted (data->cond is set to NULL by the granter),
188
        or the waiting has been aborted (additionally data->type is set to
189
        TL_UNLOCK).
190
      - the wait has timed out (rc == ETIMEDOUT)
191
      Order of checks below is important to not report about timeout
192
      if the predicate is true.
193
    */
194
    if (data->cond == 0)
195
    {
196
      break;
197
    }
198
    if (rc == ETIMEDOUT || rc == ETIME)
199
    {
200
      result= THR_LOCK_WAIT_TIMEOUT;
201
      break;
202
    }
203
  }
204
  if (data->cond || data->type == TL_UNLOCK)
205
  {
206
    if (data->cond)                             /* aborted or timed out */
207
    {
208
      if (((*data->prev)=data->next))		/* remove from wait-list */
209
	data->next->prev= data->prev;
210
      else
211
	wait->last=data->prev;
212
      data->type= TL_UNLOCK;                    /* No lock */
213
      wake_up_waiters(data->lock);
214
    }
215
  }
216
  else
217
  {
218
    result= THR_LOCK_SUCCESS;
219
  }
1689.2.11 by Brian Aker
Encapsulate more of the thr lock.
220
  data->lock->unlock();
1 by brian
clean slate
221
222
  /* The following must be done after unlock of lock->mutex */
223
  pthread_mutex_lock(&thread_var->mutex);
1054.1.4 by Brian Aker
Formatting.
224
  thread_var->current_mutex= NULL;
225
  thread_var->current_cond= NULL;
1 by brian
clean slate
226
  pthread_mutex_unlock(&thread_var->mutex);
51.3.14 by Jay Pipes
Phase 2 removal of DBUG in mysys
227
  return(result);
1 by brian
clean slate
228
}
229
230
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
231
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
232
{
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
233
  THR_LOCK *lock= data->lock;
1 by brian
clean slate
234
  enum enum_thr_lock_result result= THR_LOCK_SUCCESS;
235
  struct st_lock_list *wait_queue;
236
  THR_LOCK_DATA *lock_owner;
237
238
  data->next=0;
239
  data->cond=0;					/* safety */
240
  data->type=lock_type;
241
  data->owner= owner;                           /* Must be reset ! */
1689.2.11 by Brian Aker
Encapsulate more of the thr lock.
242
  lock->lock();
1 by brian
clean slate
243
  if ((int) lock_type <= (int) TL_READ_NO_INSERT)
244
  {
245
    /* Request for READ lock */
246
    if (lock->write.data)
247
    {
248
      /* We can allow a read lock even if there is already a write lock
249
	 on the table in one the following cases:
250
	 - This thread alread have a write lock on the table
251
	 - The write lock is TL_WRITE_ALLOW_READ or TL_WRITE_DELAYED
252
           and the read lock is TL_READ_HIGH_PRIORITY or TL_READ
253
         - The write lock is TL_WRITE_CONCURRENT_INSERT or TL_WRITE_ALLOW_WRITE
254
	   and the read lock is not TL_READ_NO_INSERT
255
      */
256
257
      if (thr_lock_owner_equal(data->owner, lock->write.data->owner) ||
1008.1.1 by Brian Aker
Remove dead lock code around delayed INSERT.
258
	  (lock->write.data->type <= TL_WRITE_CONCURRENT_INSERT &&
1008.1.4 by Brian Aker
Removed TL_READ_HIGH_PRIORITY
259
	   (((int) lock_type <= (int) TL_READ_WITH_SHARED_LOCKS) ||
1 by brian
clean slate
260
	    (lock->write.data->type != TL_WRITE_CONCURRENT_INSERT &&
261
	     lock->write.data->type != TL_WRITE_ALLOW_READ))))
262
      {						/* Already got a write lock */
263
	(*lock->read.last)=data;		/* Add to running FIFO */
264
	data->prev=lock->read.last;
265
	lock->read.last= &data->next;
266
	if (lock_type == TL_READ_NO_INSERT)
267
	  lock->read_no_write_count++;
1537.2.1 by Joe Daly
add statistics_variables.h
268
        status_var_increment(current_global_counters.locks_immediate);
1 by brian
clean slate
269
	goto end;
270
      }
271
      if (lock->write.data->type == TL_WRITE_ONLY)
272
      {
273
	/* We are not allowed to get a READ lock in this case */
274
	data->type=TL_UNLOCK;
275
        result= THR_LOCK_ABORTED;               /* Can't wait for this one */
276
	goto end;
277
      }
278
    }
279
    else if (!lock->write_wait.data ||
1008.1.2 by Brian Aker
Removed old DELAYED keyword from parser (plus cleaned up tests). Also
280
	     lock->write_wait.data->type <= TL_WRITE_DEFAULT ||
1 by brian
clean slate
281
	     have_old_read_lock(lock->read.data, data->owner))
282
    {						/* No important write-locks */
283
      (*lock->read.last)=data;			/* Add to running FIFO */
284
      data->prev=lock->read.last;
285
      lock->read.last= &data->next;
286
      if (lock_type == TL_READ_NO_INSERT)
287
	lock->read_no_write_count++;
1537.2.1 by Joe Daly
add statistics_variables.h
288
      status_var_increment(current_global_counters.locks_immediate);
1 by brian
clean slate
289
      goto end;
290
    }
291
    /*
292
      We're here if there is an active write lock or no write
293
      lock but a high priority write waiting in the write_wait queue.
294
      In the latter case we should yield the lock to the writer.
295
    */
296
    wait_queue= &lock->read_wait;
297
  }
298
  else						/* Request for WRITE lock */
299
  {
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
300
    if (lock_type == TL_WRITE_CONCURRENT_INSERT)
1 by brian
clean slate
301
      data->type=lock_type= thr_upgraded_concurrent_insert_lock;
302
303
    if (lock->write.data)			/* If there is a write lock */
304
    {
305
      if (lock->write.data->type == TL_WRITE_ONLY)
306
      {
307
        /* Allow lock owner to bypass TL_WRITE_ONLY. */
308
        if (!thr_lock_owner_equal(data->owner, lock->write.data->owner))
309
        {
310
          /* We are not allowed to get a lock in this case */
311
          data->type=TL_UNLOCK;
312
          result= THR_LOCK_ABORTED;               /* Can't wait for this one */
313
          goto end;
314
        }
315
      }
316
317
      /*
318
	The following test will not work if the old lock was a
319
	TL_WRITE_ALLOW_WRITE, TL_WRITE_ALLOW_READ or TL_WRITE_DELAYED in
320
	the same thread, but this will never happen within MySQL.
321
      */
322
      if (thr_lock_owner_equal(data->owner, lock->write.data->owner) ||
323
	  (lock_type == TL_WRITE_ALLOW_WRITE &&
324
	   !lock->write_wait.data &&
325
	   lock->write.data->type == TL_WRITE_ALLOW_WRITE))
326
      {
327
	/*
328
          We have already got a write lock or all locks are
329
          TL_WRITE_ALLOW_WRITE
330
        */
331
332
	(*lock->write.last)=data;	/* Add to running fifo */
333
	data->prev=lock->write.last;
334
	lock->write.last= &data->next;
1537.2.1 by Joe Daly
add statistics_variables.h
335
        status_var_increment(current_global_counters.locks_immediate);
1 by brian
clean slate
336
	goto end;
337
      }
338
    }
339
    else
340
    {
341
      if (!lock->write_wait.data)
342
      {						/* no scheduled write locks */
146 by Brian Aker
my_bool cleanup.
343
        bool concurrent_insert= 0;
1 by brian
clean slate
344
	if (lock_type == TL_WRITE_CONCURRENT_INSERT)
345
        {
346
          concurrent_insert= 1;
347
        }
348
349
	if (!lock->read.data ||
1008.1.1 by Brian Aker
Remove dead lock code around delayed INSERT.
350
	    (lock_type <= TL_WRITE_CONCURRENT_INSERT &&
1 by brian
clean slate
351
	     ((lock_type != TL_WRITE_CONCURRENT_INSERT &&
352
	       lock_type != TL_WRITE_ALLOW_WRITE) ||
353
	      !lock->read_no_write_count)))
354
	{
355
	  (*lock->write.last)=data;		/* Add as current write lock */
356
	  data->prev=lock->write.last;
357
	  lock->write.last= &data->next;
1537.2.1 by Joe Daly
add statistics_variables.h
358
          status_var_increment(current_global_counters.locks_immediate);
1 by brian
clean slate
359
	  goto end;
360
	}
361
      }
362
    }
363
    wait_queue= &lock->write_wait;
364
  }
365
  /*
366
    Try to detect a trivial deadlock when using cursors: attempt to
367
    lock a table that is already locked by an open cursor within the
368
    same connection. lock_owner can be zero if we succumbed to a high
369
    priority writer in the write_wait queue.
370
  */
371
  lock_owner= lock->read.data ? lock->read.data : lock->write.data;
372
  if (lock_owner && lock_owner->owner->info == owner->info)
373
  {
374
    result= THR_LOCK_DEADLOCK;
375
    goto end;
376
  }
1689.2.11 by Brian Aker
Encapsulate more of the thr lock.
377
1 by brian
clean slate
378
  /* Can't get lock yet;  Wait for it */
51.3.14 by Jay Pipes
Phase 2 removal of DBUG in mysys
379
  return(wait_for_lock(wait_queue, data, 0));
1 by brian
clean slate
380
end:
1689.2.11 by Brian Aker
Encapsulate more of the thr lock.
381
  lock->unlock();
382
51.3.14 by Jay Pipes
Phase 2 removal of DBUG in mysys
383
  return(result);
1 by brian
clean slate
384
}
385
386
1022.2.29 by Monty Taylor
Fixed some no-inline warnings.
387
static void free_all_read_locks(THR_LOCK *lock, bool using_concurrent_insert)
1 by brian
clean slate
388
{
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
389
  THR_LOCK_DATA *data= lock->read_wait.data;
1 by brian
clean slate
390
391
  /* move all locks from read_wait list to read list */
392
  (*lock->read.last)=data;
393
  data->prev=lock->read.last;
394
  lock->read.last=lock->read_wait.last;
395
396
  /* Clear read_wait list */
397
  lock->read_wait.last= &lock->read_wait.data;
398
399
  do
400
  {
401
    pthread_cond_t *cond=data->cond;
402
    if ((int) data->type == (int) TL_READ_NO_INSERT)
403
    {
404
      if (using_concurrent_insert)
405
      {
406
	/*
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
407
	  We can't free this lock;
1 by brian
clean slate
408
	  Link lock away from read chain back into read_wait chain
409
	*/
410
	if (((*data->prev)=data->next))
411
	  data->next->prev=data->prev;
412
	else
413
	  lock->read.last=data->prev;
414
	*lock->read_wait.last= data;
415
	data->prev= lock->read_wait.last;
416
	lock->read_wait.last= &data->next;
417
	continue;
418
      }
419
      lock->read_no_write_count++;
660.1.3 by Eric Herman
removed trailing whitespace with simple script:
420
    }
1 by brian
clean slate
421
    data->cond=0;				/* Mark thread free */
398.1.10 by Monty Taylor
Actually removed VOID() this time.
422
    pthread_cond_signal(cond);
1 by brian
clean slate
423
  } while ((data=data->next));
424
  *lock->read_wait.last=0;
425
  if (!lock->read_wait.data)
426
    lock->write_lock_count=0;
427
}
428
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
429
/* Unlock lock and free next thread on same lock */
1 by brian
clean slate
430
1165.1.89 by Stewart Smith
make thr_unlock() static to mysys/thr_lock.cc
431
static void thr_unlock(THR_LOCK_DATA *data)
1 by brian
clean slate
432
{
433
  THR_LOCK *lock=data->lock;
434
  enum thr_lock_type lock_type=data->type;
1689.2.11 by Brian Aker
Encapsulate more of the thr lock.
435
  lock->lock();
1 by brian
clean slate
436
437
  if (((*data->prev)=data->next))		/* remove from lock-list */
438
    data->next->prev= data->prev;
439
  else if (lock_type <= TL_READ_NO_INSERT)
440
    lock->read.last=data->prev;
441
  else
442
    lock->write.last=data->prev;
443
  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
444
  { }
1 by brian
clean slate
445
  else
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
446
  { }
1 by brian
clean slate
447
  if (lock_type == TL_READ_NO_INSERT)
448
    lock->read_no_write_count--;
449
  data->type=TL_UNLOCK;				/* Mark unlocked */
450
  wake_up_waiters(lock);
1689.2.11 by Brian Aker
Encapsulate more of the thr lock.
451
  lock->unlock();
1 by brian
clean slate
452
}
453
454
455
/**
456
  @brief  Wake up all threads which pending requests for the lock
457
          can be satisfied.
458
459
  @param  lock  Lock for which threads should be woken up
460
461
*/
462
463
static void wake_up_waiters(THR_LOCK *lock)
464
{
465
  THR_LOCK_DATA *data;
466
  enum thr_lock_type lock_type;
467
468
  if (!lock->write.data)			/* If no active write locks */
469
  {
470
    data=lock->write_wait.data;
471
    if (!lock->read.data)			/* If no more locks in use */
472
    {
473
      /* Release write-locks with TL_WRITE or TL_WRITE_ONLY priority first */
474
      if (data &&
1008.1.4 by Brian Aker
Removed TL_READ_HIGH_PRIORITY
475
	  (!lock->read_wait.data || lock->read_wait.data->type <= TL_READ_WITH_SHARED_LOCKS))
1 by brian
clean slate
476
      {
477
	if (lock->write_lock_count++ > max_write_lock_count)
478
	{
479
	  /* Too many write locks in a row;  Release all waiting read locks */
480
	  lock->write_lock_count=0;
481
	  if (lock->read_wait.data)
482
	  {
483
	    free_all_read_locks(lock,0);
484
	    goto end;
485
	  }
486
	}
487
	for (;;)
488
	{
489
	  if (((*data->prev)=data->next))	/* remove from wait-list */
490
	    data->next->prev= data->prev;
491
	  else
492
	    lock->write_wait.last=data->prev;
493
	  (*lock->write.last)=data;		/* Put in execute list */
494
	  data->prev=lock->write.last;
495
	  data->next=0;
496
	  lock->write.last= &data->next;
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
497
1 by brian
clean slate
498
	  {
499
	    pthread_cond_t *cond=data->cond;
500
	    data->cond=0;				/* Mark thread free */
398.1.10 by Monty Taylor
Actually removed VOID() this time.
501
	    pthread_cond_signal(cond);	/* Start waiting thread */
1 by brian
clean slate
502
	  }
503
	  if (data->type != TL_WRITE_ALLOW_WRITE ||
504
	      !lock->write_wait.data ||
505
	      lock->write_wait.data->type != TL_WRITE_ALLOW_WRITE)
506
	    break;
507
	  data=lock->write_wait.data;		/* Free this too */
508
	}
1008.1.2 by Brian Aker
Removed old DELAYED keyword from parser (plus cleaned up tests). Also
509
	if (data->type >= TL_WRITE)
1 by brian
clean slate
510
          goto end;
511
	/* Release possible read locks together with the write lock */
512
      }
513
      if (lock->read_wait.data)
514
	free_all_read_locks(lock,
515
			    data &&
516
			    (data->type == TL_WRITE_CONCURRENT_INSERT ||
517
			     data->type == TL_WRITE_ALLOW_WRITE));
518
    }
519
    else if (data &&
1008.1.1 by Brian Aker
Remove dead lock code around delayed INSERT.
520
	     (lock_type=data->type) <= TL_WRITE_CONCURRENT_INSERT &&
1 by brian
clean slate
521
	     ((lock_type != TL_WRITE_CONCURRENT_INSERT &&
522
	       lock_type != TL_WRITE_ALLOW_WRITE) ||
523
	      !lock->read_no_write_count))
524
    {
525
      do {
526
	pthread_cond_t *cond=data->cond;
527
	if (((*data->prev)=data->next))		/* remove from wait-list */
528
	  data->next->prev= data->prev;
529
	else
530
	  lock->write_wait.last=data->prev;
531
	(*lock->write.last)=data;		/* Put in execute list */
532
	data->prev=lock->write.last;
533
	lock->write.last= &data->next;
534
	data->next=0;				/* Only one write lock */
535
	data->cond=0;				/* Mark thread free */
398.1.10 by Monty Taylor
Actually removed VOID() this time.
536
	pthread_cond_signal(cond);	/* Start waiting thread */
1 by brian
clean slate
537
      } while (lock_type == TL_WRITE_ALLOW_WRITE &&
538
	       (data=lock->write_wait.data) &&
539
	       data->type == TL_WRITE_ALLOW_WRITE);
540
      if (lock->read_wait.data)
541
	free_all_read_locks(lock,
542
			    (lock_type == TL_WRITE_CONCURRENT_INSERT ||
543
			     lock_type == TL_WRITE_ALLOW_WRITE));
544
    }
545
    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
546
    {
1 by brian
clean slate
547
      free_all_read_locks(lock,0);
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
548
    }
1 by brian
clean slate
549
  }
550
end:
51.3.14 by Jay Pipes
Phase 2 removal of DBUG in mysys
551
  return;
1 by brian
clean slate
552
}
553
554
555
/*
556
** Get all locks in a specific order to avoid dead-locks
557
** Sort acording to lock position and put write_locks before read_locks if
558
** lock on same lock.
559
*/
560
561
895 by Brian Aker
Completion (?) of uint conversion.
562
#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
563
482 by Brian Aker
Remove uint.
564
static void sort_locks(THR_LOCK_DATA **data,uint32_t count)
1 by brian
clean slate
565
{
566
  THR_LOCK_DATA **pos,**end,**prev,*tmp;
567
568
  /* Sort locks with insertion sort (fast because almost always few locks) */
569
570
  for (pos=data+1,end=data+count; pos < end ; pos++)
571
  {
572
    tmp= *pos;
573
    if (LOCK_CMP(tmp,pos[-1]))
574
    {
575
      prev=pos;
576
      do {
577
	prev[0]=prev[-1];
578
      } while (--prev != data && LOCK_CMP(tmp,prev[-1]));
579
      prev[0]=tmp;
580
    }
581
  }
582
}
583
584
585
enum enum_thr_lock_result
482 by Brian Aker
Remove uint.
586
thr_multi_lock(THR_LOCK_DATA **data, uint32_t count, THR_LOCK_OWNER *owner)
1 by brian
clean slate
587
{
588
  THR_LOCK_DATA **pos,**end;
589
  if (count > 1)
590
    sort_locks(data,count);
591
  /* lock everything */
592
  for (pos=data,end=data+count; pos < end ; pos++)
593
  {
594
    enum enum_thr_lock_result result= thr_lock(*pos, owner, (*pos)->type);
595
    if (result != THR_LOCK_SUCCESS)
596
    {						/* Aborted */
895 by Brian Aker
Completion (?) of uint conversion.
597
      thr_multi_unlock(data,(uint32_t) (pos-data));
51.3.14 by Jay Pipes
Phase 2 removal of DBUG in mysys
598
      return(result);
1 by brian
clean slate
599
    }
600
  }
601
  /*
602
    Ensure that all get_locks() have the same status
603
    If we lock the same table multiple times, we must use the same
604
    status_param!
605
  */
606
#if !defined(DONT_USE_RW_LOCKS)
607
  if (count > 1)
608
  {
609
    THR_LOCK_DATA *last_lock= end[-1];
610
    pos=end-1;
611
    do
612
    {
613
      pos--;
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
614
      last_lock=(*pos);
1 by brian
clean slate
615
    } while (pos != data);
616
  }
617
#endif
51.3.14 by Jay Pipes
Phase 2 removal of DBUG in mysys
618
  return(THR_LOCK_SUCCESS);
1 by brian
clean slate
619
}
620
621
  /* free all locks */
622
482 by Brian Aker
Remove uint.
623
void thr_multi_unlock(THR_LOCK_DATA **data,uint32_t count)
1 by brian
clean slate
624
{
625
  THR_LOCK_DATA **pos,**end;
626
627
  for (pos=data,end=data+count; pos < end ; pos++)
628
  {
629
    if ((*pos)->type != TL_UNLOCK)
630
      thr_unlock(*pos);
631
  }
51.3.14 by Jay Pipes
Phase 2 removal of DBUG in mysys
632
  return;
1 by brian
clean slate
633
}
634
635
/*
636
  Abort all threads waiting for a lock. The lock will be upgraded to
637
  TL_WRITE_ONLY to abort any new accesses to the lock
638
*/
639
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
640
void THR_LOCK::abort_locks()
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
  pthread_mutex_lock(&mutex);
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
  for (THR_LOCK_DATA *local_data= read_wait.data; local_data ; local_data= local_data->next)
1 by brian
clean slate
645
  {
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
646
    local_data->type= TL_UNLOCK;			/* Mark killed */
1 by brian
clean slate
647
    /* It's safe to signal the cond first: we're still holding the mutex. */
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
648
    pthread_cond_signal(local_data->cond);
649
    local_data->cond= NULL;				/* Removed from list */
1 by brian
clean slate
650
  }
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
651
  for (THR_LOCK_DATA *local_data= write_wait.data; local_data ; local_data= local_data->next)
1 by brian
clean slate
652
  {
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
653
    local_data->type= TL_UNLOCK;
654
    pthread_cond_signal(local_data->cond);
655
    local_data->cond= NULL;
1 by brian
clean slate
656
  }
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
657
  read_wait.last= &read_wait.data;
658
  write_wait.last= &write_wait.data;
659
  read_wait.data= write_wait.data=0;
660
  if (write.data)
661
    write.data->type=TL_WRITE_ONLY;
662
  pthread_mutex_unlock(&mutex);
1 by brian
clean slate
663
}
664
665
666
/*
667
  Abort all locks for specific table/thread combination
668
669
  This is used to abort all locks for a specific thread
670
*/
671
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
672
bool THR_LOCK::abort_locks_for_thread(uint64_t thread_id_arg)
1 by brian
clean slate
673
{
163 by Brian Aker
Merge Monty's code.
674
  bool found= false;
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
  pthread_mutex_lock(&mutex);
677
  for (THR_LOCK_DATA *local_data= read_wait.data; local_data ; local_data= local_data->next)
1 by brian
clean slate
678
  {
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
679
    if (local_data->owner->info->thread_id == thread_id_arg)
1 by brian
clean slate
680
    {
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
681
      local_data->type= TL_UNLOCK;			/* Mark killed */
1 by brian
clean slate
682
      /* It's safe to signal the cond first: we're still holding the mutex. */
163 by Brian Aker
Merge Monty's code.
683
      found= true;
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
684
      pthread_cond_signal(local_data->cond);
685
      local_data->cond= 0;				/* Removed from list */
1 by brian
clean slate
686
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
687
      if (((*local_data->prev)= local_data->next))
688
	local_data->next->prev= local_data->prev;
1 by brian
clean slate
689
      else
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
690
	read_wait.last= local_data->prev;
1 by brian
clean slate
691
    }
692
  }
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
693
  for (THR_LOCK_DATA *local_data= write_wait.data; local_data ; local_data= local_data->next)
1 by brian
clean slate
694
  {
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
695
    if (local_data->owner->info->thread_id == thread_id_arg)
1 by brian
clean slate
696
    {
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
697
      local_data->type= TL_UNLOCK;
163 by Brian Aker
Merge Monty's code.
698
      found= true;
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
699
      pthread_cond_signal(local_data->cond);
700
      local_data->cond= NULL;
1 by brian
clean slate
701
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
702
      if (((*local_data->prev)= local_data->next))
703
	local_data->next->prev= local_data->prev;
1 by brian
clean slate
704
      else
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
705
	write_wait.last= local_data->prev;
1 by brian
clean slate
706
    }
707
  }
1685.2.1 by Brian Aker
This removes custom myisam lock code from the kernel (and removes the
708
  wake_up_waiters(this);
709
  pthread_mutex_unlock(&mutex);
710
711
  return found;
1 by brian
clean slate
712
}
1280.1.10 by Monty Taylor
Put everything in drizzled into drizzled namespace.
713
714
} /* namespace drizzled */