~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to storage/myisam/mf_keycache.c

mergeĀ mainline

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 "my_global.h"
 
105
#include "mysys_err.h"
 
106
#include <my_sys.h>
107
107
#include <keycache.h>
108
 
#include <mystrings/m_string.h>
109
 
#include <mysys/my_bit.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
 
214
225
                          pthread_mutex_t *mutex);
215
226
static void release_whole_queue(KEYCACHE_WQUEUE *wqueue);
216
227
static void free_block(KEY_CACHE *keycache, BLOCK_LINK *block);
 
228
#if !defined(DBUG_OFF)
 
229
static void test_key_cache(KEY_CACHE *keycache,
 
230
                           const char *where, my_bool lock);
 
231
#endif
217
232
 
218
233
#define KEYCACHE_HASH(f, pos)                                                 \
219
 
(((uint32_t) ((pos) / keycache->key_cache_block_size) +                          \
220
 
                                     (uint32_t) (f)) & (keycache->hash_entries-1))
 
234
(((ulong) ((pos) / keycache->key_cache_block_size) +                          \
 
235
                                     (ulong) (f)) & (keycache->hash_entries-1))
221
236
#define FILE_HASH(f)                 ((uint) (f) & (CHANGED_BLOCKS_HASH-1))
222
237
 
 
238
#define DEFAULT_KEYCACHE_DEBUG_LOG  "keycache_debug.log"
 
239
 
 
240
#if defined(KEYCACHE_DEBUG) && ! defined(KEYCACHE_DEBUG_LOG)
 
241
#define KEYCACHE_DEBUG_LOG  DEFAULT_KEYCACHE_DEBUG_LOG
 
242
#endif
 
243
 
 
244
#if defined(KEYCACHE_DEBUG_LOG)
 
245
static FILE *keycache_debug_log=NULL;
 
246
static void keycache_debug_print _VARARGS((const char *fmt,...));
 
247
#define KEYCACHE_DEBUG_OPEN                                                   \
 
248
          if (!keycache_debug_log)                                            \
 
249
          {                                                                   \
 
250
            keycache_debug_log= fopen(KEYCACHE_DEBUG_LOG, "w");               \
 
251
            (void) setvbuf(keycache_debug_log, NULL, _IOLBF, BUFSIZ);         \
 
252
          }
 
253
 
 
254
#define KEYCACHE_DEBUG_CLOSE                                                  \
 
255
          if (keycache_debug_log)                                             \
 
256
          {                                                                   \
 
257
            fclose(keycache_debug_log);                                       \
 
258
            keycache_debug_log= 0;                                            \
 
259
          }
 
260
#else
 
261
#define KEYCACHE_DEBUG_OPEN
 
262
#define KEYCACHE_DEBUG_CLOSE
 
263
#endif /* defined(KEYCACHE_DEBUG_LOG) */
 
264
 
 
265
#if defined(KEYCACHE_DEBUG_LOG) && defined(KEYCACHE_DEBUG)
 
266
#define KEYCACHE_DBUG_PRINT(l, m)                                             \
 
267
            { if (keycache_debug_log) fprintf(keycache_debug_log, "%s: ", l); \
 
268
              keycache_debug_print m; }
 
269
 
 
270
#define KEYCACHE_DBUG_ASSERT(a)                                               \
 
271
            { if (! (a) && keycache_debug_log) fclose(keycache_debug_log);    \
 
272
              assert(a); }
 
273
#else
 
274
#define KEYCACHE_DBUG_PRINT(l, m)  DBUG_PRINT(l, m)
 
275
#define KEYCACHE_DBUG_ASSERT(a)    DBUG_ASSERT(a)
 
276
#endif /* defined(KEYCACHE_DEBUG_LOG) && defined(KEYCACHE_DEBUG) */
 
277
 
 
278
#if defined(KEYCACHE_DEBUG) || !defined(DBUG_OFF)
 
279
static long keycache_thread_id;
 
280
#define KEYCACHE_THREAD_TRACE(l)                                              \
 
281
             KEYCACHE_DBUG_PRINT(l,("|thread %ld",keycache_thread_id))
 
282
 
 
283
#define KEYCACHE_THREAD_TRACE_BEGIN(l)                                        \
 
284
            { struct st_my_thread_var *thread_var= my_thread_var;             \
 
285
              keycache_thread_id= thread_var->id;                             \
 
286
              KEYCACHE_DBUG_PRINT(l,("[thread %ld",keycache_thread_id)) }
 
287
 
 
288
#define KEYCACHE_THREAD_TRACE_END(l)                                          \
 
289
            KEYCACHE_DBUG_PRINT(l,("]thread %ld",keycache_thread_id))
 
290
#else
 
291
#define KEYCACHE_THREAD_TRACE_BEGIN(l)
 
292
#define KEYCACHE_THREAD_TRACE_END(l)
 
293
#define KEYCACHE_THREAD_TRACE(l)
 
294
#endif /* defined(KEYCACHE_DEBUG) || !defined(DBUG_OFF) */
 
295
 
223
296
#define BLOCK_NUMBER(b)                                                       \
224
297
  ((uint) (((char*)(b)-(char *) keycache->block_root)/sizeof(BLOCK_LINK)))
225
298
#define HASH_LINK_NUMBER(h)                                                   \
226
299
  ((uint) (((char*)(h)-(char *) keycache->hash_link_root)/sizeof(HASH_LINK)))
227
300
 
228
 
#ifdef KEYCACHE_TIMEOUT
 
301
#if (defined(KEYCACHE_TIMEOUT)) || defined(KEYCACHE_DEBUG)
229
302
static int keycache_pthread_cond_wait(pthread_cond_t *cond,
230
303
                                      pthread_mutex_t *mutex);
231
304
#else
232
305
#define  keycache_pthread_cond_wait pthread_cond_wait
233
306
#endif
234
307
 
 
308
#if defined(KEYCACHE_DEBUG)
 
309
static int keycache_pthread_mutex_lock(pthread_mutex_t *mutex);
 
310
static void keycache_pthread_mutex_unlock(pthread_mutex_t *mutex);
 
311
static int keycache_pthread_cond_signal(pthread_cond_t *cond);
 
312
#else
235
313
#define keycache_pthread_mutex_lock pthread_mutex_lock
236
314
#define keycache_pthread_mutex_unlock pthread_mutex_unlock
237
315
#define keycache_pthread_cond_signal pthread_cond_signal
238
 
 
239
 
static inline uint32_t next_power(uint32_t value)
 
316
#endif /* defined(KEYCACHE_DEBUG) */
 
317
 
 
318
#if !defined(DBUG_OFF)
 
319
#if defined(inline)
 
320
#undef inline
 
321
#endif
 
322
#define inline  /* disabled inline for easier debugging */
 
323
static int fail_block(BLOCK_LINK *block);
 
324
static int fail_hlink(HASH_LINK *hlink);
 
325
static int cache_empty(KEY_CACHE *keycache);
 
326
#endif
 
327
 
 
328
static inline uint next_power(uint value)
240
329
{
241
 
  return (uint) my_round_up_to_next_power((uint32_t) value) << 1;
 
330
  return (uint) my_round_up_to_next_power((uint32) value) << 1;
242
331
}
243
332
 
244
333
 
267
356
 
268
357
*/
269
358
 
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)
 
359
int init_key_cache(KEY_CACHE *keycache, uint key_cache_block_size,
 
360
                   size_t use_mem, uint division_limit,
 
361
                   uint age_threshold)
273
362
{
274
 
  uint32_t blocks, hash_links;
 
363
  ulong blocks, hash_links;
275
364
  size_t length;
276
365
  int error;
277
 
  assert(key_cache_block_size >= 512);
 
366
  DBUG_ENTER("init_key_cache");
 
367
  DBUG_ASSERT(key_cache_block_size >= 512);
278
368
 
 
369
  KEYCACHE_DEBUG_OPEN;
279
370
  if (keycache->key_cache_inited && keycache->disk_blocks > 0)
280
371
  {
281
 
    return(0);
 
372
    DBUG_PRINT("warning",("key cache already in use"));
 
373
    DBUG_RETURN(0);
282
374
  }
283
375
 
284
376
  keycache->global_cache_w_requests= keycache->global_cache_r_requests= 0;
302
394
 
303
395
  keycache->key_cache_mem_size= use_mem;
304
396
  keycache->key_cache_block_size= key_cache_block_size;
 
397
  DBUG_PRINT("info", ("key_cache_block_size: %u",
 
398
                      key_cache_block_size));
305
399
 
306
 
  blocks= (uint32_t) (use_mem / (sizeof(BLOCK_LINK) + 2 * sizeof(HASH_LINK) +
 
400
  blocks= (ulong) (use_mem / (sizeof(BLOCK_LINK) + 2 * sizeof(HASH_LINK) +
307
401
                              sizeof(HASH_LINK*) * 5/4 + key_cache_block_size));
308
402
  /* It doesn't make sense to have too few blocks (less than 8) */
309
403
  if (blocks >= 8)
353
447
    keycache->hash_link_root= (HASH_LINK*) ((char*) keycache->hash_root +
354
448
                                            ALIGN_SIZE((sizeof(HASH_LINK*) *
355
449
                                                        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));
 
450
    bzero((uchar*) keycache->block_root,
 
451
          keycache->disk_blocks * sizeof(BLOCK_LINK));
 
452
    bzero((uchar*) keycache->hash_root,
 
453
          keycache->hash_entries * sizeof(HASH_LINK*));
 
454
    bzero((uchar*) keycache->hash_link_root,
 
455
          keycache->hash_links * sizeof(HASH_LINK));
362
456
    keycache->hash_links_used= 0;
363
457
    keycache->free_hash_list= NULL;
364
458
    keycache->blocks_used= keycache->blocks_changed= 0;
383
477
 
384
478
    keycache->waiting_for_hash_link.last_thread= NULL;
385
479
    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);
 
480
    DBUG_PRINT("exit",
 
481
               ("disk_blocks: %d  block_root: 0x%lx  hash_entries: %d\
 
482
 hash_root: 0x%lx  hash_links: %d  hash_link_root: 0x%lx",
 
483
                keycache->disk_blocks,  (long) keycache->block_root,
 
484
                keycache->hash_entries, (long) keycache->hash_root,
 
485
                keycache->hash_links,   (long) keycache->hash_link_root));
 
486
    bzero((uchar*) keycache->changed_blocks,
 
487
          sizeof(keycache->changed_blocks[0]) * CHANGED_BLOCKS_HASH);
 
488
    bzero((uchar*) keycache->file_blocks,
 
489
          sizeof(keycache->file_blocks[0]) * CHANGED_BLOCKS_HASH);
390
490
  }
391
491
  else
392
492
  {
395
495
  }
396
496
 
397
497
  keycache->blocks= keycache->disk_blocks > 0 ? keycache->disk_blocks : 0;
398
 
  return((int) keycache->disk_blocks);
 
498
  DBUG_RETURN((int) keycache->disk_blocks);
399
499
 
400
500
err:
401
501
  error= my_errno;
408
508
  }
409
509
  if (keycache->block_root)
410
510
  {
411
 
    free((unsigned char*) keycache->block_root);
 
511
    my_free((uchar*) keycache->block_root, MYF(0));
412
512
    keycache->block_root= NULL;
413
513
  }
414
514
  my_errno= error;
415
515
  keycache->can_be_used= 0;
416
 
  return(0);
 
516
  DBUG_RETURN(0);
417
517
}
418
518
 
419
519
 
446
546
    (when cnt_for_resize=0).
447
547
*/
448
548
 
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)
 
549
int resize_key_cache(KEY_CACHE *keycache, uint key_cache_block_size,
 
550
                     size_t use_mem, uint division_limit,
 
551
                     uint age_threshold)
452
552
{
453
553
  int blocks;
 
554
  DBUG_ENTER("resize_key_cache");
454
555
 
455
556
  if (!keycache->key_cache_inited)
456
 
    return(keycache->disk_blocks);
 
557
    DBUG_RETURN(keycache->disk_blocks);
457
558
 
458
559
  if(key_cache_block_size == keycache->key_cache_block_size &&
459
560
     use_mem == keycache->key_cache_mem_size)
460
561
  {
461
562
    change_key_cache_param(keycache, division_limit, age_threshold);
462
 
    return(keycache->disk_blocks);
 
563
    DBUG_RETURN(keycache->disk_blocks);
463
564
  }
464
565
 
465
566
  keycache_pthread_mutex_lock(&keycache->cache_lock);
498
599
      keycache->can_be_used= 0;
499
600
      goto finish;
500
601
    }
 
602
    DBUG_ASSERT(cache_empty(keycache));
501
603
 
502
604
    /* End the flush phase. */
503
605
    keycache->resize_in_flush= 0;
539
641
  release_whole_queue(&keycache->resize_queue);
540
642
 
541
643
  keycache_pthread_mutex_unlock(&keycache->cache_lock);
542
 
  return(blocks);
 
644
  DBUG_RETURN(blocks);
543
645
}
544
646
 
545
647
 
580
682
    age_threshold.
581
683
*/
582
684
 
583
 
void change_key_cache_param(KEY_CACHE *keycache, uint32_t division_limit,
584
 
                            uint32_t age_threshold)
 
685
void change_key_cache_param(KEY_CACHE *keycache, uint division_limit,
 
686
                            uint age_threshold)
585
687
{
 
688
  DBUG_ENTER("change_key_cache_param");
 
689
 
586
690
  keycache_pthread_mutex_lock(&keycache->cache_lock);
587
691
  if (division_limit)
588
692
    keycache->min_warm_blocks= (keycache->disk_blocks *
591
695
    keycache->age_threshold=   (keycache->disk_blocks *
592
696
                                age_threshold / 100);
593
697
  keycache_pthread_mutex_unlock(&keycache->cache_lock);
594
 
  return;
 
698
  DBUG_VOID_RETURN;
595
699
}
596
700
 
597
701
 
607
711
    none
608
712
*/
609
713
 
610
 
void end_key_cache(KEY_CACHE *keycache, bool cleanup)
 
714
void end_key_cache(KEY_CACHE *keycache, my_bool cleanup)
611
715
{
 
716
  DBUG_ENTER("end_key_cache");
 
717
  DBUG_PRINT("enter", ("key_cache: 0x%lx", (long) keycache));
 
718
 
612
719
  if (!keycache->key_cache_inited)
613
 
    return;
 
720
    DBUG_VOID_RETURN;
614
721
 
615
722
  if (keycache->disk_blocks > 0)
616
723
  {
618
725
    {
619
726
      free(keycache->block_mem);
620
727
      keycache->block_mem= NULL;
621
 
      free((unsigned char*) keycache->block_root);
 
728
      my_free((uchar*) keycache->block_root, MYF(0));
622
729
      keycache->block_root= NULL;
623
730
    }
624
731
    keycache->disk_blocks= -1;
626
733
    keycache->blocks_changed= 0;
627
734
  }
628
735
 
 
736
  DBUG_PRINT("status", ("used: %lu  changed: %lu  w_requests: %lu  "
 
737
                        "writes: %lu  r_requests: %lu  reads: %lu",
 
738
                        keycache->blocks_used, keycache->global_blocks_changed,
 
739
                        (ulong) keycache->global_cache_w_requests,
 
740
                        (ulong) keycache->global_cache_write,
 
741
                        (ulong) keycache->global_cache_r_requests,
 
742
                        (ulong) keycache->global_cache_read));
 
743
 
629
744
  if (cleanup)
630
745
  {
631
746
    pthread_mutex_destroy(&keycache->cache_lock);
632
747
    keycache->key_cache_inited= keycache->can_be_used= 0;
 
748
    KEYCACHE_DEBUG_CLOSE;
633
749
  }
634
 
  return;
 
750
  DBUG_VOID_RETURN;
635
751
} /* end_key_cache */
636
752
 
637
753
 
657
773
{
658
774
  struct st_my_thread_var *last;
659
775
 
660
 
  assert(!thread->next && !thread->prev);
 
776
  DBUG_ASSERT(!thread->next && !thread->prev);
661
777
  if (! (last= wqueue->last_thread))
662
778
  {
663
779
    /* Queue is empty */
692
808
static void unlink_from_queue(KEYCACHE_WQUEUE *wqueue,
693
809
                                     struct st_my_thread_var *thread)
694
810
{
695
 
  assert(thread->next && thread->prev);
 
811
  KEYCACHE_DBUG_PRINT("unlink_from_queue", ("thread %ld", thread->id));
 
812
  DBUG_ASSERT(thread->next && thread->prev);
696
813
  if (thread->next == thread)
697
814
    /* The queue contains only one member */
698
815
    wqueue->last_thread= NULL;
705
822
                                      thread->prev);
706
823
  }
707
824
  thread->next= NULL;
 
825
#if !defined(DBUG_OFF)
 
826
  /*
 
827
    This makes it easier to see it's not in a chain during debugging.
 
828
    And some DBUG_ASSERT() rely on it.
 
829
  */
708
830
  thread->prev= NULL;
 
831
#endif
709
832
}
710
833
 
711
834
 
739
862
  struct st_my_thread_var *thread= my_thread_var;
740
863
 
741
864
  /* Add to queue. */
742
 
  assert(!thread->next);
743
 
  assert(!thread->prev); /* Not required, but must be true anyway. */
 
865
  DBUG_ASSERT(!thread->next);
 
866
  DBUG_ASSERT(!thread->prev); /* Not required, but must be true anyway. */
744
867
  if (! (last= wqueue->last_thread))
745
868
    thread->next= thread;
746
869
  else
756
879
  */
757
880
  do
758
881
  {
 
882
    KEYCACHE_DBUG_PRINT("wait", ("suspend thread %ld", thread->id));
759
883
    keycache_pthread_cond_wait(&thread->suspend, mutex);
760
884
  }
761
885
  while (thread->next);
792
916
  do
793
917
  {
794
918
    thread=next;
 
919
    KEYCACHE_DBUG_PRINT("release_whole_queue: signal",
 
920
                        ("thread %ld", thread->id));
795
921
    /* Signal the thread. */
796
922
    keycache_pthread_cond_signal(&thread->suspend);
797
923
    /* Take thread from queue. */
808
934
/*
809
935
  Unlink a block from the chain of dirty/clean blocks
810
936
*/
 
937
 
811
938
static inline void unlink_changed(BLOCK_LINK *block)
812
939
{
813
 
  assert(block->prev_changed && *block->prev_changed == block);
 
940
  DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
814
941
  if (block->next_changed)
815
942
    block->next_changed->prev_changed= block->prev_changed;
816
943
  *block->prev_changed= block->next_changed;
 
944
 
 
945
#if !defined(DBUG_OFF)
 
946
  /*
 
947
    This makes it easier to see it's not in a chain during debugging.
 
948
    And some DBUG_ASSERT() rely on it.
 
949
  */
817
950
  block->next_changed= NULL;
818
951
  block->prev_changed= NULL;
 
952
#endif
819
953
}
820
954
 
821
955
 
825
959
 
826
960
static inline void link_changed(BLOCK_LINK *block, BLOCK_LINK **phead)
827
961
{
828
 
  assert(!block->next_changed);
829
 
  assert(!block->prev_changed);
 
962
  DBUG_ASSERT(!block->next_changed);
 
963
  DBUG_ASSERT(!block->prev_changed);
830
964
  block->prev_changed= phead;
831
965
  if ((block->next_changed= *phead))
832
966
    (*phead)->prev_changed= &block->next_changed;
861
995
 
862
996
static void link_to_file_list(KEY_CACHE *keycache,
863
997
                              BLOCK_LINK *block, int file,
864
 
                              bool unlink_block)
 
998
                              my_bool unlink_block)
865
999
{
866
 
  assert(block->status & BLOCK_IN_USE);
867
 
  assert(block->hash_link && block->hash_link->block == block);
868
 
  assert(block->hash_link->file == file);
 
1000
  DBUG_ASSERT(block->status & BLOCK_IN_USE);
 
1001
  DBUG_ASSERT(block->hash_link && block->hash_link->block == block);
 
1002
  DBUG_ASSERT(block->hash_link->file == file);
869
1003
  if (unlink_block)
870
1004
    unlink_changed(block);
871
1005
  link_changed(block, &keycache->file_blocks[FILE_HASH(file)]);
903
1037
static void link_to_changed_list(KEY_CACHE *keycache,
904
1038
                                 BLOCK_LINK *block)
905
1039
{
906
 
  assert(block->status & BLOCK_IN_USE);
907
 
  assert(!(block->status & BLOCK_CHANGED));
908
 
  assert(block->hash_link && block->hash_link->block == block);
 
1040
  DBUG_ASSERT(block->status & BLOCK_IN_USE);
 
1041
  DBUG_ASSERT(!(block->status & BLOCK_CHANGED));
 
1042
  DBUG_ASSERT(block->hash_link && block->hash_link->block == block);
909
1043
 
910
1044
  unlink_changed(block);
911
1045
  link_changed(block,
955
1089
    not linked in the LRU ring.
956
1090
*/
957
1091
 
958
 
static void link_block(KEY_CACHE *keycache, BLOCK_LINK *block, bool hot,
959
 
                       bool at_end)
 
1092
static void link_block(KEY_CACHE *keycache, BLOCK_LINK *block, my_bool hot,
 
1093
                       my_bool at_end)
960
1094
{
961
1095
  BLOCK_LINK *ins;
962
1096
  BLOCK_LINK **pins;
963
1097
 
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);
 
1098
  DBUG_ASSERT((block->status & ~BLOCK_CHANGED) == (BLOCK_READ | BLOCK_IN_USE));
 
1099
  DBUG_ASSERT(block->hash_link); /*backptr to block NULL from free_block()*/
 
1100
  DBUG_ASSERT(!block->requests);
 
1101
  DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
 
1102
  DBUG_ASSERT(!block->next_used);
 
1103
  DBUG_ASSERT(!block->prev_used);
970
1104
  if (!hot && keycache->waiting_for_block.last_thread)
971
1105
  {
972
1106
    /* Signal that in the LRU warm sub-chain an available block has appeared */
986
1120
      */
987
1121
      if ((HASH_LINK *) thread->opt_info == hash_link)
988
1122
      {
 
1123
        KEYCACHE_DBUG_PRINT("link_block: signal", ("thread %ld", thread->id));
989
1124
        keycache_pthread_cond_signal(&thread->suspend);
990
1125
        unlink_from_queue(&keycache->waiting_for_block, thread);
991
1126
        block->requests++;
1016
1151
      probably easier to read.
1017
1152
    */
1018
1153
    block->status|= BLOCK_IN_EVICTION;
 
1154
    KEYCACHE_THREAD_TRACE("link_block: after signaling");
 
1155
#if defined(KEYCACHE_DEBUG)
 
1156
    KEYCACHE_DBUG_PRINT("link_block",
 
1157
        ("linked,unlinked block %u  status=%x  #requests=%u  #available=%u",
 
1158
         BLOCK_NUMBER(block), block->status,
 
1159
         block->requests, keycache->blocks_available));
 
1160
#endif
1019
1161
    return;
1020
1162
  }
1021
1163
  pins= hot ? &keycache->used_ins : &keycache->used_last;
1035
1177
    keycache->used_last= keycache->used_ins= block->next_used= block;
1036
1178
    block->prev_used= &block->next_used;
1037
1179
  }
 
1180
  KEYCACHE_THREAD_TRACE("link_block");
 
1181
#if defined(KEYCACHE_DEBUG)
 
1182
  keycache->blocks_available++;
 
1183
  KEYCACHE_DBUG_PRINT("link_block",
 
1184
      ("linked block %u:%1u  status=%x  #requests=%u  #available=%u",
 
1185
       BLOCK_NUMBER(block), at_end, block->status,
 
1186
       block->requests, keycache->blocks_available));
 
1187
  KEYCACHE_DBUG_ASSERT((ulong) keycache->blocks_available <=
 
1188
                       keycache->blocks_used);
 
1189
#endif
1038
1190
}
1039
1191
 
1040
1192
 
1055
1207
 
1056
1208
static void unlink_block(KEY_CACHE *keycache, BLOCK_LINK *block)
1057
1209
{
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 &&
 
1210
  DBUG_ASSERT((block->status & ~BLOCK_CHANGED) == (BLOCK_READ | BLOCK_IN_USE));
 
1211
  DBUG_ASSERT(block->hash_link); /*backptr to block NULL from free_block()*/
 
1212
  DBUG_ASSERT(!block->requests);
 
1213
  DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
 
1214
  DBUG_ASSERT(block->next_used && block->prev_used &&
1063
1215
              (block->next_used->prev_used == &block->next_used) &&
1064
1216
              (*block->prev_used == block));
1065
1217
  if (block->next_used == block)
1075
1227
      keycache->used_ins=STRUCT_PTR(BLOCK_LINK, next_used, block->prev_used);
1076
1228
  }
1077
1229
  block->next_used= NULL;
 
1230
#if !defined(DBUG_OFF)
 
1231
  /*
 
1232
    This makes it easier to see it's not in a chain during debugging.
 
1233
    And some DBUG_ASSERT() rely on it.
 
1234
  */
1078
1235
  block->prev_used= NULL;
 
1236
#endif
 
1237
 
 
1238
  KEYCACHE_THREAD_TRACE("unlink_block");
 
1239
#if defined(KEYCACHE_DEBUG)
 
1240
  KEYCACHE_DBUG_ASSERT(keycache->blocks_available != 0);
 
1241
  keycache->blocks_available--;
 
1242
  KEYCACHE_DBUG_PRINT("unlink_block",
 
1243
    ("unlinked block %u  status=%x   #requests=%u  #available=%u",
 
1244
     BLOCK_NUMBER(block), block->status,
 
1245
     block->requests, keycache->blocks_available));
 
1246
#endif
1079
1247
}
1080
1248
 
1081
1249
 
1097
1265
*/
1098
1266
static void reg_requests(KEY_CACHE *keycache, BLOCK_LINK *block, int count)
1099
1267
{
1100
 
  assert(block->status & BLOCK_IN_USE);
1101
 
  assert(block->hash_link);
 
1268
  DBUG_ASSERT(block->status & BLOCK_IN_USE);
 
1269
  DBUG_ASSERT(block->hash_link);
1102
1270
 
1103
1271
  if (!block->requests)
1104
1272
    unlink_block(keycache, block);
1121
1289
 
1122
1290
  NOTES.
1123
1291
    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
 
1292
    counter (if it's positive). If the at_end parameter is TRUE the block is
1125
1293
    added either at the end of warm sub-chain or at the end of hot sub-chain.
1126
1294
    It is added to the hot subchain if its counter is zero and number of
1127
1295
    blocks in warm sub-chain is not less than some low limit (determined by
1128
1296
    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
 
1297
    sub-chain. If the at_end parameter is FALSE the block is always added
1130
1298
    at beginning of the warm sub-chain.
1131
1299
    Thus a warm block can be promoted to the hot sub-chain when its counter
1132
1300
    becomes zero for the first time.
1141
1309
static void unreg_request(KEY_CACHE *keycache,
1142
1310
                          BLOCK_LINK *block, int at_end)
1143
1311
{
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);
 
1312
  DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
1313
  DBUG_ASSERT(block->hash_link); /*backptr to block NULL from free_block()*/
 
1314
  DBUG_ASSERT(block->requests);
 
1315
  DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
 
1316
  DBUG_ASSERT(!block->next_used);
 
1317
  DBUG_ASSERT(!block->prev_used);
1150
1318
  if (! --block->requests)
1151
1319
  {
1152
 
    bool hot;
 
1320
    my_bool hot;
1153
1321
    if (block->hits_left)
1154
1322
      block->hits_left--;
1155
1323
    hot= !block->hits_left && at_end &&
1159
1327
      if (block->temperature == BLOCK_WARM)
1160
1328
        keycache->warm_blocks--;
1161
1329
      block->temperature= BLOCK_HOT;
 
1330
      KEYCACHE_DBUG_PRINT("unreg_request", ("#warm_blocks: %lu",
 
1331
                           keycache->warm_blocks));
1162
1332
    }
1163
 
    link_block(keycache, block, hot, (bool)at_end);
 
1333
    link_block(keycache, block, hot, (my_bool)at_end);
1164
1334
    block->last_hit_time= keycache->keycache_time;
1165
1335
    keycache->keycache_time++;
1166
1336
    /*
1189
1359
        keycache->warm_blocks++;
1190
1360
        block->temperature= BLOCK_WARM;
1191
1361
      }
 
1362
      KEYCACHE_DBUG_PRINT("unreg_request", ("#warm_blocks: %lu",
 
1363
                           keycache->warm_blocks));
1192
1364
    }
1193
1365
  }
1194
1366
}
1199
1371
 
1200
1372
static void remove_reader(BLOCK_LINK *block)
1201
1373
{
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);
 
1374
  DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
1375
  DBUG_ASSERT(block->hash_link && block->hash_link->block == block);
 
1376
  DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
 
1377
  DBUG_ASSERT(!block->next_used);
 
1378
  DBUG_ASSERT(!block->prev_used);
 
1379
  DBUG_ASSERT(block->hash_link->requests);
1208
1380
  if (! --block->hash_link->requests && block->condvar)
1209
1381
    keycache_pthread_cond_signal(block->condvar);
1210
1382
}
1219
1391
                             BLOCK_LINK *block)
1220
1392
{
1221
1393
  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 |
 
1394
  DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
1395
  DBUG_ASSERT(!(block->status & (BLOCK_ERROR | BLOCK_IN_FLUSH |
1224
1396
                                 BLOCK_CHANGED)));
1225
 
  assert(block->hash_link);
1226
 
  assert(block->hash_link->block == block);
 
1397
  DBUG_ASSERT(block->hash_link);
 
1398
  DBUG_ASSERT(block->hash_link->block == block);
1227
1399
  /* Linked in file_blocks or changed_blocks hash. */
1228
 
  assert(block->prev_changed && *block->prev_changed == block);
 
1400
  DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
1229
1401
  /* Not linked in LRU ring. */
1230
 
  assert(!block->next_used);
1231
 
  assert(!block->prev_used);
 
1402
  DBUG_ASSERT(!block->next_used);
 
1403
  DBUG_ASSERT(!block->prev_used);
1232
1404
  while (block->hash_link->requests)
1233
1405
  {
 
1406
    KEYCACHE_DBUG_PRINT("wait_for_readers: wait",
 
1407
                        ("suspend thread %ld  block %u",
 
1408
                         thread->id, BLOCK_NUMBER(block)));
1234
1409
    /* There must be no other waiter. We have no queue here. */
1235
 
    assert(!block->condvar);
 
1410
    DBUG_ASSERT(!block->condvar);
1236
1411
    block->condvar= &thread->suspend;
1237
1412
    keycache_pthread_cond_wait(&thread->suspend, &keycache->cache_lock);
1238
1413
    block->condvar= NULL;
1260
1435
 
1261
1436
static void unlink_hash(KEY_CACHE *keycache, HASH_LINK *hash_link)
1262
1437
{
1263
 
  assert(hash_link->requests == 0);
 
1438
  KEYCACHE_DBUG_PRINT("unlink_hash", ("fd: %u  pos_ %lu  #requests=%u",
 
1439
      (uint) hash_link->file,(ulong) hash_link->diskpos, hash_link->requests));
 
1440
  KEYCACHE_DBUG_ASSERT(hash_link->requests == 0);
1264
1441
  if ((*hash_link->prev= hash_link->next))
1265
1442
    hash_link->next->prev= hash_link->prev;
1266
1443
  hash_link->block= NULL;
1288
1465
      */
1289
1466
      if (page->file == hash_link->file && page->filepos == hash_link->diskpos)
1290
1467
      {
 
1468
        KEYCACHE_DBUG_PRINT("unlink_hash: signal", ("thread %ld", thread->id));
1291
1469
        keycache_pthread_cond_signal(&thread->suspend);
1292
1470
        unlink_from_queue(&keycache->waiting_for_hash_link, thread);
1293
1471
      }
1311
1489
                                int file, my_off_t filepos)
1312
1490
{
1313
1491
  register HASH_LINK *hash_link, **start;
 
1492
#if defined(KEYCACHE_DEBUG)
 
1493
  int cnt;
 
1494
#endif
 
1495
 
 
1496
  KEYCACHE_DBUG_PRINT("get_hash_link", ("fd: %u  pos: %lu",
 
1497
                      (uint) file,(ulong) filepos));
1314
1498
 
1315
1499
restart:
1316
1500
  /*
1319
1503
     hash_link points to the first member of the list
1320
1504
  */
1321
1505
  hash_link= *(start= &keycache->hash_root[KEYCACHE_HASH(file, filepos)]);
 
1506
#if defined(KEYCACHE_DEBUG)
 
1507
  cnt= 0;
 
1508
#endif
1322
1509
  /* Look for an element for the pair (file, filepos) in the bucket chain */
1323
1510
  while (hash_link &&
1324
1511
         (hash_link->diskpos != filepos || hash_link->file != file))
1325
1512
  {
1326
1513
    hash_link= hash_link->next;
 
1514
#if defined(KEYCACHE_DEBUG)
 
1515
    cnt++;
 
1516
    if (! (cnt <= keycache->hash_links_used))
 
1517
    {
 
1518
      int i;
 
1519
      for (i=0, hash_link= *start ;
 
1520
           i < cnt ; i++, hash_link= hash_link->next)
 
1521
      {
 
1522
        KEYCACHE_DBUG_PRINT("get_hash_link", ("fd: %u  pos: %lu",
 
1523
            (uint) hash_link->file,(ulong) hash_link->diskpos));
 
1524
      }
 
1525
    }
 
1526
    KEYCACHE_DBUG_ASSERT(cnt <= keycache->hash_links_used);
 
1527
#endif
1327
1528
  }
1328
1529
  if (! hash_link)
1329
1530
  {
1342
1543
      /* Wait for a free hash link */
1343
1544
      struct st_my_thread_var *thread= my_thread_var;
1344
1545
      KEYCACHE_PAGE page;
 
1546
      KEYCACHE_DBUG_PRINT("get_hash_link", ("waiting"));
1345
1547
      page.file= file;
1346
1548
      page.filepos= filepos;
1347
1549
      thread->opt_info= (void *) &page;
1348
1550
      link_into_queue(&keycache->waiting_for_hash_link, thread);
 
1551
      KEYCACHE_DBUG_PRINT("get_hash_link: wait",
 
1552
                        ("suspend thread %ld", thread->id));
1349
1553
      keycache_pthread_cond_wait(&thread->suspend,
1350
1554
                                 &keycache->cache_lock);
1351
1555
      thread->opt_info= NULL;
1408
1612
  int error= 0;
1409
1613
  int page_status;
1410
1614
 
 
1615
  DBUG_ENTER("find_key_block");
 
1616
  KEYCACHE_THREAD_TRACE("find_key_block:begin");
 
1617
  DBUG_PRINT("enter", ("fd: %d  pos: %lu  wrmode: %d",
 
1618
                       file, (ulong) filepos, wrmode));
 
1619
  KEYCACHE_DBUG_PRINT("find_key_block", ("fd: %d  pos: %lu  wrmode: %d",
 
1620
                                         file, (ulong) filepos,
 
1621
                                         wrmode));
 
1622
#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
 
1623
  DBUG_EXECUTE("check_keycache2",
 
1624
               test_key_cache(keycache, "start of find_key_block", 0););
 
1625
#endif
 
1626
 
1411
1627
restart:
1412
1628
  /*
1413
1629
    If the flush phase of a resize operation fails, the cache is left
1414
1630
    unusable. This will be detected only after "goto restart".
1415
1631
  */
1416
1632
  if (!keycache->can_be_used)
1417
 
    return(0);
 
1633
    DBUG_RETURN(0);
1418
1634
 
1419
1635
  /*
1420
1636
    Find the hash_link for the requested file block (file, filepos). We
1440
1656
          - not changed (clean).
1441
1657
  */
1442
1658
  hash_link= get_hash_link(keycache, file, filepos);
1443
 
  assert((hash_link->file == file) && (hash_link->diskpos == filepos));
 
1659
  DBUG_ASSERT((hash_link->file == file) && (hash_link->diskpos == filepos));
1444
1660
 
1445
1661
  page_status= -1;
1446
1662
  if ((block= hash_link->block) &&
1479
1695
        */
1480
1696
        hash_link->requests--;
1481
1697
        unlink_hash(keycache, hash_link);
1482
 
        return(0);
 
1698
        DBUG_RETURN(0);
1483
1699
      }
1484
1700
 
1485
1701
      /*
1498
1714
      link_into_queue(&keycache->waiting_for_block, thread);
1499
1715
      do
1500
1716
      {
 
1717
        KEYCACHE_DBUG_PRINT("find_key_block: wait",
 
1718
                            ("suspend thread %ld", thread->id));
1501
1719
        keycache_pthread_cond_wait(&thread->suspend,
1502
1720
                                   &keycache->cache_lock);
1503
1721
      } while (thread->next);
1544
1762
        only. Waiting here on COND_FOR_REQUESTED works in all
1545
1763
        situations.
1546
1764
      */
1547
 
      assert(((block->hash_link != hash_link) &&
 
1765
      DBUG_ASSERT(((block->hash_link != hash_link) &&
1548
1766
                   (block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH))) ||
1549
1767
                  ((block->hash_link == hash_link) &&
1550
1768
                   !(block->status & BLOCK_READ)));
1559
1777
        again in eviction because we registered an request on it before
1560
1778
        starting to wait.
1561
1779
      */
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)));
 
1780
      DBUG_ASSERT(block->hash_link == hash_link);
 
1781
      DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
1782
      DBUG_ASSERT(!(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH)));
1565
1783
    }
1566
1784
    /*
1567
1785
      The block is in the cache. Assigned to the hash_link. Valid data.
1573
1791
    {
1574
1792
      /* A reader can just read the block. */
1575
1793
      *page_st= PAGE_READ;
1576
 
      assert((hash_link->file == file) &&
 
1794
      DBUG_ASSERT((hash_link->file == file) &&
1577
1795
                  (hash_link->diskpos == filepos) &&
1578
1796
                  (block->hash_link == hash_link));
1579
 
      return(block);
 
1797
      DBUG_RETURN(block);
1580
1798
    }
1581
1799
 
1582
1800
    /*
1583
1801
      This is a writer. No two writers for the same block can exist.
1584
1802
      This must be assured by locks outside of the key cache.
1585
1803
    */
1586
 
    assert(!(block->status & BLOCK_FOR_UPDATE));
 
1804
    DBUG_ASSERT(!(block->status & BLOCK_FOR_UPDATE) || fail_block(block));
1587
1805
 
1588
1806
    while (block->status & BLOCK_IN_FLUSH)
1589
1807
    {
1607
1825
        unreg_request(keycache, block, 1);
1608
1826
        goto restart;
1609
1827
      }
1610
 
      assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
1611
 
      assert(!(block->status & BLOCK_FOR_UPDATE));
1612
 
      assert(block->hash_link == hash_link);
 
1828
      DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
1829
      DBUG_ASSERT(!(block->status & BLOCK_FOR_UPDATE) || fail_block(block));
 
1830
      DBUG_ASSERT(block->hash_link == hash_link);
1613
1831
    }
1614
1832
 
1615
1833
    if (block->status & BLOCK_CHANGED)
1622
1840
        not yet been selected for flush, we can still add our changes.
1623
1841
      */
1624
1842
      *page_st= PAGE_READ;
1625
 
      assert((hash_link->file == file) &&
 
1843
      DBUG_ASSERT((hash_link->file == file) &&
1626
1844
                  (hash_link->diskpos == filepos) &&
1627
1845
                  (block->hash_link == hash_link));
1628
 
      return(block);
 
1846
      DBUG_RETURN(block);
1629
1847
    }
1630
1848
 
1631
1849
    /*
1693
1911
               (block->hash_link->file == file) &&
1694
1912
               (block->hash_link->diskpos == filepos));
1695
1913
    }
1696
 
    return(0);
 
1914
    DBUG_RETURN(0);
1697
1915
  }
1698
1916
 
1699
1917
  if (page_status == PAGE_READ &&
1708
1926
      (BLOCK_IN_SWITCH), readers of the block have not finished yet
1709
1927
      (BLOCK_REASSIGNED), or the evicting thread did not yet awake after
1710
1928
      the block has been selected for it (BLOCK_IN_EVICTION).
 
1929
    */
1711
1930
 
 
1931
    KEYCACHE_DBUG_PRINT("find_key_block",
 
1932
                        ("request for old page in block %u "
 
1933
                         "wrmode: %d  block->status: %d",
 
1934
                         BLOCK_NUMBER(block), wrmode, block->status));
 
1935
    /*
1712
1936
       Only reading requests can proceed until the old dirty page is flushed,
1713
1937
       all others are to be suspended, then resubmitted
1714
1938
    */
1736
1960
        as soon as possible. Again we must wait so that we don't find
1737
1961
        the same hash_link + block again and again.
1738
1962
      */
1739
 
      assert(hash_link->requests);
 
1963
      DBUG_ASSERT(hash_link->requests);
1740
1964
      hash_link->requests--;
 
1965
      KEYCACHE_DBUG_PRINT("find_key_block",
 
1966
                          ("request waiting for old page to be saved"));
1741
1967
      wait_on_queue(&block->wqueue[COND_FOR_SAVED], &keycache->cache_lock);
 
1968
      KEYCACHE_DBUG_PRINT("find_key_block",
 
1969
                          ("request for old page resubmitted"));
1742
1970
      /*
1743
1971
        The block is no longer assigned to this hash_link.
1744
1972
        Get another one.
1773
2001
        else
1774
2002
        {
1775
2003
          /* There are some never used blocks, take first of them */
1776
 
          assert(keycache->blocks_used <
1777
 
                      (uint32_t) keycache->disk_blocks);
 
2004
          DBUG_ASSERT(keycache->blocks_used <
 
2005
                      (ulong) keycache->disk_blocks);
1778
2006
          block= &keycache->block_root[keycache->blocks_used];
1779
2007
          block->buffer= ADD_TO_PTR(keycache->block_mem,
1780
 
                                    ((uint32_t) keycache->blocks_used*
 
2008
                                    ((ulong) keycache->blocks_used*
1781
2009
                                     keycache->key_cache_block_size),
1782
 
                                    unsigned char*);
 
2010
                                    uchar*);
1783
2011
          keycache->blocks_used++;
1784
 
          assert(!block->next_used);
 
2012
          DBUG_ASSERT(!block->next_used);
1785
2013
        }
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);
 
2014
        DBUG_ASSERT(!block->prev_used);
 
2015
        DBUG_ASSERT(!block->next_changed);
 
2016
        DBUG_ASSERT(!block->prev_changed);
 
2017
        DBUG_ASSERT(!block->hash_link);
 
2018
        DBUG_ASSERT(!block->status);
 
2019
        DBUG_ASSERT(!block->requests);
1792
2020
        keycache->blocks_unused--;
1793
2021
        block->status= BLOCK_IN_USE;
1794
2022
        block->length= 0;
1801
2029
        hash_link->block= block;
1802
2030
        link_to_file_list(keycache, block, file, 0);
1803
2031
        page_status= PAGE_TO_BE_READ;
 
2032
        KEYCACHE_DBUG_PRINT("find_key_block",
 
2033
                            ("got free or never used block %u",
 
2034
                             BLOCK_NUMBER(block)));
1804
2035
      }
1805
2036
      else
1806
2037
      {
1828
2059
          link_into_queue(&keycache->waiting_for_block, thread);
1829
2060
          do
1830
2061
          {
 
2062
            KEYCACHE_DBUG_PRINT("find_key_block: wait",
 
2063
                                ("suspend thread %ld", thread->id));
1831
2064
            keycache_pthread_cond_wait(&thread->suspend,
1832
2065
                                       &keycache->cache_lock);
1833
2066
          }
1834
2067
          while (thread->next);
1835
2068
          thread->opt_info= NULL;
1836
2069
          /* Assert that block has a request registered. */
1837
 
          assert(hash_link->block->requests);
 
2070
          DBUG_ASSERT(hash_link->block->requests);
1838
2071
          /* Assert that block is not in LRU ring. */
1839
 
          assert(!hash_link->block->next_used);
1840
 
          assert(!hash_link->block->prev_used);
 
2072
          DBUG_ASSERT(!hash_link->block->next_used);
 
2073
          DBUG_ASSERT(!hash_link->block->prev_used);
1841
2074
        }
1842
2075
        /*
1843
2076
          If we waited above, hash_link->block has been assigned by
1856
2089
            Register a request on the block. This unlinks it from the
1857
2090
            LRU ring and protects it against eviction.
1858
2091
          */
1859
 
          assert(!block->requests);
 
2092
          DBUG_ASSERT(!block->requests);
1860
2093
          reg_requests(keycache, block,1);
1861
2094
          /*
1862
2095
            We do not need to set block->status|= BLOCK_IN_EVICTION here
1880
2113
          /* this is a primary request for a new page */
1881
2114
          block->status|= BLOCK_IN_SWITCH;
1882
2115
 
 
2116
          KEYCACHE_DBUG_PRINT("find_key_block",
 
2117
                        ("got block %u for new page", BLOCK_NUMBER(block)));
 
2118
 
1883
2119
          if (block->status & BLOCK_CHANGED)
1884
2120
          {
1885
2121
            /* The block contains a dirty page - push it out of the cache */
1886
2122
 
 
2123
            KEYCACHE_DBUG_PRINT("find_key_block", ("block is dirty"));
1887
2124
            if (block->status & BLOCK_IN_FLUSH)
1888
2125
            {
1889
2126
              /*
1899
2136
                The block is marked BLOCK_IN_SWITCH. It should be left
1900
2137
                alone except for reading. No free, no write.
1901
2138
              */
1902
 
              assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
1903
 
              assert(!(block->status & (BLOCK_REASSIGNED |
 
2139
              DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
2140
              DBUG_ASSERT(!(block->status & (BLOCK_REASSIGNED |
1904
2141
                                             BLOCK_CHANGED |
1905
2142
                                             BLOCK_FOR_UPDATE)));
1906
2143
            }
1911
2148
                BLOCK_IN_EVICTION may be true or not. Other flags must
1912
2149
                have a fixed value.
1913
2150
              */
1914
 
              assert((block->status & ~BLOCK_IN_EVICTION) ==
 
2151
              DBUG_ASSERT((block->status & ~BLOCK_IN_EVICTION) ==
1915
2152
                          (BLOCK_READ | BLOCK_IN_SWITCH |
1916
2153
                           BLOCK_IN_FLUSH | BLOCK_IN_FLUSHWRITE |
1917
2154
                           BLOCK_CHANGED | BLOCK_IN_USE));
1918
 
              assert(block->hash_link);
 
2155
              DBUG_ASSERT(block->hash_link);
1919
2156
 
1920
2157
              keycache_pthread_mutex_unlock(&keycache->cache_lock);
1921
2158
              /*
1929
2166
              keycache_pthread_mutex_lock(&keycache->cache_lock);
1930
2167
 
1931
2168
              /* Block status must not have changed. */
1932
 
              assert((block->status & ~BLOCK_IN_EVICTION) ==
 
2169
              DBUG_ASSERT((block->status & ~BLOCK_IN_EVICTION) ==
1933
2170
                          (BLOCK_READ | BLOCK_IN_SWITCH |
1934
2171
                           BLOCK_IN_FLUSH | BLOCK_IN_FLUSHWRITE |
1935
 
                           BLOCK_CHANGED | BLOCK_IN_USE));
 
2172
                           BLOCK_CHANGED | BLOCK_IN_USE) || fail_block(block));
1936
2173
              keycache->global_cache_write++;
1937
2174
            }
1938
2175
          }
1942
2179
            The block comes from the LRU ring. It must have a hash_link
1943
2180
            assigned.
1944
2181
          */
1945
 
          assert(block->hash_link);
 
2182
          DBUG_ASSERT(block->hash_link);
1946
2183
          if (block->hash_link)
1947
2184
          {
1948
2185
            /*
1969
2206
              a page in the cache in a sweep, without yielding control)
1970
2207
            */
1971
2208
            wait_for_readers(keycache, block);
1972
 
            assert(block->hash_link && block->hash_link->block == block &&
 
2209
            DBUG_ASSERT(block->hash_link && block->hash_link->block == block &&
1973
2210
                        block->prev_changed);
1974
2211
            /* The reader must not have been a writer. */
1975
 
            assert(!(block->status & BLOCK_CHANGED));
 
2212
            DBUG_ASSERT(!(block->status & BLOCK_CHANGED));
1976
2213
 
1977
2214
            /* Wake flushers that might have found the block in between. */
1978
2215
            release_whole_queue(&block->wqueue[COND_FOR_SAVED]);
1985
2222
              and hash_link refer to each other. Hence we need to assign
1986
2223
              the hash_link first, but then we would not know if it was
1987
2224
              linked before. Hence we would not know if to unlink it. So
1988
 
              unlink it here and call link_to_file_list(..., false).
 
2225
              unlink it here and call link_to_file_list(..., FALSE).
1989
2226
            */
1990
2227
            unlink_changed(block);
1991
2228
          }
1996
2233
          link_to_file_list(keycache, block, file, 0);
1997
2234
          page_status= PAGE_TO_BE_READ;
1998
2235
 
1999
 
          assert(block->hash_link->block == block);
2000
 
          assert(hash_link->block->hash_link == hash_link);
 
2236
          KEYCACHE_DBUG_ASSERT(block->hash_link->block == block);
 
2237
          KEYCACHE_DBUG_ASSERT(hash_link->block->hash_link == hash_link);
2001
2238
        }
2002
2239
        else
2003
2240
        {
2015
2252
            attached to the same hash_link and as such destined for the
2016
2253
            same file block.
2017
2254
          */
 
2255
          KEYCACHE_DBUG_PRINT("find_key_block",
 
2256
                              ("block->hash_link: %p  hash_link: %p  "
 
2257
                               "block->status: %u", block->hash_link,
 
2258
                               hash_link, block->status ));
2018
2259
          page_status= (((block->hash_link == hash_link) &&
2019
2260
                         (block->status & BLOCK_READ)) ?
2020
2261
                        PAGE_READ : PAGE_WAIT_TO_BE_READ);
2043
2284
        Register a request on the block. This is another protection
2044
2285
        against eviction.
2045
2286
      */
2046
 
      assert(((block->hash_link != hash_link) &&
 
2287
      DBUG_ASSERT(((block->hash_link != hash_link) &&
2047
2288
                   (block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH))) ||
2048
2289
                  ((block->hash_link == hash_link) &&
2049
2290
                   !(block->status & BLOCK_READ)) ||
2050
2291
                  ((block->status & BLOCK_READ) &&
2051
2292
                   !(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH))));
2052
2293
      reg_requests(keycache, block, 1);
 
2294
      KEYCACHE_DBUG_PRINT("find_key_block",
 
2295
                          ("block->hash_link: %p  hash_link: %p  "
 
2296
                           "block->status: %u", block->hash_link,
 
2297
                           hash_link, block->status ));
2053
2298
      page_status= (((block->hash_link == hash_link) &&
2054
2299
                     (block->status & BLOCK_READ)) ?
2055
2300
                    PAGE_READ : PAGE_WAIT_TO_BE_READ);
2056
2301
    }
2057
2302
  }
2058
2303
 
2059
 
  assert(page_status != -1);
 
2304
  KEYCACHE_DBUG_ASSERT(page_status != -1);
2060
2305
  /* Same assert basically, but be very sure. */
2061
 
  assert(block);
 
2306
  KEYCACHE_DBUG_ASSERT(block);
2062
2307
  /* 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);
 
2308
  DBUG_ASSERT(block->requests);
 
2309
  DBUG_ASSERT(!block->next_used);
 
2310
  DBUG_ASSERT(!block->prev_used);
2066
2311
  /* Assert that we return the correct block. */
2067
 
  assert((page_status == PAGE_WAIT_TO_BE_READ) ||
 
2312
  DBUG_ASSERT((page_status == PAGE_WAIT_TO_BE_READ) ||
2068
2313
              ((block->hash_link->file == file) &&
2069
2314
               (block->hash_link->diskpos == filepos)));
2070
2315
  *page_st=page_status;
 
2316
  KEYCACHE_DBUG_PRINT("find_key_block",
 
2317
                      ("fd: %d  pos: %lu  block->status: %u  page_status: %d",
 
2318
                       file, (ulong) filepos, block->status,
 
2319
                       page_status));
2071
2320
 
2072
 
  return(block);
 
2321
#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
 
2322
  DBUG_EXECUTE("check_keycache2",
 
2323
               test_key_cache(keycache, "end of find_key_block",0););
 
2324
#endif
 
2325
  KEYCACHE_THREAD_TRACE("find_key_block:end");
 
2326
  DBUG_RETURN(block);
2073
2327
}
2074
2328
 
2075
2329
 
2098
2352
*/
2099
2353
 
2100
2354
static void read_block(KEY_CACHE *keycache,
2101
 
                       BLOCK_LINK *block, uint32_t read_length,
2102
 
                       uint32_t min_length, bool primary)
 
2355
                       BLOCK_LINK *block, uint read_length,
 
2356
                       uint min_length, my_bool primary)
2103
2357
{
2104
 
  uint32_t got_length;
 
2358
  uint got_length;
2105
2359
 
2106
2360
  /* On entry cache_lock is locked */
2107
2361
 
 
2362
  KEYCACHE_THREAD_TRACE("read_block");
2108
2363
  if (primary)
2109
2364
  {
2110
2365
    /*
2113
2368
      request for the block become secondary requests. For a primary
2114
2369
      request the block must be properly initialized.
2115
2370
    */
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));
 
2371
    DBUG_ASSERT(((block->status & ~BLOCK_FOR_UPDATE) == BLOCK_IN_USE) ||
 
2372
                fail_block(block));
 
2373
    DBUG_ASSERT((block->length == 0) || fail_block(block));
 
2374
    DBUG_ASSERT((block->offset == keycache->key_cache_block_size) ||
 
2375
                fail_block(block));
 
2376
    DBUG_ASSERT((block->requests > 0) || fail_block(block));
 
2377
 
 
2378
    KEYCACHE_DBUG_PRINT("read_block",
 
2379
                        ("page to be read by primary request"));
2120
2380
 
2121
2381
    keycache->global_cache_read++;
2122
2382
    /* Page is not in buffer yet, is to be read from disk */
2131
2391
      The block can now have been marked for free (in case of
2132
2392
      FLUSH_RELEASE). Otherwise the state must be unchanged.
2133
2393
    */
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));
 
2394
    DBUG_ASSERT(((block->status & ~(BLOCK_REASSIGNED |
 
2395
                                    BLOCK_FOR_UPDATE)) == BLOCK_IN_USE) ||
 
2396
                fail_block(block));
 
2397
    DBUG_ASSERT((block->length == 0) || fail_block(block));
 
2398
    DBUG_ASSERT((block->offset == keycache->key_cache_block_size) ||
 
2399
                fail_block(block));
 
2400
    DBUG_ASSERT((block->requests > 0) || fail_block(block));
2139
2401
 
2140
2402
    if (got_length < min_length)
2141
2403
      block->status|= BLOCK_ERROR;
2150
2412
        keycache->key_cache_block_size.
2151
2413
      */
2152
2414
    }
 
2415
    KEYCACHE_DBUG_PRINT("read_block",
 
2416
                        ("primary request: new page in cache"));
2153
2417
    /* Signal that all pending requests for this page now can be processed */
2154
2418
    release_whole_queue(&block->wqueue[COND_FOR_REQUESTED]);
2155
2419
  }
2164
2428
      for the requested file block nor the file and position. So we have
2165
2429
      to assert this in the caller.
2166
2430
    */
 
2431
    KEYCACHE_DBUG_PRINT("read_block",
 
2432
                      ("secondary request waiting for new page to be read"));
2167
2433
    wait_on_queue(&block->wqueue[COND_FOR_REQUESTED], &keycache->cache_lock);
 
2434
    KEYCACHE_DBUG_PRINT("read_block",
 
2435
                        ("secondary request: new page in cache"));
2168
2436
  }
2169
2437
}
2170
2438
 
2191
2459
    The function ensures that a block of data of size length from file
2192
2460
    positioned at filepos is in the buffers for some key cache blocks.
2193
2461
    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
 
2462
    if return_buffer is TRUE, it just returns the pointer to the key cache
2195
2463
    buffer with the data.
2196
2464
    Filepos must be a multiple of 'block_length', but it doesn't
2197
2465
    have to be a multiple of key_cache_block_size;
2198
2466
*/
2199
2467
 
2200
 
unsigned char *key_cache_read(KEY_CACHE *keycache,
 
2468
uchar *key_cache_read(KEY_CACHE *keycache,
2201
2469
                      File file, my_off_t filepos, int level,
2202
 
                      unsigned char *buff, uint32_t length,
2203
 
                      uint32_t block_length __attribute__((unused)),
 
2470
                      uchar *buff, uint length,
 
2471
                      uint block_length __attribute__((unused)),
2204
2472
                      int return_buffer __attribute__((unused)))
2205
2473
{
2206
 
  bool locked_and_incremented= false;
 
2474
  my_bool locked_and_incremented= FALSE;
2207
2475
  int error=0;
2208
 
  unsigned char *start= buff;
 
2476
  uchar *start= buff;
 
2477
  DBUG_ENTER("key_cache_read");
 
2478
  DBUG_PRINT("enter", ("fd: %u  pos: %lu  length: %u",
 
2479
               (uint) file, (ulong) filepos, length));
2209
2480
 
2210
2481
  if (keycache->key_cache_inited)
2211
2482
  {
2212
2483
    /* Key cache is used */
2213
2484
    register BLOCK_LINK *block;
2214
 
    uint32_t read_length;
2215
 
    uint32_t offset;
2216
 
    uint32_t status;
 
2485
    uint read_length;
 
2486
    uint offset;
 
2487
    uint status;
2217
2488
    int page_st;
2218
2489
 
2219
2490
    /*
2241
2512
      wait_on_queue(&keycache->resize_queue, &keycache->cache_lock);
2242
2513
    /* Register the I/O for the next resize. */
2243
2514
    inc_counter_for_resize_op(keycache);
2244
 
    locked_and_incremented= true;
 
2515
    locked_and_incremented= TRUE;
2245
2516
    /* Requested data may not always be aligned to cache blocks. */
2246
2517
    offset= (uint) (filepos % keycache->key_cache_block_size);
2247
2518
    /* Read data in key_cache_block_size increments */
2256
2527
      /* Do not read beyond the end of the cache block. */
2257
2528
      read_length= length;
2258
2529
      set_if_smaller(read_length, keycache->key_cache_block_size-offset);
2259
 
      assert(read_length > 0);
 
2530
      KEYCACHE_DBUG_ASSERT(read_length > 0);
2260
2531
 
2261
2532
      /* Request the cache block that matches file/pos. */
2262
2533
      keycache->global_cache_r_requests++;
2270
2541
        */
2271
2542
        keycache->global_cache_read++;
2272
2543
        keycache_pthread_mutex_unlock(&keycache->cache_lock);
2273
 
        error= (pread(file, (unsigned char*) buff, read_length, filepos + offset) == 0);
 
2544
        error= (pread(file, (uchar*) buff, read_length, filepos + offset) == 0);
2274
2545
        keycache_pthread_mutex_lock(&keycache->cache_lock);
2275
2546
        goto next_block;
2276
2547
      }
2281
2552
          /* The requested page is to be read into the block buffer */
2282
2553
          read_block(keycache, block,
2283
2554
                     keycache->key_cache_block_size, read_length+offset,
2284
 
                     (bool)(page_st == PAGE_TO_BE_READ));
 
2555
                     (my_bool)(page_st == PAGE_TO_BE_READ));
2285
2556
          /*
2286
2557
            A secondary request must now have the block assigned to the
2287
2558
            requested file block. It does not hurt to check it for
2288
2559
            primary requests too.
2289
2560
          */
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));
 
2561
          DBUG_ASSERT(keycache->can_be_used);
 
2562
          DBUG_ASSERT(block->hash_link->file == file);
 
2563
          DBUG_ASSERT(block->hash_link->diskpos == filepos);
 
2564
          DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
2294
2565
        }
2295
2566
        else if (block->length < read_length + offset)
2296
2567
        {
2308
2579
      if (!((status= block->status) & BLOCK_ERROR))
2309
2580
      {
2310
2581
        {
2311
 
          assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
2582
          DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
2312
2583
#if !defined(SERIALIZED_READ_FROM_CACHE)
2313
2584
          keycache_pthread_mutex_unlock(&keycache->cache_lock);
2314
2585
#endif
2315
2586
 
2316
2587
          /* Copy data from the cache buffer */
2317
 
          memcpy(buff, block->buffer+offset, (size_t) read_length);
 
2588
          if (!(read_length & 511))
 
2589
            bmove512(buff, block->buffer+offset, read_length);
 
2590
          else
 
2591
            memcpy(buff, block->buffer+offset, (size_t) read_length);
2318
2592
 
2319
2593
#if !defined(SERIALIZED_READ_FROM_CACHE)
2320
2594
          keycache_pthread_mutex_lock(&keycache->cache_lock);
2321
 
          assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
2595
          DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
2322
2596
#endif
2323
2597
        }
2324
2598
      }
2354
2628
 
2355
2629
  if (locked_and_incremented)
2356
2630
    keycache_pthread_mutex_unlock(&keycache->cache_lock);
2357
 
  if (pread(file, (unsigned char*) buff, length, filepos))
 
2631
  if (pread(file, (uchar*) buff, length, filepos))
2358
2632
    error= 1;
2359
2633
  if (locked_and_incremented)
2360
2634
    keycache_pthread_mutex_lock(&keycache->cache_lock);
2365
2639
    dec_counter_for_resize_op(keycache);
2366
2640
    keycache_pthread_mutex_unlock(&keycache->cache_lock);
2367
2641
  }
2368
 
  return(error ? (unsigned char*) 0 : start);
 
2642
  DBUG_RETURN(error ? (uchar*) 0 : start);
2369
2643
}
2370
2644
 
2371
2645
 
2391
2665
 
2392
2666
int key_cache_insert(KEY_CACHE *keycache,
2393
2667
                     File file, my_off_t filepos, int level,
2394
 
                     unsigned char *buff, uint32_t length)
 
2668
                     uchar *buff, uint length)
2395
2669
{
2396
2670
  int error= 0;
 
2671
  DBUG_ENTER("key_cache_insert");
 
2672
  DBUG_PRINT("enter", ("fd: %u  pos: %lu  length: %u",
 
2673
               (uint) file,(ulong) filepos, length));
2397
2674
 
2398
2675
  if (keycache->key_cache_inited)
2399
2676
  {
2400
2677
    /* Key cache is used */
2401
2678
    register BLOCK_LINK *block;
2402
 
    uint32_t read_length;
2403
 
    uint32_t offset;
 
2679
    uint read_length;
 
2680
    uint offset;
2404
2681
    int page_st;
2405
 
    bool locked_and_incremented= false;
 
2682
    my_bool locked_and_incremented= FALSE;
2406
2683
 
2407
2684
    /*
2408
2685
      When the keycache is once initialized, we use the cache_lock to
2419
2696
        goto no_key_cache;
2420
2697
    /* Register the pseudo I/O for the next resize. */
2421
2698
    inc_counter_for_resize_op(keycache);
2422
 
    locked_and_incremented= true;
 
2699
    locked_and_incremented= TRUE;
2423
2700
    /* Loaded data may not always be aligned to cache blocks. */
2424
2701
    offset= (uint) (filepos % keycache->key_cache_block_size);
2425
2702
    /* Load data in key_cache_block_size increments. */
2433
2710
      /* Do not load beyond the end of the cache block. */
2434
2711
      read_length= length;
2435
2712
      set_if_smaller(read_length, keycache->key_cache_block_size-offset);
2436
 
      assert(read_length > 0);
 
2713
      KEYCACHE_DBUG_ASSERT(read_length > 0);
2437
2714
 
2438
2715
      /* The block has been read by the caller already. */
2439
2716
      keycache->global_cache_read++;
2464
2741
            hash_link). So we cannot call remove_reader() on the block.
2465
2742
            And we cannot access the hash_link directly here. We need to
2466
2743
            wait until the assignment is complete. read_block() executes
2467
 
            the correct wait when called with primary == false.
 
2744
            the correct wait when called with primary == FALSE.
2468
2745
 
2469
2746
            Or
2470
2747
 
2489
2766
            requested file block. It does not hurt to check it for
2490
2767
            primary requests too.
2491
2768
          */
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));
 
2769
          DBUG_ASSERT(keycache->can_be_used);
 
2770
          DBUG_ASSERT(block->hash_link->file == file);
 
2771
          DBUG_ASSERT(block->hash_link->diskpos == filepos);
 
2772
          DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
2496
2773
        }
2497
2774
        else if (page_st == PAGE_TO_BE_READ)
2498
2775
        {
2500
2777
            This is a new block in the cache. If we come here, we have
2501
2778
            data for the whole block.
2502
2779
          */
2503
 
          assert(block->hash_link->requests);
2504
 
          assert(block->status & BLOCK_IN_USE);
2505
 
          assert((page_st == PAGE_TO_BE_READ) ||
 
2780
          DBUG_ASSERT(block->hash_link->requests);
 
2781
          DBUG_ASSERT(block->status & BLOCK_IN_USE);
 
2782
          DBUG_ASSERT((page_st == PAGE_TO_BE_READ) ||
2506
2783
                      (block->status & BLOCK_READ));
2507
2784
 
2508
2785
#if !defined(SERIALIZED_READ_FROM_CACHE)
2514
2791
#endif
2515
2792
 
2516
2793
          /* Copy data from buff */
2517
 
          memcpy(block->buffer+offset, buff, (size_t) read_length);
 
2794
          if (!(read_length & 511))
 
2795
            bmove512(block->buffer+offset, buff, read_length);
 
2796
          else
 
2797
            memcpy(block->buffer+offset, buff, (size_t) read_length);
2518
2798
 
2519
2799
#if !defined(SERIALIZED_READ_FROM_CACHE)
2520
2800
          keycache_pthread_mutex_lock(&keycache->cache_lock);
2521
 
          assert(block->status & BLOCK_IN_USE);
2522
 
          assert((page_st == PAGE_TO_BE_READ) ||
 
2801
          DBUG_ASSERT(block->status & BLOCK_IN_USE);
 
2802
          DBUG_ASSERT((page_st == PAGE_TO_BE_READ) ||
2523
2803
                      (block->status & BLOCK_READ));
2524
2804
#endif
2525
2805
          /*
2536
2816
            only a writer may set block->offset down from
2537
2817
            keycache->key_cache_block_size.
2538
2818
          */
 
2819
          KEYCACHE_DBUG_PRINT("key_cache_insert",
 
2820
                              ("primary request: new page in cache"));
2539
2821
          /* Signal all pending requests. */
2540
2822
          release_whole_queue(&block->wqueue[COND_FOR_REQUESTED]);
2541
2823
        }
2551
2833
            with the new data. If the condition is met, we can simply
2552
2834
            ignore the block.
2553
2835
          */
2554
 
          assert((page_st == PAGE_READ) &&
 
2836
          DBUG_ASSERT((page_st == PAGE_READ) &&
2555
2837
                      (read_length + offset <= block->length));
2556
2838
        }
2557
2839
 
2560
2842
          requested file block. It does not hurt to check it for primary
2561
2843
          requests too.
2562
2844
        */
2563
 
        assert(block->hash_link->file == file);
2564
 
        assert(block->hash_link->diskpos == filepos);
2565
 
        assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
2845
        DBUG_ASSERT(block->hash_link->file == file);
 
2846
        DBUG_ASSERT(block->hash_link->diskpos == filepos);
 
2847
        DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
2566
2848
      } /* end of if (!(block->status & BLOCK_ERROR)) */
2567
2849
 
2568
2850
 
2590
2872
      dec_counter_for_resize_op(keycache);
2591
2873
    keycache_pthread_mutex_unlock(&keycache->cache_lock);
2592
2874
  }
2593
 
  return(error);
 
2875
  DBUG_RETURN(error);
2594
2876
}
2595
2877
 
2596
2878
 
2616
2898
    The function copies the data of size length from buff into buffers
2617
2899
    for key cache blocks that are  assigned to contain the portion of
2618
2900
    the file starting with position filepos.
2619
 
    It ensures that this data is flushed to the file if dont_write is false.
 
2901
    It ensures that this data is flushed to the file if dont_write is FALSE.
2620
2902
    Filepos must be a multiple of 'block_length', but it doesn't
2621
2903
    have to be a multiple of key_cache_block_size;
2622
2904
 
2623
 
    dont_write is always true in the server (info->lock_type is never F_UNLCK).
 
2905
    dont_write is always TRUE in the server (info->lock_type is never F_UNLCK).
2624
2906
*/
2625
2907
 
2626
2908
int key_cache_write(KEY_CACHE *keycache,
2627
2909
                    File file, my_off_t filepos, int level,
2628
 
                    unsigned char *buff, uint32_t length,
2629
 
                    uint32_t block_length  __attribute__((unused)),
 
2910
                    uchar *buff, uint length,
 
2911
                    uint block_length  __attribute__((unused)),
2630
2912
                    int dont_write)
2631
2913
{
2632
 
  bool locked_and_incremented= false;
 
2914
  my_bool locked_and_incremented= FALSE;
2633
2915
  int error=0;
 
2916
  DBUG_ENTER("key_cache_write");
 
2917
  DBUG_PRINT("enter",
 
2918
             ("fd: %u  pos: %lu  length: %u  block_length: %u"
 
2919
              "  key_block_length: %u",
 
2920
              (uint) file, (ulong) filepos, length, block_length,
 
2921
              keycache ? keycache->key_cache_block_size : 0));
2634
2922
 
2635
2923
  if (!dont_write)
2636
2924
  {
2640
2928
    keycache->global_cache_w_requests++;
2641
2929
    keycache->global_cache_write++;
2642
2930
    if (pwrite(file, buff, length, filepos) == 0)
2643
 
      return(1);
 
2931
      DBUG_RETURN(1);
2644
2932
    /* purecov: end */
2645
2933
  }
2646
2934
 
 
2935
#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
 
2936
  DBUG_EXECUTE("check_keycache",
 
2937
               test_key_cache(keycache, "start of key_cache_write", 1););
 
2938
#endif
 
2939
 
2647
2940
  if (keycache->key_cache_inited)
2648
2941
  {
2649
2942
    /* Key cache is used */
2650
2943
    register BLOCK_LINK *block;
2651
 
    uint32_t read_length;
2652
 
    uint32_t offset;
 
2944
    uint read_length;
 
2945
    uint offset;
2653
2946
    int page_st;
2654
2947
 
2655
2948
    /*
2678
2971
      wait_on_queue(&keycache->resize_queue, &keycache->cache_lock);
2679
2972
    /* Register the I/O for the next resize. */
2680
2973
    inc_counter_for_resize_op(keycache);
2681
 
    locked_and_incremented= true;
 
2974
    locked_and_incremented= TRUE;
2682
2975
    /* Requested data may not always be aligned to cache blocks. */
2683
2976
    offset= (uint) (filepos % keycache->key_cache_block_size);
2684
2977
    /* Write data in key_cache_block_size increments. */
2692
2985
      /* Do not write beyond the end of the cache block. */
2693
2986
      read_length= length;
2694
2987
      set_if_smaller(read_length, keycache->key_cache_block_size-offset);
2695
 
      assert(read_length > 0);
 
2988
      KEYCACHE_DBUG_ASSERT(read_length > 0);
2696
2989
 
2697
2990
      /* Request the cache block that matches file/pos. */
2698
2991
      keycache->global_cache_w_requests++;
2709
3002
          /* Used in the server. */
2710
3003
          keycache->global_cache_write++;
2711
3004
          keycache_pthread_mutex_unlock(&keycache->cache_lock);
2712
 
          if (pwrite(file, (unsigned char*) buff, read_length, filepos + offset) == 0)
 
3005
          if (pwrite(file, (uchar*) buff, read_length, filepos + offset) == 0)
2713
3006
            error=1;
2714
3007
          keycache_pthread_mutex_lock(&keycache->cache_lock);
2715
3008
        }
2744
3037
                   offset + read_length >= keycache->key_cache_block_size?
2745
3038
                   offset : keycache->key_cache_block_size,
2746
3039
                   offset, (page_st == PAGE_TO_BE_READ));
2747
 
        assert(keycache->can_be_used);
2748
 
        assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
3040
        DBUG_ASSERT(keycache->can_be_used);
 
3041
        DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
2749
3042
        /*
2750
3043
          Prevent block from flushing and from being selected for to be
2751
3044
          freed. This must be set when we release the cache_lock.
2757
3050
        The block should always be assigned to the requested file block
2758
3051
        here. It need not be BLOCK_READ when overwriting the whole block.
2759
3052
      */
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));
 
3053
      DBUG_ASSERT(block->hash_link->file == file);
 
3054
      DBUG_ASSERT(block->hash_link->diskpos == filepos);
 
3055
      DBUG_ASSERT(block->status & BLOCK_IN_USE);
 
3056
      DBUG_ASSERT((page_st == PAGE_TO_BE_READ) || (block->status & BLOCK_READ));
2764
3057
      /*
2765
3058
        The block to be written must not be marked BLOCK_REASSIGNED.
2766
3059
        Otherwise it could be freed in dirty state or reused without
2769
3062
        the flusher could clear BLOCK_CHANGED without flushing the
2770
3063
        new changes again.
2771
3064
      */
2772
 
      assert(!(block->status & BLOCK_REASSIGNED));
 
3065
      DBUG_ASSERT(!(block->status & BLOCK_REASSIGNED));
2773
3066
 
2774
3067
      while (block->status & BLOCK_IN_FLUSHWRITE)
2775
3068
      {
2783
3076
          another hash_link until we release our request on it.
2784
3077
        */
2785
3078
        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));
 
3079
        DBUG_ASSERT(keycache->can_be_used);
 
3080
        DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
2788
3081
        /* Still must not be marked for free. */
2789
 
        assert(!(block->status & BLOCK_REASSIGNED));
2790
 
        assert(block->hash_link && (block->hash_link->block == block));
 
3082
        DBUG_ASSERT(!(block->status & BLOCK_REASSIGNED));
 
3083
        DBUG_ASSERT(block->hash_link && (block->hash_link->block == block));
2791
3084
      }
2792
3085
 
2793
3086
      /*
2804
3097
#if !defined(SERIALIZED_READ_FROM_CACHE)
2805
3098
        keycache_pthread_mutex_unlock(&keycache->cache_lock);
2806
3099
#endif
2807
 
        memcpy(block->buffer+offset, buff, (size_t) read_length);
 
3100
        if (!(read_length & 511))
 
3101
          bmove512(block->buffer+offset, buff, read_length);
 
3102
        else
 
3103
          memcpy(block->buffer+offset, buff, (size_t) read_length);
2808
3104
 
2809
3105
#if !defined(SERIALIZED_READ_FROM_CACHE)
2810
3106
        keycache_pthread_mutex_lock(&keycache->cache_lock);
2873
3169
    keycache->global_cache_write++;
2874
3170
    if (locked_and_incremented)
2875
3171
      keycache_pthread_mutex_unlock(&keycache->cache_lock);
2876
 
    if (pwrite(file, (unsigned char*) buff, length, filepos) == 0)
 
3172
    if (pwrite(file, (uchar*) buff, length, filepos) == 0)
2877
3173
      error=1;
2878
3174
    if (locked_and_incremented)
2879
3175
      keycache_pthread_mutex_lock(&keycache->cache_lock);
2885
3181
    dec_counter_for_resize_op(keycache);
2886
3182
    keycache_pthread_mutex_unlock(&keycache->cache_lock);
2887
3183
  }
2888
 
  return(error);
 
3184
#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
 
3185
  DBUG_EXECUTE("exec",
 
3186
               test_key_cache(keycache, "end of key_cache_write", 1););
 
3187
#endif
 
3188
  DBUG_RETURN(error);
2889
3189
}
2890
3190
 
2891
3191
 
2918
3218
 
2919
3219
static void free_block(KEY_CACHE *keycache, BLOCK_LINK *block)
2920
3220
{
 
3221
  KEYCACHE_THREAD_TRACE("free block");
 
3222
  KEYCACHE_DBUG_PRINT("free_block",
 
3223
                      ("block %u to be freed, hash_link %p",
 
3224
                       BLOCK_NUMBER(block), block->hash_link));
2921
3225
  /*
2922
3226
    Assert that the block is not free already. And that it is in a clean
2923
3227
    state. Note that the block might just be assigned to a hash_link and
2925
3229
    is registered in the hash_link and free_block() will wait for it
2926
3230
    below.
2927
3231
  */
2928
 
  assert((block->status & BLOCK_IN_USE) &&
 
3232
  DBUG_ASSERT((block->status & BLOCK_IN_USE) &&
2929
3233
              !(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH |
2930
3234
                                 BLOCK_REASSIGNED | BLOCK_IN_FLUSH |
2931
3235
                                 BLOCK_CHANGED | BLOCK_FOR_UPDATE)));
2932
3236
  /* Assert that the block is in a file_blocks chain. */
2933
 
  assert(block->prev_changed && *block->prev_changed == block);
 
3237
  DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
2934
3238
  /* Assert that the block is not in the LRU ring. */
2935
 
  assert(!block->next_used && !block->prev_used);
 
3239
  DBUG_ASSERT(!block->next_used && !block->prev_used);
2936
3240
  /*
2937
3241
    IMHO the below condition (if()) makes no sense. I can't see how it
2938
3242
    could be possible that free_block() is entered with a NULL hash_link
2939
3243
    pointer. The only place where it can become NULL is in free_block()
2940
3244
    (or before its first use ever, but for those blocks free_block() is
2941
3245
    not called). I don't remove the conditional as it cannot harm, but
2942
 
    place an assert to confirm my hypothesis. Eventually the
 
3246
    place an DBUG_ASSERT to confirm my hypothesis. Eventually the
2943
3247
    condition (if()) can be removed.
2944
3248
  */
2945
 
  assert(block->hash_link && block->hash_link->block == block);
 
3249
  DBUG_ASSERT(block->hash_link && block->hash_link->block == block);
2946
3250
  if (block->hash_link)
2947
3251
  {
2948
3252
    /*
2958
3262
      checks. An additional requirement is that it must be read now
2959
3263
      (BLOCK_READ).
2960
3264
    */
2961
 
    assert(block->hash_link && block->hash_link->block == block);
2962
 
    assert((block->status & (BLOCK_READ | BLOCK_IN_USE |
 
3265
    DBUG_ASSERT(block->hash_link && block->hash_link->block == block);
 
3266
    DBUG_ASSERT((block->status & (BLOCK_READ | BLOCK_IN_USE |
2963
3267
                                  BLOCK_REASSIGNED)) &&
2964
3268
                !(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH |
2965
3269
                                   BLOCK_IN_FLUSH | BLOCK_CHANGED |
2966
3270
                                   BLOCK_FOR_UPDATE)));
2967
 
    assert(block->prev_changed && *block->prev_changed == block);
2968
 
    assert(!block->prev_used);
 
3271
    DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
 
3272
    DBUG_ASSERT(!block->prev_used);
2969
3273
    /*
2970
3274
      Unset BLOCK_REASSIGNED again. If we hand the block to an evicting
2971
3275
      thread (through unreg_request() below), other threads must not see
2988
3292
    operation in this case. Assert that there are no other requests
2989
3293
    registered.
2990
3294
  */
2991
 
  assert(block->requests == 1);
 
3295
  DBUG_ASSERT(block->requests == 1);
2992
3296
  unreg_request(keycache, block, 0);
2993
3297
  /*
2994
3298
    Note that even without releasing the cache lock it is possible that
3000
3304
    return;
3001
3305
 
3002
3306
  /* Here the block must be in the LRU ring. Unlink it again. */
3003
 
  assert(block->next_used && block->prev_used &&
 
3307
  DBUG_ASSERT(block->next_used && block->prev_used &&
3004
3308
              *block->prev_used == block);
3005
3309
  unlink_block(keycache, block);
3006
3310
  if (block->temperature == BLOCK_WARM)
3017
3321
  block->status= 0;
3018
3322
  block->length= 0;
3019
3323
  block->offset= keycache->key_cache_block_size;
 
3324
  KEYCACHE_THREAD_TRACE("free block");
 
3325
  KEYCACHE_DBUG_PRINT("free_block", ("block is freed"));
3020
3326
 
3021
3327
  /* Enforced by unlink_changed(), but just to be sure. */
3022
 
  assert(!block->next_changed && !block->prev_changed);
 
3328
  DBUG_ASSERT(!block->next_changed && !block->prev_changed);
3023
3329
  /* Enforced by unlink_block(): not in LRU ring nor in free_block_list. */
3024
 
  assert(!block->next_used && !block->prev_used);
 
3330
  DBUG_ASSERT(!block->next_used && !block->prev_used);
3025
3331
  /* Insert the free block in the free list. */
3026
3332
  block->next_used= keycache->free_block_list;
3027
3333
  keycache->free_block_list= block;
3052
3358
{
3053
3359
  int error;
3054
3360
  int last_errno= 0;
3055
 
  uint32_t count= (uint) (end-cache);
 
3361
  uint count= (uint) (end-cache);
3056
3362
 
3057
3363
  /* Don't lock the cache during the flush */
3058
3364
  keycache_pthread_mutex_unlock(&keycache->cache_lock);
3060
3366
     As all blocks referred in 'cache' are marked by BLOCK_IN_FLUSH
3061
3367
     we are guarunteed no thread will change them
3062
3368
  */
3063
 
  my_qsort((unsigned char*) cache, count, sizeof(*cache), (qsort_cmp) cmp_sec_link);
 
3369
  my_qsort((uchar*) cache, count, sizeof(*cache), (qsort_cmp) cmp_sec_link);
3064
3370
 
3065
3371
  keycache_pthread_mutex_lock(&keycache->cache_lock);
3066
3372
  /*
3071
3377
  for ( ; cache != end ; cache++)
3072
3378
  {
3073
3379
    BLOCK_LINK *block= *cache;
 
3380
 
 
3381
    KEYCACHE_DBUG_PRINT("flush_cached_blocks",
 
3382
                        ("block %u to be flushed", BLOCK_NUMBER(block)));
3074
3383
    /*
3075
3384
      If the block contents is going to be changed, we abandon the flush
3076
3385
      for this block. flush_key_blocks_int() will restart its search and
3079
3388
    if (!(block->status & BLOCK_FOR_UPDATE))
3080
3389
    {
3081
3390
      /* 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) ==
 
3391
      DBUG_ASSERT(block->hash_link);
 
3392
      DBUG_ASSERT(block->hash_link->block == block);
 
3393
      DBUG_ASSERT(block->hash_link->file == file);
 
3394
      DBUG_ASSERT((block->status & ~BLOCK_IN_EVICTION) ==
3086
3395
                  (BLOCK_READ | BLOCK_IN_FLUSH | BLOCK_CHANGED | BLOCK_IN_USE));
3087
3396
      block->status|= BLOCK_IN_FLUSHWRITE;
3088
3397
      keycache_pthread_mutex_unlock(&keycache->cache_lock);
3100
3409
      }
3101
3410
      block->status&= ~BLOCK_IN_FLUSHWRITE;
3102
3411
      /* 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)) ==
 
3412
      DBUG_ASSERT(block->hash_link);
 
3413
      DBUG_ASSERT(block->hash_link->block == block);
 
3414
      DBUG_ASSERT(block->hash_link->file == file);
 
3415
      DBUG_ASSERT((block->status & ~(BLOCK_FOR_UPDATE | BLOCK_IN_EVICTION)) ==
3107
3416
                  (BLOCK_READ | BLOCK_IN_FLUSH | BLOCK_CHANGED | BLOCK_IN_USE));
3108
3417
      /*
3109
3418
        Set correct status and link in right queue for free or later use.
3177
3486
  BLOCK_LINK *cache_buff[FLUSH_CACHE],**cache;
3178
3487
  int last_errno= 0;
3179
3488
  int last_errcnt= 0;
 
3489
  DBUG_ENTER("flush_key_blocks_int");
 
3490
  DBUG_PRINT("enter",("file: %d  blocks_used: %lu  blocks_changed: %lu",
 
3491
              file, keycache->blocks_used, keycache->blocks_changed));
 
3492
 
 
3493
#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
 
3494
    DBUG_EXECUTE("check_keycache",
 
3495
                 test_key_cache(keycache, "start of flush_key_blocks", 0););
 
3496
#endif
3180
3497
 
3181
3498
  cache= cache_buff;
3182
3499
  if (keycache->disk_blocks > 0 &&
3184
3501
  {
3185
3502
    /* Key cache exists and flush is not disabled */
3186
3503
    int error= 0;
3187
 
    uint32_t count= FLUSH_CACHE;
 
3504
    uint count= FLUSH_CACHE;
3188
3505
    BLOCK_LINK **pos,**end;
3189
3506
    BLOCK_LINK *first_in_switch= NULL;
3190
3507
    BLOCK_LINK *last_in_flush;
3191
3508
    BLOCK_LINK *last_for_update;
3192
3509
    BLOCK_LINK *block, *next;
 
3510
#if defined(KEYCACHE_DEBUG)
 
3511
    uint cnt=0;
 
3512
#endif
3193
3513
 
3194
3514
    if (type != FLUSH_IGNORE_CHANGED)
3195
3515
    {
3206
3526
            !(block->status & BLOCK_IN_FLUSH))
3207
3527
        {
3208
3528
          count++;
3209
 
          assert(count<= keycache->blocks_used);
 
3529
          KEYCACHE_DBUG_ASSERT(count<= keycache->blocks_used);
3210
3530
        }
3211
3531
      }
3212
3532
      /*
3235
3555
         block ;
3236
3556
         block= next)
3237
3557
    {
 
3558
#if defined(KEYCACHE_DEBUG)
 
3559
      cnt++;
 
3560
      KEYCACHE_DBUG_ASSERT(cnt <= keycache->blocks_used);
 
3561
#endif
3238
3562
      next= block->next_changed;
3239
3563
      if (block->hash_link->file == file)
3240
3564
      {
3298
3622
            else
3299
3623
            {
3300
3624
              /* It's a temporary file */
3301
 
              assert(!(block->status & BLOCK_REASSIGNED));
 
3625
              DBUG_ASSERT(!(block->status & BLOCK_REASSIGNED));
3302
3626
 
3303
3627
              /*
3304
3628
                free_block() must not be called with BLOCK_CHANGED. Note
3419
3743
    */
3420
3744
    while (first_in_switch)
3421
3745
    {
 
3746
#if defined(KEYCACHE_DEBUG)
 
3747
      cnt= 0;
 
3748
#endif
3422
3749
      wait_on_queue(&first_in_switch->wqueue[COND_FOR_SAVED],
3423
3750
                    &keycache->cache_lock);
 
3751
#if defined(KEYCACHE_DEBUG)
 
3752
      cnt++;
 
3753
      KEYCACHE_DBUG_ASSERT(cnt <= keycache->blocks_used);
 
3754
#endif
3424
3755
      /*
3425
3756
        Do not restart here. We have flushed all blocks that were
3426
3757
        changed when entering this function and were not marked for
3433
3764
    {
3434
3765
      BLOCK_LINK *last_for_update= NULL;
3435
3766
      BLOCK_LINK *last_in_switch= NULL;
3436
 
      uint32_t total_found= 0;
3437
 
      uint32_t found;
 
3767
      uint total_found= 0;
 
3768
      uint found;
3438
3769
 
3439
3770
      /*
3440
3771
        Finally free all clean blocks for this file.
3451
3782
          next= block->next_changed;
3452
3783
 
3453
3784
          /* Changed blocks cannot appear in the file_blocks hash. */
3454
 
          assert(!(block->status & BLOCK_CHANGED));
 
3785
          DBUG_ASSERT(!(block->status & BLOCK_CHANGED));
3455
3786
          if (block->hash_link->file == file)
3456
3787
          {
3457
3788
            /* We must skip blocks that will be changed. */
3469
3800
            if (!(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH |
3470
3801
                                   BLOCK_REASSIGNED)))
3471
3802
            {
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;
 
3803
              struct st_hash_link *next_hash_link;
 
3804
              my_off_t            next_diskpos;
 
3805
              File                next_file;
 
3806
              uint                next_status;
 
3807
              uint                hash_requests;
3477
3808
 
3478
3809
              total_found++;
3479
3810
              found++;
3480
 
              assert(found <= keycache->blocks_used);
 
3811
              KEYCACHE_DBUG_ASSERT(found <= keycache->blocks_used);
3481
3812
 
3482
3813
              /*
3483
3814
                Register a request. This unlinks the block from the LRU
3499
3830
                next_hash_link= next->hash_link;
3500
3831
                next_diskpos=   next_hash_link->diskpos;
3501
3832
                next_file=      next_hash_link->file;
3502
 
                assert(next == next_hash_link->block);
 
3833
                DBUG_ASSERT(next == next_hash_link->block);
3503
3834
              }
3504
3835
 
3505
3836
              free_block(keycache, block);
3546
3877
      if (last_for_update)
3547
3878
      {
3548
3879
        /* We did not wait. Block must not have changed status. */
3549
 
        assert(last_for_update->status & BLOCK_FOR_UPDATE);
 
3880
        DBUG_ASSERT(last_for_update->status & BLOCK_FOR_UPDATE);
3550
3881
        wait_on_queue(&last_for_update->wqueue[COND_FOR_REQUESTED],
3551
3882
                      &keycache->cache_lock);
3552
3883
        goto restart;
3559
3890
      if (last_in_switch)
3560
3891
      {
3561
3892
        /* We did not wait. Block must not have changed status. */
3562
 
        assert(last_in_switch->status & (BLOCK_IN_EVICTION |
 
3893
        DBUG_ASSERT(last_in_switch->status & (BLOCK_IN_EVICTION |
3563
3894
                                              BLOCK_IN_SWITCH |
3564
3895
                                              BLOCK_REASSIGNED));
3565
3896
        wait_on_queue(&last_in_switch->wqueue[COND_FOR_SAVED],
3571
3902
 
3572
3903
  } /* if (keycache->disk_blocks > 0 */
3573
3904
 
 
3905
#ifndef DBUG_OFF
 
3906
  DBUG_EXECUTE("check_keycache",
 
3907
               test_key_cache(keycache, "end of flush_key_blocks", 0););
 
3908
#endif
3574
3909
err:
3575
3910
  if (cache != cache_buff)
3576
 
    free((unsigned char*) cache);
 
3911
    my_free((uchar*) cache, MYF(0));
3577
3912
  if (last_errno)
3578
3913
    errno=last_errno;                /* Return first error */
3579
 
  return(last_errno != 0);
 
3914
  DBUG_RETURN(last_errno != 0);
3580
3915
}
3581
3916
 
3582
3917
 
3599
3934
                     File file, enum flush_type type)
3600
3935
{
3601
3936
  int res= 0;
 
3937
  DBUG_ENTER("flush_key_blocks");
 
3938
  DBUG_PRINT("enter", ("keycache: 0x%lx", (long) keycache));
3602
3939
 
3603
3940
  if (!keycache->key_cache_inited)
3604
 
    return(0);
 
3941
    DBUG_RETURN(0);
3605
3942
 
3606
3943
  keycache_pthread_mutex_lock(&keycache->cache_lock);
3607
3944
  /* While waiting for lock, keycache could have been ended. */
3612
3949
    dec_counter_for_resize_op(keycache);
3613
3950
  }
3614
3951
  keycache_pthread_mutex_unlock(&keycache->cache_lock);
3615
 
  return(res);
 
3952
  DBUG_RETURN(res);
3616
3953
}
3617
3954
 
3618
3955
 
3651
3988
static int flush_all_key_blocks(KEY_CACHE *keycache)
3652
3989
{
3653
3990
  BLOCK_LINK    *block;
3654
 
  uint32_t          total_found;
3655
 
  uint32_t          found;
3656
 
  uint32_t          idx;
 
3991
  uint          total_found;
 
3992
  uint          found;
 
3993
  uint          idx;
 
3994
  DBUG_ENTER("flush_all_key_blocks");
3657
3995
 
3658
3996
  do
3659
3997
  {
3688
4026
          */
3689
4027
          if (flush_key_blocks_int(keycache, block->hash_link->file,
3690
4028
                                   FLUSH_FORCE_WRITE))
3691
 
            return(1);
 
4029
            DBUG_RETURN(1);
3692
4030
        }
3693
4031
      }
3694
4032
 
3722
4060
          found++;
3723
4061
          if (flush_key_blocks_int(keycache, block->hash_link->file,
3724
4062
                                   FLUSH_RELEASE))
3725
 
            return(1);
 
4063
            DBUG_RETURN(1);
3726
4064
        }
3727
4065
      }
3728
4066
 
3735
4073
      before the resize started (BLOCK_FOR_UPDATE). Re-check the hashes.
3736
4074
    */
3737
4075
  } while (total_found);
3738
 
  return(0);
 
4076
 
 
4077
#ifndef DBUG_OFF
 
4078
  /* Now there should not exist any block any more. */
 
4079
  for (idx= 0; idx < CHANGED_BLOCKS_HASH; idx++)
 
4080
  {
 
4081
    DBUG_ASSERT(!keycache->changed_blocks[idx]);
 
4082
    DBUG_ASSERT(!keycache->file_blocks[idx]);
 
4083
  }
 
4084
#endif
 
4085
 
 
4086
  DBUG_RETURN(0);
3739
4087
}
3740
4088
 
3741
4089
 
3758
4106
int reset_key_cache_counters(const char *name __attribute__((unused)),
3759
4107
                             KEY_CACHE *key_cache)
3760
4108
{
 
4109
  DBUG_ENTER("reset_key_cache_counters");
3761
4110
  if (!key_cache->key_cache_inited)
3762
4111
  {
3763
 
    return(0);
 
4112
    DBUG_PRINT("info", ("Key cache %s not initialized.", name));
 
4113
    DBUG_RETURN(0);
3764
4114
  }
 
4115
  DBUG_PRINT("info", ("Resetting counters for key cache %s.", name));
 
4116
 
3765
4117
  key_cache->global_blocks_changed= 0;   /* Key_blocks_not_flushed */
3766
4118
  key_cache->global_cache_r_requests= 0; /* Key_read_requests */
3767
4119
  key_cache->global_cache_read= 0;       /* Key_reads */
3768
4120
  key_cache->global_cache_w_requests= 0; /* Key_write_requests */
3769
4121
  key_cache->global_cache_write= 0;      /* Key_writes */
3770
 
  return(0);
3771
 
}
 
4122
  DBUG_RETURN(0);
 
4123
}
 
4124
 
 
4125
 
 
4126
#ifndef DBUG_OFF
 
4127
/*
 
4128
  Test if disk-cache is ok
 
4129
*/
 
4130
static void test_key_cache(KEY_CACHE *keycache __attribute__((unused)),
 
4131
                           const char *where __attribute__((unused)),
 
4132
                           my_bool lock __attribute__((unused)))
 
4133
{
 
4134
  /* TODO */
 
4135
}
 
4136
#endif
3772
4137
 
3773
4138
#if defined(KEYCACHE_TIMEOUT)
3774
4139
 
3784
4149
  BLOCK_LINK *block;
3785
4150
  HASH_LINK *hash_link;
3786
4151
  KEYCACHE_PAGE *page;
3787
 
  uint32_t i;
 
4152
  uint i;
3788
4153
 
3789
4154
  fprintf(keycache_dump_file, "thread:%u\n", thread->id);
3790
4155
 
3798
4163
      page= (KEYCACHE_PAGE *) thread->opt_info;
3799
4164
      fprintf(keycache_dump_file,
3800
4165
              "thread:%u, (file,filepos)=(%u,%lu)\n",
3801
 
              thread->id,(uint) page->file,(uint32_t) page->filepos);
 
4166
              thread->id,(uint) page->file,(ulong) page->filepos);
3802
4167
      if (++i == MAX_QUEUE_LEN)
3803
4168
        break;
3804
4169
    }
3813
4178
      thread=thread->next;
3814
4179
      hash_link= (HASH_LINK *) thread->opt_info;
3815
4180
      fprintf(keycache_dump_file,
3816
 
        "thread:%u hash_link:%u (file,filepos)=(%u,%u)\n",
 
4181
        "thread:%u hash_link:%u (file,filepos)=(%u,%lu)\n",
3817
4182
        thread->id, (uint) HASH_LINK_NUMBER(hash_link),
3818
 
        (uint) hash_link->file,(uint32_t) hash_link->diskpos);
 
4183
        (uint) hash_link->file,(ulong) hash_link->diskpos);
3819
4184
      if (++i == MAX_QUEUE_LEN)
3820
4185
        break;
3821
4186
    }
3866
4231
  fclose(keycache_dump_file);
3867
4232
}
3868
4233
 
 
4234
#endif /* defined(KEYCACHE_TIMEOUT) */
 
4235
 
 
4236
#if defined(KEYCACHE_TIMEOUT)
 
4237
 
 
4238
 
3869
4239
static int keycache_pthread_cond_wait(pthread_cond_t *cond,
3870
4240
                                      pthread_mutex_t *mutex)
3871
4241
{
3873
4243
  struct timeval  now;            /* time when we started waiting        */
3874
4244
  struct timespec timeout;        /* timeout value for the wait function */
3875
4245
  struct timezone tz;
 
4246
#if defined(KEYCACHE_DEBUG)
 
4247
  int cnt=0;
 
4248
#endif
3876
4249
 
3877
4250
  /* Get current time */
3878
4251
  gettimeofday(&now, &tz);
3884
4257
   1 nanosecond = 1000 micro seconds
3885
4258
 */
3886
4259
  timeout.tv_nsec= now.tv_usec * 1000;
 
4260
  KEYCACHE_THREAD_TRACE_END("started waiting");
 
4261
#if defined(KEYCACHE_DEBUG)
 
4262
  cnt++;
 
4263
  if (cnt % 100 == 0)
 
4264
    fprintf(keycache_debug_log, "waiting...\n");
 
4265
    fflush(keycache_debug_log);
 
4266
#endif
3887
4267
  rc= pthread_cond_timedwait(cond, mutex, &timeout);
 
4268
  KEYCACHE_THREAD_TRACE_BEGIN("finished waiting");
3888
4269
  if (rc == ETIMEDOUT || rc == ETIME)
3889
4270
  {
 
4271
#if defined(KEYCACHE_DEBUG)
 
4272
    fprintf(keycache_debug_log,"aborted by keycache timeout\n");
 
4273
    fclose(keycache_debug_log);
 
4274
    abort();
 
4275
#endif
3890
4276
    keycache_dump();
3891
4277
  }
3892
4278
 
 
4279
#if defined(KEYCACHE_DEBUG)
 
4280
  KEYCACHE_DBUG_ASSERT(rc != ETIMEDOUT);
 
4281
#else
3893
4282
  assert(rc != ETIMEDOUT);
3894
 
  return rc;
3895
 
}
 
4283
#endif
 
4284
  return rc;
 
4285
}
 
4286
#else
 
4287
#if defined(KEYCACHE_DEBUG)
 
4288
static int keycache_pthread_cond_wait(pthread_cond_t *cond,
 
4289
                                      pthread_mutex_t *mutex)
 
4290
{
 
4291
  int rc;
 
4292
  KEYCACHE_THREAD_TRACE_END("started waiting");
 
4293
  rc= pthread_cond_wait(cond, mutex);
 
4294
  KEYCACHE_THREAD_TRACE_BEGIN("finished waiting");
 
4295
  return rc;
 
4296
}
 
4297
#endif
3896
4298
#endif /* defined(KEYCACHE_TIMEOUT) */
 
4299
 
 
4300
#if defined(KEYCACHE_DEBUG)
 
4301
 
 
4302
 
 
4303
static int keycache_pthread_mutex_lock(pthread_mutex_t *mutex)
 
4304
{
 
4305
  int rc;
 
4306
  rc= pthread_mutex_lock(mutex);
 
4307
  KEYCACHE_THREAD_TRACE_BEGIN("");
 
4308
  return rc;
 
4309
}
 
4310
 
 
4311
 
 
4312
static void keycache_pthread_mutex_unlock(pthread_mutex_t *mutex)
 
4313
{
 
4314
  KEYCACHE_THREAD_TRACE_END("");
 
4315
  pthread_mutex_unlock(mutex);
 
4316
}
 
4317
 
 
4318
 
 
4319
static int keycache_pthread_cond_signal(pthread_cond_t *cond)
 
4320
{
 
4321
  int rc;
 
4322
  KEYCACHE_THREAD_TRACE("signal");
 
4323
  rc= pthread_cond_signal(cond);
 
4324
  return rc;
 
4325
}
 
4326
 
 
4327
 
 
4328
#if defined(KEYCACHE_DEBUG_LOG)
 
4329
 
 
4330
 
 
4331
static void keycache_debug_print(const char * fmt,...)
 
4332
{
 
4333
  va_list args;
 
4334
  va_start(args,fmt);
 
4335
  if (keycache_debug_log)
 
4336
  {
 
4337
    VOID(vfprintf(keycache_debug_log, fmt, args));
 
4338
    VOID(fputc('\n',keycache_debug_log));
 
4339
  }
 
4340
  va_end(args);
 
4341
}
 
4342
#endif /* defined(KEYCACHE_DEBUG_LOG) */
 
4343
 
 
4344
#if defined(KEYCACHE_DEBUG_LOG)
 
4345
 
 
4346
 
 
4347
void keycache_debug_log_close(void)
 
4348
{
 
4349
  if (keycache_debug_log)
 
4350
    fclose(keycache_debug_log);
 
4351
}
 
4352
#endif /* defined(KEYCACHE_DEBUG_LOG) */
 
4353
 
 
4354
#endif /* defined(KEYCACHE_DEBUG) */
 
4355
 
 
4356
#if !defined(DBUG_OFF)
 
4357
#define F_B_PRT(_f_, _v_) DBUG_PRINT("assert_fail", (_f_, _v_))
 
4358
 
 
4359
static int fail_block(BLOCK_LINK *block)
 
4360
{
 
4361
  F_B_PRT("block->next_used:    %lx\n", (ulong) block->next_used);
 
4362
  F_B_PRT("block->prev_used:    %lx\n", (ulong) block->prev_used);
 
4363
  F_B_PRT("block->next_changed: %lx\n", (ulong) block->next_changed);
 
4364
  F_B_PRT("block->prev_changed: %lx\n", (ulong) block->prev_changed);
 
4365
  F_B_PRT("block->hash_link:    %lx\n", (ulong) block->hash_link);
 
4366
  F_B_PRT("block->status:       %u\n", block->status);
 
4367
  F_B_PRT("block->length:       %u\n", block->length);
 
4368
  F_B_PRT("block->offset:       %u\n", block->offset);
 
4369
  F_B_PRT("block->requests:     %u\n", block->requests);
 
4370
  F_B_PRT("block->temperature:  %u\n", block->temperature);
 
4371
  return 0; /* Let the assert fail. */
 
4372
}
 
4373
 
 
4374
static int fail_hlink(HASH_LINK *hlink)
 
4375
{
 
4376
  F_B_PRT("hlink->next:    %lx\n", (ulong) hlink->next);
 
4377
  F_B_PRT("hlink->prev:    %lx\n", (ulong) hlink->prev);
 
4378
  F_B_PRT("hlink->block:   %lx\n", (ulong) hlink->block);
 
4379
  F_B_PRT("hlink->diskpos: %lu\n", (ulong) hlink->diskpos);
 
4380
  F_B_PRT("hlink->file:    %d\n", hlink->file);
 
4381
  return 0; /* Let the assert fail. */
 
4382
}
 
4383
 
 
4384
static int cache_empty(KEY_CACHE *keycache)
 
4385
{
 
4386
  int errcnt= 0;
 
4387
  int idx;
 
4388
  if (keycache->disk_blocks <= 0)
 
4389
    return 1;
 
4390
  for (idx= 0; idx < keycache->disk_blocks; idx++)
 
4391
  {
 
4392
    BLOCK_LINK *block= keycache->block_root + idx;
 
4393
    if (block->status || block->requests || block->hash_link)
 
4394
    {
 
4395
      fprintf(stderr, "block index: %u\n", idx);
 
4396
      fail_block(block);
 
4397
      errcnt++;
 
4398
    }
 
4399
  }
 
4400
  for (idx= 0; idx < keycache->hash_links; idx++)
 
4401
  {
 
4402
    HASH_LINK *hash_link= keycache->hash_link_root + idx;
 
4403
    if (hash_link->requests || hash_link->block)
 
4404
    {
 
4405
      fprintf(stderr, "hash_link index: %u\n", idx);
 
4406
      fail_hlink(hash_link);
 
4407
      errcnt++;
 
4408
    }
 
4409
  }
 
4410
  if (errcnt)
 
4411
  {
 
4412
    fprintf(stderr, "blocks: %d  used: %lu\n",
 
4413
            keycache->disk_blocks, keycache->blocks_used);
 
4414
    fprintf(stderr, "hash_links: %d  used: %d\n",
 
4415
            keycache->hash_links, keycache->hash_links_used);
 
4416
    fprintf(stderr, "\n");
 
4417
  }
 
4418
  return !errcnt;
 
4419
}
 
4420
#endif
 
4421