~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to mysys/mf_keycache.c

Removed SCCS references.

Show diffs side-by-side

added added

removed removed

Lines of Context:
101
101
  I/O finished.
102
102
*/
103
103
 
104
 
#include <drizzled/global.h>
105
 
#include <mysys/mysys_err.h>
106
 
#include <mysys/my_sys.h>
 
104
#include "mysys_priv.h"
 
105
#include "mysys_err.h"
107
106
#include <keycache.h>
108
 
#include <mystrings/m_string.h>
109
 
#include <mysys/my_bit.h>
 
107
#include "my_static.h"
 
108
#include <m_string.h>
 
109
#include <my_bit.h>
110
110
#include <errno.h>
111
111
#include <stdarg.h>
112
112
 
130
130
    situation, which theoretically should not happen;
131
131
    to set timeout equal to <T> seconds add
132
132
      #define KEYCACHE_TIMEOUT <T>
 
133
  - to enable the module traps and to send debug information from
 
134
    key cache module to a special debug log add:
 
135
      #define KEYCACHE_DEBUG
 
136
    the name of this debug log file <LOG NAME> can be set through:
 
137
      #define KEYCACHE_DEBUG_LOG  <LOG NAME>
 
138
    if the name is not defined, it's set by default;
 
139
    if the KEYCACHE_DEBUG flag is not set up and we are in a debug
 
140
    mode, i.e. when ! defined(DBUG_OFF), the debug information from the
 
141
    module is sent to the regular debug log.
133
142
 
134
143
  Example of the settings:
135
144
    #define SERIALIZED_READ_FROM_CACHE
136
145
    #define MAX_THREADS   100
137
146
    #define KEYCACHE_TIMEOUT  1
 
147
    #define KEYCACHE_DEBUG
 
148
    #define KEYCACHE_DEBUG_LOG  "my_key_cache_debug.log"
138
149
*/
139
150
 
140
151
#define STRUCT_PTR(TYPE, MEMBER, a)                                           \
161
172
  struct st_block_link *block;       /* reference to the block for the page: */
162
173
  File file;                         /* from such a file                     */
163
174
  my_off_t diskpos;                  /* with such an offset                  */
164
 
  uint32_t requests;                     /* number of requests for the page      */
 
175
  uint requests;                     /* number of requests for the page      */
165
176
};
166
177
 
167
178
/* simple states of a block */
193
204
    *next_changed, **prev_changed; /* for lists of file dirty/clean blocks   */
194
205
  struct st_hash_link *hash_link; /* backward ptr to referring hash_link     */
195
206
  KEYCACHE_WQUEUE wqueue[2]; /* queues on waiting requests for new/old pages */
196
 
  uint32_t requests;          /* number of requests for the block                */
197
 
  unsigned char *buffer;           /* buffer for the block page                       */
198
 
  uint32_t offset;            /* beginning of modified data in the buffer        */
199
 
  uint32_t length;            /* end of data in the buffer                       */
200
 
  uint32_t status;            /* state of the block                              */
 
207
  uint requests;          /* number of requests for the block                */
 
208
  uchar *buffer;           /* buffer for the block page                       */
 
209
  uint offset;            /* beginning of modified data in the buffer        */
 
210
  uint length;            /* end of data in the buffer                       */
 
211
  uint status;            /* state of the block                              */
201
212
  enum BLOCK_TEMPERATURE temperature; /* block temperature: cold, warm, hot */
202
 
  uint32_t hits_left;         /* number of hits left until promotion             */
203
 
  uint64_t last_hit_time; /* timestamp of the last hit                      */
 
213
  uint hits_left;         /* number of hits left until promotion             */
 
214
  ulonglong last_hit_time; /* timestamp of the last hit                      */
204
215
  KEYCACHE_CONDVAR *condvar; /* condition variable for 'no readers' event    */
205
216
};
206
217
 
210
221
#define FLUSH_CACHE         2000            /* sort this many blocks at once */
211
222
 
212
223
static int flush_all_key_blocks(KEY_CACHE *keycache);
 
224
#ifdef THREAD
213
225
static void wait_on_queue(KEYCACHE_WQUEUE *wqueue,
214
226
                          pthread_mutex_t *mutex);
215
227
static void release_whole_queue(KEYCACHE_WQUEUE *wqueue);
 
228
#else
 
229
#define wait_on_queue(wqueue, mutex)    do {} while (0)
 
230
#define release_whole_queue(wqueue)     do {} while (0)
 
231
#endif
216
232
static void free_block(KEY_CACHE *keycache, BLOCK_LINK *block);
 
233
#if !defined(DBUG_OFF)
 
234
static void test_key_cache(KEY_CACHE *keycache,
 
235
                           const char *where, my_bool lock);
 
236
#endif
217
237
 
218
238
#define KEYCACHE_HASH(f, pos)                                                 \
219
 
(((uint32_t) ((pos) / keycache->key_cache_block_size) +                          \
220
 
                                     (uint32_t) (f)) & (keycache->hash_entries-1))
 
239
(((ulong) ((pos) / keycache->key_cache_block_size) +                          \
 
240
                                     (ulong) (f)) & (keycache->hash_entries-1))
221
241
#define FILE_HASH(f)                 ((uint) (f) & (CHANGED_BLOCKS_HASH-1))
222
242
 
 
243
#define DEFAULT_KEYCACHE_DEBUG_LOG  "keycache_debug.log"
 
244
 
 
245
#if defined(KEYCACHE_DEBUG) && ! defined(KEYCACHE_DEBUG_LOG)
 
246
#define KEYCACHE_DEBUG_LOG  DEFAULT_KEYCACHE_DEBUG_LOG
 
247
#endif
 
248
 
 
249
#if defined(KEYCACHE_DEBUG_LOG)
 
250
static FILE *keycache_debug_log=NULL;
 
251
static void keycache_debug_print _VARARGS((const char *fmt,...));
 
252
#define KEYCACHE_DEBUG_OPEN                                                   \
 
253
          if (!keycache_debug_log)                                            \
 
254
          {                                                                   \
 
255
            keycache_debug_log= fopen(KEYCACHE_DEBUG_LOG, "w");               \
 
256
            (void) setvbuf(keycache_debug_log, NULL, _IOLBF, BUFSIZ);         \
 
257
          }
 
258
 
 
259
#define KEYCACHE_DEBUG_CLOSE                                                  \
 
260
          if (keycache_debug_log)                                             \
 
261
          {                                                                   \
 
262
            fclose(keycache_debug_log);                                       \
 
263
            keycache_debug_log= 0;                                            \
 
264
          }
 
265
#else
 
266
#define KEYCACHE_DEBUG_OPEN
 
267
#define KEYCACHE_DEBUG_CLOSE
 
268
#endif /* defined(KEYCACHE_DEBUG_LOG) */
 
269
 
 
270
#if defined(KEYCACHE_DEBUG_LOG) && defined(KEYCACHE_DEBUG)
 
271
#define KEYCACHE_DBUG_PRINT(l, m)                                             \
 
272
            { if (keycache_debug_log) fprintf(keycache_debug_log, "%s: ", l); \
 
273
              keycache_debug_print m; }
 
274
 
 
275
#define KEYCACHE_DBUG_ASSERT(a)                                               \
 
276
            { if (! (a) && keycache_debug_log) fclose(keycache_debug_log);    \
 
277
              assert(a); }
 
278
#else
 
279
#define KEYCACHE_DBUG_PRINT(l, m)  DBUG_PRINT(l, m)
 
280
#define KEYCACHE_DBUG_ASSERT(a)    DBUG_ASSERT(a)
 
281
#endif /* defined(KEYCACHE_DEBUG_LOG) && defined(KEYCACHE_DEBUG) */
 
282
 
 
283
#if defined(KEYCACHE_DEBUG) || !defined(DBUG_OFF)
 
284
#ifdef THREAD
 
285
static long keycache_thread_id;
 
286
#define KEYCACHE_THREAD_TRACE(l)                                              \
 
287
             KEYCACHE_DBUG_PRINT(l,("|thread %ld",keycache_thread_id))
 
288
 
 
289
#define KEYCACHE_THREAD_TRACE_BEGIN(l)                                        \
 
290
            { struct st_my_thread_var *thread_var= my_thread_var;             \
 
291
              keycache_thread_id= thread_var->id;                             \
 
292
              KEYCACHE_DBUG_PRINT(l,("[thread %ld",keycache_thread_id)) }
 
293
 
 
294
#define KEYCACHE_THREAD_TRACE_END(l)                                          \
 
295
            KEYCACHE_DBUG_PRINT(l,("]thread %ld",keycache_thread_id))
 
296
#else /* THREAD */
 
297
#define KEYCACHE_THREAD_TRACE(l)        KEYCACHE_DBUG_PRINT(l,(""))
 
298
#define KEYCACHE_THREAD_TRACE_BEGIN(l)  KEYCACHE_DBUG_PRINT(l,(""))
 
299
#define KEYCACHE_THREAD_TRACE_END(l)    KEYCACHE_DBUG_PRINT(l,(""))
 
300
#endif /* THREAD */
 
301
#else
 
302
#define KEYCACHE_THREAD_TRACE_BEGIN(l)
 
303
#define KEYCACHE_THREAD_TRACE_END(l)
 
304
#define KEYCACHE_THREAD_TRACE(l)
 
305
#endif /* defined(KEYCACHE_DEBUG) || !defined(DBUG_OFF) */
 
306
 
223
307
#define BLOCK_NUMBER(b)                                                       \
224
308
  ((uint) (((char*)(b)-(char *) keycache->block_root)/sizeof(BLOCK_LINK)))
225
309
#define HASH_LINK_NUMBER(h)                                                   \
226
310
  ((uint) (((char*)(h)-(char *) keycache->hash_link_root)/sizeof(HASH_LINK)))
227
311
 
228
 
#ifdef KEYCACHE_TIMEOUT
 
312
#if (defined(KEYCACHE_TIMEOUT)) || defined(KEYCACHE_DEBUG)
229
313
static int keycache_pthread_cond_wait(pthread_cond_t *cond,
230
314
                                      pthread_mutex_t *mutex);
231
315
#else
232
316
#define  keycache_pthread_cond_wait pthread_cond_wait
233
317
#endif
234
318
 
 
319
#if defined(KEYCACHE_DEBUG)
 
320
static int keycache_pthread_mutex_lock(pthread_mutex_t *mutex);
 
321
static void keycache_pthread_mutex_unlock(pthread_mutex_t *mutex);
 
322
static int keycache_pthread_cond_signal(pthread_cond_t *cond);
 
323
#else
235
324
#define keycache_pthread_mutex_lock pthread_mutex_lock
236
325
#define keycache_pthread_mutex_unlock pthread_mutex_unlock
237
326
#define keycache_pthread_cond_signal pthread_cond_signal
238
 
 
239
 
static inline uint32_t next_power(uint32_t value)
 
327
#endif /* defined(KEYCACHE_DEBUG) */
 
328
 
 
329
#if !defined(DBUG_OFF)
 
330
#if defined(inline)
 
331
#undef inline
 
332
#endif
 
333
#define inline  /* disabled inline for easier debugging */
 
334
static int fail_block(BLOCK_LINK *block);
 
335
static int fail_hlink(HASH_LINK *hlink);
 
336
static int cache_empty(KEY_CACHE *keycache);
 
337
#endif
 
338
 
 
339
static inline uint next_power(uint value)
240
340
{
241
 
  return (uint) my_round_up_to_next_power((uint32_t) value) << 1;
 
341
  return (uint) my_round_up_to_next_power((uint32) value) << 1;
242
342
}
243
343
 
244
344
 
267
367
 
268
368
*/
269
369
 
270
 
int init_key_cache(KEY_CACHE *keycache, uint32_t key_cache_block_size,
271
 
                   size_t use_mem, uint32_t division_limit,
272
 
                   uint32_t age_threshold)
 
370
int init_key_cache(KEY_CACHE *keycache, uint key_cache_block_size,
 
371
                   size_t use_mem, uint division_limit,
 
372
                   uint age_threshold)
273
373
{
274
 
  uint32_t blocks, hash_links;
 
374
  ulong blocks, hash_links;
275
375
  size_t length;
276
376
  int error;
277
 
  assert(key_cache_block_size >= 512);
 
377
  DBUG_ENTER("init_key_cache");
 
378
  DBUG_ASSERT(key_cache_block_size >= 512);
278
379
 
 
380
  KEYCACHE_DEBUG_OPEN;
279
381
  if (keycache->key_cache_inited && keycache->disk_blocks > 0)
280
382
  {
281
 
    return(0);
 
383
    DBUG_PRINT("warning",("key cache already in use"));
 
384
    DBUG_RETURN(0);
282
385
  }
283
386
 
284
387
  keycache->global_cache_w_requests= keycache->global_cache_r_requests= 0;
302
405
 
303
406
  keycache->key_cache_mem_size= use_mem;
304
407
  keycache->key_cache_block_size= key_cache_block_size;
 
408
  DBUG_PRINT("info", ("key_cache_block_size: %u",
 
409
                      key_cache_block_size));
305
410
 
306
 
  blocks= (uint32_t) (use_mem / (sizeof(BLOCK_LINK) + 2 * sizeof(HASH_LINK) +
 
411
  blocks= (ulong) (use_mem / (sizeof(BLOCK_LINK) + 2 * sizeof(HASH_LINK) +
307
412
                              sizeof(HASH_LINK*) * 5/4 + key_cache_block_size));
308
413
  /* It doesn't make sense to have too few blocks (less than 8) */
309
414
  if (blocks >= 8)
325
430
             ((size_t) blocks * keycache->key_cache_block_size) > use_mem)
326
431
        blocks--;
327
432
      /* Allocate memory for cache page buffers */
328
 
      if ((keycache->block_mem= malloc((size_t) blocks * keycache->key_cache_block_size)))
 
433
      if ((keycache->block_mem=
 
434
           my_large_malloc((size_t) blocks * keycache->key_cache_block_size,
 
435
                          MYF(0))))
329
436
      {
330
437
        /*
331
438
          Allocate memory for blocks, hash_links and hash entries;
334
441
        if ((keycache->block_root= (BLOCK_LINK*) my_malloc(length,
335
442
                                                           MYF(0))))
336
443
          break;
337
 
        free(keycache->block_mem);
 
444
        my_large_free(keycache->block_mem, MYF(0));
338
445
        keycache->block_mem= 0;
339
446
      }
340
447
      if (blocks < 8)
353
460
    keycache->hash_link_root= (HASH_LINK*) ((char*) keycache->hash_root +
354
461
                                            ALIGN_SIZE((sizeof(HASH_LINK*) *
355
462
                                                        keycache->hash_entries)));
356
 
    memset(keycache->block_root, 0,
357
 
           keycache->disk_blocks * sizeof(BLOCK_LINK));
358
 
    memset(keycache->hash_root, 0,
359
 
           keycache->hash_entries * sizeof(HASH_LINK*));
360
 
    memset(keycache->hash_link_root, 0,
361
 
           keycache->hash_links * sizeof(HASH_LINK));
 
463
    bzero((uchar*) keycache->block_root,
 
464
          keycache->disk_blocks * sizeof(BLOCK_LINK));
 
465
    bzero((uchar*) keycache->hash_root,
 
466
          keycache->hash_entries * sizeof(HASH_LINK*));
 
467
    bzero((uchar*) keycache->hash_link_root,
 
468
          keycache->hash_links * sizeof(HASH_LINK));
362
469
    keycache->hash_links_used= 0;
363
470
    keycache->free_hash_list= NULL;
364
471
    keycache->blocks_used= keycache->blocks_changed= 0;
383
490
 
384
491
    keycache->waiting_for_hash_link.last_thread= NULL;
385
492
    keycache->waiting_for_block.last_thread= NULL;
386
 
    memset(keycache->changed_blocks, 0,
387
 
           sizeof(keycache->changed_blocks[0]) * CHANGED_BLOCKS_HASH);
388
 
    memset(keycache->file_blocks, 0,
389
 
           sizeof(keycache->file_blocks[0]) * CHANGED_BLOCKS_HASH);
 
493
    DBUG_PRINT("exit",
 
494
               ("disk_blocks: %d  block_root: 0x%lx  hash_entries: %d\
 
495
 hash_root: 0x%lx  hash_links: %d  hash_link_root: 0x%lx",
 
496
                keycache->disk_blocks,  (long) keycache->block_root,
 
497
                keycache->hash_entries, (long) keycache->hash_root,
 
498
                keycache->hash_links,   (long) keycache->hash_link_root));
 
499
    bzero((uchar*) keycache->changed_blocks,
 
500
          sizeof(keycache->changed_blocks[0]) * CHANGED_BLOCKS_HASH);
 
501
    bzero((uchar*) keycache->file_blocks,
 
502
          sizeof(keycache->file_blocks[0]) * CHANGED_BLOCKS_HASH);
390
503
  }
391
504
  else
392
505
  {
395
508
  }
396
509
 
397
510
  keycache->blocks= keycache->disk_blocks > 0 ? keycache->disk_blocks : 0;
398
 
  return((int) keycache->disk_blocks);
 
511
  DBUG_RETURN((int) keycache->disk_blocks);
399
512
 
400
513
err:
401
514
  error= my_errno;
403
516
  keycache->blocks=  0;
404
517
  if (keycache->block_mem)
405
518
  {
406
 
    free(keycache->block_mem);
 
519
    my_large_free((uchar*) keycache->block_mem, MYF(0));
407
520
    keycache->block_mem= NULL;
408
521
  }
409
522
  if (keycache->block_root)
410
523
  {
411
 
    free((unsigned char*) keycache->block_root);
 
524
    my_free((uchar*) keycache->block_root, MYF(0));
412
525
    keycache->block_root= NULL;
413
526
  }
414
527
  my_errno= error;
415
528
  keycache->can_be_used= 0;
416
 
  return(0);
 
529
  DBUG_RETURN(0);
417
530
}
418
531
 
419
532
 
446
559
    (when cnt_for_resize=0).
447
560
*/
448
561
 
449
 
int resize_key_cache(KEY_CACHE *keycache, uint32_t key_cache_block_size,
450
 
                     size_t use_mem, uint32_t division_limit,
451
 
                     uint32_t age_threshold)
 
562
int resize_key_cache(KEY_CACHE *keycache, uint key_cache_block_size,
 
563
                     size_t use_mem, uint division_limit,
 
564
                     uint age_threshold)
452
565
{
453
566
  int blocks;
 
567
  DBUG_ENTER("resize_key_cache");
454
568
 
455
569
  if (!keycache->key_cache_inited)
456
 
    return(keycache->disk_blocks);
 
570
    DBUG_RETURN(keycache->disk_blocks);
457
571
 
458
572
  if(key_cache_block_size == keycache->key_cache_block_size &&
459
573
     use_mem == keycache->key_cache_mem_size)
460
574
  {
461
575
    change_key_cache_param(keycache, division_limit, age_threshold);
462
 
    return(keycache->disk_blocks);
 
576
    DBUG_RETURN(keycache->disk_blocks);
463
577
  }
464
578
 
465
579
  keycache_pthread_mutex_lock(&keycache->cache_lock);
466
580
 
 
581
#ifdef THREAD
467
582
  /*
468
583
    We may need to wait for another thread which is doing a resize
469
584
    already. This cannot happen in the MySQL server though. It allows
476
591
    wait_on_queue(&keycache->resize_queue, &keycache->cache_lock);
477
592
    /* purecov: end */
478
593
  }
 
594
#endif
479
595
 
480
596
  /*
481
597
    Mark the operation in progress. This blocks other threads from doing
498
614
      keycache->can_be_used= 0;
499
615
      goto finish;
500
616
    }
 
617
    DBUG_ASSERT(cache_empty(keycache));
501
618
 
502
619
    /* End the flush phase. */
503
620
    keycache->resize_in_flush= 0;
504
621
  }
505
622
 
 
623
#ifdef THREAD
506
624
  /*
507
625
    Some direct read/write operations (bypassing the cache) may still be
508
626
    unfinished. Wait until they are done. If the key cache can be used,
516
634
  */
517
635
  while (keycache->cnt_for_resize_op)
518
636
    wait_on_queue(&keycache->waiting_for_resize_cnt, &keycache->cache_lock);
 
637
#else
 
638
  KEYCACHE_DBUG_ASSERT(keycache->cnt_for_resize_op == 0);
 
639
#endif
519
640
 
520
641
  /*
521
642
    Free old cache structures, allocate new structures, and initialize
539
660
  release_whole_queue(&keycache->resize_queue);
540
661
 
541
662
  keycache_pthread_mutex_unlock(&keycache->cache_lock);
542
 
  return(blocks);
 
663
  DBUG_RETURN(blocks);
543
664
}
544
665
 
545
666
 
580
701
    age_threshold.
581
702
*/
582
703
 
583
 
void change_key_cache_param(KEY_CACHE *keycache, uint32_t division_limit,
584
 
                            uint32_t age_threshold)
 
704
void change_key_cache_param(KEY_CACHE *keycache, uint division_limit,
 
705
                            uint age_threshold)
585
706
{
 
707
  DBUG_ENTER("change_key_cache_param");
 
708
 
586
709
  keycache_pthread_mutex_lock(&keycache->cache_lock);
587
710
  if (division_limit)
588
711
    keycache->min_warm_blocks= (keycache->disk_blocks *
591
714
    keycache->age_threshold=   (keycache->disk_blocks *
592
715
                                age_threshold / 100);
593
716
  keycache_pthread_mutex_unlock(&keycache->cache_lock);
594
 
  return;
 
717
  DBUG_VOID_RETURN;
595
718
}
596
719
 
597
720
 
607
730
    none
608
731
*/
609
732
 
610
 
void end_key_cache(KEY_CACHE *keycache, bool cleanup)
 
733
void end_key_cache(KEY_CACHE *keycache, my_bool cleanup)
611
734
{
 
735
  DBUG_ENTER("end_key_cache");
 
736
  DBUG_PRINT("enter", ("key_cache: 0x%lx", (long) keycache));
 
737
 
612
738
  if (!keycache->key_cache_inited)
613
 
    return;
 
739
    DBUG_VOID_RETURN;
614
740
 
615
741
  if (keycache->disk_blocks > 0)
616
742
  {
617
743
    if (keycache->block_mem)
618
744
    {
619
 
      free(keycache->block_mem);
 
745
      my_large_free((uchar*) keycache->block_mem, MYF(0));
620
746
      keycache->block_mem= NULL;
621
 
      free((unsigned char*) keycache->block_root);
 
747
      my_free((uchar*) keycache->block_root, MYF(0));
622
748
      keycache->block_root= NULL;
623
749
    }
624
750
    keycache->disk_blocks= -1;
626
752
    keycache->blocks_changed= 0;
627
753
  }
628
754
 
 
755
  DBUG_PRINT("status", ("used: %lu  changed: %lu  w_requests: %lu  "
 
756
                        "writes: %lu  r_requests: %lu  reads: %lu",
 
757
                        keycache->blocks_used, keycache->global_blocks_changed,
 
758
                        (ulong) keycache->global_cache_w_requests,
 
759
                        (ulong) keycache->global_cache_write,
 
760
                        (ulong) keycache->global_cache_r_requests,
 
761
                        (ulong) keycache->global_cache_read));
 
762
 
629
763
  if (cleanup)
630
764
  {
631
765
    pthread_mutex_destroy(&keycache->cache_lock);
632
766
    keycache->key_cache_inited= keycache->can_be_used= 0;
 
767
    KEYCACHE_DEBUG_CLOSE;
633
768
  }
634
 
  return;
 
769
  DBUG_VOID_RETURN;
635
770
} /* end_key_cache */
636
771
 
637
772
 
 
773
#ifdef THREAD
 
774
 
638
775
/*
639
776
  Link a thread into double-linked queue of waiting threads.
640
777
 
657
794
{
658
795
  struct st_my_thread_var *last;
659
796
 
660
 
  assert(!thread->next && !thread->prev);
 
797
  DBUG_ASSERT(!thread->next && !thread->prev);
661
798
  if (! (last= wqueue->last_thread))
662
799
  {
663
800
    /* Queue is empty */
692
829
static void unlink_from_queue(KEYCACHE_WQUEUE *wqueue,
693
830
                                     struct st_my_thread_var *thread)
694
831
{
695
 
  assert(thread->next && thread->prev);
 
832
  KEYCACHE_DBUG_PRINT("unlink_from_queue", ("thread %ld", thread->id));
 
833
  DBUG_ASSERT(thread->next && thread->prev);
696
834
  if (thread->next == thread)
697
835
    /* The queue contains only one member */
698
836
    wqueue->last_thread= NULL;
705
843
                                      thread->prev);
706
844
  }
707
845
  thread->next= NULL;
 
846
#if !defined(DBUG_OFF)
 
847
  /*
 
848
    This makes it easier to see it's not in a chain during debugging.
 
849
    And some DBUG_ASSERT() rely on it.
 
850
  */
708
851
  thread->prev= NULL;
 
852
#endif
709
853
}
710
854
 
711
855
 
739
883
  struct st_my_thread_var *thread= my_thread_var;
740
884
 
741
885
  /* Add to queue. */
742
 
  assert(!thread->next);
743
 
  assert(!thread->prev); /* Not required, but must be true anyway. */
 
886
  DBUG_ASSERT(!thread->next);
 
887
  DBUG_ASSERT(!thread->prev); /* Not required, but must be true anyway. */
744
888
  if (! (last= wqueue->last_thread))
745
889
    thread->next= thread;
746
890
  else
756
900
  */
757
901
  do
758
902
  {
 
903
    KEYCACHE_DBUG_PRINT("wait", ("suspend thread %ld", thread->id));
759
904
    keycache_pthread_cond_wait(&thread->suspend, mutex);
760
905
  }
761
906
  while (thread->next);
792
937
  do
793
938
  {
794
939
    thread=next;
 
940
    KEYCACHE_DBUG_PRINT("release_whole_queue: signal",
 
941
                        ("thread %ld", thread->id));
795
942
    /* Signal the thread. */
796
943
    keycache_pthread_cond_signal(&thread->suspend);
797
944
    /* Take thread from queue. */
804
951
  wqueue->last_thread= NULL;
805
952
}
806
953
 
 
954
#endif /* THREAD */
 
955
 
807
956
 
808
957
/*
809
958
  Unlink a block from the chain of dirty/clean blocks
810
959
*/
 
960
 
811
961
static inline void unlink_changed(BLOCK_LINK *block)
812
962
{
813
 
  assert(block->prev_changed && *block->prev_changed == block);
 
963
  DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
814
964
  if (block->next_changed)
815
965
    block->next_changed->prev_changed= block->prev_changed;
816
966
  *block->prev_changed= block->next_changed;
 
967
 
 
968
#if !defined(DBUG_OFF)
 
969
  /*
 
970
    This makes it easier to see it's not in a chain during debugging.
 
971
    And some DBUG_ASSERT() rely on it.
 
972
  */
817
973
  block->next_changed= NULL;
818
974
  block->prev_changed= NULL;
 
975
#endif
819
976
}
820
977
 
821
978
 
825
982
 
826
983
static inline void link_changed(BLOCK_LINK *block, BLOCK_LINK **phead)
827
984
{
828
 
  assert(!block->next_changed);
829
 
  assert(!block->prev_changed);
 
985
  DBUG_ASSERT(!block->next_changed);
 
986
  DBUG_ASSERT(!block->prev_changed);
830
987
  block->prev_changed= phead;
831
988
  if ((block->next_changed= *phead))
832
989
    (*phead)->prev_changed= &block->next_changed;
861
1018
 
862
1019
static void link_to_file_list(KEY_CACHE *keycache,
863
1020
                              BLOCK_LINK *block, int file,
864
 
                              bool unlink_block)
 
1021
                              my_bool unlink_block)
865
1022
{
866
 
  assert(block->status & BLOCK_IN_USE);
867
 
  assert(block->hash_link && block->hash_link->block == block);
868
 
  assert(block->hash_link->file == file);
 
1023
  DBUG_ASSERT(block->status & BLOCK_IN_USE);
 
1024
  DBUG_ASSERT(block->hash_link && block->hash_link->block == block);
 
1025
  DBUG_ASSERT(block->hash_link->file == file);
869
1026
  if (unlink_block)
870
1027
    unlink_changed(block);
871
1028
  link_changed(block, &keycache->file_blocks[FILE_HASH(file)]);
903
1060
static void link_to_changed_list(KEY_CACHE *keycache,
904
1061
                                 BLOCK_LINK *block)
905
1062
{
906
 
  assert(block->status & BLOCK_IN_USE);
907
 
  assert(!(block->status & BLOCK_CHANGED));
908
 
  assert(block->hash_link && block->hash_link->block == block);
 
1063
  DBUG_ASSERT(block->status & BLOCK_IN_USE);
 
1064
  DBUG_ASSERT(!(block->status & BLOCK_CHANGED));
 
1065
  DBUG_ASSERT(block->hash_link && block->hash_link->block == block);
909
1066
 
910
1067
  unlink_changed(block);
911
1068
  link_changed(block,
955
1112
    not linked in the LRU ring.
956
1113
*/
957
1114
 
958
 
static void link_block(KEY_CACHE *keycache, BLOCK_LINK *block, bool hot,
959
 
                       bool at_end)
 
1115
static void link_block(KEY_CACHE *keycache, BLOCK_LINK *block, my_bool hot,
 
1116
                       my_bool at_end)
960
1117
{
961
1118
  BLOCK_LINK *ins;
962
1119
  BLOCK_LINK **pins;
963
1120
 
964
 
  assert((block->status & ~BLOCK_CHANGED) == (BLOCK_READ | BLOCK_IN_USE));
965
 
  assert(block->hash_link); /*backptr to block NULL from free_block()*/
966
 
  assert(!block->requests);
967
 
  assert(block->prev_changed && *block->prev_changed == block);
968
 
  assert(!block->next_used);
969
 
  assert(!block->prev_used);
 
1121
  DBUG_ASSERT((block->status & ~BLOCK_CHANGED) == (BLOCK_READ | BLOCK_IN_USE));
 
1122
  DBUG_ASSERT(block->hash_link); /*backptr to block NULL from free_block()*/
 
1123
  DBUG_ASSERT(!block->requests);
 
1124
  DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
 
1125
  DBUG_ASSERT(!block->next_used);
 
1126
  DBUG_ASSERT(!block->prev_used);
 
1127
#ifdef THREAD
970
1128
  if (!hot && keycache->waiting_for_block.last_thread)
971
1129
  {
972
1130
    /* Signal that in the LRU warm sub-chain an available block has appeared */
986
1144
      */
987
1145
      if ((HASH_LINK *) thread->opt_info == hash_link)
988
1146
      {
 
1147
        KEYCACHE_DBUG_PRINT("link_block: signal", ("thread %ld", thread->id));
989
1148
        keycache_pthread_cond_signal(&thread->suspend);
990
1149
        unlink_from_queue(&keycache->waiting_for_block, thread);
991
1150
        block->requests++;
1016
1175
      probably easier to read.
1017
1176
    */
1018
1177
    block->status|= BLOCK_IN_EVICTION;
 
1178
    KEYCACHE_THREAD_TRACE("link_block: after signaling");
 
1179
#if defined(KEYCACHE_DEBUG)
 
1180
    KEYCACHE_DBUG_PRINT("link_block",
 
1181
        ("linked,unlinked block %u  status=%x  #requests=%u  #available=%u",
 
1182
         BLOCK_NUMBER(block), block->status,
 
1183
         block->requests, keycache->blocks_available));
 
1184
#endif
1019
1185
    return;
1020
1186
  }
 
1187
#else /* THREAD */
 
1188
  KEYCACHE_DBUG_ASSERT(! (!hot && keycache->waiting_for_block.last_thread));
 
1189
      /* Condition not transformed using DeMorgan, to keep the text identical */
 
1190
#endif /* THREAD */
1021
1191
  pins= hot ? &keycache->used_ins : &keycache->used_last;
1022
1192
  ins= *pins;
1023
1193
  if (ins)
1035
1205
    keycache->used_last= keycache->used_ins= block->next_used= block;
1036
1206
    block->prev_used= &block->next_used;
1037
1207
  }
 
1208
  KEYCACHE_THREAD_TRACE("link_block");
 
1209
#if defined(KEYCACHE_DEBUG)
 
1210
  keycache->blocks_available++;
 
1211
  KEYCACHE_DBUG_PRINT("link_block",
 
1212
      ("linked block %u:%1u  status=%x  #requests=%u  #available=%u",
 
1213
       BLOCK_NUMBER(block), at_end, block->status,
 
1214
       block->requests, keycache->blocks_available));
 
1215
  KEYCACHE_DBUG_ASSERT((ulong) keycache->blocks_available <=
 
1216
                       keycache->blocks_used);
 
1217
#endif
1038
1218
}
1039
1219
 
1040
1220
 
1055
1235
 
1056
1236
static void unlink_block(KEY_CACHE *keycache, BLOCK_LINK *block)
1057
1237
{
1058
 
  assert((block->status & ~BLOCK_CHANGED) == (BLOCK_READ | BLOCK_IN_USE));
1059
 
  assert(block->hash_link); /*backptr to block NULL from free_block()*/
1060
 
  assert(!block->requests);
1061
 
  assert(block->prev_changed && *block->prev_changed == block);
1062
 
  assert(block->next_used && block->prev_used &&
 
1238
  DBUG_ASSERT((block->status & ~BLOCK_CHANGED) == (BLOCK_READ | BLOCK_IN_USE));
 
1239
  DBUG_ASSERT(block->hash_link); /*backptr to block NULL from free_block()*/
 
1240
  DBUG_ASSERT(!block->requests);
 
1241
  DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
 
1242
  DBUG_ASSERT(block->next_used && block->prev_used &&
1063
1243
              (block->next_used->prev_used == &block->next_used) &&
1064
1244
              (*block->prev_used == block));
1065
1245
  if (block->next_used == block)
1075
1255
      keycache->used_ins=STRUCT_PTR(BLOCK_LINK, next_used, block->prev_used);
1076
1256
  }
1077
1257
  block->next_used= NULL;
 
1258
#if !defined(DBUG_OFF)
 
1259
  /*
 
1260
    This makes it easier to see it's not in a chain during debugging.
 
1261
    And some DBUG_ASSERT() rely on it.
 
1262
  */
1078
1263
  block->prev_used= NULL;
 
1264
#endif
 
1265
 
 
1266
  KEYCACHE_THREAD_TRACE("unlink_block");
 
1267
#if defined(KEYCACHE_DEBUG)
 
1268
  KEYCACHE_DBUG_ASSERT(keycache->blocks_available != 0);
 
1269
  keycache->blocks_available--;
 
1270
  KEYCACHE_DBUG_PRINT("unlink_block",
 
1271
    ("unlinked block %u  status=%x   #requests=%u  #available=%u",
 
1272
     BLOCK_NUMBER(block), block->status,
 
1273
     block->requests, keycache->blocks_available));
 
1274
#endif
1079
1275
}
1080
1276
 
1081
1277
 
1097
1293
*/
1098
1294
static void reg_requests(KEY_CACHE *keycache, BLOCK_LINK *block, int count)
1099
1295
{
1100
 
  assert(block->status & BLOCK_IN_USE);
1101
 
  assert(block->hash_link);
 
1296
  DBUG_ASSERT(block->status & BLOCK_IN_USE);
 
1297
  DBUG_ASSERT(block->hash_link);
1102
1298
 
1103
1299
  if (!block->requests)
1104
1300
    unlink_block(keycache, block);
1121
1317
 
1122
1318
  NOTES.
1123
1319
    Every linking to the LRU ring decrements by one a special block
1124
 
    counter (if it's positive). If the at_end parameter is true the block is
 
1320
    counter (if it's positive). If the at_end parameter is TRUE the block is
1125
1321
    added either at the end of warm sub-chain or at the end of hot sub-chain.
1126
1322
    It is added to the hot subchain if its counter is zero and number of
1127
1323
    blocks in warm sub-chain is not less than some low limit (determined by
1128
1324
    the division_limit parameter). Otherwise the block is added to the warm
1129
 
    sub-chain. If the at_end parameter is false the block is always added
 
1325
    sub-chain. If the at_end parameter is FALSE the block is always added
1130
1326
    at beginning of the warm sub-chain.
1131
1327
    Thus a warm block can be promoted to the hot sub-chain when its counter
1132
1328
    becomes zero for the first time.
1141
1337
static void unreg_request(KEY_CACHE *keycache,
1142
1338
                          BLOCK_LINK *block, int at_end)
1143
1339
{
1144
 
  assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
1145
 
  assert(block->hash_link); /*backptr to block NULL from free_block()*/
1146
 
  assert(block->requests);
1147
 
  assert(block->prev_changed && *block->prev_changed == block);
1148
 
  assert(!block->next_used);
1149
 
  assert(!block->prev_used);
 
1340
  DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
1341
  DBUG_ASSERT(block->hash_link); /*backptr to block NULL from free_block()*/
 
1342
  DBUG_ASSERT(block->requests);
 
1343
  DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
 
1344
  DBUG_ASSERT(!block->next_used);
 
1345
  DBUG_ASSERT(!block->prev_used);
1150
1346
  if (! --block->requests)
1151
1347
  {
1152
 
    bool hot;
 
1348
    my_bool hot;
1153
1349
    if (block->hits_left)
1154
1350
      block->hits_left--;
1155
1351
    hot= !block->hits_left && at_end &&
1159
1355
      if (block->temperature == BLOCK_WARM)
1160
1356
        keycache->warm_blocks--;
1161
1357
      block->temperature= BLOCK_HOT;
 
1358
      KEYCACHE_DBUG_PRINT("unreg_request", ("#warm_blocks: %lu",
 
1359
                           keycache->warm_blocks));
1162
1360
    }
1163
 
    link_block(keycache, block, hot, (bool)at_end);
 
1361
    link_block(keycache, block, hot, (my_bool)at_end);
1164
1362
    block->last_hit_time= keycache->keycache_time;
1165
1363
    keycache->keycache_time++;
1166
1364
    /*
1189
1387
        keycache->warm_blocks++;
1190
1388
        block->temperature= BLOCK_WARM;
1191
1389
      }
 
1390
      KEYCACHE_DBUG_PRINT("unreg_request", ("#warm_blocks: %lu",
 
1391
                           keycache->warm_blocks));
1192
1392
    }
1193
1393
  }
1194
1394
}
1199
1399
 
1200
1400
static void remove_reader(BLOCK_LINK *block)
1201
1401
{
1202
 
  assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
1203
 
  assert(block->hash_link && block->hash_link->block == block);
1204
 
  assert(block->prev_changed && *block->prev_changed == block);
1205
 
  assert(!block->next_used);
1206
 
  assert(!block->prev_used);
1207
 
  assert(block->hash_link->requests);
 
1402
  DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
1403
  DBUG_ASSERT(block->hash_link && block->hash_link->block == block);
 
1404
  DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
 
1405
  DBUG_ASSERT(!block->next_used);
 
1406
  DBUG_ASSERT(!block->prev_used);
 
1407
  DBUG_ASSERT(block->hash_link->requests);
 
1408
#ifdef THREAD
1208
1409
  if (! --block->hash_link->requests && block->condvar)
1209
1410
    keycache_pthread_cond_signal(block->condvar);
 
1411
#else
 
1412
  --block->hash_link->requests;
 
1413
#endif
1210
1414
}
1211
1415
 
1212
1416
 
1218
1422
static void wait_for_readers(KEY_CACHE *keycache,
1219
1423
                             BLOCK_LINK *block)
1220
1424
{
 
1425
#ifdef THREAD
1221
1426
  struct st_my_thread_var *thread= my_thread_var;
1222
 
  assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
1223
 
  assert(!(block->status & (BLOCK_ERROR | BLOCK_IN_FLUSH |
 
1427
  DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
1428
  DBUG_ASSERT(!(block->status & (BLOCK_ERROR | BLOCK_IN_FLUSH |
1224
1429
                                 BLOCK_CHANGED)));
1225
 
  assert(block->hash_link);
1226
 
  assert(block->hash_link->block == block);
 
1430
  DBUG_ASSERT(block->hash_link);
 
1431
  DBUG_ASSERT(block->hash_link->block == block);
1227
1432
  /* Linked in file_blocks or changed_blocks hash. */
1228
 
  assert(block->prev_changed && *block->prev_changed == block);
 
1433
  DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
1229
1434
  /* Not linked in LRU ring. */
1230
 
  assert(!block->next_used);
1231
 
  assert(!block->prev_used);
 
1435
  DBUG_ASSERT(!block->next_used);
 
1436
  DBUG_ASSERT(!block->prev_used);
1232
1437
  while (block->hash_link->requests)
1233
1438
  {
 
1439
    KEYCACHE_DBUG_PRINT("wait_for_readers: wait",
 
1440
                        ("suspend thread %ld  block %u",
 
1441
                         thread->id, BLOCK_NUMBER(block)));
1234
1442
    /* There must be no other waiter. We have no queue here. */
1235
 
    assert(!block->condvar);
 
1443
    DBUG_ASSERT(!block->condvar);
1236
1444
    block->condvar= &thread->suspend;
1237
1445
    keycache_pthread_cond_wait(&thread->suspend, &keycache->cache_lock);
1238
1446
    block->condvar= NULL;
1239
1447
  }
 
1448
#else
 
1449
  KEYCACHE_DBUG_ASSERT(block->hash_link->requests == 0);
 
1450
#endif
1240
1451
}
1241
1452
 
1242
1453
 
1260
1471
 
1261
1472
static void unlink_hash(KEY_CACHE *keycache, HASH_LINK *hash_link)
1262
1473
{
1263
 
  assert(hash_link->requests == 0);
 
1474
  KEYCACHE_DBUG_PRINT("unlink_hash", ("fd: %u  pos_ %lu  #requests=%u",
 
1475
      (uint) hash_link->file,(ulong) hash_link->diskpos, hash_link->requests));
 
1476
  KEYCACHE_DBUG_ASSERT(hash_link->requests == 0);
1264
1477
  if ((*hash_link->prev= hash_link->next))
1265
1478
    hash_link->next->prev= hash_link->prev;
1266
1479
  hash_link->block= NULL;
 
1480
#ifdef THREAD
1267
1481
  if (keycache->waiting_for_hash_link.last_thread)
1268
1482
  {
1269
1483
    /* Signal that a free hash link has appeared */
1288
1502
      */
1289
1503
      if (page->file == hash_link->file && page->filepos == hash_link->diskpos)
1290
1504
      {
 
1505
        KEYCACHE_DBUG_PRINT("unlink_hash: signal", ("thread %ld", thread->id));
1291
1506
        keycache_pthread_cond_signal(&thread->suspend);
1292
1507
        unlink_from_queue(&keycache->waiting_for_hash_link, thread);
1293
1508
      }
1298
1513
              hash_link);
1299
1514
    return;
1300
1515
  }
 
1516
#else /* THREAD */
 
1517
  KEYCACHE_DBUG_ASSERT(! (keycache->waiting_for_hash_link.last_thread));
 
1518
#endif /* THREAD */
1301
1519
  hash_link->next= keycache->free_hash_list;
1302
1520
  keycache->free_hash_list= hash_link;
1303
1521
}
1311
1529
                                int file, my_off_t filepos)
1312
1530
{
1313
1531
  register HASH_LINK *hash_link, **start;
 
1532
#if defined(KEYCACHE_DEBUG)
 
1533
  int cnt;
 
1534
#endif
 
1535
 
 
1536
  KEYCACHE_DBUG_PRINT("get_hash_link", ("fd: %u  pos: %lu",
 
1537
                      (uint) file,(ulong) filepos));
1314
1538
 
1315
1539
restart:
1316
1540
  /*
1319
1543
     hash_link points to the first member of the list
1320
1544
  */
1321
1545
  hash_link= *(start= &keycache->hash_root[KEYCACHE_HASH(file, filepos)]);
 
1546
#if defined(KEYCACHE_DEBUG)
 
1547
  cnt= 0;
 
1548
#endif
1322
1549
  /* Look for an element for the pair (file, filepos) in the bucket chain */
1323
1550
  while (hash_link &&
1324
1551
         (hash_link->diskpos != filepos || hash_link->file != file))
1325
1552
  {
1326
1553
    hash_link= hash_link->next;
 
1554
#if defined(KEYCACHE_DEBUG)
 
1555
    cnt++;
 
1556
    if (! (cnt <= keycache->hash_links_used))
 
1557
    {
 
1558
      int i;
 
1559
      for (i=0, hash_link= *start ;
 
1560
           i < cnt ; i++, hash_link= hash_link->next)
 
1561
      {
 
1562
        KEYCACHE_DBUG_PRINT("get_hash_link", ("fd: %u  pos: %lu",
 
1563
            (uint) hash_link->file,(ulong) hash_link->diskpos));
 
1564
      }
 
1565
    }
 
1566
    KEYCACHE_DBUG_ASSERT(cnt <= keycache->hash_links_used);
 
1567
#endif
1327
1568
  }
1328
1569
  if (! hash_link)
1329
1570
  {
1339
1580
    }
1340
1581
    else
1341
1582
    {
 
1583
#ifdef THREAD
1342
1584
      /* Wait for a free hash link */
1343
1585
      struct st_my_thread_var *thread= my_thread_var;
1344
1586
      KEYCACHE_PAGE page;
 
1587
      KEYCACHE_DBUG_PRINT("get_hash_link", ("waiting"));
1345
1588
      page.file= file;
1346
1589
      page.filepos= filepos;
1347
1590
      thread->opt_info= (void *) &page;
1348
1591
      link_into_queue(&keycache->waiting_for_hash_link, thread);
 
1592
      KEYCACHE_DBUG_PRINT("get_hash_link: wait",
 
1593
                        ("suspend thread %ld", thread->id));
1349
1594
      keycache_pthread_cond_wait(&thread->suspend,
1350
1595
                                 &keycache->cache_lock);
1351
1596
      thread->opt_info= NULL;
 
1597
#else
 
1598
      KEYCACHE_DBUG_ASSERT(0);
 
1599
#endif
1352
1600
      goto restart;
1353
1601
    }
1354
1602
    hash_link->file= file;
1408
1656
  int error= 0;
1409
1657
  int page_status;
1410
1658
 
 
1659
  DBUG_ENTER("find_key_block");
 
1660
  KEYCACHE_THREAD_TRACE("find_key_block:begin");
 
1661
  DBUG_PRINT("enter", ("fd: %d  pos: %lu  wrmode: %d",
 
1662
                       file, (ulong) filepos, wrmode));
 
1663
  KEYCACHE_DBUG_PRINT("find_key_block", ("fd: %d  pos: %lu  wrmode: %d",
 
1664
                                         file, (ulong) filepos,
 
1665
                                         wrmode));
 
1666
#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
 
1667
  DBUG_EXECUTE("check_keycache2",
 
1668
               test_key_cache(keycache, "start of find_key_block", 0););
 
1669
#endif
 
1670
 
1411
1671
restart:
1412
1672
  /*
1413
1673
    If the flush phase of a resize operation fails, the cache is left
1414
1674
    unusable. This will be detected only after "goto restart".
1415
1675
  */
1416
1676
  if (!keycache->can_be_used)
1417
 
    return(0);
 
1677
    DBUG_RETURN(0);
1418
1678
 
1419
1679
  /*
1420
1680
    Find the hash_link for the requested file block (file, filepos). We
1440
1700
          - not changed (clean).
1441
1701
  */
1442
1702
  hash_link= get_hash_link(keycache, file, filepos);
1443
 
  assert((hash_link->file == file) && (hash_link->diskpos == filepos));
 
1703
  DBUG_ASSERT((hash_link->file == file) && (hash_link->diskpos == filepos));
1444
1704
 
1445
1705
  page_status= -1;
1446
1706
  if ((block= hash_link->block) &&
1479
1739
        */
1480
1740
        hash_link->requests--;
1481
1741
        unlink_hash(keycache, hash_link);
1482
 
        return(0);
 
1742
        DBUG_RETURN(0);
1483
1743
      }
1484
1744
 
1485
1745
      /*
1498
1758
      link_into_queue(&keycache->waiting_for_block, thread);
1499
1759
      do
1500
1760
      {
 
1761
        KEYCACHE_DBUG_PRINT("find_key_block: wait",
 
1762
                            ("suspend thread %ld", thread->id));
1501
1763
        keycache_pthread_cond_wait(&thread->suspend,
1502
1764
                                   &keycache->cache_lock);
1503
1765
      } while (thread->next);
1544
1806
        only. Waiting here on COND_FOR_REQUESTED works in all
1545
1807
        situations.
1546
1808
      */
1547
 
      assert(((block->hash_link != hash_link) &&
 
1809
      DBUG_ASSERT(((block->hash_link != hash_link) &&
1548
1810
                   (block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH))) ||
1549
1811
                  ((block->hash_link == hash_link) &&
1550
1812
                   !(block->status & BLOCK_READ)));
1559
1821
        again in eviction because we registered an request on it before
1560
1822
        starting to wait.
1561
1823
      */
1562
 
      assert(block->hash_link == hash_link);
1563
 
      assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
1564
 
      assert(!(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH)));
 
1824
      DBUG_ASSERT(block->hash_link == hash_link);
 
1825
      DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
1826
      DBUG_ASSERT(!(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH)));
1565
1827
    }
1566
1828
    /*
1567
1829
      The block is in the cache. Assigned to the hash_link. Valid data.
1573
1835
    {
1574
1836
      /* A reader can just read the block. */
1575
1837
      *page_st= PAGE_READ;
1576
 
      assert((hash_link->file == file) &&
 
1838
      DBUG_ASSERT((hash_link->file == file) &&
1577
1839
                  (hash_link->diskpos == filepos) &&
1578
1840
                  (block->hash_link == hash_link));
1579
 
      return(block);
 
1841
      DBUG_RETURN(block);
1580
1842
    }
1581
1843
 
1582
1844
    /*
1583
1845
      This is a writer. No two writers for the same block can exist.
1584
1846
      This must be assured by locks outside of the key cache.
1585
1847
    */
1586
 
    assert(!(block->status & BLOCK_FOR_UPDATE));
 
1848
    DBUG_ASSERT(!(block->status & BLOCK_FOR_UPDATE) || fail_block(block));
1587
1849
 
1588
1850
    while (block->status & BLOCK_IN_FLUSH)
1589
1851
    {
1607
1869
        unreg_request(keycache, block, 1);
1608
1870
        goto restart;
1609
1871
      }
1610
 
      assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
1611
 
      assert(!(block->status & BLOCK_FOR_UPDATE));
1612
 
      assert(block->hash_link == hash_link);
 
1872
      DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
1873
      DBUG_ASSERT(!(block->status & BLOCK_FOR_UPDATE) || fail_block(block));
 
1874
      DBUG_ASSERT(block->hash_link == hash_link);
1613
1875
    }
1614
1876
 
1615
1877
    if (block->status & BLOCK_CHANGED)
1622
1884
        not yet been selected for flush, we can still add our changes.
1623
1885
      */
1624
1886
      *page_st= PAGE_READ;
1625
 
      assert((hash_link->file == file) &&
 
1887
      DBUG_ASSERT((hash_link->file == file) &&
1626
1888
                  (hash_link->diskpos == filepos) &&
1627
1889
                  (block->hash_link == hash_link));
1628
 
      return(block);
 
1890
      DBUG_RETURN(block);
1629
1891
    }
1630
1892
 
1631
1893
    /*
1693
1955
               (block->hash_link->file == file) &&
1694
1956
               (block->hash_link->diskpos == filepos));
1695
1957
    }
1696
 
    return(0);
 
1958
    DBUG_RETURN(0);
1697
1959
  }
1698
1960
 
1699
1961
  if (page_status == PAGE_READ &&
1708
1970
      (BLOCK_IN_SWITCH), readers of the block have not finished yet
1709
1971
      (BLOCK_REASSIGNED), or the evicting thread did not yet awake after
1710
1972
      the block has been selected for it (BLOCK_IN_EVICTION).
 
1973
    */
1711
1974
 
 
1975
    KEYCACHE_DBUG_PRINT("find_key_block",
 
1976
                        ("request for old page in block %u "
 
1977
                         "wrmode: %d  block->status: %d",
 
1978
                         BLOCK_NUMBER(block), wrmode, block->status));
 
1979
    /*
1712
1980
       Only reading requests can proceed until the old dirty page is flushed,
1713
1981
       all others are to be suspended, then resubmitted
1714
1982
    */
1736
2004
        as soon as possible. Again we must wait so that we don't find
1737
2005
        the same hash_link + block again and again.
1738
2006
      */
1739
 
      assert(hash_link->requests);
 
2007
      DBUG_ASSERT(hash_link->requests);
1740
2008
      hash_link->requests--;
 
2009
      KEYCACHE_DBUG_PRINT("find_key_block",
 
2010
                          ("request waiting for old page to be saved"));
1741
2011
      wait_on_queue(&block->wqueue[COND_FOR_SAVED], &keycache->cache_lock);
 
2012
      KEYCACHE_DBUG_PRINT("find_key_block",
 
2013
                          ("request for old page resubmitted"));
1742
2014
      /*
1743
2015
        The block is no longer assigned to this hash_link.
1744
2016
        Get another one.
1773
2045
        else
1774
2046
        {
1775
2047
          /* There are some never used blocks, take first of them */
1776
 
          assert(keycache->blocks_used <
1777
 
                      (uint32_t) keycache->disk_blocks);
 
2048
          DBUG_ASSERT(keycache->blocks_used <
 
2049
                      (ulong) keycache->disk_blocks);
1778
2050
          block= &keycache->block_root[keycache->blocks_used];
1779
2051
          block->buffer= ADD_TO_PTR(keycache->block_mem,
1780
 
                                    ((uint32_t) keycache->blocks_used*
 
2052
                                    ((ulong) keycache->blocks_used*
1781
2053
                                     keycache->key_cache_block_size),
1782
 
                                    unsigned char*);
 
2054
                                    uchar*);
1783
2055
          keycache->blocks_used++;
1784
 
          assert(!block->next_used);
 
2056
          DBUG_ASSERT(!block->next_used);
1785
2057
        }
1786
 
        assert(!block->prev_used);
1787
 
        assert(!block->next_changed);
1788
 
        assert(!block->prev_changed);
1789
 
        assert(!block->hash_link);
1790
 
        assert(!block->status);
1791
 
        assert(!block->requests);
 
2058
        DBUG_ASSERT(!block->prev_used);
 
2059
        DBUG_ASSERT(!block->next_changed);
 
2060
        DBUG_ASSERT(!block->prev_changed);
 
2061
        DBUG_ASSERT(!block->hash_link);
 
2062
        DBUG_ASSERT(!block->status);
 
2063
        DBUG_ASSERT(!block->requests);
1792
2064
        keycache->blocks_unused--;
1793
2065
        block->status= BLOCK_IN_USE;
1794
2066
        block->length= 0;
1801
2073
        hash_link->block= block;
1802
2074
        link_to_file_list(keycache, block, file, 0);
1803
2075
        page_status= PAGE_TO_BE_READ;
 
2076
        KEYCACHE_DBUG_PRINT("find_key_block",
 
2077
                            ("got free or never used block %u",
 
2078
                             BLOCK_NUMBER(block)));
1804
2079
      }
1805
2080
      else
1806
2081
      {
1809
2084
          from the LRU ring.
1810
2085
        */
1811
2086
 
 
2087
#ifdef THREAD
1812
2088
        if (! keycache->used_last)
1813
2089
        {
1814
2090
          /*
1828
2104
          link_into_queue(&keycache->waiting_for_block, thread);
1829
2105
          do
1830
2106
          {
 
2107
            KEYCACHE_DBUG_PRINT("find_key_block: wait",
 
2108
                                ("suspend thread %ld", thread->id));
1831
2109
            keycache_pthread_cond_wait(&thread->suspend,
1832
2110
                                       &keycache->cache_lock);
1833
2111
          }
1834
2112
          while (thread->next);
1835
2113
          thread->opt_info= NULL;
1836
2114
          /* Assert that block has a request registered. */
1837
 
          assert(hash_link->block->requests);
 
2115
          DBUG_ASSERT(hash_link->block->requests);
1838
2116
          /* Assert that block is not in LRU ring. */
1839
 
          assert(!hash_link->block->next_used);
1840
 
          assert(!hash_link->block->prev_used);
 
2117
          DBUG_ASSERT(!hash_link->block->next_used);
 
2118
          DBUG_ASSERT(!hash_link->block->prev_used);
1841
2119
        }
 
2120
#else
 
2121
        KEYCACHE_DBUG_ASSERT(keycache->used_last);
 
2122
#endif
1842
2123
        /*
1843
2124
          If we waited above, hash_link->block has been assigned by
1844
2125
          link_block(). Otherwise it is still NULL. In the latter case
1856
2137
            Register a request on the block. This unlinks it from the
1857
2138
            LRU ring and protects it against eviction.
1858
2139
          */
1859
 
          assert(!block->requests);
 
2140
          DBUG_ASSERT(!block->requests);
1860
2141
          reg_requests(keycache, block,1);
1861
2142
          /*
1862
2143
            We do not need to set block->status|= BLOCK_IN_EVICTION here
1880
2161
          /* this is a primary request for a new page */
1881
2162
          block->status|= BLOCK_IN_SWITCH;
1882
2163
 
 
2164
          KEYCACHE_DBUG_PRINT("find_key_block",
 
2165
                        ("got block %u for new page", BLOCK_NUMBER(block)));
 
2166
 
1883
2167
          if (block->status & BLOCK_CHANGED)
1884
2168
          {
1885
2169
            /* The block contains a dirty page - push it out of the cache */
1886
2170
 
 
2171
            KEYCACHE_DBUG_PRINT("find_key_block", ("block is dirty"));
1887
2172
            if (block->status & BLOCK_IN_FLUSH)
1888
2173
            {
1889
2174
              /*
1899
2184
                The block is marked BLOCK_IN_SWITCH. It should be left
1900
2185
                alone except for reading. No free, no write.
1901
2186
              */
1902
 
              assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
1903
 
              assert(!(block->status & (BLOCK_REASSIGNED |
 
2187
              DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
2188
              DBUG_ASSERT(!(block->status & (BLOCK_REASSIGNED |
1904
2189
                                             BLOCK_CHANGED |
1905
2190
                                             BLOCK_FOR_UPDATE)));
1906
2191
            }
1911
2196
                BLOCK_IN_EVICTION may be true or not. Other flags must
1912
2197
                have a fixed value.
1913
2198
              */
1914
 
              assert((block->status & ~BLOCK_IN_EVICTION) ==
 
2199
              DBUG_ASSERT((block->status & ~BLOCK_IN_EVICTION) ==
1915
2200
                          (BLOCK_READ | BLOCK_IN_SWITCH |
1916
2201
                           BLOCK_IN_FLUSH | BLOCK_IN_FLUSHWRITE |
1917
2202
                           BLOCK_CHANGED | BLOCK_IN_USE));
1918
 
              assert(block->hash_link);
 
2203
              DBUG_ASSERT(block->hash_link);
1919
2204
 
1920
2205
              keycache_pthread_mutex_unlock(&keycache->cache_lock);
1921
2206
              /*
1922
2207
                The call is thread safe because only the current
1923
2208
                thread might change the block->hash_link value
1924
2209
              */
1925
 
              error= (pwrite(block->hash_link->file,
1926
 
                             block->buffer+block->offset,
1927
 
                             block->length - block->offset,
1928
 
                             block->hash_link->diskpos+ block->offset) == 0);
 
2210
              error= my_pwrite(block->hash_link->file,
 
2211
                               block->buffer+block->offset,
 
2212
                               block->length - block->offset,
 
2213
                               block->hash_link->diskpos+ block->offset,
 
2214
                               MYF(MY_NABP | MY_WAIT_IF_FULL));
1929
2215
              keycache_pthread_mutex_lock(&keycache->cache_lock);
1930
2216
 
1931
2217
              /* Block status must not have changed. */
1932
 
              assert((block->status & ~BLOCK_IN_EVICTION) ==
 
2218
              DBUG_ASSERT((block->status & ~BLOCK_IN_EVICTION) ==
1933
2219
                          (BLOCK_READ | BLOCK_IN_SWITCH |
1934
2220
                           BLOCK_IN_FLUSH | BLOCK_IN_FLUSHWRITE |
1935
 
                           BLOCK_CHANGED | BLOCK_IN_USE));
 
2221
                           BLOCK_CHANGED | BLOCK_IN_USE) || fail_block(block));
1936
2222
              keycache->global_cache_write++;
1937
2223
            }
1938
2224
          }
1942
2228
            The block comes from the LRU ring. It must have a hash_link
1943
2229
            assigned.
1944
2230
          */
1945
 
          assert(block->hash_link);
 
2231
          DBUG_ASSERT(block->hash_link);
1946
2232
          if (block->hash_link)
1947
2233
          {
1948
2234
            /*
1969
2255
              a page in the cache in a sweep, without yielding control)
1970
2256
            */
1971
2257
            wait_for_readers(keycache, block);
1972
 
            assert(block->hash_link && block->hash_link->block == block &&
 
2258
            DBUG_ASSERT(block->hash_link && block->hash_link->block == block &&
1973
2259
                        block->prev_changed);
1974
2260
            /* The reader must not have been a writer. */
1975
 
            assert(!(block->status & BLOCK_CHANGED));
 
2261
            DBUG_ASSERT(!(block->status & BLOCK_CHANGED));
1976
2262
 
1977
2263
            /* Wake flushers that might have found the block in between. */
1978
2264
            release_whole_queue(&block->wqueue[COND_FOR_SAVED]);
1985
2271
              and hash_link refer to each other. Hence we need to assign
1986
2272
              the hash_link first, but then we would not know if it was
1987
2273
              linked before. Hence we would not know if to unlink it. So
1988
 
              unlink it here and call link_to_file_list(..., false).
 
2274
              unlink it here and call link_to_file_list(..., FALSE).
1989
2275
            */
1990
2276
            unlink_changed(block);
1991
2277
          }
1996
2282
          link_to_file_list(keycache, block, file, 0);
1997
2283
          page_status= PAGE_TO_BE_READ;
1998
2284
 
1999
 
          assert(block->hash_link->block == block);
2000
 
          assert(hash_link->block->hash_link == hash_link);
 
2285
          KEYCACHE_DBUG_ASSERT(block->hash_link->block == block);
 
2286
          KEYCACHE_DBUG_ASSERT(hash_link->block->hash_link == hash_link);
2001
2287
        }
2002
2288
        else
2003
2289
        {
2015
2301
            attached to the same hash_link and as such destined for the
2016
2302
            same file block.
2017
2303
          */
 
2304
          KEYCACHE_DBUG_PRINT("find_key_block",
 
2305
                              ("block->hash_link: %p  hash_link: %p  "
 
2306
                               "block->status: %u", block->hash_link,
 
2307
                               hash_link, block->status ));
2018
2308
          page_status= (((block->hash_link == hash_link) &&
2019
2309
                         (block->status & BLOCK_READ)) ?
2020
2310
                        PAGE_READ : PAGE_WAIT_TO_BE_READ);
2043
2333
        Register a request on the block. This is another protection
2044
2334
        against eviction.
2045
2335
      */
2046
 
      assert(((block->hash_link != hash_link) &&
 
2336
      DBUG_ASSERT(((block->hash_link != hash_link) &&
2047
2337
                   (block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH))) ||
2048
2338
                  ((block->hash_link == hash_link) &&
2049
2339
                   !(block->status & BLOCK_READ)) ||
2050
2340
                  ((block->status & BLOCK_READ) &&
2051
2341
                   !(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH))));
2052
2342
      reg_requests(keycache, block, 1);
 
2343
      KEYCACHE_DBUG_PRINT("find_key_block",
 
2344
                          ("block->hash_link: %p  hash_link: %p  "
 
2345
                           "block->status: %u", block->hash_link,
 
2346
                           hash_link, block->status ));
2053
2347
      page_status= (((block->hash_link == hash_link) &&
2054
2348
                     (block->status & BLOCK_READ)) ?
2055
2349
                    PAGE_READ : PAGE_WAIT_TO_BE_READ);
2056
2350
    }
2057
2351
  }
2058
2352
 
2059
 
  assert(page_status != -1);
 
2353
  KEYCACHE_DBUG_ASSERT(page_status != -1);
2060
2354
  /* Same assert basically, but be very sure. */
2061
 
  assert(block);
 
2355
  KEYCACHE_DBUG_ASSERT(block);
2062
2356
  /* Assert that block has a request and is not in LRU ring. */
2063
 
  assert(block->requests);
2064
 
  assert(!block->next_used);
2065
 
  assert(!block->prev_used);
 
2357
  DBUG_ASSERT(block->requests);
 
2358
  DBUG_ASSERT(!block->next_used);
 
2359
  DBUG_ASSERT(!block->prev_used);
2066
2360
  /* Assert that we return the correct block. */
2067
 
  assert((page_status == PAGE_WAIT_TO_BE_READ) ||
 
2361
  DBUG_ASSERT((page_status == PAGE_WAIT_TO_BE_READ) ||
2068
2362
              ((block->hash_link->file == file) &&
2069
2363
               (block->hash_link->diskpos == filepos)));
2070
2364
  *page_st=page_status;
 
2365
  KEYCACHE_DBUG_PRINT("find_key_block",
 
2366
                      ("fd: %d  pos: %lu  block->status: %u  page_status: %d",
 
2367
                       file, (ulong) filepos, block->status,
 
2368
                       page_status));
2071
2369
 
2072
 
  return(block);
 
2370
#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
 
2371
  DBUG_EXECUTE("check_keycache2",
 
2372
               test_key_cache(keycache, "end of find_key_block",0););
 
2373
#endif
 
2374
  KEYCACHE_THREAD_TRACE("find_key_block:end");
 
2375
  DBUG_RETURN(block);
2073
2376
}
2074
2377
 
2075
2378
 
2098
2401
*/
2099
2402
 
2100
2403
static void read_block(KEY_CACHE *keycache,
2101
 
                       BLOCK_LINK *block, uint32_t read_length,
2102
 
                       uint32_t min_length, bool primary)
 
2404
                       BLOCK_LINK *block, uint read_length,
 
2405
                       uint min_length, my_bool primary)
2103
2406
{
2104
 
  uint32_t got_length;
 
2407
  uint got_length;
2105
2408
 
2106
2409
  /* On entry cache_lock is locked */
2107
2410
 
 
2411
  KEYCACHE_THREAD_TRACE("read_block");
2108
2412
  if (primary)
2109
2413
  {
2110
2414
    /*
2113
2417
      request for the block become secondary requests. For a primary
2114
2418
      request the block must be properly initialized.
2115
2419
    */
2116
 
    assert(((block->status & ~BLOCK_FOR_UPDATE) == BLOCK_IN_USE));
2117
 
    assert((block->length == 0));
2118
 
    assert((block->offset == keycache->key_cache_block_size));
2119
 
    assert((block->requests > 0));
 
2420
    DBUG_ASSERT(((block->status & ~BLOCK_FOR_UPDATE) == BLOCK_IN_USE) ||
 
2421
                fail_block(block));
 
2422
    DBUG_ASSERT((block->length == 0) || fail_block(block));
 
2423
    DBUG_ASSERT((block->offset == keycache->key_cache_block_size) ||
 
2424
                fail_block(block));
 
2425
    DBUG_ASSERT((block->requests > 0) || fail_block(block));
 
2426
 
 
2427
    KEYCACHE_DBUG_PRINT("read_block",
 
2428
                        ("page to be read by primary request"));
2120
2429
 
2121
2430
    keycache->global_cache_read++;
2122
2431
    /* Page is not in buffer yet, is to be read from disk */
2125
2434
      Here other threads may step in and register as secondary readers.
2126
2435
      They will register in block->wqueue[COND_FOR_REQUESTED].
2127
2436
    */
2128
 
    got_length= pread(block->hash_link->file, block->buffer, read_length, block->hash_link->diskpos);
 
2437
    got_length= my_pread(block->hash_link->file, block->buffer,
 
2438
                         read_length, block->hash_link->diskpos, MYF(0));
2129
2439
    keycache_pthread_mutex_lock(&keycache->cache_lock);
2130
2440
    /*
2131
2441
      The block can now have been marked for free (in case of
2132
2442
      FLUSH_RELEASE). Otherwise the state must be unchanged.
2133
2443
    */
2134
 
    assert(((block->status & ~(BLOCK_REASSIGNED |
2135
 
                                    BLOCK_FOR_UPDATE)) == BLOCK_IN_USE));
2136
 
    assert((block->length == 0));
2137
 
    assert((block->offset == keycache->key_cache_block_size));
2138
 
    assert((block->requests > 0));
 
2444
    DBUG_ASSERT(((block->status & ~(BLOCK_REASSIGNED |
 
2445
                                    BLOCK_FOR_UPDATE)) == BLOCK_IN_USE) ||
 
2446
                fail_block(block));
 
2447
    DBUG_ASSERT((block->length == 0) || fail_block(block));
 
2448
    DBUG_ASSERT((block->offset == keycache->key_cache_block_size) ||
 
2449
                fail_block(block));
 
2450
    DBUG_ASSERT((block->requests > 0) || fail_block(block));
2139
2451
 
2140
2452
    if (got_length < min_length)
2141
2453
      block->status|= BLOCK_ERROR;
2150
2462
        keycache->key_cache_block_size.
2151
2463
      */
2152
2464
    }
 
2465
    KEYCACHE_DBUG_PRINT("read_block",
 
2466
                        ("primary request: new page in cache"));
2153
2467
    /* Signal that all pending requests for this page now can be processed */
2154
2468
    release_whole_queue(&block->wqueue[COND_FOR_REQUESTED]);
2155
2469
  }
2164
2478
      for the requested file block nor the file and position. So we have
2165
2479
      to assert this in the caller.
2166
2480
    */
 
2481
    KEYCACHE_DBUG_PRINT("read_block",
 
2482
                      ("secondary request waiting for new page to be read"));
2167
2483
    wait_on_queue(&block->wqueue[COND_FOR_REQUESTED], &keycache->cache_lock);
 
2484
    KEYCACHE_DBUG_PRINT("read_block",
 
2485
                        ("secondary request: new page in cache"));
2168
2486
  }
2169
2487
}
2170
2488
 
2191
2509
    The function ensures that a block of data of size length from file
2192
2510
    positioned at filepos is in the buffers for some key cache blocks.
2193
2511
    Then the function either copies the data into the buffer buff, or,
2194
 
    if return_buffer is true, it just returns the pointer to the key cache
 
2512
    if return_buffer is TRUE, it just returns the pointer to the key cache
2195
2513
    buffer with the data.
2196
2514
    Filepos must be a multiple of 'block_length', but it doesn't
2197
2515
    have to be a multiple of key_cache_block_size;
2198
2516
*/
2199
2517
 
2200
 
unsigned char *key_cache_read(KEY_CACHE *keycache,
 
2518
uchar *key_cache_read(KEY_CACHE *keycache,
2201
2519
                      File file, my_off_t filepos, int level,
2202
 
                      unsigned char *buff, uint32_t length,
2203
 
                      uint32_t block_length __attribute__((unused)),
 
2520
                      uchar *buff, uint length,
 
2521
                      uint block_length __attribute__((unused)),
2204
2522
                      int return_buffer __attribute__((unused)))
2205
2523
{
2206
 
  bool locked_and_incremented= false;
 
2524
  my_bool locked_and_incremented= FALSE;
2207
2525
  int error=0;
2208
 
  unsigned char *start= buff;
 
2526
  uchar *start= buff;
 
2527
  DBUG_ENTER("key_cache_read");
 
2528
  DBUG_PRINT("enter", ("fd: %u  pos: %lu  length: %u",
 
2529
               (uint) file, (ulong) filepos, length));
2209
2530
 
2210
2531
  if (keycache->key_cache_inited)
2211
2532
  {
2212
2533
    /* Key cache is used */
2213
2534
    register BLOCK_LINK *block;
2214
 
    uint32_t read_length;
2215
 
    uint32_t offset;
2216
 
    uint32_t status;
 
2535
    uint read_length;
 
2536
    uint offset;
 
2537
    uint status;
2217
2538
    int page_st;
2218
2539
 
2219
2540
    /*
2241
2562
      wait_on_queue(&keycache->resize_queue, &keycache->cache_lock);
2242
2563
    /* Register the I/O for the next resize. */
2243
2564
    inc_counter_for_resize_op(keycache);
2244
 
    locked_and_incremented= true;
 
2565
    locked_and_incremented= TRUE;
2245
2566
    /* Requested data may not always be aligned to cache blocks. */
2246
2567
    offset= (uint) (filepos % keycache->key_cache_block_size);
2247
2568
    /* Read data in key_cache_block_size increments */
2256
2577
      /* Do not read beyond the end of the cache block. */
2257
2578
      read_length= length;
2258
2579
      set_if_smaller(read_length, keycache->key_cache_block_size-offset);
2259
 
      assert(read_length > 0);
 
2580
      KEYCACHE_DBUG_ASSERT(read_length > 0);
 
2581
 
 
2582
#ifndef THREAD
 
2583
      if (block_length > keycache->key_cache_block_size || offset)
 
2584
        return_buffer=0;
 
2585
#endif
2260
2586
 
2261
2587
      /* Request the cache block that matches file/pos. */
2262
2588
      keycache->global_cache_r_requests++;
2270
2596
        */
2271
2597
        keycache->global_cache_read++;
2272
2598
        keycache_pthread_mutex_unlock(&keycache->cache_lock);
2273
 
        error= (pread(file, (unsigned char*) buff, read_length, filepos + offset) == 0);
 
2599
        error= (my_pread(file, (uchar*) buff, read_length,
 
2600
                         filepos + offset, MYF(MY_NABP)) != 0);
2274
2601
        keycache_pthread_mutex_lock(&keycache->cache_lock);
2275
2602
        goto next_block;
2276
2603
      }
2281
2608
          /* The requested page is to be read into the block buffer */
2282
2609
          read_block(keycache, block,
2283
2610
                     keycache->key_cache_block_size, read_length+offset,
2284
 
                     (bool)(page_st == PAGE_TO_BE_READ));
 
2611
                     (my_bool)(page_st == PAGE_TO_BE_READ));
2285
2612
          /*
2286
2613
            A secondary request must now have the block assigned to the
2287
2614
            requested file block. It does not hurt to check it for
2288
2615
            primary requests too.
2289
2616
          */
2290
 
          assert(keycache->can_be_used);
2291
 
          assert(block->hash_link->file == file);
2292
 
          assert(block->hash_link->diskpos == filepos);
2293
 
          assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
2617
          DBUG_ASSERT(keycache->can_be_used);
 
2618
          DBUG_ASSERT(block->hash_link->file == file);
 
2619
          DBUG_ASSERT(block->hash_link->diskpos == filepos);
 
2620
          DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
2294
2621
        }
2295
2622
        else if (block->length < read_length + offset)
2296
2623
        {
2307
2634
      /* block status may have added BLOCK_ERROR in the above 'if'. */
2308
2635
      if (!((status= block->status) & BLOCK_ERROR))
2309
2636
      {
 
2637
#ifndef THREAD
 
2638
        if (! return_buffer)
 
2639
#endif
2310
2640
        {
2311
 
          assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
2641
          DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
2312
2642
#if !defined(SERIALIZED_READ_FROM_CACHE)
2313
2643
          keycache_pthread_mutex_unlock(&keycache->cache_lock);
2314
2644
#endif
2315
2645
 
2316
2646
          /* Copy data from the cache buffer */
2317
 
          memcpy(buff, block->buffer+offset, (size_t) read_length);
 
2647
          if (!(read_length & 511))
 
2648
            bmove512(buff, block->buffer+offset, read_length);
 
2649
          else
 
2650
            memcpy(buff, block->buffer+offset, (size_t) read_length);
2318
2651
 
2319
2652
#if !defined(SERIALIZED_READ_FROM_CACHE)
2320
2653
          keycache_pthread_mutex_lock(&keycache->cache_lock);
2321
 
          assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
2654
          DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
2322
2655
#endif
2323
2656
        }
2324
2657
      }
2337
2670
        break;
2338
2671
      }
2339
2672
 
 
2673
#ifndef THREAD
 
2674
      /* This is only true if we where able to read everything in one block */
 
2675
      if (return_buffer)
 
2676
        DBUG_RETURN(block->buffer);
 
2677
#endif
2340
2678
  next_block:
2341
2679
      buff+= read_length;
2342
2680
      filepos+= read_length+offset;
2354
2692
 
2355
2693
  if (locked_and_incremented)
2356
2694
    keycache_pthread_mutex_unlock(&keycache->cache_lock);
2357
 
  if (pread(file, (unsigned char*) buff, length, filepos))
 
2695
  if (my_pread(file, (uchar*) buff, length, filepos, MYF(MY_NABP)))
2358
2696
    error= 1;
2359
2697
  if (locked_and_incremented)
2360
2698
    keycache_pthread_mutex_lock(&keycache->cache_lock);
2365
2703
    dec_counter_for_resize_op(keycache);
2366
2704
    keycache_pthread_mutex_unlock(&keycache->cache_lock);
2367
2705
  }
2368
 
  return(error ? (unsigned char*) 0 : start);
 
2706
  DBUG_RETURN(error ? (uchar*) 0 : start);
2369
2707
}
2370
2708
 
2371
2709
 
2391
2729
 
2392
2730
int key_cache_insert(KEY_CACHE *keycache,
2393
2731
                     File file, my_off_t filepos, int level,
2394
 
                     unsigned char *buff, uint32_t length)
 
2732
                     uchar *buff, uint length)
2395
2733
{
2396
2734
  int error= 0;
 
2735
  DBUG_ENTER("key_cache_insert");
 
2736
  DBUG_PRINT("enter", ("fd: %u  pos: %lu  length: %u",
 
2737
               (uint) file,(ulong) filepos, length));
2397
2738
 
2398
2739
  if (keycache->key_cache_inited)
2399
2740
  {
2400
2741
    /* Key cache is used */
2401
2742
    register BLOCK_LINK *block;
2402
 
    uint32_t read_length;
2403
 
    uint32_t offset;
 
2743
    uint read_length;
 
2744
    uint offset;
2404
2745
    int page_st;
2405
 
    bool locked_and_incremented= false;
 
2746
    my_bool locked_and_incremented= FALSE;
2406
2747
 
2407
2748
    /*
2408
2749
      When the keycache is once initialized, we use the cache_lock to
2419
2760
        goto no_key_cache;
2420
2761
    /* Register the pseudo I/O for the next resize. */
2421
2762
    inc_counter_for_resize_op(keycache);
2422
 
    locked_and_incremented= true;
 
2763
    locked_and_incremented= TRUE;
2423
2764
    /* Loaded data may not always be aligned to cache blocks. */
2424
2765
    offset= (uint) (filepos % keycache->key_cache_block_size);
2425
2766
    /* Load data in key_cache_block_size increments. */
2433
2774
      /* Do not load beyond the end of the cache block. */
2434
2775
      read_length= length;
2435
2776
      set_if_smaller(read_length, keycache->key_cache_block_size-offset);
2436
 
      assert(read_length > 0);
 
2777
      KEYCACHE_DBUG_ASSERT(read_length > 0);
2437
2778
 
2438
2779
      /* The block has been read by the caller already. */
2439
2780
      keycache->global_cache_read++;
2464
2805
            hash_link). So we cannot call remove_reader() on the block.
2465
2806
            And we cannot access the hash_link directly here. We need to
2466
2807
            wait until the assignment is complete. read_block() executes
2467
 
            the correct wait when called with primary == false.
 
2808
            the correct wait when called with primary == FALSE.
2468
2809
 
2469
2810
            Or
2470
2811
 
2489
2830
            requested file block. It does not hurt to check it for
2490
2831
            primary requests too.
2491
2832
          */
2492
 
          assert(keycache->can_be_used);
2493
 
          assert(block->hash_link->file == file);
2494
 
          assert(block->hash_link->diskpos == filepos);
2495
 
          assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
2833
          DBUG_ASSERT(keycache->can_be_used);
 
2834
          DBUG_ASSERT(block->hash_link->file == file);
 
2835
          DBUG_ASSERT(block->hash_link->diskpos == filepos);
 
2836
          DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
2496
2837
        }
2497
2838
        else if (page_st == PAGE_TO_BE_READ)
2498
2839
        {
2500
2841
            This is a new block in the cache. If we come here, we have
2501
2842
            data for the whole block.
2502
2843
          */
2503
 
          assert(block->hash_link->requests);
2504
 
          assert(block->status & BLOCK_IN_USE);
2505
 
          assert((page_st == PAGE_TO_BE_READ) ||
 
2844
          DBUG_ASSERT(block->hash_link->requests);
 
2845
          DBUG_ASSERT(block->status & BLOCK_IN_USE);
 
2846
          DBUG_ASSERT((page_st == PAGE_TO_BE_READ) ||
2506
2847
                      (block->status & BLOCK_READ));
2507
2848
 
2508
2849
#if !defined(SERIALIZED_READ_FROM_CACHE)
2514
2855
#endif
2515
2856
 
2516
2857
          /* Copy data from buff */
2517
 
          memcpy(block->buffer+offset, buff, (size_t) read_length);
 
2858
          if (!(read_length & 511))
 
2859
            bmove512(block->buffer+offset, buff, read_length);
 
2860
          else
 
2861
            memcpy(block->buffer+offset, buff, (size_t) read_length);
2518
2862
 
2519
2863
#if !defined(SERIALIZED_READ_FROM_CACHE)
2520
2864
          keycache_pthread_mutex_lock(&keycache->cache_lock);
2521
 
          assert(block->status & BLOCK_IN_USE);
2522
 
          assert((page_st == PAGE_TO_BE_READ) ||
 
2865
          DBUG_ASSERT(block->status & BLOCK_IN_USE);
 
2866
          DBUG_ASSERT((page_st == PAGE_TO_BE_READ) ||
2523
2867
                      (block->status & BLOCK_READ));
2524
2868
#endif
2525
2869
          /*
2536
2880
            only a writer may set block->offset down from
2537
2881
            keycache->key_cache_block_size.
2538
2882
          */
 
2883
          KEYCACHE_DBUG_PRINT("key_cache_insert",
 
2884
                              ("primary request: new page in cache"));
2539
2885
          /* Signal all pending requests. */
2540
2886
          release_whole_queue(&block->wqueue[COND_FOR_REQUESTED]);
2541
2887
        }
2551
2897
            with the new data. If the condition is met, we can simply
2552
2898
            ignore the block.
2553
2899
          */
2554
 
          assert((page_st == PAGE_READ) &&
 
2900
          DBUG_ASSERT((page_st == PAGE_READ) &&
2555
2901
                      (read_length + offset <= block->length));
2556
2902
        }
2557
2903
 
2560
2906
          requested file block. It does not hurt to check it for primary
2561
2907
          requests too.
2562
2908
        */
2563
 
        assert(block->hash_link->file == file);
2564
 
        assert(block->hash_link->diskpos == filepos);
2565
 
        assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
2909
        DBUG_ASSERT(block->hash_link->file == file);
 
2910
        DBUG_ASSERT(block->hash_link->diskpos == filepos);
 
2911
        DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
2566
2912
      } /* end of if (!(block->status & BLOCK_ERROR)) */
2567
2913
 
2568
2914
 
2590
2936
      dec_counter_for_resize_op(keycache);
2591
2937
    keycache_pthread_mutex_unlock(&keycache->cache_lock);
2592
2938
  }
2593
 
  return(error);
 
2939
  DBUG_RETURN(error);
2594
2940
}
2595
2941
 
2596
2942
 
2616
2962
    The function copies the data of size length from buff into buffers
2617
2963
    for key cache blocks that are  assigned to contain the portion of
2618
2964
    the file starting with position filepos.
2619
 
    It ensures that this data is flushed to the file if dont_write is false.
 
2965
    It ensures that this data is flushed to the file if dont_write is FALSE.
2620
2966
    Filepos must be a multiple of 'block_length', but it doesn't
2621
2967
    have to be a multiple of key_cache_block_size;
2622
2968
 
2623
 
    dont_write is always true in the server (info->lock_type is never F_UNLCK).
 
2969
    dont_write is always TRUE in the server (info->lock_type is never F_UNLCK).
2624
2970
*/
2625
2971
 
2626
2972
int key_cache_write(KEY_CACHE *keycache,
2627
2973
                    File file, my_off_t filepos, int level,
2628
 
                    unsigned char *buff, uint32_t length,
2629
 
                    uint32_t block_length  __attribute__((unused)),
 
2974
                    uchar *buff, uint length,
 
2975
                    uint block_length  __attribute__((unused)),
2630
2976
                    int dont_write)
2631
2977
{
2632
 
  bool locked_and_incremented= false;
 
2978
  my_bool locked_and_incremented= FALSE;
2633
2979
  int error=0;
 
2980
  DBUG_ENTER("key_cache_write");
 
2981
  DBUG_PRINT("enter",
 
2982
             ("fd: %u  pos: %lu  length: %u  block_length: %u"
 
2983
              "  key_block_length: %u",
 
2984
              (uint) file, (ulong) filepos, length, block_length,
 
2985
              keycache ? keycache->key_cache_block_size : 0));
2634
2986
 
2635
2987
  if (!dont_write)
2636
2988
  {
2639
2991
    /* Force writing from buff into disk. */
2640
2992
    keycache->global_cache_w_requests++;
2641
2993
    keycache->global_cache_write++;
2642
 
    if (pwrite(file, buff, length, filepos) == 0)
2643
 
      return(1);
 
2994
    if (my_pwrite(file, buff, length, filepos, MYF(MY_NABP | MY_WAIT_IF_FULL)))
 
2995
      DBUG_RETURN(1);
2644
2996
    /* purecov: end */
2645
2997
  }
2646
2998
 
 
2999
#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
 
3000
  DBUG_EXECUTE("check_keycache",
 
3001
               test_key_cache(keycache, "start of key_cache_write", 1););
 
3002
#endif
 
3003
 
2647
3004
  if (keycache->key_cache_inited)
2648
3005
  {
2649
3006
    /* Key cache is used */
2650
3007
    register BLOCK_LINK *block;
2651
 
    uint32_t read_length;
2652
 
    uint32_t offset;
 
3008
    uint read_length;
 
3009
    uint offset;
2653
3010
    int page_st;
2654
3011
 
2655
3012
    /*
2678
3035
      wait_on_queue(&keycache->resize_queue, &keycache->cache_lock);
2679
3036
    /* Register the I/O for the next resize. */
2680
3037
    inc_counter_for_resize_op(keycache);
2681
 
    locked_and_incremented= true;
 
3038
    locked_and_incremented= TRUE;
2682
3039
    /* Requested data may not always be aligned to cache blocks. */
2683
3040
    offset= (uint) (filepos % keycache->key_cache_block_size);
2684
3041
    /* Write data in key_cache_block_size increments. */
2692
3049
      /* Do not write beyond the end of the cache block. */
2693
3050
      read_length= length;
2694
3051
      set_if_smaller(read_length, keycache->key_cache_block_size-offset);
2695
 
      assert(read_length > 0);
 
3052
      KEYCACHE_DBUG_ASSERT(read_length > 0);
2696
3053
 
2697
3054
      /* Request the cache block that matches file/pos. */
2698
3055
      keycache->global_cache_w_requests++;
2709
3066
          /* Used in the server. */
2710
3067
          keycache->global_cache_write++;
2711
3068
          keycache_pthread_mutex_unlock(&keycache->cache_lock);
2712
 
          if (pwrite(file, (unsigned char*) buff, read_length, filepos + offset) == 0)
 
3069
          if (my_pwrite(file, (uchar*) buff, read_length, filepos + offset,
 
3070
                        MYF(MY_NABP | MY_WAIT_IF_FULL)))
2713
3071
            error=1;
2714
3072
          keycache_pthread_mutex_lock(&keycache->cache_lock);
2715
3073
        }
2744
3102
                   offset + read_length >= keycache->key_cache_block_size?
2745
3103
                   offset : keycache->key_cache_block_size,
2746
3104
                   offset, (page_st == PAGE_TO_BE_READ));
2747
 
        assert(keycache->can_be_used);
2748
 
        assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
3105
        DBUG_ASSERT(keycache->can_be_used);
 
3106
        DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
2749
3107
        /*
2750
3108
          Prevent block from flushing and from being selected for to be
2751
3109
          freed. This must be set when we release the cache_lock.
2757
3115
        The block should always be assigned to the requested file block
2758
3116
        here. It need not be BLOCK_READ when overwriting the whole block.
2759
3117
      */
2760
 
      assert(block->hash_link->file == file);
2761
 
      assert(block->hash_link->diskpos == filepos);
2762
 
      assert(block->status & BLOCK_IN_USE);
2763
 
      assert((page_st == PAGE_TO_BE_READ) || (block->status & BLOCK_READ));
 
3118
      DBUG_ASSERT(block->hash_link->file == file);
 
3119
      DBUG_ASSERT(block->hash_link->diskpos == filepos);
 
3120
      DBUG_ASSERT(block->status & BLOCK_IN_USE);
 
3121
      DBUG_ASSERT((page_st == PAGE_TO_BE_READ) || (block->status & BLOCK_READ));
2764
3122
      /*
2765
3123
        The block to be written must not be marked BLOCK_REASSIGNED.
2766
3124
        Otherwise it could be freed in dirty state or reused without
2769
3127
        the flusher could clear BLOCK_CHANGED without flushing the
2770
3128
        new changes again.
2771
3129
      */
2772
 
      assert(!(block->status & BLOCK_REASSIGNED));
 
3130
      DBUG_ASSERT(!(block->status & BLOCK_REASSIGNED));
2773
3131
 
2774
3132
      while (block->status & BLOCK_IN_FLUSHWRITE)
2775
3133
      {
2783
3141
          another hash_link until we release our request on it.
2784
3142
        */
2785
3143
        wait_on_queue(&block->wqueue[COND_FOR_SAVED], &keycache->cache_lock);
2786
 
        assert(keycache->can_be_used);
2787
 
        assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
3144
        DBUG_ASSERT(keycache->can_be_used);
 
3145
        DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
2788
3146
        /* Still must not be marked for free. */
2789
 
        assert(!(block->status & BLOCK_REASSIGNED));
2790
 
        assert(block->hash_link && (block->hash_link->block == block));
 
3147
        DBUG_ASSERT(!(block->status & BLOCK_REASSIGNED));
 
3148
        DBUG_ASSERT(block->hash_link && (block->hash_link->block == block));
2791
3149
      }
2792
3150
 
2793
3151
      /*
2804
3162
#if !defined(SERIALIZED_READ_FROM_CACHE)
2805
3163
        keycache_pthread_mutex_unlock(&keycache->cache_lock);
2806
3164
#endif
2807
 
        memcpy(block->buffer+offset, buff, (size_t) read_length);
 
3165
        if (!(read_length & 511))
 
3166
          bmove512(block->buffer+offset, buff, read_length);
 
3167
        else
 
3168
          memcpy(block->buffer+offset, buff, (size_t) read_length);
2808
3169
 
2809
3170
#if !defined(SERIALIZED_READ_FROM_CACHE)
2810
3171
        keycache_pthread_mutex_lock(&keycache->cache_lock);
2873
3234
    keycache->global_cache_write++;
2874
3235
    if (locked_and_incremented)
2875
3236
      keycache_pthread_mutex_unlock(&keycache->cache_lock);
2876
 
    if (pwrite(file, (unsigned char*) buff, length, filepos) == 0)
 
3237
    if (my_pwrite(file, (uchar*) buff, length, filepos,
 
3238
                  MYF(MY_NABP | MY_WAIT_IF_FULL)))
2877
3239
      error=1;
2878
3240
    if (locked_and_incremented)
2879
3241
      keycache_pthread_mutex_lock(&keycache->cache_lock);
2885
3247
    dec_counter_for_resize_op(keycache);
2886
3248
    keycache_pthread_mutex_unlock(&keycache->cache_lock);
2887
3249
  }
2888
 
  return(error);
 
3250
#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
 
3251
  DBUG_EXECUTE("exec",
 
3252
               test_key_cache(keycache, "end of key_cache_write", 1););
 
3253
#endif
 
3254
  DBUG_RETURN(error);
2889
3255
}
2890
3256
 
2891
3257
 
2918
3284
 
2919
3285
static void free_block(KEY_CACHE *keycache, BLOCK_LINK *block)
2920
3286
{
 
3287
  KEYCACHE_THREAD_TRACE("free block");
 
3288
  KEYCACHE_DBUG_PRINT("free_block",
 
3289
                      ("block %u to be freed, hash_link %p",
 
3290
                       BLOCK_NUMBER(block), block->hash_link));
2921
3291
  /*
2922
3292
    Assert that the block is not free already. And that it is in a clean
2923
3293
    state. Note that the block might just be assigned to a hash_link and
2925
3295
    is registered in the hash_link and free_block() will wait for it
2926
3296
    below.
2927
3297
  */
2928
 
  assert((block->status & BLOCK_IN_USE) &&
 
3298
  DBUG_ASSERT((block->status & BLOCK_IN_USE) &&
2929
3299
              !(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH |
2930
3300
                                 BLOCK_REASSIGNED | BLOCK_IN_FLUSH |
2931
3301
                                 BLOCK_CHANGED | BLOCK_FOR_UPDATE)));
2932
3302
  /* Assert that the block is in a file_blocks chain. */
2933
 
  assert(block->prev_changed && *block->prev_changed == block);
 
3303
  DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
2934
3304
  /* Assert that the block is not in the LRU ring. */
2935
 
  assert(!block->next_used && !block->prev_used);
 
3305
  DBUG_ASSERT(!block->next_used && !block->prev_used);
2936
3306
  /*
2937
3307
    IMHO the below condition (if()) makes no sense. I can't see how it
2938
3308
    could be possible that free_block() is entered with a NULL hash_link
2939
3309
    pointer. The only place where it can become NULL is in free_block()
2940
3310
    (or before its first use ever, but for those blocks free_block() is
2941
3311
    not called). I don't remove the conditional as it cannot harm, but
2942
 
    place an assert to confirm my hypothesis. Eventually the
 
3312
    place an DBUG_ASSERT to confirm my hypothesis. Eventually the
2943
3313
    condition (if()) can be removed.
2944
3314
  */
2945
 
  assert(block->hash_link && block->hash_link->block == block);
 
3315
  DBUG_ASSERT(block->hash_link && block->hash_link->block == block);
2946
3316
  if (block->hash_link)
2947
3317
  {
2948
3318
    /*
2958
3328
      checks. An additional requirement is that it must be read now
2959
3329
      (BLOCK_READ).
2960
3330
    */
2961
 
    assert(block->hash_link && block->hash_link->block == block);
2962
 
    assert((block->status & (BLOCK_READ | BLOCK_IN_USE |
 
3331
    DBUG_ASSERT(block->hash_link && block->hash_link->block == block);
 
3332
    DBUG_ASSERT((block->status & (BLOCK_READ | BLOCK_IN_USE |
2963
3333
                                  BLOCK_REASSIGNED)) &&
2964
3334
                !(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH |
2965
3335
                                   BLOCK_IN_FLUSH | BLOCK_CHANGED |
2966
3336
                                   BLOCK_FOR_UPDATE)));
2967
 
    assert(block->prev_changed && *block->prev_changed == block);
2968
 
    assert(!block->prev_used);
 
3337
    DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
 
3338
    DBUG_ASSERT(!block->prev_used);
2969
3339
    /*
2970
3340
      Unset BLOCK_REASSIGNED again. If we hand the block to an evicting
2971
3341
      thread (through unreg_request() below), other threads must not see
2988
3358
    operation in this case. Assert that there are no other requests
2989
3359
    registered.
2990
3360
  */
2991
 
  assert(block->requests == 1);
 
3361
  DBUG_ASSERT(block->requests == 1);
2992
3362
  unreg_request(keycache, block, 0);
2993
3363
  /*
2994
3364
    Note that even without releasing the cache lock it is possible that
3000
3370
    return;
3001
3371
 
3002
3372
  /* Here the block must be in the LRU ring. Unlink it again. */
3003
 
  assert(block->next_used && block->prev_used &&
 
3373
  DBUG_ASSERT(block->next_used && block->prev_used &&
3004
3374
              *block->prev_used == block);
3005
3375
  unlink_block(keycache, block);
3006
3376
  if (block->temperature == BLOCK_WARM)
3017
3387
  block->status= 0;
3018
3388
  block->length= 0;
3019
3389
  block->offset= keycache->key_cache_block_size;
 
3390
  KEYCACHE_THREAD_TRACE("free block");
 
3391
  KEYCACHE_DBUG_PRINT("free_block", ("block is freed"));
3020
3392
 
3021
3393
  /* Enforced by unlink_changed(), but just to be sure. */
3022
 
  assert(!block->next_changed && !block->prev_changed);
 
3394
  DBUG_ASSERT(!block->next_changed && !block->prev_changed);
3023
3395
  /* Enforced by unlink_block(): not in LRU ring nor in free_block_list. */
3024
 
  assert(!block->next_used && !block->prev_used);
 
3396
  DBUG_ASSERT(!block->next_used && !block->prev_used);
3025
3397
  /* Insert the free block in the free list. */
3026
3398
  block->next_used= keycache->free_block_list;
3027
3399
  keycache->free_block_list= block;
3052
3424
{
3053
3425
  int error;
3054
3426
  int last_errno= 0;
3055
 
  uint32_t count= (uint) (end-cache);
 
3427
  uint count= (uint) (end-cache);
3056
3428
 
3057
3429
  /* Don't lock the cache during the flush */
3058
3430
  keycache_pthread_mutex_unlock(&keycache->cache_lock);
3060
3432
     As all blocks referred in 'cache' are marked by BLOCK_IN_FLUSH
3061
3433
     we are guarunteed no thread will change them
3062
3434
  */
3063
 
  my_qsort((unsigned char*) cache, count, sizeof(*cache), (qsort_cmp) cmp_sec_link);
 
3435
  my_qsort((uchar*) cache, count, sizeof(*cache), (qsort_cmp) cmp_sec_link);
3064
3436
 
3065
3437
  keycache_pthread_mutex_lock(&keycache->cache_lock);
3066
3438
  /*
3071
3443
  for ( ; cache != end ; cache++)
3072
3444
  {
3073
3445
    BLOCK_LINK *block= *cache;
 
3446
 
 
3447
    KEYCACHE_DBUG_PRINT("flush_cached_blocks",
 
3448
                        ("block %u to be flushed", BLOCK_NUMBER(block)));
3074
3449
    /*
3075
3450
      If the block contents is going to be changed, we abandon the flush
3076
3451
      for this block. flush_key_blocks_int() will restart its search and
3079
3454
    if (!(block->status & BLOCK_FOR_UPDATE))
3080
3455
    {
3081
3456
      /* Blocks coming here must have a certain status. */
3082
 
      assert(block->hash_link);
3083
 
      assert(block->hash_link->block == block);
3084
 
      assert(block->hash_link->file == file);
3085
 
      assert((block->status & ~BLOCK_IN_EVICTION) ==
 
3457
      DBUG_ASSERT(block->hash_link);
 
3458
      DBUG_ASSERT(block->hash_link->block == block);
 
3459
      DBUG_ASSERT(block->hash_link->file == file);
 
3460
      DBUG_ASSERT((block->status & ~BLOCK_IN_EVICTION) ==
3086
3461
                  (BLOCK_READ | BLOCK_IN_FLUSH | BLOCK_CHANGED | BLOCK_IN_USE));
3087
3462
      block->status|= BLOCK_IN_FLUSHWRITE;
3088
3463
      keycache_pthread_mutex_unlock(&keycache->cache_lock);
3089
 
      error= (pwrite(file,
3090
 
                     block->buffer+block->offset,
3091
 
                     block->length - block->offset,
3092
 
                     block->hash_link->diskpos+ block->offset) == 0);
 
3464
      error= my_pwrite(file,
 
3465
                       block->buffer+block->offset,
 
3466
                       block->length - block->offset,
 
3467
                       block->hash_link->diskpos+ block->offset,
 
3468
                       MYF(MY_NABP | MY_WAIT_IF_FULL));
3093
3469
      keycache_pthread_mutex_lock(&keycache->cache_lock);
3094
3470
      keycache->global_cache_write++;
3095
3471
      if (error)
3100
3476
      }
3101
3477
      block->status&= ~BLOCK_IN_FLUSHWRITE;
3102
3478
      /* Block must not have changed status except BLOCK_FOR_UPDATE. */
3103
 
      assert(block->hash_link);
3104
 
      assert(block->hash_link->block == block);
3105
 
      assert(block->hash_link->file == file);
3106
 
      assert((block->status & ~(BLOCK_FOR_UPDATE | BLOCK_IN_EVICTION)) ==
 
3479
      DBUG_ASSERT(block->hash_link);
 
3480
      DBUG_ASSERT(block->hash_link->block == block);
 
3481
      DBUG_ASSERT(block->hash_link->file == file);
 
3482
      DBUG_ASSERT((block->status & ~(BLOCK_FOR_UPDATE | BLOCK_IN_EVICTION)) ==
3107
3483
                  (BLOCK_READ | BLOCK_IN_FLUSH | BLOCK_CHANGED | BLOCK_IN_USE));
3108
3484
      /*
3109
3485
        Set correct status and link in right queue for free or later use.
3177
3553
  BLOCK_LINK *cache_buff[FLUSH_CACHE],**cache;
3178
3554
  int last_errno= 0;
3179
3555
  int last_errcnt= 0;
 
3556
  DBUG_ENTER("flush_key_blocks_int");
 
3557
  DBUG_PRINT("enter",("file: %d  blocks_used: %lu  blocks_changed: %lu",
 
3558
              file, keycache->blocks_used, keycache->blocks_changed));
 
3559
 
 
3560
#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
 
3561
    DBUG_EXECUTE("check_keycache",
 
3562
                 test_key_cache(keycache, "start of flush_key_blocks", 0););
 
3563
#endif
3180
3564
 
3181
3565
  cache= cache_buff;
3182
3566
  if (keycache->disk_blocks > 0 &&
3184
3568
  {
3185
3569
    /* Key cache exists and flush is not disabled */
3186
3570
    int error= 0;
3187
 
    uint32_t count= FLUSH_CACHE;
 
3571
    uint count= FLUSH_CACHE;
3188
3572
    BLOCK_LINK **pos,**end;
3189
3573
    BLOCK_LINK *first_in_switch= NULL;
3190
3574
    BLOCK_LINK *last_in_flush;
3191
3575
    BLOCK_LINK *last_for_update;
3192
3576
    BLOCK_LINK *block, *next;
 
3577
#if defined(KEYCACHE_DEBUG)
 
3578
    uint cnt=0;
 
3579
#endif
3193
3580
 
3194
3581
    if (type != FLUSH_IGNORE_CHANGED)
3195
3582
    {
3206
3593
            !(block->status & BLOCK_IN_FLUSH))
3207
3594
        {
3208
3595
          count++;
3209
 
          assert(count<= keycache->blocks_used);
 
3596
          KEYCACHE_DBUG_ASSERT(count<= keycache->blocks_used);
3210
3597
        }
3211
3598
      }
3212
3599
      /*
3235
3622
         block ;
3236
3623
         block= next)
3237
3624
    {
 
3625
#if defined(KEYCACHE_DEBUG)
 
3626
      cnt++;
 
3627
      KEYCACHE_DBUG_ASSERT(cnt <= keycache->blocks_used);
 
3628
#endif
3238
3629
      next= block->next_changed;
3239
3630
      if (block->hash_link->file == file)
3240
3631
      {
3298
3689
            else
3299
3690
            {
3300
3691
              /* It's a temporary file */
3301
 
              assert(!(block->status & BLOCK_REASSIGNED));
 
3692
              DBUG_ASSERT(!(block->status & BLOCK_REASSIGNED));
3302
3693
 
3303
3694
              /*
3304
3695
                free_block() must not be called with BLOCK_CHANGED. Note
3419
3810
    */
3420
3811
    while (first_in_switch)
3421
3812
    {
 
3813
#if defined(KEYCACHE_DEBUG)
 
3814
      cnt= 0;
 
3815
#endif
3422
3816
      wait_on_queue(&first_in_switch->wqueue[COND_FOR_SAVED],
3423
3817
                    &keycache->cache_lock);
 
3818
#if defined(KEYCACHE_DEBUG)
 
3819
      cnt++;
 
3820
      KEYCACHE_DBUG_ASSERT(cnt <= keycache->blocks_used);
 
3821
#endif
3424
3822
      /*
3425
3823
        Do not restart here. We have flushed all blocks that were
3426
3824
        changed when entering this function and were not marked for
3433
3831
    {
3434
3832
      BLOCK_LINK *last_for_update= NULL;
3435
3833
      BLOCK_LINK *last_in_switch= NULL;
3436
 
      uint32_t total_found= 0;
3437
 
      uint32_t found;
 
3834
      uint total_found= 0;
 
3835
      uint found;
3438
3836
 
3439
3837
      /*
3440
3838
        Finally free all clean blocks for this file.
3451
3849
          next= block->next_changed;
3452
3850
 
3453
3851
          /* Changed blocks cannot appear in the file_blocks hash. */
3454
 
          assert(!(block->status & BLOCK_CHANGED));
 
3852
          DBUG_ASSERT(!(block->status & BLOCK_CHANGED));
3455
3853
          if (block->hash_link->file == file)
3456
3854
          {
3457
3855
            /* We must skip blocks that will be changed. */
3469
3867
            if (!(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH |
3470
3868
                                   BLOCK_REASSIGNED)))
3471
3869
            {
3472
 
              struct st_hash_link *next_hash_link= NULL;
3473
 
              my_off_t            next_diskpos= 0;
3474
 
              File                next_file= 0;
3475
 
              uint32_t                next_status= 0;
3476
 
              uint32_t                hash_requests= 0;
 
3870
              struct st_hash_link *next_hash_link;
 
3871
              my_off_t            next_diskpos;
 
3872
              File                next_file;
 
3873
              uint                next_status;
 
3874
              uint                hash_requests;
3477
3875
 
3478
3876
              total_found++;
3479
3877
              found++;
3480
 
              assert(found <= keycache->blocks_used);
 
3878
              KEYCACHE_DBUG_ASSERT(found <= keycache->blocks_used);
3481
3879
 
3482
3880
              /*
3483
3881
                Register a request. This unlinks the block from the LRU
3499
3897
                next_hash_link= next->hash_link;
3500
3898
                next_diskpos=   next_hash_link->diskpos;
3501
3899
                next_file=      next_hash_link->file;
3502
 
                assert(next == next_hash_link->block);
 
3900
                DBUG_ASSERT(next == next_hash_link->block);
3503
3901
              }
3504
3902
 
3505
3903
              free_block(keycache, block);
3546
3944
      if (last_for_update)
3547
3945
      {
3548
3946
        /* We did not wait. Block must not have changed status. */
3549
 
        assert(last_for_update->status & BLOCK_FOR_UPDATE);
 
3947
        DBUG_ASSERT(last_for_update->status & BLOCK_FOR_UPDATE);
3550
3948
        wait_on_queue(&last_for_update->wqueue[COND_FOR_REQUESTED],
3551
3949
                      &keycache->cache_lock);
3552
3950
        goto restart;
3559
3957
      if (last_in_switch)
3560
3958
      {
3561
3959
        /* We did not wait. Block must not have changed status. */
3562
 
        assert(last_in_switch->status & (BLOCK_IN_EVICTION |
 
3960
        DBUG_ASSERT(last_in_switch->status & (BLOCK_IN_EVICTION |
3563
3961
                                              BLOCK_IN_SWITCH |
3564
3962
                                              BLOCK_REASSIGNED));
3565
3963
        wait_on_queue(&last_in_switch->wqueue[COND_FOR_SAVED],
3571
3969
 
3572
3970
  } /* if (keycache->disk_blocks > 0 */
3573
3971
 
 
3972
#ifndef DBUG_OFF
 
3973
  DBUG_EXECUTE("check_keycache",
 
3974
               test_key_cache(keycache, "end of flush_key_blocks", 0););
 
3975
#endif
3574
3976
err:
3575
3977
  if (cache != cache_buff)
3576
 
    free((unsigned char*) cache);
 
3978
    my_free((uchar*) cache, MYF(0));
3577
3979
  if (last_errno)
3578
3980
    errno=last_errno;                /* Return first error */
3579
 
  return(last_errno != 0);
 
3981
  DBUG_RETURN(last_errno != 0);
3580
3982
}
3581
3983
 
3582
3984
 
3599
4001
                     File file, enum flush_type type)
3600
4002
{
3601
4003
  int res= 0;
 
4004
  DBUG_ENTER("flush_key_blocks");
 
4005
  DBUG_PRINT("enter", ("keycache: 0x%lx", (long) keycache));
3602
4006
 
3603
4007
  if (!keycache->key_cache_inited)
3604
 
    return(0);
 
4008
    DBUG_RETURN(0);
3605
4009
 
3606
4010
  keycache_pthread_mutex_lock(&keycache->cache_lock);
3607
4011
  /* While waiting for lock, keycache could have been ended. */
3612
4016
    dec_counter_for_resize_op(keycache);
3613
4017
  }
3614
4018
  keycache_pthread_mutex_unlock(&keycache->cache_lock);
3615
 
  return(res);
 
4019
  DBUG_RETURN(res);
3616
4020
}
3617
4021
 
3618
4022
 
3651
4055
static int flush_all_key_blocks(KEY_CACHE *keycache)
3652
4056
{
3653
4057
  BLOCK_LINK    *block;
3654
 
  uint32_t          total_found;
3655
 
  uint32_t          found;
3656
 
  uint32_t          idx;
 
4058
  uint          total_found;
 
4059
  uint          found;
 
4060
  uint          idx;
 
4061
  DBUG_ENTER("flush_all_key_blocks");
3657
4062
 
3658
4063
  do
3659
4064
  {
3688
4093
          */
3689
4094
          if (flush_key_blocks_int(keycache, block->hash_link->file,
3690
4095
                                   FLUSH_FORCE_WRITE))
3691
 
            return(1);
 
4096
            DBUG_RETURN(1);
3692
4097
        }
3693
4098
      }
3694
4099
 
3722
4127
          found++;
3723
4128
          if (flush_key_blocks_int(keycache, block->hash_link->file,
3724
4129
                                   FLUSH_RELEASE))
3725
 
            return(1);
 
4130
            DBUG_RETURN(1);
3726
4131
        }
3727
4132
      }
3728
4133
 
3735
4140
      before the resize started (BLOCK_FOR_UPDATE). Re-check the hashes.
3736
4141
    */
3737
4142
  } while (total_found);
3738
 
  return(0);
 
4143
 
 
4144
#ifndef DBUG_OFF
 
4145
  /* Now there should not exist any block any more. */
 
4146
  for (idx= 0; idx < CHANGED_BLOCKS_HASH; idx++)
 
4147
  {
 
4148
    DBUG_ASSERT(!keycache->changed_blocks[idx]);
 
4149
    DBUG_ASSERT(!keycache->file_blocks[idx]);
 
4150
  }
 
4151
#endif
 
4152
 
 
4153
  DBUG_RETURN(0);
3739
4154
}
3740
4155
 
3741
4156
 
3758
4173
int reset_key_cache_counters(const char *name __attribute__((unused)),
3759
4174
                             KEY_CACHE *key_cache)
3760
4175
{
 
4176
  DBUG_ENTER("reset_key_cache_counters");
3761
4177
  if (!key_cache->key_cache_inited)
3762
4178
  {
3763
 
    return(0);
 
4179
    DBUG_PRINT("info", ("Key cache %s not initialized.", name));
 
4180
    DBUG_RETURN(0);
3764
4181
  }
 
4182
  DBUG_PRINT("info", ("Resetting counters for key cache %s.", name));
 
4183
 
3765
4184
  key_cache->global_blocks_changed= 0;   /* Key_blocks_not_flushed */
3766
4185
  key_cache->global_cache_r_requests= 0; /* Key_read_requests */
3767
4186
  key_cache->global_cache_read= 0;       /* Key_reads */
3768
4187
  key_cache->global_cache_w_requests= 0; /* Key_write_requests */
3769
4188
  key_cache->global_cache_write= 0;      /* Key_writes */
3770
 
  return(0);
3771
 
}
 
4189
  DBUG_RETURN(0);
 
4190
}
 
4191
 
 
4192
 
 
4193
#ifndef DBUG_OFF
 
4194
/*
 
4195
  Test if disk-cache is ok
 
4196
*/
 
4197
static void test_key_cache(KEY_CACHE *keycache __attribute__((unused)),
 
4198
                           const char *where __attribute__((unused)),
 
4199
                           my_bool lock __attribute__((unused)))
 
4200
{
 
4201
  /* TODO */
 
4202
}
 
4203
#endif
3772
4204
 
3773
4205
#if defined(KEYCACHE_TIMEOUT)
3774
4206
 
3784
4216
  BLOCK_LINK *block;
3785
4217
  HASH_LINK *hash_link;
3786
4218
  KEYCACHE_PAGE *page;
3787
 
  uint32_t i;
 
4219
  uint i;
3788
4220
 
3789
4221
  fprintf(keycache_dump_file, "thread:%u\n", thread->id);
3790
4222
 
3798
4230
      page= (KEYCACHE_PAGE *) thread->opt_info;
3799
4231
      fprintf(keycache_dump_file,
3800
4232
              "thread:%u, (file,filepos)=(%u,%lu)\n",
3801
 
              thread->id,(uint) page->file,(uint32_t) page->filepos);
 
4233
              thread->id,(uint) page->file,(ulong) page->filepos);
3802
4234
      if (++i == MAX_QUEUE_LEN)
3803
4235
        break;
3804
4236
    }
3813
4245
      thread=thread->next;
3814
4246
      hash_link= (HASH_LINK *) thread->opt_info;
3815
4247
      fprintf(keycache_dump_file,
3816
 
        "thread:%u hash_link:%u (file,filepos)=(%u,%u)\n",
 
4248
        "thread:%u hash_link:%u (file,filepos)=(%u,%lu)\n",
3817
4249
        thread->id, (uint) HASH_LINK_NUMBER(hash_link),
3818
 
        (uint) hash_link->file,(uint32_t) hash_link->diskpos);
 
4250
        (uint) hash_link->file,(ulong) hash_link->diskpos);
3819
4251
      if (++i == MAX_QUEUE_LEN)
3820
4252
        break;
3821
4253
    }
3866
4298
  fclose(keycache_dump_file);
3867
4299
}
3868
4300
 
 
4301
#endif /* defined(KEYCACHE_TIMEOUT) */
 
4302
 
 
4303
#if defined(KEYCACHE_TIMEOUT)
 
4304
 
 
4305
 
3869
4306
static int keycache_pthread_cond_wait(pthread_cond_t *cond,
3870
4307
                                      pthread_mutex_t *mutex)
3871
4308
{
3873
4310
  struct timeval  now;            /* time when we started waiting        */
3874
4311
  struct timespec timeout;        /* timeout value for the wait function */
3875
4312
  struct timezone tz;
 
4313
#if defined(KEYCACHE_DEBUG)
 
4314
  int cnt=0;
 
4315
#endif
3876
4316
 
3877
4317
  /* Get current time */
3878
4318
  gettimeofday(&now, &tz);
3884
4324
   1 nanosecond = 1000 micro seconds
3885
4325
 */
3886
4326
  timeout.tv_nsec= now.tv_usec * 1000;
 
4327
  KEYCACHE_THREAD_TRACE_END("started waiting");
 
4328
#if defined(KEYCACHE_DEBUG)
 
4329
  cnt++;
 
4330
  if (cnt % 100 == 0)
 
4331
    fprintf(keycache_debug_log, "waiting...\n");
 
4332
    fflush(keycache_debug_log);
 
4333
#endif
3887
4334
  rc= pthread_cond_timedwait(cond, mutex, &timeout);
 
4335
  KEYCACHE_THREAD_TRACE_BEGIN("finished waiting");
3888
4336
  if (rc == ETIMEDOUT || rc == ETIME)
3889
4337
  {
 
4338
#if defined(KEYCACHE_DEBUG)
 
4339
    fprintf(keycache_debug_log,"aborted by keycache timeout\n");
 
4340
    fclose(keycache_debug_log);
 
4341
    abort();
 
4342
#endif
3890
4343
    keycache_dump();
3891
4344
  }
3892
4345
 
 
4346
#if defined(KEYCACHE_DEBUG)
 
4347
  KEYCACHE_DBUG_ASSERT(rc != ETIMEDOUT);
 
4348
#else
3893
4349
  assert(rc != ETIMEDOUT);
3894
 
  return rc;
3895
 
}
 
4350
#endif
 
4351
  return rc;
 
4352
}
 
4353
#else
 
4354
#if defined(KEYCACHE_DEBUG)
 
4355
static int keycache_pthread_cond_wait(pthread_cond_t *cond,
 
4356
                                      pthread_mutex_t *mutex)
 
4357
{
 
4358
  int rc;
 
4359
  KEYCACHE_THREAD_TRACE_END("started waiting");
 
4360
  rc= pthread_cond_wait(cond, mutex);
 
4361
  KEYCACHE_THREAD_TRACE_BEGIN("finished waiting");
 
4362
  return rc;
 
4363
}
 
4364
#endif
3896
4365
#endif /* defined(KEYCACHE_TIMEOUT) */
 
4366
 
 
4367
#if defined(KEYCACHE_DEBUG)
 
4368
 
 
4369
 
 
4370
static int keycache_pthread_mutex_lock(pthread_mutex_t *mutex)
 
4371
{
 
4372
  int rc;
 
4373
  rc= pthread_mutex_lock(mutex);
 
4374
  KEYCACHE_THREAD_TRACE_BEGIN("");
 
4375
  return rc;
 
4376
}
 
4377
 
 
4378
 
 
4379
static void keycache_pthread_mutex_unlock(pthread_mutex_t *mutex)
 
4380
{
 
4381
  KEYCACHE_THREAD_TRACE_END("");
 
4382
  pthread_mutex_unlock(mutex);
 
4383
}
 
4384
 
 
4385
 
 
4386
static int keycache_pthread_cond_signal(pthread_cond_t *cond)
 
4387
{
 
4388
  int rc;
 
4389
  KEYCACHE_THREAD_TRACE("signal");
 
4390
  rc= pthread_cond_signal(cond);
 
4391
  return rc;
 
4392
}
 
4393
 
 
4394
 
 
4395
#if defined(KEYCACHE_DEBUG_LOG)
 
4396
 
 
4397
 
 
4398
static void keycache_debug_print(const char * fmt,...)
 
4399
{
 
4400
  va_list args;
 
4401
  va_start(args,fmt);
 
4402
  if (keycache_debug_log)
 
4403
  {
 
4404
    VOID(vfprintf(keycache_debug_log, fmt, args));
 
4405
    VOID(fputc('\n',keycache_debug_log));
 
4406
  }
 
4407
  va_end(args);
 
4408
}
 
4409
#endif /* defined(KEYCACHE_DEBUG_LOG) */
 
4410
 
 
4411
#if defined(KEYCACHE_DEBUG_LOG)
 
4412
 
 
4413
 
 
4414
void keycache_debug_log_close(void)
 
4415
{
 
4416
  if (keycache_debug_log)
 
4417
    fclose(keycache_debug_log);
 
4418
}
 
4419
#endif /* defined(KEYCACHE_DEBUG_LOG) */
 
4420
 
 
4421
#endif /* defined(KEYCACHE_DEBUG) */
 
4422
 
 
4423
#if !defined(DBUG_OFF)
 
4424
#define F_B_PRT(_f_, _v_) DBUG_PRINT("assert_fail", (_f_, _v_))
 
4425
 
 
4426
static int fail_block(BLOCK_LINK *block)
 
4427
{
 
4428
  F_B_PRT("block->next_used:    %lx\n", (ulong) block->next_used);
 
4429
  F_B_PRT("block->prev_used:    %lx\n", (ulong) block->prev_used);
 
4430
  F_B_PRT("block->next_changed: %lx\n", (ulong) block->next_changed);
 
4431
  F_B_PRT("block->prev_changed: %lx\n", (ulong) block->prev_changed);
 
4432
  F_B_PRT("block->hash_link:    %lx\n", (ulong) block->hash_link);
 
4433
  F_B_PRT("block->status:       %u\n", block->status);
 
4434
  F_B_PRT("block->length:       %u\n", block->length);
 
4435
  F_B_PRT("block->offset:       %u\n", block->offset);
 
4436
  F_B_PRT("block->requests:     %u\n", block->requests);
 
4437
  F_B_PRT("block->temperature:  %u\n", block->temperature);
 
4438
  return 0; /* Let the assert fail. */
 
4439
}
 
4440
 
 
4441
static int fail_hlink(HASH_LINK *hlink)
 
4442
{
 
4443
  F_B_PRT("hlink->next:    %lx\n", (ulong) hlink->next);
 
4444
  F_B_PRT("hlink->prev:    %lx\n", (ulong) hlink->prev);
 
4445
  F_B_PRT("hlink->block:   %lx\n", (ulong) hlink->block);
 
4446
  F_B_PRT("hlink->diskpos: %lu\n", (ulong) hlink->diskpos);
 
4447
  F_B_PRT("hlink->file:    %d\n", hlink->file);
 
4448
  return 0; /* Let the assert fail. */
 
4449
}
 
4450
 
 
4451
static int cache_empty(KEY_CACHE *keycache)
 
4452
{
 
4453
  int errcnt= 0;
 
4454
  int idx;
 
4455
  if (keycache->disk_blocks <= 0)
 
4456
    return 1;
 
4457
  for (idx= 0; idx < keycache->disk_blocks; idx++)
 
4458
  {
 
4459
    BLOCK_LINK *block= keycache->block_root + idx;
 
4460
    if (block->status || block->requests || block->hash_link)
 
4461
    {
 
4462
      fprintf(stderr, "block index: %u\n", idx);
 
4463
      fail_block(block);
 
4464
      errcnt++;
 
4465
    }
 
4466
  }
 
4467
  for (idx= 0; idx < keycache->hash_links; idx++)
 
4468
  {
 
4469
    HASH_LINK *hash_link= keycache->hash_link_root + idx;
 
4470
    if (hash_link->requests || hash_link->block)
 
4471
    {
 
4472
      fprintf(stderr, "hash_link index: %u\n", idx);
 
4473
      fail_hlink(hash_link);
 
4474
      errcnt++;
 
4475
    }
 
4476
  }
 
4477
  if (errcnt)
 
4478
  {
 
4479
    fprintf(stderr, "blocks: %d  used: %lu\n",
 
4480
            keycache->disk_blocks, keycache->blocks_used);
 
4481
    fprintf(stderr, "hash_links: %d  used: %d\n",
 
4482
            keycache->hash_links, keycache->hash_links_used);
 
4483
    fprintf(stderr, "\n");
 
4484
  }
 
4485
  return !errcnt;
 
4486
}
 
4487
#endif
 
4488