~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to storage/myisam/mi_locking.c

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
  isamdatabase.
21
21
*/
22
22
 
23
 
#include "myisam_priv.h"
24
 
#include "drizzled/charset_info.h"
25
 
#include <drizzled/util/test.h>
26
 
 
27
 
using namespace std;
 
23
#include "ftdefs.h"
28
24
 
29
25
        /* lock table by F_UNLCK, F_RDLCK or F_WRLCK */
30
26
 
31
27
int mi_lock_database(MI_INFO *info, int lock_type)
32
28
{
33
29
  int error;
34
 
  uint32_t count;
 
30
  uint count;
35
31
  MYISAM_SHARE *share=info->s;
36
 
  uint32_t flag;
37
 
 
38
 
  pthread_mutex_lock(&share->intern_lock);
39
 
  if (!info->s->in_use)
40
 
    info->s->in_use= new list<Session *>;
41
 
 
 
32
  uint flag;
 
33
  DBUG_ENTER("mi_lock_database");
 
34
  DBUG_PRINT("enter",("lock_type: %d  old lock %d  r_locks: %u  w_locks: %u "
 
35
                      "global_changed:  %d  open_count: %u  name: '%s'",
 
36
                      lock_type, info->lock_type, share->r_locks,
 
37
                      share->w_locks,
 
38
                      share->global_changed, share->state.open_count,
 
39
                      share->index_file_name));
 
40
  if (share->options & HA_OPTION_READ_ONLY_DATA ||
 
41
      info->lock_type == lock_type)
 
42
    DBUG_RETURN(0);
42
43
  if (lock_type == F_EXTRA_LCK)                 /* Used by TMP tables */
43
44
  {
44
 
    pthread_mutex_unlock(&share->intern_lock);
45
45
    ++share->w_locks;
46
46
    ++share->tot_locks;
47
47
    info->lock_type= lock_type;
48
 
    info->s->in_use->push_front(info->in_use);
49
 
    return(0);
 
48
    info->s->in_use= list_add(info->s->in_use, &info->in_use);
 
49
    DBUG_RETURN(0);
50
50
  }
51
51
 
52
52
  flag=error=0;
 
53
  pthread_mutex_lock(&share->intern_lock);
53
54
  if (share->kfile >= 0)                /* May only be false on windows */
54
55
  {
55
56
    switch (lock_type) {
56
57
    case F_UNLCK:
 
58
      ftparser_call_deinitializer(info);
57
59
      if (info->lock_type == F_RDLCK)
58
60
        count= --share->r_locks;
59
61
      else
63
65
          !share->delay_key_write && flush_key_blocks(share->key_cache,
64
66
                                                      share->kfile,FLUSH_KEEP))
65
67
      {
66
 
        error=errno;
 
68
        error=my_errno;
67
69
        mi_print_error(info->s, HA_ERR_CRASHED);
68
70
        mi_mark_crashed(info);          /* Mark that table must be checked */
69
71
      }
71
73
      {
72
74
        if (end_io_cache(&info->rec_cache))
73
75
        {
74
 
          error=errno;
 
76
          error=my_errno;
75
77
          mi_print_error(info->s, HA_ERR_CRASHED);
76
78
          mi_mark_crashed(info);
77
79
        }
78
80
      }
79
81
      if (!count)
80
82
      {
 
83
        DBUG_PRINT("info",("changed: %u  w_locks: %u",
 
84
                           (uint) share->changed, share->w_locks));
81
85
        if (share->changed && !share->w_locks)
82
86
        {
 
87
#ifdef HAVE_MMAP
83
88
    if ((info->s->mmaped_length != info->s->state.state.data_file_length) &&
84
89
        (info->s->nonmmaped_inserts > MAX_NONMAPPED_INSERTS))
85
90
    {
86
91
      if (info->s->concurrent_insert)
87
 
        pthread_rwlock_wrlock(&info->s->mmap_lock);
 
92
        rw_wrlock(&info->s->mmap_lock);
88
93
      mi_remap_file(info, info->s->state.state.data_file_length);
89
94
      info->s->nonmmaped_inserts= 0;
90
95
      if (info->s->concurrent_insert)
91
 
        pthread_rwlock_unlock(&info->s->mmap_lock);
 
96
        rw_unlock(&info->s->mmap_lock);
92
97
    }
 
98
#endif
93
99
          share->state.process= share->last_process=share->this_process;
94
100
          share->state.unique=   info->last_unique=  info->this_unique;
95
101
          share->state.update_count= info->last_loop= ++info->this_loop;
96
102
          if (mi_state_info_write(share->kfile, &share->state, 1))
97
 
            error=errno;
 
103
            error=my_errno;
98
104
          share->changed=0;
99
 
          share->not_flushed=1;
 
105
          if (myisam_flush)
 
106
          {
 
107
            if (my_sync(share->kfile, MYF(0)))
 
108
              error= my_errno;
 
109
            if (my_sync(info->dfile, MYF(0)))
 
110
              error= my_errno;
 
111
          }
 
112
          else
 
113
            share->not_flushed=1;
100
114
          if (error)
101
115
          {
102
116
            mi_print_error(info->s, HA_ERR_CRASHED);
108
122
          if (share->r_locks)
109
123
          {                                     /* Only read locks left */
110
124
            flag=1;
 
125
            if (my_lock(share->kfile,F_RDLCK,0L,F_TO_EOF,
 
126
                        MYF(MY_WME | MY_SEEK_NOT_DONE)) && !error)
 
127
              error=my_errno;
111
128
          }
112
129
          else if (!share->w_locks)
113
130
          {                                     /* No more locks */
114
131
            flag=1;
 
132
            if (my_lock(share->kfile,F_UNLCK,0L,F_TO_EOF,
 
133
                        MYF(MY_WME | MY_SEEK_NOT_DONE)) && !error)
 
134
              error=my_errno;
115
135
          }
116
136
        }
117
137
      }
118
138
      info->opt_flag&= ~(READ_CACHE_USED | WRITE_CACHE_USED);
119
139
      info->lock_type= F_UNLCK;
120
 
      info->s->in_use->remove(info->in_use);
 
140
      info->s->in_use= list_delete(info->s->in_use, &info->in_use);
121
141
      break;
122
142
    case F_RDLCK:
123
143
      if (info->lock_type == F_WRLCK)
131
151
        if (share->w_locks == 1)
132
152
        {
133
153
          flag=1;
 
154
          if (my_lock(share->kfile,lock_type,0L,F_TO_EOF,
 
155
                      MYF(MY_SEEK_NOT_DONE)))
 
156
          {
 
157
            error=my_errno;
 
158
            break;
 
159
          }
134
160
        }
135
161
        share->w_locks--;
136
162
        share->r_locks++;
140
166
      if (!share->r_locks && !share->w_locks)
141
167
      {
142
168
        flag=1;
143
 
        if (mi_state_info_read_dsk(share->kfile, &share->state, 1))
 
169
        if (my_lock(share->kfile,lock_type,0L,F_TO_EOF,
 
170
                    info->lock_wait | MY_SEEK_NOT_DONE))
144
171
        {
145
 
          error=errno;
 
172
          error=my_errno;
146
173
          break;
147
174
        }
148
175
        if (mi_state_info_read_dsk(share->kfile, &share->state, 1))
149
176
        {
150
 
          error=errno;
151
 
          errno=error;
 
177
          error=my_errno;
 
178
          VOID(my_lock(share->kfile,F_UNLCK,0L,F_TO_EOF,MYF(MY_SEEK_NOT_DONE)));
 
179
          my_errno=error;
152
180
          break;
153
181
        }
154
182
      }
155
 
      _mi_test_if_changed(info);
 
183
      VOID(_mi_test_if_changed(info));
156
184
      share->r_locks++;
157
185
      share->tot_locks++;
158
186
      info->lock_type=lock_type;
159
 
      info->s->in_use->push_front(info->in_use);
 
187
      info->s->in_use= list_add(info->s->in_use, &info->in_use);
160
188
      break;
161
189
    case F_WRLCK:
162
190
      if (info->lock_type == F_RDLCK)
164
192
        if (share->r_locks == 1)
165
193
        {
166
194
          flag=1;
 
195
          if (my_lock(share->kfile,lock_type,0L,F_TO_EOF,
 
196
                      MYF(info->lock_wait | MY_SEEK_NOT_DONE)))
 
197
          {
 
198
            error=my_errno;
 
199
            break;
 
200
          }
167
201
          share->r_locks--;
168
202
          share->w_locks++;
169
203
          info->lock_type=lock_type;
175
209
        if (!share->w_locks)
176
210
        {
177
211
          flag=1;
 
212
          if (my_lock(share->kfile,lock_type,0L,F_TO_EOF,
 
213
                      info->lock_wait | MY_SEEK_NOT_DONE))
 
214
          {
 
215
            error=my_errno;
 
216
            break;
 
217
          }
178
218
          if (!share->r_locks)
179
219
          {
180
220
            if (mi_state_info_read_dsk(share->kfile, &share->state, 1))
181
221
            {
182
 
              error=errno;
183
 
              errno=error;
 
222
              error=my_errno;
 
223
              VOID(my_lock(share->kfile,F_UNLCK,0L,F_TO_EOF,
 
224
                           info->lock_wait | MY_SEEK_NOT_DONE));
 
225
              my_errno=error;
184
226
              break;
185
227
            }
186
228
          }
187
229
        }
188
230
      }
189
 
      _mi_test_if_changed(info);
190
 
 
 
231
      VOID(_mi_test_if_changed(info));
 
232
        
191
233
      info->lock_type=lock_type;
 
234
      info->invalidator=info->s->invalidator;
192
235
      share->w_locks++;
193
236
      share->tot_locks++;
194
 
      info->s->in_use->push_front(info->in_use);
 
237
      info->s->in_use= list_add(info->s->in_use, &info->in_use);
195
238
      break;
196
239
    default:
197
240
      break;                            /* Impossible */
203
246
    /*
204
247
       Check for bad file descriptors if this table is part
205
248
       of a merge union. Failing to capture this may cause
206
 
       a crash on windows if the table is renamed and
 
249
       a crash on windows if the table is renamed and 
207
250
       later on referenced by the merge table.
208
251
     */
209
252
    if( info->owned_by_merge && (info->s)->kfile < 0 )
215
258
  pthread_mutex_unlock(&share->intern_lock);
216
259
#if defined(FULL_LOG) || defined(_lint)
217
260
  lock_type|=(int) (flag << 8);         /* Set bit to set if real lock */
218
 
  myisam_log_command(MI_LOG_LOCK,info,(unsigned char*) &lock_type,sizeof(lock_type),
 
261
  myisam_log_command(MI_LOG_LOCK,info,(uchar*) &lock_type,sizeof(lock_type),
219
262
                     error);
220
263
#endif
221
 
  return(error);
 
264
  DBUG_RETURN(error);
222
265
} /* mi_lock_database */
223
266
 
224
267
 
239
282
void mi_get_status(void* param, int concurrent_insert)
240
283
{
241
284
  MI_INFO *info=(MI_INFO*) param;
242
 
 
 
285
  DBUG_ENTER("mi_get_status");
 
286
  DBUG_PRINT("info",("key_file: %ld  data_file: %ld  concurrent_insert: %d",
 
287
                     (long) info->s->state.state.key_file_length,
 
288
                     (long) info->s->state.state.data_file_length,
 
289
                     concurrent_insert));
 
290
#ifndef DBUG_OFF
 
291
  if (info->state->key_file_length > info->s->state.state.key_file_length ||
 
292
      info->state->data_file_length > info->s->state.state.data_file_length)
 
293
    DBUG_PRINT("warning",("old info:  key_file: %ld  data_file: %ld",
 
294
                          (long) info->state->key_file_length,
 
295
                          (long) info->state->data_file_length));
 
296
#endif
243
297
  info->save_state=info->s->state.state;
244
298
  info->state= &info->save_state;
245
299
  info->append_insert_at_end= concurrent_insert;
246
 
  return;
 
300
  DBUG_VOID_RETURN;
247
301
}
248
302
 
249
303
 
258
312
  */
259
313
  if (info->state == &info->save_state)
260
314
  {
 
315
#ifndef DBUG_OFF
 
316
    DBUG_PRINT("info",("updating status:  key_file: %ld  data_file: %ld",
 
317
                       (long) info->state->key_file_length,
 
318
                       (long) info->state->data_file_length));
 
319
    if (info->state->key_file_length < info->s->state.state.key_file_length ||
 
320
        info->state->data_file_length < info->s->state.state.data_file_length)
 
321
      DBUG_PRINT("warning",("old info:  key_file: %ld  data_file: %ld",
 
322
                            (long) info->s->state.state.key_file_length,
 
323
                            (long) info->s->state.state.data_file_length));
 
324
#endif
261
325
    info->s->state.state= *info->state;
262
326
    info->state= &info->s->state.state;
263
327
  }
298
362
 
299
363
  IMPLEMENTATION
300
364
    Allow concurrent inserts if we don't have a hole in the table or
301
 
    if there is no active write lock and there is active read locks and
 
365
    if there is no active write lock and there is active read locks and 
302
366
    myisam_concurrent_insert == 2. In this last case the new
303
367
    row('s) are inserted at end of file instead of filling up the hole.
304
368
 
314
378
    1  not ok
315
379
*/
316
380
 
317
 
bool mi_check_status(void *param)
 
381
my_bool mi_check_status(void *param)
318
382
{
319
383
  MI_INFO *info=(MI_INFO*) param;
320
384
  /*
322
386
    external lock (in other words: w_locks == 1 means no other threads has
323
387
    a write lock)
324
388
  */
325
 
  return (bool) !(info->s->state.dellink == HA_OFFSET_ERROR ||
 
389
  DBUG_PRINT("info",("dellink: %ld  r_locks: %u  w_locks: %u",
 
390
                     (long) info->s->state.dellink, (uint) info->s->r_locks,
 
391
                     (uint) info->s->w_locks));
 
392
  return (my_bool) !(info->s->state.dellink == HA_OFFSET_ERROR ||
326
393
                     (myisam_concurrent_insert == 2 && info->s->r_locks &&
327
394
                      info->s->w_locks == 1));
328
395
}
334
401
 
335
402
int _mi_readinfo(register MI_INFO *info, int lock_type, int check_keybuffer)
336
403
{
 
404
  DBUG_ENTER("_mi_readinfo");
 
405
 
337
406
  if (info->lock_type == F_UNLCK)
338
407
  {
339
408
    MYISAM_SHARE *share=info->s;
340
409
    if (!share->tot_locks)
341
410
    {
 
411
      if (my_lock(share->kfile,lock_type,0L,F_TO_EOF,
 
412
                  info->lock_wait | MY_SEEK_NOT_DONE))
 
413
        DBUG_RETURN(1);
342
414
      if (mi_state_info_read_dsk(share->kfile, &share->state, 1))
343
415
      {
344
 
        int error=errno ? errno : -1;
345
 
        errno=error;
346
 
        return(1);
 
416
        int error=my_errno ? my_errno : -1;
 
417
        VOID(my_lock(share->kfile,F_UNLCK,0L,F_TO_EOF,
 
418
                     MYF(MY_SEEK_NOT_DONE)));
 
419
        my_errno=error;
 
420
        DBUG_RETURN(1);
347
421
      }
348
422
    }
349
423
    if (check_keybuffer)
350
 
      _mi_test_if_changed(info);
 
424
      VOID(_mi_test_if_changed(info));
 
425
    info->invalidator=info->s->invalidator;
351
426
  }
352
427
  else if (lock_type == F_WRLCK && info->lock_type == F_RDLCK)
353
428
  {
354
 
    errno=EACCES;                               /* Not allowed to change */
355
 
    return(-1);                         /* when have read_lock() */
 
429
    my_errno=EACCES;                            /* Not allowed to change */
 
430
    DBUG_RETURN(-1);                            /* when have read_lock() */
356
431
  }
357
 
  return(0);
 
432
  DBUG_RETURN(0);
358
433
} /* _mi_readinfo */
359
434
 
360
435
 
363
438
  request
364
439
*/
365
440
 
366
 
int _mi_writeinfo(register MI_INFO *info, uint32_t operation)
 
441
int _mi_writeinfo(register MI_INFO *info, uint operation)
367
442
{
368
443
  int error,olderror;
369
444
  MYISAM_SHARE *share=info->s;
 
445
  DBUG_ENTER("_mi_writeinfo");
 
446
  DBUG_PRINT("info",("operation: %u  tot_locks: %u", operation,
 
447
                     share->tot_locks));
370
448
 
371
449
  error=0;
372
450
  if (share->tot_locks == 0)
373
451
  {
374
 
    olderror=errno;                     /* Remember last error */
 
452
    olderror=my_errno;                  /* Remember last error */
375
453
    if (operation)
376
454
    {                                   /* Two threads can't be here */
377
455
      share->state.process= share->last_process=   share->this_process;
378
456
      share->state.unique=  info->last_unique=     info->this_unique;
379
457
      share->state.update_count= info->last_loop= ++info->this_loop;
380
458
      if ((error=mi_state_info_write(share->kfile, &share->state, 1)))
381
 
        olderror=errno;
 
459
        olderror=my_errno;
 
460
#ifdef __WIN__
 
461
      if (myisam_flush)
 
462
      {
 
463
        _commit(share->kfile);
 
464
        _commit(info->dfile);
 
465
      }
 
466
#endif
382
467
    }
383
 
    errno=olderror;
 
468
    if (!(operation & WRITEINFO_NO_UNLOCK) &&
 
469
        my_lock(share->kfile,F_UNLCK,0L,F_TO_EOF,
 
470
                MYF(MY_WME | MY_SEEK_NOT_DONE)) && !error)
 
471
      DBUG_RETURN(1);
 
472
    my_errno=olderror;
384
473
  }
385
474
  else if (operation)
386
475
    share->changed= 1;                  /* Mark keyfile changed */
387
 
  return(error);
 
476
  DBUG_RETURN(error);
388
477
} /* _mi_writeinfo */
389
478
 
390
479
 
398
487
      share->state.unique  != info->last_unique ||
399
488
      share->state.update_count != info->last_loop)
400
489
  {                                             /* Keyfile has changed */
 
490
    DBUG_PRINT("info",("index file changed"));
401
491
    if (share->state.process != share->this_process)
402
 
      flush_key_blocks(share->key_cache, share->kfile, FLUSH_RELEASE);
 
492
      VOID(flush_key_blocks(share->key_cache, share->kfile, FLUSH_RELEASE));
403
493
    share->last_process=share->state.process;
404
494
    info->last_unique=  share->state.unique;
405
495
    info->last_loop=    share->state.update_count;
427
517
    was incremented in the same process.
428
518
 
429
519
  This mean that if we are the only process using the file, the open_count
430
 
  tells us if the MYISAM file wasn't properly closed.*/
 
520
  tells us if the MYISAM file wasn't properly closed. (This is true if
 
521
  my_disable_locking is set).
 
522
*/
431
523
 
432
524
 
433
525
int _mi_mark_file_changed(MI_INFO *info)
434
526
{
435
 
  unsigned char buff[3];
 
527
  uchar buff[3];
436
528
  register MYISAM_SHARE *share=info->s;
 
529
  DBUG_ENTER("_mi_mark_file_changed");
437
530
 
438
531
  if (!(share->state.changed & STATE_CHANGED) || ! share->global_changed)
439
532
  {
448
541
    {
449
542
      mi_int2store(buff,share->state.open_count);
450
543
      buff[2]=1;                                /* Mark that it's changed */
451
 
      return(my_pwrite(share->kfile,buff,sizeof(buff),
 
544
      DBUG_RETURN(my_pwrite(share->kfile,buff,sizeof(buff),
452
545
                            sizeof(share->state.header),
453
546
                            MYF(MY_NABP)));
454
547
    }
455
548
  }
456
 
  return(0);
 
549
  DBUG_RETURN(0);
457
550
}
458
551
 
459
552
 
464
557
 
465
558
int _mi_decrement_open_count(MI_INFO *info)
466
559
{
467
 
  unsigned char buff[2];
 
560
  uchar buff[2];
468
561
  register MYISAM_SHARE *share=info->s;
469
562
  int lock_error=0,write_error=0;
470
563
  if (share->global_changed)
471
564
  {
472
 
    uint32_t old_lock=info->lock_type;
 
565
    uint old_lock=info->lock_type;
473
566
    share->global_changed=0;
474
567
    lock_error=mi_lock_database(info,F_WRLCK);
475
568
    /* Its not fatal even if we couldn't get the lock ! */