~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to storage/myisam/mf_keycache.c

  • Committer: Monty Taylor
  • Date: 2008-07-16 19:10:24 UTC
  • mfrom: (51.1.127 remove-dbug)
  • mto: This revision was merged to the branch mainline in revision 176.
  • Revision ID: monty@inaugust.com-20080716191024-prjgoh7fbri7rx26
MergedĀ fromĀ remove-dbug.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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.
142
133
 
143
134
  Example of the settings:
144
135
    #define SERIALIZED_READ_FROM_CACHE
145
136
    #define MAX_THREADS   100
146
137
    #define KEYCACHE_TIMEOUT  1
147
 
    #define KEYCACHE_DEBUG
148
 
    #define KEYCACHE_DEBUG_LOG  "my_key_cache_debug.log"
149
138
*/
150
139
 
151
140
#define STRUCT_PTR(TYPE, MEMBER, a)                                           \
225
214
                          pthread_mutex_t *mutex);
226
215
static void release_whole_queue(KEYCACHE_WQUEUE *wqueue);
227
216
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
232
217
 
233
218
#define KEYCACHE_HASH(f, pos)                                                 \
234
219
(((ulong) ((pos) / keycache->key_cache_block_size) +                          \
235
220
                                     (ulong) (f)) & (keycache->hash_entries-1))
236
221
#define FILE_HASH(f)                 ((uint) (f) & (CHANGED_BLOCKS_HASH-1))
237
222
 
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
 
 
296
223
#define BLOCK_NUMBER(b)                                                       \
297
224
  ((uint) (((char*)(b)-(char *) keycache->block_root)/sizeof(BLOCK_LINK)))
298
225
#define HASH_LINK_NUMBER(h)                                                   \
299
226
  ((uint) (((char*)(h)-(char *) keycache->hash_link_root)/sizeof(HASH_LINK)))
300
227
 
301
 
#if (defined(KEYCACHE_TIMEOUT)) || defined(KEYCACHE_DEBUG)
 
228
#ifdef KEYCACHE_TIMEOUT
302
229
static int keycache_pthread_cond_wait(pthread_cond_t *cond,
303
230
                                      pthread_mutex_t *mutex);
304
231
#else
305
232
#define  keycache_pthread_cond_wait pthread_cond_wait
306
233
#endif
307
234
 
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
313
235
#define keycache_pthread_mutex_lock pthread_mutex_lock
314
236
#define keycache_pthread_mutex_unlock pthread_mutex_unlock
315
237
#define keycache_pthread_cond_signal pthread_cond_signal
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
238
 
328
239
static inline uint next_power(uint value)
329
240
{
363
274
  ulong blocks, hash_links;
364
275
  size_t length;
365
276
  int error;
366
 
  DBUG_ENTER("init_key_cache");
367
 
  DBUG_ASSERT(key_cache_block_size >= 512);
 
277
  assert(key_cache_block_size >= 512);
368
278
 
369
 
  KEYCACHE_DEBUG_OPEN;
370
279
  if (keycache->key_cache_inited && keycache->disk_blocks > 0)
371
280
  {
372
 
    DBUG_PRINT("warning",("key cache already in use"));
373
 
    DBUG_RETURN(0);
 
281
    return(0);
374
282
  }
375
283
 
376
284
  keycache->global_cache_w_requests= keycache->global_cache_r_requests= 0;
394
302
 
395
303
  keycache->key_cache_mem_size= use_mem;
396
304
  keycache->key_cache_block_size= key_cache_block_size;
397
 
  DBUG_PRINT("info", ("key_cache_block_size: %u",
398
 
                      key_cache_block_size));
399
305
 
400
306
  blocks= (ulong) (use_mem / (sizeof(BLOCK_LINK) + 2 * sizeof(HASH_LINK) +
401
307
                              sizeof(HASH_LINK*) * 5/4 + key_cache_block_size));
477
383
 
478
384
    keycache->waiting_for_hash_link.last_thread= NULL;
479
385
    keycache->waiting_for_block.last_thread= NULL;
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
386
    bzero((uchar*) keycache->changed_blocks,
487
387
          sizeof(keycache->changed_blocks[0]) * CHANGED_BLOCKS_HASH);
488
388
    bzero((uchar*) keycache->file_blocks,
495
395
  }
496
396
 
497
397
  keycache->blocks= keycache->disk_blocks > 0 ? keycache->disk_blocks : 0;
498
 
  DBUG_RETURN((int) keycache->disk_blocks);
 
398
  return((int) keycache->disk_blocks);
499
399
 
500
400
err:
501
401
  error= my_errno;
513
413
  }
514
414
  my_errno= error;
515
415
  keycache->can_be_used= 0;
516
 
  DBUG_RETURN(0);
 
416
  return(0);
517
417
}
518
418
 
519
419
 
551
451
                     uint age_threshold)
552
452
{
553
453
  int blocks;
554
 
  DBUG_ENTER("resize_key_cache");
555
454
 
556
455
  if (!keycache->key_cache_inited)
557
 
    DBUG_RETURN(keycache->disk_blocks);
 
456
    return(keycache->disk_blocks);
558
457
 
559
458
  if(key_cache_block_size == keycache->key_cache_block_size &&
560
459
     use_mem == keycache->key_cache_mem_size)
561
460
  {
562
461
    change_key_cache_param(keycache, division_limit, age_threshold);
563
 
    DBUG_RETURN(keycache->disk_blocks);
 
462
    return(keycache->disk_blocks);
564
463
  }
565
464
 
566
465
  keycache_pthread_mutex_lock(&keycache->cache_lock);
599
498
      keycache->can_be_used= 0;
600
499
      goto finish;
601
500
    }
602
 
    DBUG_ASSERT(cache_empty(keycache));
603
501
 
604
502
    /* End the flush phase. */
605
503
    keycache->resize_in_flush= 0;
641
539
  release_whole_queue(&keycache->resize_queue);
642
540
 
643
541
  keycache_pthread_mutex_unlock(&keycache->cache_lock);
644
 
  DBUG_RETURN(blocks);
 
542
  return(blocks);
645
543
}
646
544
 
647
545
 
685
583
void change_key_cache_param(KEY_CACHE *keycache, uint division_limit,
686
584
                            uint age_threshold)
687
585
{
688
 
  DBUG_ENTER("change_key_cache_param");
689
 
 
690
586
  keycache_pthread_mutex_lock(&keycache->cache_lock);
691
587
  if (division_limit)
692
588
    keycache->min_warm_blocks= (keycache->disk_blocks *
695
591
    keycache->age_threshold=   (keycache->disk_blocks *
696
592
                                age_threshold / 100);
697
593
  keycache_pthread_mutex_unlock(&keycache->cache_lock);
698
 
  DBUG_VOID_RETURN;
 
594
  return;
699
595
}
700
596
 
701
597
 
713
609
 
714
610
void end_key_cache(KEY_CACHE *keycache, my_bool cleanup)
715
611
{
716
 
  DBUG_ENTER("end_key_cache");
717
 
  DBUG_PRINT("enter", ("key_cache: 0x%lx", (long) keycache));
718
 
 
719
612
  if (!keycache->key_cache_inited)
720
 
    DBUG_VOID_RETURN;
 
613
    return;
721
614
 
722
615
  if (keycache->disk_blocks > 0)
723
616
  {
733
626
    keycache->blocks_changed= 0;
734
627
  }
735
628
 
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
 
 
744
629
  if (cleanup)
745
630
  {
746
631
    pthread_mutex_destroy(&keycache->cache_lock);
747
632
    keycache->key_cache_inited= keycache->can_be_used= 0;
748
 
    KEYCACHE_DEBUG_CLOSE;
749
633
  }
750
 
  DBUG_VOID_RETURN;
 
634
  return;
751
635
} /* end_key_cache */
752
636
 
753
637
 
773
657
{
774
658
  struct st_my_thread_var *last;
775
659
 
776
 
  DBUG_ASSERT(!thread->next && !thread->prev);
 
660
  assert(!thread->next && !thread->prev);
777
661
  if (! (last= wqueue->last_thread))
778
662
  {
779
663
    /* Queue is empty */
808
692
static void unlink_from_queue(KEYCACHE_WQUEUE *wqueue,
809
693
                                     struct st_my_thread_var *thread)
810
694
{
811
 
  KEYCACHE_DBUG_PRINT("unlink_from_queue", ("thread %ld", thread->id));
812
 
  DBUG_ASSERT(thread->next && thread->prev);
 
695
  assert(thread->next && thread->prev);
813
696
  if (thread->next == thread)
814
697
    /* The queue contains only one member */
815
698
    wqueue->last_thread= NULL;
822
705
                                      thread->prev);
823
706
  }
824
707
  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
 
  */
830
708
  thread->prev= NULL;
831
 
#endif
832
709
}
833
710
 
834
711
 
862
739
  struct st_my_thread_var *thread= my_thread_var;
863
740
 
864
741
  /* Add to queue. */
865
 
  DBUG_ASSERT(!thread->next);
866
 
  DBUG_ASSERT(!thread->prev); /* Not required, but must be true anyway. */
 
742
  assert(!thread->next);
 
743
  assert(!thread->prev); /* Not required, but must be true anyway. */
867
744
  if (! (last= wqueue->last_thread))
868
745
    thread->next= thread;
869
746
  else
879
756
  */
880
757
  do
881
758
  {
882
 
    KEYCACHE_DBUG_PRINT("wait", ("suspend thread %ld", thread->id));
883
759
    keycache_pthread_cond_wait(&thread->suspend, mutex);
884
760
  }
885
761
  while (thread->next);
916
792
  do
917
793
  {
918
794
    thread=next;
919
 
    KEYCACHE_DBUG_PRINT("release_whole_queue: signal",
920
 
                        ("thread %ld", thread->id));
921
795
    /* Signal the thread. */
922
796
    keycache_pthread_cond_signal(&thread->suspend);
923
797
    /* Take thread from queue. */
934
808
/*
935
809
  Unlink a block from the chain of dirty/clean blocks
936
810
*/
937
 
 
938
811
static inline void unlink_changed(BLOCK_LINK *block)
939
812
{
940
 
  DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
 
813
  assert(block->prev_changed && *block->prev_changed == block);
941
814
  if (block->next_changed)
942
815
    block->next_changed->prev_changed= block->prev_changed;
943
816
  *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
 
  */
950
817
  block->next_changed= NULL;
951
818
  block->prev_changed= NULL;
952
 
#endif
953
819
}
954
820
 
955
821
 
959
825
 
960
826
static inline void link_changed(BLOCK_LINK *block, BLOCK_LINK **phead)
961
827
{
962
 
  DBUG_ASSERT(!block->next_changed);
963
 
  DBUG_ASSERT(!block->prev_changed);
 
828
  assert(!block->next_changed);
 
829
  assert(!block->prev_changed);
964
830
  block->prev_changed= phead;
965
831
  if ((block->next_changed= *phead))
966
832
    (*phead)->prev_changed= &block->next_changed;
997
863
                              BLOCK_LINK *block, int file,
998
864
                              my_bool unlink_block)
999
865
{
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);
 
866
  assert(block->status & BLOCK_IN_USE);
 
867
  assert(block->hash_link && block->hash_link->block == block);
 
868
  assert(block->hash_link->file == file);
1003
869
  if (unlink_block)
1004
870
    unlink_changed(block);
1005
871
  link_changed(block, &keycache->file_blocks[FILE_HASH(file)]);
1037
903
static void link_to_changed_list(KEY_CACHE *keycache,
1038
904
                                 BLOCK_LINK *block)
1039
905
{
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);
 
906
  assert(block->status & BLOCK_IN_USE);
 
907
  assert(!(block->status & BLOCK_CHANGED));
 
908
  assert(block->hash_link && block->hash_link->block == block);
1043
909
 
1044
910
  unlink_changed(block);
1045
911
  link_changed(block,
1095
961
  BLOCK_LINK *ins;
1096
962
  BLOCK_LINK **pins;
1097
963
 
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);
 
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);
1104
970
  if (!hot && keycache->waiting_for_block.last_thread)
1105
971
  {
1106
972
    /* Signal that in the LRU warm sub-chain an available block has appeared */
1120
986
      */
1121
987
      if ((HASH_LINK *) thread->opt_info == hash_link)
1122
988
      {
1123
 
        KEYCACHE_DBUG_PRINT("link_block: signal", ("thread %ld", thread->id));
1124
989
        keycache_pthread_cond_signal(&thread->suspend);
1125
990
        unlink_from_queue(&keycache->waiting_for_block, thread);
1126
991
        block->requests++;
1151
1016
      probably easier to read.
1152
1017
    */
1153
1018
    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
1161
1019
    return;
1162
1020
  }
1163
1021
  pins= hot ? &keycache->used_ins : &keycache->used_last;
1177
1035
    keycache->used_last= keycache->used_ins= block->next_used= block;
1178
1036
    block->prev_used= &block->next_used;
1179
1037
  }
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
1190
1038
}
1191
1039
 
1192
1040
 
1207
1055
 
1208
1056
static void unlink_block(KEY_CACHE *keycache, BLOCK_LINK *block)
1209
1057
{
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 &&
 
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 &&
1215
1063
              (block->next_used->prev_used == &block->next_used) &&
1216
1064
              (*block->prev_used == block));
1217
1065
  if (block->next_used == block)
1227
1075
      keycache->used_ins=STRUCT_PTR(BLOCK_LINK, next_used, block->prev_used);
1228
1076
  }
1229
1077
  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
 
  */
1235
1078
  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
1247
1079
}
1248
1080
 
1249
1081
 
1265
1097
*/
1266
1098
static void reg_requests(KEY_CACHE *keycache, BLOCK_LINK *block, int count)
1267
1099
{
1268
 
  DBUG_ASSERT(block->status & BLOCK_IN_USE);
1269
 
  DBUG_ASSERT(block->hash_link);
 
1100
  assert(block->status & BLOCK_IN_USE);
 
1101
  assert(block->hash_link);
1270
1102
 
1271
1103
  if (!block->requests)
1272
1104
    unlink_block(keycache, block);
1309
1141
static void unreg_request(KEY_CACHE *keycache,
1310
1142
                          BLOCK_LINK *block, int at_end)
1311
1143
{
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);
 
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);
1318
1150
  if (! --block->requests)
1319
1151
  {
1320
1152
    my_bool hot;
1327
1159
      if (block->temperature == BLOCK_WARM)
1328
1160
        keycache->warm_blocks--;
1329
1161
      block->temperature= BLOCK_HOT;
1330
 
      KEYCACHE_DBUG_PRINT("unreg_request", ("#warm_blocks: %lu",
1331
 
                           keycache->warm_blocks));
1332
1162
    }
1333
1163
    link_block(keycache, block, hot, (my_bool)at_end);
1334
1164
    block->last_hit_time= keycache->keycache_time;
1359
1189
        keycache->warm_blocks++;
1360
1190
        block->temperature= BLOCK_WARM;
1361
1191
      }
1362
 
      KEYCACHE_DBUG_PRINT("unreg_request", ("#warm_blocks: %lu",
1363
 
                           keycache->warm_blocks));
1364
1192
    }
1365
1193
  }
1366
1194
}
1371
1199
 
1372
1200
static void remove_reader(BLOCK_LINK *block)
1373
1201
{
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);
 
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);
1380
1208
  if (! --block->hash_link->requests && block->condvar)
1381
1209
    keycache_pthread_cond_signal(block->condvar);
1382
1210
}
1391
1219
                             BLOCK_LINK *block)
1392
1220
{
1393
1221
  struct st_my_thread_var *thread= my_thread_var;
1394
 
  DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
1395
 
  DBUG_ASSERT(!(block->status & (BLOCK_ERROR | BLOCK_IN_FLUSH |
 
1222
  assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
1223
  assert(!(block->status & (BLOCK_ERROR | BLOCK_IN_FLUSH |
1396
1224
                                 BLOCK_CHANGED)));
1397
 
  DBUG_ASSERT(block->hash_link);
1398
 
  DBUG_ASSERT(block->hash_link->block == block);
 
1225
  assert(block->hash_link);
 
1226
  assert(block->hash_link->block == block);
1399
1227
  /* Linked in file_blocks or changed_blocks hash. */
1400
 
  DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
 
1228
  assert(block->prev_changed && *block->prev_changed == block);
1401
1229
  /* Not linked in LRU ring. */
1402
 
  DBUG_ASSERT(!block->next_used);
1403
 
  DBUG_ASSERT(!block->prev_used);
 
1230
  assert(!block->next_used);
 
1231
  assert(!block->prev_used);
1404
1232
  while (block->hash_link->requests)
1405
1233
  {
1406
 
    KEYCACHE_DBUG_PRINT("wait_for_readers: wait",
1407
 
                        ("suspend thread %ld  block %u",
1408
 
                         thread->id, BLOCK_NUMBER(block)));
1409
1234
    /* There must be no other waiter. We have no queue here. */
1410
 
    DBUG_ASSERT(!block->condvar);
 
1235
    assert(!block->condvar);
1411
1236
    block->condvar= &thread->suspend;
1412
1237
    keycache_pthread_cond_wait(&thread->suspend, &keycache->cache_lock);
1413
1238
    block->condvar= NULL;
1435
1260
 
1436
1261
static void unlink_hash(KEY_CACHE *keycache, HASH_LINK *hash_link)
1437
1262
{
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);
 
1263
  assert(hash_link->requests == 0);
1441
1264
  if ((*hash_link->prev= hash_link->next))
1442
1265
    hash_link->next->prev= hash_link->prev;
1443
1266
  hash_link->block= NULL;
1465
1288
      */
1466
1289
      if (page->file == hash_link->file && page->filepos == hash_link->diskpos)
1467
1290
      {
1468
 
        KEYCACHE_DBUG_PRINT("unlink_hash: signal", ("thread %ld", thread->id));
1469
1291
        keycache_pthread_cond_signal(&thread->suspend);
1470
1292
        unlink_from_queue(&keycache->waiting_for_hash_link, thread);
1471
1293
      }
1489
1311
                                int file, my_off_t filepos)
1490
1312
{
1491
1313
  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));
1498
1314
 
1499
1315
restart:
1500
1316
  /*
1503
1319
     hash_link points to the first member of the list
1504
1320
  */
1505
1321
  hash_link= *(start= &keycache->hash_root[KEYCACHE_HASH(file, filepos)]);
1506
 
#if defined(KEYCACHE_DEBUG)
1507
 
  cnt= 0;
1508
 
#endif
1509
1322
  /* Look for an element for the pair (file, filepos) in the bucket chain */
1510
1323
  while (hash_link &&
1511
1324
         (hash_link->diskpos != filepos || hash_link->file != file))
1512
1325
  {
1513
1326
    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
1528
1327
  }
1529
1328
  if (! hash_link)
1530
1329
  {
1543
1342
      /* Wait for a free hash link */
1544
1343
      struct st_my_thread_var *thread= my_thread_var;
1545
1344
      KEYCACHE_PAGE page;
1546
 
      KEYCACHE_DBUG_PRINT("get_hash_link", ("waiting"));
1547
1345
      page.file= file;
1548
1346
      page.filepos= filepos;
1549
1347
      thread->opt_info= (void *) &page;
1550
1348
      link_into_queue(&keycache->waiting_for_hash_link, thread);
1551
 
      KEYCACHE_DBUG_PRINT("get_hash_link: wait",
1552
 
                        ("suspend thread %ld", thread->id));
1553
1349
      keycache_pthread_cond_wait(&thread->suspend,
1554
1350
                                 &keycache->cache_lock);
1555
1351
      thread->opt_info= NULL;
1612
1408
  int error= 0;
1613
1409
  int page_status;
1614
1410
 
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
 
 
1627
1411
restart:
1628
1412
  /*
1629
1413
    If the flush phase of a resize operation fails, the cache is left
1630
1414
    unusable. This will be detected only after "goto restart".
1631
1415
  */
1632
1416
  if (!keycache->can_be_used)
1633
 
    DBUG_RETURN(0);
 
1417
    return(0);
1634
1418
 
1635
1419
  /*
1636
1420
    Find the hash_link for the requested file block (file, filepos). We
1656
1440
          - not changed (clean).
1657
1441
  */
1658
1442
  hash_link= get_hash_link(keycache, file, filepos);
1659
 
  DBUG_ASSERT((hash_link->file == file) && (hash_link->diskpos == filepos));
 
1443
  assert((hash_link->file == file) && (hash_link->diskpos == filepos));
1660
1444
 
1661
1445
  page_status= -1;
1662
1446
  if ((block= hash_link->block) &&
1695
1479
        */
1696
1480
        hash_link->requests--;
1697
1481
        unlink_hash(keycache, hash_link);
1698
 
        DBUG_RETURN(0);
 
1482
        return(0);
1699
1483
      }
1700
1484
 
1701
1485
      /*
1714
1498
      link_into_queue(&keycache->waiting_for_block, thread);
1715
1499
      do
1716
1500
      {
1717
 
        KEYCACHE_DBUG_PRINT("find_key_block: wait",
1718
 
                            ("suspend thread %ld", thread->id));
1719
1501
        keycache_pthread_cond_wait(&thread->suspend,
1720
1502
                                   &keycache->cache_lock);
1721
1503
      } while (thread->next);
1762
1544
        only. Waiting here on COND_FOR_REQUESTED works in all
1763
1545
        situations.
1764
1546
      */
1765
 
      DBUG_ASSERT(((block->hash_link != hash_link) &&
 
1547
      assert(((block->hash_link != hash_link) &&
1766
1548
                   (block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH))) ||
1767
1549
                  ((block->hash_link == hash_link) &&
1768
1550
                   !(block->status & BLOCK_READ)));
1777
1559
        again in eviction because we registered an request on it before
1778
1560
        starting to wait.
1779
1561
      */
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)));
 
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)));
1783
1565
    }
1784
1566
    /*
1785
1567
      The block is in the cache. Assigned to the hash_link. Valid data.
1791
1573
    {
1792
1574
      /* A reader can just read the block. */
1793
1575
      *page_st= PAGE_READ;
1794
 
      DBUG_ASSERT((hash_link->file == file) &&
 
1576
      assert((hash_link->file == file) &&
1795
1577
                  (hash_link->diskpos == filepos) &&
1796
1578
                  (block->hash_link == hash_link));
1797
 
      DBUG_RETURN(block);
 
1579
      return(block);
1798
1580
    }
1799
1581
 
1800
1582
    /*
1801
1583
      This is a writer. No two writers for the same block can exist.
1802
1584
      This must be assured by locks outside of the key cache.
1803
1585
    */
1804
 
    DBUG_ASSERT(!(block->status & BLOCK_FOR_UPDATE) || fail_block(block));
 
1586
    assert(!(block->status & BLOCK_FOR_UPDATE));
1805
1587
 
1806
1588
    while (block->status & BLOCK_IN_FLUSH)
1807
1589
    {
1825
1607
        unreg_request(keycache, block, 1);
1826
1608
        goto restart;
1827
1609
      }
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);
 
1610
      assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
1611
      assert(!(block->status & BLOCK_FOR_UPDATE));
 
1612
      assert(block->hash_link == hash_link);
1831
1613
    }
1832
1614
 
1833
1615
    if (block->status & BLOCK_CHANGED)
1840
1622
        not yet been selected for flush, we can still add our changes.
1841
1623
      */
1842
1624
      *page_st= PAGE_READ;
1843
 
      DBUG_ASSERT((hash_link->file == file) &&
 
1625
      assert((hash_link->file == file) &&
1844
1626
                  (hash_link->diskpos == filepos) &&
1845
1627
                  (block->hash_link == hash_link));
1846
 
      DBUG_RETURN(block);
 
1628
      return(block);
1847
1629
    }
1848
1630
 
1849
1631
    /*
1911
1693
               (block->hash_link->file == file) &&
1912
1694
               (block->hash_link->diskpos == filepos));
1913
1695
    }
1914
 
    DBUG_RETURN(0);
 
1696
    return(0);
1915
1697
  }
1916
1698
 
1917
1699
  if (page_status == PAGE_READ &&
1926
1708
      (BLOCK_IN_SWITCH), readers of the block have not finished yet
1927
1709
      (BLOCK_REASSIGNED), or the evicting thread did not yet awake after
1928
1710
      the block has been selected for it (BLOCK_IN_EVICTION).
1929
 
    */
1930
1711
 
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
 
    /*
1936
1712
       Only reading requests can proceed until the old dirty page is flushed,
1937
1713
       all others are to be suspended, then resubmitted
1938
1714
    */
1960
1736
        as soon as possible. Again we must wait so that we don't find
1961
1737
        the same hash_link + block again and again.
1962
1738
      */
1963
 
      DBUG_ASSERT(hash_link->requests);
 
1739
      assert(hash_link->requests);
1964
1740
      hash_link->requests--;
1965
 
      KEYCACHE_DBUG_PRINT("find_key_block",
1966
 
                          ("request waiting for old page to be saved"));
1967
1741
      wait_on_queue(&block->wqueue[COND_FOR_SAVED], &keycache->cache_lock);
1968
 
      KEYCACHE_DBUG_PRINT("find_key_block",
1969
 
                          ("request for old page resubmitted"));
1970
1742
      /*
1971
1743
        The block is no longer assigned to this hash_link.
1972
1744
        Get another one.
2001
1773
        else
2002
1774
        {
2003
1775
          /* There are some never used blocks, take first of them */
2004
 
          DBUG_ASSERT(keycache->blocks_used <
 
1776
          assert(keycache->blocks_used <
2005
1777
                      (ulong) keycache->disk_blocks);
2006
1778
          block= &keycache->block_root[keycache->blocks_used];
2007
1779
          block->buffer= ADD_TO_PTR(keycache->block_mem,
2009
1781
                                     keycache->key_cache_block_size),
2010
1782
                                    uchar*);
2011
1783
          keycache->blocks_used++;
2012
 
          DBUG_ASSERT(!block->next_used);
 
1784
          assert(!block->next_used);
2013
1785
        }
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);
 
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);
2020
1792
        keycache->blocks_unused--;
2021
1793
        block->status= BLOCK_IN_USE;
2022
1794
        block->length= 0;
2029
1801
        hash_link->block= block;
2030
1802
        link_to_file_list(keycache, block, file, 0);
2031
1803
        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)));
2035
1804
      }
2036
1805
      else
2037
1806
      {
2059
1828
          link_into_queue(&keycache->waiting_for_block, thread);
2060
1829
          do
2061
1830
          {
2062
 
            KEYCACHE_DBUG_PRINT("find_key_block: wait",
2063
 
                                ("suspend thread %ld", thread->id));
2064
1831
            keycache_pthread_cond_wait(&thread->suspend,
2065
1832
                                       &keycache->cache_lock);
2066
1833
          }
2067
1834
          while (thread->next);
2068
1835
          thread->opt_info= NULL;
2069
1836
          /* Assert that block has a request registered. */
2070
 
          DBUG_ASSERT(hash_link->block->requests);
 
1837
          assert(hash_link->block->requests);
2071
1838
          /* Assert that block is not in LRU ring. */
2072
 
          DBUG_ASSERT(!hash_link->block->next_used);
2073
 
          DBUG_ASSERT(!hash_link->block->prev_used);
 
1839
          assert(!hash_link->block->next_used);
 
1840
          assert(!hash_link->block->prev_used);
2074
1841
        }
2075
1842
        /*
2076
1843
          If we waited above, hash_link->block has been assigned by
2089
1856
            Register a request on the block. This unlinks it from the
2090
1857
            LRU ring and protects it against eviction.
2091
1858
          */
2092
 
          DBUG_ASSERT(!block->requests);
 
1859
          assert(!block->requests);
2093
1860
          reg_requests(keycache, block,1);
2094
1861
          /*
2095
1862
            We do not need to set block->status|= BLOCK_IN_EVICTION here
2113
1880
          /* this is a primary request for a new page */
2114
1881
          block->status|= BLOCK_IN_SWITCH;
2115
1882
 
2116
 
          KEYCACHE_DBUG_PRINT("find_key_block",
2117
 
                        ("got block %u for new page", BLOCK_NUMBER(block)));
2118
 
 
2119
1883
          if (block->status & BLOCK_CHANGED)
2120
1884
          {
2121
1885
            /* The block contains a dirty page - push it out of the cache */
2122
1886
 
2123
 
            KEYCACHE_DBUG_PRINT("find_key_block", ("block is dirty"));
2124
1887
            if (block->status & BLOCK_IN_FLUSH)
2125
1888
            {
2126
1889
              /*
2136
1899
                The block is marked BLOCK_IN_SWITCH. It should be left
2137
1900
                alone except for reading. No free, no write.
2138
1901
              */
2139
 
              DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
2140
 
              DBUG_ASSERT(!(block->status & (BLOCK_REASSIGNED |
 
1902
              assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
1903
              assert(!(block->status & (BLOCK_REASSIGNED |
2141
1904
                                             BLOCK_CHANGED |
2142
1905
                                             BLOCK_FOR_UPDATE)));
2143
1906
            }
2148
1911
                BLOCK_IN_EVICTION may be true or not. Other flags must
2149
1912
                have a fixed value.
2150
1913
              */
2151
 
              DBUG_ASSERT((block->status & ~BLOCK_IN_EVICTION) ==
 
1914
              assert((block->status & ~BLOCK_IN_EVICTION) ==
2152
1915
                          (BLOCK_READ | BLOCK_IN_SWITCH |
2153
1916
                           BLOCK_IN_FLUSH | BLOCK_IN_FLUSHWRITE |
2154
1917
                           BLOCK_CHANGED | BLOCK_IN_USE));
2155
 
              DBUG_ASSERT(block->hash_link);
 
1918
              assert(block->hash_link);
2156
1919
 
2157
1920
              keycache_pthread_mutex_unlock(&keycache->cache_lock);
2158
1921
              /*
2166
1929
              keycache_pthread_mutex_lock(&keycache->cache_lock);
2167
1930
 
2168
1931
              /* Block status must not have changed. */
2169
 
              DBUG_ASSERT((block->status & ~BLOCK_IN_EVICTION) ==
 
1932
              assert((block->status & ~BLOCK_IN_EVICTION) ==
2170
1933
                          (BLOCK_READ | BLOCK_IN_SWITCH |
2171
1934
                           BLOCK_IN_FLUSH | BLOCK_IN_FLUSHWRITE |
2172
 
                           BLOCK_CHANGED | BLOCK_IN_USE) || fail_block(block));
 
1935
                           BLOCK_CHANGED | BLOCK_IN_USE));
2173
1936
              keycache->global_cache_write++;
2174
1937
            }
2175
1938
          }
2179
1942
            The block comes from the LRU ring. It must have a hash_link
2180
1943
            assigned.
2181
1944
          */
2182
 
          DBUG_ASSERT(block->hash_link);
 
1945
          assert(block->hash_link);
2183
1946
          if (block->hash_link)
2184
1947
          {
2185
1948
            /*
2206
1969
              a page in the cache in a sweep, without yielding control)
2207
1970
            */
2208
1971
            wait_for_readers(keycache, block);
2209
 
            DBUG_ASSERT(block->hash_link && block->hash_link->block == block &&
 
1972
            assert(block->hash_link && block->hash_link->block == block &&
2210
1973
                        block->prev_changed);
2211
1974
            /* The reader must not have been a writer. */
2212
 
            DBUG_ASSERT(!(block->status & BLOCK_CHANGED));
 
1975
            assert(!(block->status & BLOCK_CHANGED));
2213
1976
 
2214
1977
            /* Wake flushers that might have found the block in between. */
2215
1978
            release_whole_queue(&block->wqueue[COND_FOR_SAVED]);
2233
1996
          link_to_file_list(keycache, block, file, 0);
2234
1997
          page_status= PAGE_TO_BE_READ;
2235
1998
 
2236
 
          KEYCACHE_DBUG_ASSERT(block->hash_link->block == block);
2237
 
          KEYCACHE_DBUG_ASSERT(hash_link->block->hash_link == hash_link);
 
1999
          assert(block->hash_link->block == block);
 
2000
          assert(hash_link->block->hash_link == hash_link);
2238
2001
        }
2239
2002
        else
2240
2003
        {
2252
2015
            attached to the same hash_link and as such destined for the
2253
2016
            same file block.
2254
2017
          */
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 ));
2259
2018
          page_status= (((block->hash_link == hash_link) &&
2260
2019
                         (block->status & BLOCK_READ)) ?
2261
2020
                        PAGE_READ : PAGE_WAIT_TO_BE_READ);
2284
2043
        Register a request on the block. This is another protection
2285
2044
        against eviction.
2286
2045
      */
2287
 
      DBUG_ASSERT(((block->hash_link != hash_link) &&
 
2046
      assert(((block->hash_link != hash_link) &&
2288
2047
                   (block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH))) ||
2289
2048
                  ((block->hash_link == hash_link) &&
2290
2049
                   !(block->status & BLOCK_READ)) ||
2291
2050
                  ((block->status & BLOCK_READ) &&
2292
2051
                   !(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH))));
2293
2052
      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 ));
2298
2053
      page_status= (((block->hash_link == hash_link) &&
2299
2054
                     (block->status & BLOCK_READ)) ?
2300
2055
                    PAGE_READ : PAGE_WAIT_TO_BE_READ);
2301
2056
    }
2302
2057
  }
2303
2058
 
2304
 
  KEYCACHE_DBUG_ASSERT(page_status != -1);
 
2059
  assert(page_status != -1);
2305
2060
  /* Same assert basically, but be very sure. */
2306
 
  KEYCACHE_DBUG_ASSERT(block);
 
2061
  assert(block);
2307
2062
  /* Assert that block has a request and is not in LRU ring. */
2308
 
  DBUG_ASSERT(block->requests);
2309
 
  DBUG_ASSERT(!block->next_used);
2310
 
  DBUG_ASSERT(!block->prev_used);
 
2063
  assert(block->requests);
 
2064
  assert(!block->next_used);
 
2065
  assert(!block->prev_used);
2311
2066
  /* Assert that we return the correct block. */
2312
 
  DBUG_ASSERT((page_status == PAGE_WAIT_TO_BE_READ) ||
 
2067
  assert((page_status == PAGE_WAIT_TO_BE_READ) ||
2313
2068
              ((block->hash_link->file == file) &&
2314
2069
               (block->hash_link->diskpos == filepos)));
2315
2070
  *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));
2320
2071
 
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);
 
2072
  return(block);
2327
2073
}
2328
2074
 
2329
2075
 
2359
2105
 
2360
2106
  /* On entry cache_lock is locked */
2361
2107
 
2362
 
  KEYCACHE_THREAD_TRACE("read_block");
2363
2108
  if (primary)
2364
2109
  {
2365
2110
    /*
2368
2113
      request for the block become secondary requests. For a primary
2369
2114
      request the block must be properly initialized.
2370
2115
    */
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"));
 
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));
2380
2120
 
2381
2121
    keycache->global_cache_read++;
2382
2122
    /* Page is not in buffer yet, is to be read from disk */
2391
2131
      The block can now have been marked for free (in case of
2392
2132
      FLUSH_RELEASE). Otherwise the state must be unchanged.
2393
2133
    */
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));
 
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));
2401
2139
 
2402
2140
    if (got_length < min_length)
2403
2141
      block->status|= BLOCK_ERROR;
2412
2150
        keycache->key_cache_block_size.
2413
2151
      */
2414
2152
    }
2415
 
    KEYCACHE_DBUG_PRINT("read_block",
2416
 
                        ("primary request: new page in cache"));
2417
2153
    /* Signal that all pending requests for this page now can be processed */
2418
2154
    release_whole_queue(&block->wqueue[COND_FOR_REQUESTED]);
2419
2155
  }
2428
2164
      for the requested file block nor the file and position. So we have
2429
2165
      to assert this in the caller.
2430
2166
    */
2431
 
    KEYCACHE_DBUG_PRINT("read_block",
2432
 
                      ("secondary request waiting for new page to be read"));
2433
2167
    wait_on_queue(&block->wqueue[COND_FOR_REQUESTED], &keycache->cache_lock);
2434
 
    KEYCACHE_DBUG_PRINT("read_block",
2435
 
                        ("secondary request: new page in cache"));
2436
2168
  }
2437
2169
}
2438
2170
 
2474
2206
  my_bool locked_and_incremented= false;
2475
2207
  int error=0;
2476
2208
  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));
2480
2209
 
2481
2210
  if (keycache->key_cache_inited)
2482
2211
  {
2527
2256
      /* Do not read beyond the end of the cache block. */
2528
2257
      read_length= length;
2529
2258
      set_if_smaller(read_length, keycache->key_cache_block_size-offset);
2530
 
      KEYCACHE_DBUG_ASSERT(read_length > 0);
 
2259
      assert(read_length > 0);
2531
2260
 
2532
2261
      /* Request the cache block that matches file/pos. */
2533
2262
      keycache->global_cache_r_requests++;
2558
2287
            requested file block. It does not hurt to check it for
2559
2288
            primary requests too.
2560
2289
          */
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));
 
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));
2565
2294
        }
2566
2295
        else if (block->length < read_length + offset)
2567
2296
        {
2579
2308
      if (!((status= block->status) & BLOCK_ERROR))
2580
2309
      {
2581
2310
        {
2582
 
          DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
2311
          assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
2583
2312
#if !defined(SERIALIZED_READ_FROM_CACHE)
2584
2313
          keycache_pthread_mutex_unlock(&keycache->cache_lock);
2585
2314
#endif
2592
2321
 
2593
2322
#if !defined(SERIALIZED_READ_FROM_CACHE)
2594
2323
          keycache_pthread_mutex_lock(&keycache->cache_lock);
2595
 
          DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
2324
          assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
2596
2325
#endif
2597
2326
        }
2598
2327
      }
2639
2368
    dec_counter_for_resize_op(keycache);
2640
2369
    keycache_pthread_mutex_unlock(&keycache->cache_lock);
2641
2370
  }
2642
 
  DBUG_RETURN(error ? (uchar*) 0 : start);
 
2371
  return(error ? (uchar*) 0 : start);
2643
2372
}
2644
2373
 
2645
2374
 
2668
2397
                     uchar *buff, uint length)
2669
2398
{
2670
2399
  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));
2674
2400
 
2675
2401
  if (keycache->key_cache_inited)
2676
2402
  {
2710
2436
      /* Do not load beyond the end of the cache block. */
2711
2437
      read_length= length;
2712
2438
      set_if_smaller(read_length, keycache->key_cache_block_size-offset);
2713
 
      KEYCACHE_DBUG_ASSERT(read_length > 0);
 
2439
      assert(read_length > 0);
2714
2440
 
2715
2441
      /* The block has been read by the caller already. */
2716
2442
      keycache->global_cache_read++;
2766
2492
            requested file block. It does not hurt to check it for
2767
2493
            primary requests too.
2768
2494
          */
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));
 
2495
          assert(keycache->can_be_used);
 
2496
          assert(block->hash_link->file == file);
 
2497
          assert(block->hash_link->diskpos == filepos);
 
2498
          assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
2773
2499
        }
2774
2500
        else if (page_st == PAGE_TO_BE_READ)
2775
2501
        {
2777
2503
            This is a new block in the cache. If we come here, we have
2778
2504
            data for the whole block.
2779
2505
          */
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
          assert(block->hash_link->requests);
 
2507
          assert(block->status & BLOCK_IN_USE);
 
2508
          assert((page_st == PAGE_TO_BE_READ) ||
2783
2509
                      (block->status & BLOCK_READ));
2784
2510
 
2785
2511
#if !defined(SERIALIZED_READ_FROM_CACHE)
2798
2524
 
2799
2525
#if !defined(SERIALIZED_READ_FROM_CACHE)
2800
2526
          keycache_pthread_mutex_lock(&keycache->cache_lock);
2801
 
          DBUG_ASSERT(block->status & BLOCK_IN_USE);
2802
 
          DBUG_ASSERT((page_st == PAGE_TO_BE_READ) ||
 
2527
          assert(block->status & BLOCK_IN_USE);
 
2528
          assert((page_st == PAGE_TO_BE_READ) ||
2803
2529
                      (block->status & BLOCK_READ));
2804
2530
#endif
2805
2531
          /*
2816
2542
            only a writer may set block->offset down from
2817
2543
            keycache->key_cache_block_size.
2818
2544
          */
2819
 
          KEYCACHE_DBUG_PRINT("key_cache_insert",
2820
 
                              ("primary request: new page in cache"));
2821
2545
          /* Signal all pending requests. */
2822
2546
          release_whole_queue(&block->wqueue[COND_FOR_REQUESTED]);
2823
2547
        }
2833
2557
            with the new data. If the condition is met, we can simply
2834
2558
            ignore the block.
2835
2559
          */
2836
 
          DBUG_ASSERT((page_st == PAGE_READ) &&
 
2560
          assert((page_st == PAGE_READ) &&
2837
2561
                      (read_length + offset <= block->length));
2838
2562
        }
2839
2563
 
2842
2566
          requested file block. It does not hurt to check it for primary
2843
2567
          requests too.
2844
2568
        */
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));
 
2569
        assert(block->hash_link->file == file);
 
2570
        assert(block->hash_link->diskpos == filepos);
 
2571
        assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
2848
2572
      } /* end of if (!(block->status & BLOCK_ERROR)) */
2849
2573
 
2850
2574
 
2872
2596
      dec_counter_for_resize_op(keycache);
2873
2597
    keycache_pthread_mutex_unlock(&keycache->cache_lock);
2874
2598
  }
2875
 
  DBUG_RETURN(error);
 
2599
  return(error);
2876
2600
}
2877
2601
 
2878
2602
 
2913
2637
{
2914
2638
  my_bool locked_and_incremented= false;
2915
2639
  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));
2922
2640
 
2923
2641
  if (!dont_write)
2924
2642
  {
2928
2646
    keycache->global_cache_w_requests++;
2929
2647
    keycache->global_cache_write++;
2930
2648
    if (pwrite(file, buff, length, filepos) == 0)
2931
 
      DBUG_RETURN(1);
 
2649
      return(1);
2932
2650
    /* purecov: end */
2933
2651
  }
2934
2652
 
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
 
 
2940
2653
  if (keycache->key_cache_inited)
2941
2654
  {
2942
2655
    /* Key cache is used */
2985
2698
      /* Do not write beyond the end of the cache block. */
2986
2699
      read_length= length;
2987
2700
      set_if_smaller(read_length, keycache->key_cache_block_size-offset);
2988
 
      KEYCACHE_DBUG_ASSERT(read_length > 0);
 
2701
      assert(read_length > 0);
2989
2702
 
2990
2703
      /* Request the cache block that matches file/pos. */
2991
2704
      keycache->global_cache_w_requests++;
3037
2750
                   offset + read_length >= keycache->key_cache_block_size?
3038
2751
                   offset : keycache->key_cache_block_size,
3039
2752
                   offset, (page_st == PAGE_TO_BE_READ));
3040
 
        DBUG_ASSERT(keycache->can_be_used);
3041
 
        DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
2753
        assert(keycache->can_be_used);
 
2754
        assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
3042
2755
        /*
3043
2756
          Prevent block from flushing and from being selected for to be
3044
2757
          freed. This must be set when we release the cache_lock.
3050
2763
        The block should always be assigned to the requested file block
3051
2764
        here. It need not be BLOCK_READ when overwriting the whole block.
3052
2765
      */
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));
 
2766
      assert(block->hash_link->file == file);
 
2767
      assert(block->hash_link->diskpos == filepos);
 
2768
      assert(block->status & BLOCK_IN_USE);
 
2769
      assert((page_st == PAGE_TO_BE_READ) || (block->status & BLOCK_READ));
3057
2770
      /*
3058
2771
        The block to be written must not be marked BLOCK_REASSIGNED.
3059
2772
        Otherwise it could be freed in dirty state or reused without
3062
2775
        the flusher could clear BLOCK_CHANGED without flushing the
3063
2776
        new changes again.
3064
2777
      */
3065
 
      DBUG_ASSERT(!(block->status & BLOCK_REASSIGNED));
 
2778
      assert(!(block->status & BLOCK_REASSIGNED));
3066
2779
 
3067
2780
      while (block->status & BLOCK_IN_FLUSHWRITE)
3068
2781
      {
3076
2789
          another hash_link until we release our request on it.
3077
2790
        */
3078
2791
        wait_on_queue(&block->wqueue[COND_FOR_SAVED], &keycache->cache_lock);
3079
 
        DBUG_ASSERT(keycache->can_be_used);
3080
 
        DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
2792
        assert(keycache->can_be_used);
 
2793
        assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
3081
2794
        /* Still must not be marked for free. */
3082
 
        DBUG_ASSERT(!(block->status & BLOCK_REASSIGNED));
3083
 
        DBUG_ASSERT(block->hash_link && (block->hash_link->block == block));
 
2795
        assert(!(block->status & BLOCK_REASSIGNED));
 
2796
        assert(block->hash_link && (block->hash_link->block == block));
3084
2797
      }
3085
2798
 
3086
2799
      /*
3181
2894
    dec_counter_for_resize_op(keycache);
3182
2895
    keycache_pthread_mutex_unlock(&keycache->cache_lock);
3183
2896
  }
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);
 
2897
  return(error);
3189
2898
}
3190
2899
 
3191
2900
 
3218
2927
 
3219
2928
static void free_block(KEY_CACHE *keycache, BLOCK_LINK *block)
3220
2929
{
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));
3225
2930
  /*
3226
2931
    Assert that the block is not free already. And that it is in a clean
3227
2932
    state. Note that the block might just be assigned to a hash_link and
3229
2934
    is registered in the hash_link and free_block() will wait for it
3230
2935
    below.
3231
2936
  */
3232
 
  DBUG_ASSERT((block->status & BLOCK_IN_USE) &&
 
2937
  assert((block->status & BLOCK_IN_USE) &&
3233
2938
              !(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH |
3234
2939
                                 BLOCK_REASSIGNED | BLOCK_IN_FLUSH |
3235
2940
                                 BLOCK_CHANGED | BLOCK_FOR_UPDATE)));
3236
2941
  /* Assert that the block is in a file_blocks chain. */
3237
 
  DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
 
2942
  assert(block->prev_changed && *block->prev_changed == block);
3238
2943
  /* Assert that the block is not in the LRU ring. */
3239
 
  DBUG_ASSERT(!block->next_used && !block->prev_used);
 
2944
  assert(!block->next_used && !block->prev_used);
3240
2945
  /*
3241
2946
    IMHO the below condition (if()) makes no sense. I can't see how it
3242
2947
    could be possible that free_block() is entered with a NULL hash_link
3243
2948
    pointer. The only place where it can become NULL is in free_block()
3244
2949
    (or before its first use ever, but for those blocks free_block() is
3245
2950
    not called). I don't remove the conditional as it cannot harm, but
3246
 
    place an DBUG_ASSERT to confirm my hypothesis. Eventually the
 
2951
    place an assert to confirm my hypothesis. Eventually the
3247
2952
    condition (if()) can be removed.
3248
2953
  */
3249
 
  DBUG_ASSERT(block->hash_link && block->hash_link->block == block);
 
2954
  assert(block->hash_link && block->hash_link->block == block);
3250
2955
  if (block->hash_link)
3251
2956
  {
3252
2957
    /*
3262
2967
      checks. An additional requirement is that it must be read now
3263
2968
      (BLOCK_READ).
3264
2969
    */
3265
 
    DBUG_ASSERT(block->hash_link && block->hash_link->block == block);
3266
 
    DBUG_ASSERT((block->status & (BLOCK_READ | BLOCK_IN_USE |
 
2970
    assert(block->hash_link && block->hash_link->block == block);
 
2971
    assert((block->status & (BLOCK_READ | BLOCK_IN_USE |
3267
2972
                                  BLOCK_REASSIGNED)) &&
3268
2973
                !(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH |
3269
2974
                                   BLOCK_IN_FLUSH | BLOCK_CHANGED |
3270
2975
                                   BLOCK_FOR_UPDATE)));
3271
 
    DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
3272
 
    DBUG_ASSERT(!block->prev_used);
 
2976
    assert(block->prev_changed && *block->prev_changed == block);
 
2977
    assert(!block->prev_used);
3273
2978
    /*
3274
2979
      Unset BLOCK_REASSIGNED again. If we hand the block to an evicting
3275
2980
      thread (through unreg_request() below), other threads must not see
3292
2997
    operation in this case. Assert that there are no other requests
3293
2998
    registered.
3294
2999
  */
3295
 
  DBUG_ASSERT(block->requests == 1);
 
3000
  assert(block->requests == 1);
3296
3001
  unreg_request(keycache, block, 0);
3297
3002
  /*
3298
3003
    Note that even without releasing the cache lock it is possible that
3304
3009
    return;
3305
3010
 
3306
3011
  /* Here the block must be in the LRU ring. Unlink it again. */
3307
 
  DBUG_ASSERT(block->next_used && block->prev_used &&
 
3012
  assert(block->next_used && block->prev_used &&
3308
3013
              *block->prev_used == block);
3309
3014
  unlink_block(keycache, block);
3310
3015
  if (block->temperature == BLOCK_WARM)
3321
3026
  block->status= 0;
3322
3027
  block->length= 0;
3323
3028
  block->offset= keycache->key_cache_block_size;
3324
 
  KEYCACHE_THREAD_TRACE("free block");
3325
 
  KEYCACHE_DBUG_PRINT("free_block", ("block is freed"));
3326
3029
 
3327
3030
  /* Enforced by unlink_changed(), but just to be sure. */
3328
 
  DBUG_ASSERT(!block->next_changed && !block->prev_changed);
 
3031
  assert(!block->next_changed && !block->prev_changed);
3329
3032
  /* Enforced by unlink_block(): not in LRU ring nor in free_block_list. */
3330
 
  DBUG_ASSERT(!block->next_used && !block->prev_used);
 
3033
  assert(!block->next_used && !block->prev_used);
3331
3034
  /* Insert the free block in the free list. */
3332
3035
  block->next_used= keycache->free_block_list;
3333
3036
  keycache->free_block_list= block;
3377
3080
  for ( ; cache != end ; cache++)
3378
3081
  {
3379
3082
    BLOCK_LINK *block= *cache;
3380
 
 
3381
 
    KEYCACHE_DBUG_PRINT("flush_cached_blocks",
3382
 
                        ("block %u to be flushed", BLOCK_NUMBER(block)));
3383
3083
    /*
3384
3084
      If the block contents is going to be changed, we abandon the flush
3385
3085
      for this block. flush_key_blocks_int() will restart its search and
3388
3088
    if (!(block->status & BLOCK_FOR_UPDATE))
3389
3089
    {
3390
3090
      /* Blocks coming here must have a certain status. */
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) ==
 
3091
      assert(block->hash_link);
 
3092
      assert(block->hash_link->block == block);
 
3093
      assert(block->hash_link->file == file);
 
3094
      assert((block->status & ~BLOCK_IN_EVICTION) ==
3395
3095
                  (BLOCK_READ | BLOCK_IN_FLUSH | BLOCK_CHANGED | BLOCK_IN_USE));
3396
3096
      block->status|= BLOCK_IN_FLUSHWRITE;
3397
3097
      keycache_pthread_mutex_unlock(&keycache->cache_lock);
3409
3109
      }
3410
3110
      block->status&= ~BLOCK_IN_FLUSHWRITE;
3411
3111
      /* Block must not have changed status except BLOCK_FOR_UPDATE. */
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)) ==
 
3112
      assert(block->hash_link);
 
3113
      assert(block->hash_link->block == block);
 
3114
      assert(block->hash_link->file == file);
 
3115
      assert((block->status & ~(BLOCK_FOR_UPDATE | BLOCK_IN_EVICTION)) ==
3416
3116
                  (BLOCK_READ | BLOCK_IN_FLUSH | BLOCK_CHANGED | BLOCK_IN_USE));
3417
3117
      /*
3418
3118
        Set correct status and link in right queue for free or later use.
3486
3186
  BLOCK_LINK *cache_buff[FLUSH_CACHE],**cache;
3487
3187
  int last_errno= 0;
3488
3188
  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
3497
3189
 
3498
3190
  cache= cache_buff;
3499
3191
  if (keycache->disk_blocks > 0 &&
3507
3199
    BLOCK_LINK *last_in_flush;
3508
3200
    BLOCK_LINK *last_for_update;
3509
3201
    BLOCK_LINK *block, *next;
3510
 
#if defined(KEYCACHE_DEBUG)
3511
 
    uint cnt=0;
3512
 
#endif
3513
3202
 
3514
3203
    if (type != FLUSH_IGNORE_CHANGED)
3515
3204
    {
3526
3215
            !(block->status & BLOCK_IN_FLUSH))
3527
3216
        {
3528
3217
          count++;
3529
 
          KEYCACHE_DBUG_ASSERT(count<= keycache->blocks_used);
 
3218
          assert(count<= keycache->blocks_used);
3530
3219
        }
3531
3220
      }
3532
3221
      /*
3555
3244
         block ;
3556
3245
         block= next)
3557
3246
    {
3558
 
#if defined(KEYCACHE_DEBUG)
3559
 
      cnt++;
3560
 
      KEYCACHE_DBUG_ASSERT(cnt <= keycache->blocks_used);
3561
 
#endif
3562
3247
      next= block->next_changed;
3563
3248
      if (block->hash_link->file == file)
3564
3249
      {
3622
3307
            else
3623
3308
            {
3624
3309
              /* It's a temporary file */
3625
 
              DBUG_ASSERT(!(block->status & BLOCK_REASSIGNED));
 
3310
              assert(!(block->status & BLOCK_REASSIGNED));
3626
3311
 
3627
3312
              /*
3628
3313
                free_block() must not be called with BLOCK_CHANGED. Note
3743
3428
    */
3744
3429
    while (first_in_switch)
3745
3430
    {
3746
 
#if defined(KEYCACHE_DEBUG)
3747
 
      cnt= 0;
3748
 
#endif
3749
3431
      wait_on_queue(&first_in_switch->wqueue[COND_FOR_SAVED],
3750
3432
                    &keycache->cache_lock);
3751
 
#if defined(KEYCACHE_DEBUG)
3752
 
      cnt++;
3753
 
      KEYCACHE_DBUG_ASSERT(cnt <= keycache->blocks_used);
3754
 
#endif
3755
3433
      /*
3756
3434
        Do not restart here. We have flushed all blocks that were
3757
3435
        changed when entering this function and were not marked for
3782
3460
          next= block->next_changed;
3783
3461
 
3784
3462
          /* Changed blocks cannot appear in the file_blocks hash. */
3785
 
          DBUG_ASSERT(!(block->status & BLOCK_CHANGED));
 
3463
          assert(!(block->status & BLOCK_CHANGED));
3786
3464
          if (block->hash_link->file == file)
3787
3465
          {
3788
3466
            /* We must skip blocks that will be changed. */
3808
3486
 
3809
3487
              total_found++;
3810
3488
              found++;
3811
 
              KEYCACHE_DBUG_ASSERT(found <= keycache->blocks_used);
 
3489
              assert(found <= keycache->blocks_used);
3812
3490
 
3813
3491
              /*
3814
3492
                Register a request. This unlinks the block from the LRU
3830
3508
                next_hash_link= next->hash_link;
3831
3509
                next_diskpos=   next_hash_link->diskpos;
3832
3510
                next_file=      next_hash_link->file;
3833
 
                DBUG_ASSERT(next == next_hash_link->block);
 
3511
                assert(next == next_hash_link->block);
3834
3512
              }
3835
3513
 
3836
3514
              free_block(keycache, block);
3877
3555
      if (last_for_update)
3878
3556
      {
3879
3557
        /* We did not wait. Block must not have changed status. */
3880
 
        DBUG_ASSERT(last_for_update->status & BLOCK_FOR_UPDATE);
 
3558
        assert(last_for_update->status & BLOCK_FOR_UPDATE);
3881
3559
        wait_on_queue(&last_for_update->wqueue[COND_FOR_REQUESTED],
3882
3560
                      &keycache->cache_lock);
3883
3561
        goto restart;
3890
3568
      if (last_in_switch)
3891
3569
      {
3892
3570
        /* We did not wait. Block must not have changed status. */
3893
 
        DBUG_ASSERT(last_in_switch->status & (BLOCK_IN_EVICTION |
 
3571
        assert(last_in_switch->status & (BLOCK_IN_EVICTION |
3894
3572
                                              BLOCK_IN_SWITCH |
3895
3573
                                              BLOCK_REASSIGNED));
3896
3574
        wait_on_queue(&last_in_switch->wqueue[COND_FOR_SAVED],
3902
3580
 
3903
3581
  } /* if (keycache->disk_blocks > 0 */
3904
3582
 
3905
 
#ifndef DBUG_OFF
3906
 
  DBUG_EXECUTE("check_keycache",
3907
 
               test_key_cache(keycache, "end of flush_key_blocks", 0););
3908
 
#endif
3909
3583
err:
3910
3584
  if (cache != cache_buff)
3911
3585
    my_free((uchar*) cache, MYF(0));
3912
3586
  if (last_errno)
3913
3587
    errno=last_errno;                /* Return first error */
3914
 
  DBUG_RETURN(last_errno != 0);
 
3588
  return(last_errno != 0);
3915
3589
}
3916
3590
 
3917
3591
 
3934
3608
                     File file, enum flush_type type)
3935
3609
{
3936
3610
  int res= 0;
3937
 
  DBUG_ENTER("flush_key_blocks");
3938
 
  DBUG_PRINT("enter", ("keycache: 0x%lx", (long) keycache));
3939
3611
 
3940
3612
  if (!keycache->key_cache_inited)
3941
 
    DBUG_RETURN(0);
 
3613
    return(0);
3942
3614
 
3943
3615
  keycache_pthread_mutex_lock(&keycache->cache_lock);
3944
3616
  /* While waiting for lock, keycache could have been ended. */
3949
3621
    dec_counter_for_resize_op(keycache);
3950
3622
  }
3951
3623
  keycache_pthread_mutex_unlock(&keycache->cache_lock);
3952
 
  DBUG_RETURN(res);
 
3624
  return(res);
3953
3625
}
3954
3626
 
3955
3627
 
3991
3663
  uint          total_found;
3992
3664
  uint          found;
3993
3665
  uint          idx;
3994
 
  DBUG_ENTER("flush_all_key_blocks");
3995
3666
 
3996
3667
  do
3997
3668
  {
4026
3697
          */
4027
3698
          if (flush_key_blocks_int(keycache, block->hash_link->file,
4028
3699
                                   FLUSH_FORCE_WRITE))
4029
 
            DBUG_RETURN(1);
 
3700
            return(1);
4030
3701
        }
4031
3702
      }
4032
3703
 
4060
3731
          found++;
4061
3732
          if (flush_key_blocks_int(keycache, block->hash_link->file,
4062
3733
                                   FLUSH_RELEASE))
4063
 
            DBUG_RETURN(1);
 
3734
            return(1);
4064
3735
        }
4065
3736
      }
4066
3737
 
4073
3744
      before the resize started (BLOCK_FOR_UPDATE). Re-check the hashes.
4074
3745
    */
4075
3746
  } while (total_found);
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);
 
3747
  return(0);
4087
3748
}
4088
3749
 
4089
3750
 
4106
3767
int reset_key_cache_counters(const char *name __attribute__((unused)),
4107
3768
                             KEY_CACHE *key_cache)
4108
3769
{
4109
 
  DBUG_ENTER("reset_key_cache_counters");
4110
3770
  if (!key_cache->key_cache_inited)
4111
3771
  {
4112
 
    DBUG_PRINT("info", ("Key cache %s not initialized.", name));
4113
 
    DBUG_RETURN(0);
 
3772
    return(0);
4114
3773
  }
4115
 
  DBUG_PRINT("info", ("Resetting counters for key cache %s.", name));
4116
 
 
4117
3774
  key_cache->global_blocks_changed= 0;   /* Key_blocks_not_flushed */
4118
3775
  key_cache->global_cache_r_requests= 0; /* Key_read_requests */
4119
3776
  key_cache->global_cache_read= 0;       /* Key_reads */
4120
3777
  key_cache->global_cache_w_requests= 0; /* Key_write_requests */
4121
3778
  key_cache->global_cache_write= 0;      /* Key_writes */
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
 
3779
  return(0);
 
3780
}
4137
3781
 
4138
3782
#if defined(KEYCACHE_TIMEOUT)
4139
3783
 
4231
3875
  fclose(keycache_dump_file);
4232
3876
}
4233
3877
 
4234
 
#endif /* defined(KEYCACHE_TIMEOUT) */
4235
 
 
4236
 
#if defined(KEYCACHE_TIMEOUT)
4237
 
 
4238
 
 
4239
3878
static int keycache_pthread_cond_wait(pthread_cond_t *cond,
4240
3879
                                      pthread_mutex_t *mutex)
4241
3880
{
4243
3882
  struct timeval  now;            /* time when we started waiting        */
4244
3883
  struct timespec timeout;        /* timeout value for the wait function */
4245
3884
  struct timezone tz;
4246
 
#if defined(KEYCACHE_DEBUG)
4247
 
  int cnt=0;
4248
 
#endif
4249
3885
 
4250
3886
  /* Get current time */
4251
3887
  gettimeofday(&now, &tz);
4257
3893
   1 nanosecond = 1000 micro seconds
4258
3894
 */
4259
3895
  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
4267
3896
  rc= pthread_cond_timedwait(cond, mutex, &timeout);
4268
 
  KEYCACHE_THREAD_TRACE_BEGIN("finished waiting");
4269
3897
  if (rc == ETIMEDOUT || rc == ETIME)
4270
3898
  {
4271
 
#if defined(KEYCACHE_DEBUG)
4272
 
    fprintf(keycache_debug_log,"aborted by keycache timeout\n");
4273
 
    fclose(keycache_debug_log);
4274
 
    abort();
4275
 
#endif
4276
3899
    keycache_dump();
4277
3900
  }
4278
3901
 
4279
 
#if defined(KEYCACHE_DEBUG)
4280
 
  KEYCACHE_DBUG_ASSERT(rc != ETIMEDOUT);
4281
 
#else
4282
3902
  assert(rc != ETIMEDOUT);
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
 
3903
  return rc;
 
3904
}
4298
3905
#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