~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to mysys/mf_keycache.c

  • Committer: Brian Aker
  • Date: 2008-07-01 20:14:24 UTC
  • Revision ID: brian@tangent.org-20080701201424-rsof5enxl7gkr50p
More cleanup on pread()

Show diffs side-by-side

added added

removed removed

Lines of Context:
101
101
  I/O finished.
102
102
*/
103
103
 
104
 
#include <drizzled/global.h>
105
 
#include <mysys/mysys_err.h>
106
 
#include <mysys/my_sys.h>
 
104
#include "mysys_priv.h"
 
105
#include "mysys_err.h"
107
106
#include <keycache.h>
108
 
#include <mystrings/m_string.h>
109
 
#include <mysys/my_bit.h>
 
107
#include "my_static.h"
 
108
#include <m_string.h>
 
109
#include <my_bit.h>
110
110
#include <errno.h>
111
111
#include <stdarg.h>
112
112
 
130
130
    situation, which theoretically should not happen;
131
131
    to set timeout equal to <T> seconds add
132
132
      #define KEYCACHE_TIMEOUT <T>
 
133
  - to enable the module traps and to send debug information from
 
134
    key cache module to a special debug log add:
 
135
      #define KEYCACHE_DEBUG
 
136
    the name of this debug log file <LOG NAME> can be set through:
 
137
      #define KEYCACHE_DEBUG_LOG  <LOG NAME>
 
138
    if the name is not defined, it's set by default;
 
139
    if the KEYCACHE_DEBUG flag is not set up and we are in a debug
 
140
    mode, i.e. when ! defined(DBUG_OFF), the debug information from the
 
141
    module is sent to the regular debug log.
133
142
 
134
143
  Example of the settings:
135
144
    #define SERIALIZED_READ_FROM_CACHE
136
145
    #define MAX_THREADS   100
137
146
    #define KEYCACHE_TIMEOUT  1
 
147
    #define KEYCACHE_DEBUG
 
148
    #define KEYCACHE_DEBUG_LOG  "my_key_cache_debug.log"
138
149
*/
139
150
 
140
151
#define STRUCT_PTR(TYPE, MEMBER, a)                                           \
161
172
  struct st_block_link *block;       /* reference to the block for the page: */
162
173
  File file;                         /* from such a file                     */
163
174
  my_off_t diskpos;                  /* with such an offset                  */
164
 
  uint32_t requests;                     /* number of requests for the page      */
 
175
  uint requests;                     /* number of requests for the page      */
165
176
};
166
177
 
167
178
/* simple states of a block */
193
204
    *next_changed, **prev_changed; /* for lists of file dirty/clean blocks   */
194
205
  struct st_hash_link *hash_link; /* backward ptr to referring hash_link     */
195
206
  KEYCACHE_WQUEUE wqueue[2]; /* queues on waiting requests for new/old pages */
196
 
  uint32_t requests;          /* number of requests for the block                */
197
 
  unsigned char *buffer;           /* buffer for the block page                       */
198
 
  uint32_t offset;            /* beginning of modified data in the buffer        */
199
 
  uint32_t length;            /* end of data in the buffer                       */
200
 
  uint32_t status;            /* state of the block                              */
 
207
  uint requests;          /* number of requests for the block                */
 
208
  uchar *buffer;           /* buffer for the block page                       */
 
209
  uint offset;            /* beginning of modified data in the buffer        */
 
210
  uint length;            /* end of data in the buffer                       */
 
211
  uint status;            /* state of the block                              */
201
212
  enum BLOCK_TEMPERATURE temperature; /* block temperature: cold, warm, hot */
202
 
  uint32_t hits_left;         /* number of hits left until promotion             */
203
 
  uint64_t last_hit_time; /* timestamp of the last hit                      */
 
213
  uint hits_left;         /* number of hits left until promotion             */
 
214
  ulonglong last_hit_time; /* timestamp of the last hit                      */
204
215
  KEYCACHE_CONDVAR *condvar; /* condition variable for 'no readers' event    */
205
216
};
206
217
 
210
221
#define FLUSH_CACHE         2000            /* sort this many blocks at once */
211
222
 
212
223
static int flush_all_key_blocks(KEY_CACHE *keycache);
 
224
#ifdef THREAD
213
225
static void wait_on_queue(KEYCACHE_WQUEUE *wqueue,
214
226
                          pthread_mutex_t *mutex);
215
227
static void release_whole_queue(KEYCACHE_WQUEUE *wqueue);
 
228
#else
 
229
#define wait_on_queue(wqueue, mutex)    do {} while (0)
 
230
#define release_whole_queue(wqueue)     do {} while (0)
 
231
#endif
216
232
static void free_block(KEY_CACHE *keycache, BLOCK_LINK *block);
 
233
#if !defined(DBUG_OFF)
 
234
static void test_key_cache(KEY_CACHE *keycache,
 
235
                           const char *where, my_bool lock);
 
236
#endif
217
237
 
218
238
#define KEYCACHE_HASH(f, pos)                                                 \
219
 
(((uint32_t) ((pos) / keycache->key_cache_block_size) +                          \
220
 
                                     (uint32_t) (f)) & (keycache->hash_entries-1))
 
239
(((ulong) ((pos) / keycache->key_cache_block_size) +                          \
 
240
                                     (ulong) (f)) & (keycache->hash_entries-1))
221
241
#define FILE_HASH(f)                 ((uint) (f) & (CHANGED_BLOCKS_HASH-1))
222
242
 
 
243
#define DEFAULT_KEYCACHE_DEBUG_LOG  "keycache_debug.log"
 
244
 
 
245
#if defined(KEYCACHE_DEBUG) && ! defined(KEYCACHE_DEBUG_LOG)
 
246
#define KEYCACHE_DEBUG_LOG  DEFAULT_KEYCACHE_DEBUG_LOG
 
247
#endif
 
248
 
 
249
#if defined(KEYCACHE_DEBUG_LOG)
 
250
static FILE *keycache_debug_log=NULL;
 
251
static void keycache_debug_print _VARARGS((const char *fmt,...));
 
252
#define KEYCACHE_DEBUG_OPEN                                                   \
 
253
          if (!keycache_debug_log)                                            \
 
254
          {                                                                   \
 
255
            keycache_debug_log= fopen(KEYCACHE_DEBUG_LOG, "w");               \
 
256
            (void) setvbuf(keycache_debug_log, NULL, _IOLBF, BUFSIZ);         \
 
257
          }
 
258
 
 
259
#define KEYCACHE_DEBUG_CLOSE                                                  \
 
260
          if (keycache_debug_log)                                             \
 
261
          {                                                                   \
 
262
            fclose(keycache_debug_log);                                       \
 
263
            keycache_debug_log= 0;                                            \
 
264
          }
 
265
#else
 
266
#define KEYCACHE_DEBUG_OPEN
 
267
#define KEYCACHE_DEBUG_CLOSE
 
268
#endif /* defined(KEYCACHE_DEBUG_LOG) */
 
269
 
 
270
#if defined(KEYCACHE_DEBUG_LOG) && defined(KEYCACHE_DEBUG)
 
271
#define KEYCACHE_DBUG_PRINT(l, m)                                             \
 
272
            { if (keycache_debug_log) fprintf(keycache_debug_log, "%s: ", l); \
 
273
              keycache_debug_print m; }
 
274
 
 
275
#define KEYCACHE_DBUG_ASSERT(a)                                               \
 
276
            { if (! (a) && keycache_debug_log) fclose(keycache_debug_log);    \
 
277
              assert(a); }
 
278
#else
 
279
#define KEYCACHE_DBUG_PRINT(l, m)  DBUG_PRINT(l, m)
 
280
#define KEYCACHE_DBUG_ASSERT(a)    DBUG_ASSERT(a)
 
281
#endif /* defined(KEYCACHE_DEBUG_LOG) && defined(KEYCACHE_DEBUG) */
 
282
 
 
283
#if defined(KEYCACHE_DEBUG) || !defined(DBUG_OFF)
 
284
#ifdef THREAD
 
285
static long keycache_thread_id;
 
286
#define KEYCACHE_THREAD_TRACE(l)                                              \
 
287
             KEYCACHE_DBUG_PRINT(l,("|thread %ld",keycache_thread_id))
 
288
 
 
289
#define KEYCACHE_THREAD_TRACE_BEGIN(l)                                        \
 
290
            { struct st_my_thread_var *thread_var= my_thread_var;             \
 
291
              keycache_thread_id= thread_var->id;                             \
 
292
              KEYCACHE_DBUG_PRINT(l,("[thread %ld",keycache_thread_id)) }
 
293
 
 
294
#define KEYCACHE_THREAD_TRACE_END(l)                                          \
 
295
            KEYCACHE_DBUG_PRINT(l,("]thread %ld",keycache_thread_id))
 
296
#else /* THREAD */
 
297
#define KEYCACHE_THREAD_TRACE(l)        KEYCACHE_DBUG_PRINT(l,(""))
 
298
#define KEYCACHE_THREAD_TRACE_BEGIN(l)  KEYCACHE_DBUG_PRINT(l,(""))
 
299
#define KEYCACHE_THREAD_TRACE_END(l)    KEYCACHE_DBUG_PRINT(l,(""))
 
300
#endif /* THREAD */
 
301
#else
 
302
#define KEYCACHE_THREAD_TRACE_BEGIN(l)
 
303
#define KEYCACHE_THREAD_TRACE_END(l)
 
304
#define KEYCACHE_THREAD_TRACE(l)
 
305
#endif /* defined(KEYCACHE_DEBUG) || !defined(DBUG_OFF) */
 
306
 
223
307
#define BLOCK_NUMBER(b)                                                       \
224
308
  ((uint) (((char*)(b)-(char *) keycache->block_root)/sizeof(BLOCK_LINK)))
225
309
#define HASH_LINK_NUMBER(h)                                                   \
226
310
  ((uint) (((char*)(h)-(char *) keycache->hash_link_root)/sizeof(HASH_LINK)))
227
311
 
228
 
#ifdef KEYCACHE_TIMEOUT
 
312
#if (defined(KEYCACHE_TIMEOUT)) || defined(KEYCACHE_DEBUG)
229
313
static int keycache_pthread_cond_wait(pthread_cond_t *cond,
230
314
                                      pthread_mutex_t *mutex);
231
315
#else
232
316
#define  keycache_pthread_cond_wait pthread_cond_wait
233
317
#endif
234
318
 
 
319
#if defined(KEYCACHE_DEBUG)
 
320
static int keycache_pthread_mutex_lock(pthread_mutex_t *mutex);
 
321
static void keycache_pthread_mutex_unlock(pthread_mutex_t *mutex);
 
322
static int keycache_pthread_cond_signal(pthread_cond_t *cond);
 
323
#else
235
324
#define keycache_pthread_mutex_lock pthread_mutex_lock
236
325
#define keycache_pthread_mutex_unlock pthread_mutex_unlock
237
326
#define keycache_pthread_cond_signal pthread_cond_signal
238
 
 
239
 
static inline uint32_t next_power(uint32_t value)
 
327
#endif /* defined(KEYCACHE_DEBUG) */
 
328
 
 
329
#if !defined(DBUG_OFF)
 
330
#if defined(inline)
 
331
#undef inline
 
332
#endif
 
333
#define inline  /* disabled inline for easier debugging */
 
334
static int fail_block(BLOCK_LINK *block);
 
335
static int fail_hlink(HASH_LINK *hlink);
 
336
static int cache_empty(KEY_CACHE *keycache);
 
337
#endif
 
338
 
 
339
static inline uint next_power(uint value)
240
340
{
241
 
  return (uint) my_round_up_to_next_power((uint32_t) value) << 1;
 
341
  return (uint) my_round_up_to_next_power((uint32) value) << 1;
242
342
}
243
343
 
244
344
 
267
367
 
268
368
*/
269
369
 
270
 
int init_key_cache(KEY_CACHE *keycache, uint32_t key_cache_block_size,
271
 
                   size_t use_mem, uint32_t division_limit,
272
 
                   uint32_t age_threshold)
 
370
int init_key_cache(KEY_CACHE *keycache, uint key_cache_block_size,
 
371
                   size_t use_mem, uint division_limit,
 
372
                   uint age_threshold)
273
373
{
274
 
  uint32_t blocks, hash_links;
 
374
  ulong blocks, hash_links;
275
375
  size_t length;
276
376
  int error;
277
 
  assert(key_cache_block_size >= 512);
 
377
  DBUG_ENTER("init_key_cache");
 
378
  DBUG_ASSERT(key_cache_block_size >= 512);
278
379
 
 
380
  KEYCACHE_DEBUG_OPEN;
279
381
  if (keycache->key_cache_inited && keycache->disk_blocks > 0)
280
382
  {
281
 
    return(0);
 
383
    DBUG_PRINT("warning",("key cache already in use"));
 
384
    DBUG_RETURN(0);
282
385
  }
283
386
 
284
387
  keycache->global_cache_w_requests= keycache->global_cache_r_requests= 0;
302
405
 
303
406
  keycache->key_cache_mem_size= use_mem;
304
407
  keycache->key_cache_block_size= key_cache_block_size;
 
408
  DBUG_PRINT("info", ("key_cache_block_size: %u",
 
409
                      key_cache_block_size));
305
410
 
306
 
  blocks= (uint32_t) (use_mem / (sizeof(BLOCK_LINK) + 2 * sizeof(HASH_LINK) +
 
411
  blocks= (ulong) (use_mem / (sizeof(BLOCK_LINK) + 2 * sizeof(HASH_LINK) +
307
412
                              sizeof(HASH_LINK*) * 5/4 + key_cache_block_size));
308
413
  /* It doesn't make sense to have too few blocks (less than 8) */
309
414
  if (blocks >= 8)
353
458
    keycache->hash_link_root= (HASH_LINK*) ((char*) keycache->hash_root +
354
459
                                            ALIGN_SIZE((sizeof(HASH_LINK*) *
355
460
                                                        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));
 
461
    bzero((uchar*) keycache->block_root,
 
462
          keycache->disk_blocks * sizeof(BLOCK_LINK));
 
463
    bzero((uchar*) keycache->hash_root,
 
464
          keycache->hash_entries * sizeof(HASH_LINK*));
 
465
    bzero((uchar*) keycache->hash_link_root,
 
466
          keycache->hash_links * sizeof(HASH_LINK));
362
467
    keycache->hash_links_used= 0;
363
468
    keycache->free_hash_list= NULL;
364
469
    keycache->blocks_used= keycache->blocks_changed= 0;
383
488
 
384
489
    keycache->waiting_for_hash_link.last_thread= NULL;
385
490
    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);
 
491
    DBUG_PRINT("exit",
 
492
               ("disk_blocks: %d  block_root: 0x%lx  hash_entries: %d\
 
493
 hash_root: 0x%lx  hash_links: %d  hash_link_root: 0x%lx",
 
494
                keycache->disk_blocks,  (long) keycache->block_root,
 
495
                keycache->hash_entries, (long) keycache->hash_root,
 
496
                keycache->hash_links,   (long) keycache->hash_link_root));
 
497
    bzero((uchar*) keycache->changed_blocks,
 
498
          sizeof(keycache->changed_blocks[0]) * CHANGED_BLOCKS_HASH);
 
499
    bzero((uchar*) keycache->file_blocks,
 
500
          sizeof(keycache->file_blocks[0]) * CHANGED_BLOCKS_HASH);
390
501
  }
391
502
  else
392
503
  {
395
506
  }
396
507
 
397
508
  keycache->blocks= keycache->disk_blocks > 0 ? keycache->disk_blocks : 0;
398
 
  return((int) keycache->disk_blocks);
 
509
  DBUG_RETURN((int) keycache->disk_blocks);
399
510
 
400
511
err:
401
512
  error= my_errno;
408
519
  }
409
520
  if (keycache->block_root)
410
521
  {
411
 
    free((unsigned char*) keycache->block_root);
 
522
    my_free((uchar*) keycache->block_root, MYF(0));
412
523
    keycache->block_root= NULL;
413
524
  }
414
525
  my_errno= error;
415
526
  keycache->can_be_used= 0;
416
 
  return(0);
 
527
  DBUG_RETURN(0);
417
528
}
418
529
 
419
530
 
446
557
    (when cnt_for_resize=0).
447
558
*/
448
559
 
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)
 
560
int resize_key_cache(KEY_CACHE *keycache, uint key_cache_block_size,
 
561
                     size_t use_mem, uint division_limit,
 
562
                     uint age_threshold)
452
563
{
453
564
  int blocks;
 
565
  DBUG_ENTER("resize_key_cache");
454
566
 
455
567
  if (!keycache->key_cache_inited)
456
 
    return(keycache->disk_blocks);
 
568
    DBUG_RETURN(keycache->disk_blocks);
457
569
 
458
570
  if(key_cache_block_size == keycache->key_cache_block_size &&
459
571
     use_mem == keycache->key_cache_mem_size)
460
572
  {
461
573
    change_key_cache_param(keycache, division_limit, age_threshold);
462
 
    return(keycache->disk_blocks);
 
574
    DBUG_RETURN(keycache->disk_blocks);
463
575
  }
464
576
 
465
577
  keycache_pthread_mutex_lock(&keycache->cache_lock);
466
578
 
 
579
#ifdef THREAD
467
580
  /*
468
581
    We may need to wait for another thread which is doing a resize
469
582
    already. This cannot happen in the MySQL server though. It allows
476
589
    wait_on_queue(&keycache->resize_queue, &keycache->cache_lock);
477
590
    /* purecov: end */
478
591
  }
 
592
#endif
479
593
 
480
594
  /*
481
595
    Mark the operation in progress. This blocks other threads from doing
498
612
      keycache->can_be_used= 0;
499
613
      goto finish;
500
614
    }
 
615
    DBUG_ASSERT(cache_empty(keycache));
501
616
 
502
617
    /* End the flush phase. */
503
618
    keycache->resize_in_flush= 0;
504
619
  }
505
620
 
 
621
#ifdef THREAD
506
622
  /*
507
623
    Some direct read/write operations (bypassing the cache) may still be
508
624
    unfinished. Wait until they are done. If the key cache can be used,
516
632
  */
517
633
  while (keycache->cnt_for_resize_op)
518
634
    wait_on_queue(&keycache->waiting_for_resize_cnt, &keycache->cache_lock);
 
635
#else
 
636
  KEYCACHE_DBUG_ASSERT(keycache->cnt_for_resize_op == 0);
 
637
#endif
519
638
 
520
639
  /*
521
640
    Free old cache structures, allocate new structures, and initialize
539
658
  release_whole_queue(&keycache->resize_queue);
540
659
 
541
660
  keycache_pthread_mutex_unlock(&keycache->cache_lock);
542
 
  return(blocks);
 
661
  DBUG_RETURN(blocks);
543
662
}
544
663
 
545
664
 
580
699
    age_threshold.
581
700
*/
582
701
 
583
 
void change_key_cache_param(KEY_CACHE *keycache, uint32_t division_limit,
584
 
                            uint32_t age_threshold)
 
702
void change_key_cache_param(KEY_CACHE *keycache, uint division_limit,
 
703
                            uint age_threshold)
585
704
{
 
705
  DBUG_ENTER("change_key_cache_param");
 
706
 
586
707
  keycache_pthread_mutex_lock(&keycache->cache_lock);
587
708
  if (division_limit)
588
709
    keycache->min_warm_blocks= (keycache->disk_blocks *
591
712
    keycache->age_threshold=   (keycache->disk_blocks *
592
713
                                age_threshold / 100);
593
714
  keycache_pthread_mutex_unlock(&keycache->cache_lock);
594
 
  return;
 
715
  DBUG_VOID_RETURN;
595
716
}
596
717
 
597
718
 
607
728
    none
608
729
*/
609
730
 
610
 
void end_key_cache(KEY_CACHE *keycache, bool cleanup)
 
731
void end_key_cache(KEY_CACHE *keycache, my_bool cleanup)
611
732
{
 
733
  DBUG_ENTER("end_key_cache");
 
734
  DBUG_PRINT("enter", ("key_cache: 0x%lx", (long) keycache));
 
735
 
612
736
  if (!keycache->key_cache_inited)
613
 
    return;
 
737
    DBUG_VOID_RETURN;
614
738
 
615
739
  if (keycache->disk_blocks > 0)
616
740
  {
618
742
    {
619
743
      free(keycache->block_mem);
620
744
      keycache->block_mem= NULL;
621
 
      free((unsigned char*) keycache->block_root);
 
745
      my_free((uchar*) keycache->block_root, MYF(0));
622
746
      keycache->block_root= NULL;
623
747
    }
624
748
    keycache->disk_blocks= -1;
626
750
    keycache->blocks_changed= 0;
627
751
  }
628
752
 
 
753
  DBUG_PRINT("status", ("used: %lu  changed: %lu  w_requests: %lu  "
 
754
                        "writes: %lu  r_requests: %lu  reads: %lu",
 
755
                        keycache->blocks_used, keycache->global_blocks_changed,
 
756
                        (ulong) keycache->global_cache_w_requests,
 
757
                        (ulong) keycache->global_cache_write,
 
758
                        (ulong) keycache->global_cache_r_requests,
 
759
                        (ulong) keycache->global_cache_read));
 
760
 
629
761
  if (cleanup)
630
762
  {
631
763
    pthread_mutex_destroy(&keycache->cache_lock);
632
764
    keycache->key_cache_inited= keycache->can_be_used= 0;
 
765
    KEYCACHE_DEBUG_CLOSE;
633
766
  }
634
 
  return;
 
767
  DBUG_VOID_RETURN;
635
768
} /* end_key_cache */
636
769
 
637
770
 
 
771
#ifdef THREAD
 
772
 
638
773
/*
639
774
  Link a thread into double-linked queue of waiting threads.
640
775
 
657
792
{
658
793
  struct st_my_thread_var *last;
659
794
 
660
 
  assert(!thread->next && !thread->prev);
 
795
  DBUG_ASSERT(!thread->next && !thread->prev);
661
796
  if (! (last= wqueue->last_thread))
662
797
  {
663
798
    /* Queue is empty */
692
827
static void unlink_from_queue(KEYCACHE_WQUEUE *wqueue,
693
828
                                     struct st_my_thread_var *thread)
694
829
{
695
 
  assert(thread->next && thread->prev);
 
830
  KEYCACHE_DBUG_PRINT("unlink_from_queue", ("thread %ld", thread->id));
 
831
  DBUG_ASSERT(thread->next && thread->prev);
696
832
  if (thread->next == thread)
697
833
    /* The queue contains only one member */
698
834
    wqueue->last_thread= NULL;
705
841
                                      thread->prev);
706
842
  }
707
843
  thread->next= NULL;
 
844
#if !defined(DBUG_OFF)
 
845
  /*
 
846
    This makes it easier to see it's not in a chain during debugging.
 
847
    And some DBUG_ASSERT() rely on it.
 
848
  */
708
849
  thread->prev= NULL;
 
850
#endif
709
851
}
710
852
 
711
853
 
739
881
  struct st_my_thread_var *thread= my_thread_var;
740
882
 
741
883
  /* Add to queue. */
742
 
  assert(!thread->next);
743
 
  assert(!thread->prev); /* Not required, but must be true anyway. */
 
884
  DBUG_ASSERT(!thread->next);
 
885
  DBUG_ASSERT(!thread->prev); /* Not required, but must be true anyway. */
744
886
  if (! (last= wqueue->last_thread))
745
887
    thread->next= thread;
746
888
  else
756
898
  */
757
899
  do
758
900
  {
 
901
    KEYCACHE_DBUG_PRINT("wait", ("suspend thread %ld", thread->id));
759
902
    keycache_pthread_cond_wait(&thread->suspend, mutex);
760
903
  }
761
904
  while (thread->next);
792
935
  do
793
936
  {
794
937
    thread=next;
 
938
    KEYCACHE_DBUG_PRINT("release_whole_queue: signal",
 
939
                        ("thread %ld", thread->id));
795
940
    /* Signal the thread. */
796
941
    keycache_pthread_cond_signal(&thread->suspend);
797
942
    /* Take thread from queue. */
804
949
  wqueue->last_thread= NULL;
805
950
}
806
951
 
 
952
#endif /* THREAD */
 
953
 
807
954
 
808
955
/*
809
956
  Unlink a block from the chain of dirty/clean blocks
810
957
*/
 
958
 
811
959
static inline void unlink_changed(BLOCK_LINK *block)
812
960
{
813
 
  assert(block->prev_changed && *block->prev_changed == block);
 
961
  DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
814
962
  if (block->next_changed)
815
963
    block->next_changed->prev_changed= block->prev_changed;
816
964
  *block->prev_changed= block->next_changed;
 
965
 
 
966
#if !defined(DBUG_OFF)
 
967
  /*
 
968
    This makes it easier to see it's not in a chain during debugging.
 
969
    And some DBUG_ASSERT() rely on it.
 
970
  */
817
971
  block->next_changed= NULL;
818
972
  block->prev_changed= NULL;
 
973
#endif
819
974
}
820
975
 
821
976
 
825
980
 
826
981
static inline void link_changed(BLOCK_LINK *block, BLOCK_LINK **phead)
827
982
{
828
 
  assert(!block->next_changed);
829
 
  assert(!block->prev_changed);
 
983
  DBUG_ASSERT(!block->next_changed);
 
984
  DBUG_ASSERT(!block->prev_changed);
830
985
  block->prev_changed= phead;
831
986
  if ((block->next_changed= *phead))
832
987
    (*phead)->prev_changed= &block->next_changed;
861
1016
 
862
1017
static void link_to_file_list(KEY_CACHE *keycache,
863
1018
                              BLOCK_LINK *block, int file,
864
 
                              bool unlink_block)
 
1019
                              my_bool unlink_block)
865
1020
{
866
 
  assert(block->status & BLOCK_IN_USE);
867
 
  assert(block->hash_link && block->hash_link->block == block);
868
 
  assert(block->hash_link->file == file);
 
1021
  DBUG_ASSERT(block->status & BLOCK_IN_USE);
 
1022
  DBUG_ASSERT(block->hash_link && block->hash_link->block == block);
 
1023
  DBUG_ASSERT(block->hash_link->file == file);
869
1024
  if (unlink_block)
870
1025
    unlink_changed(block);
871
1026
  link_changed(block, &keycache->file_blocks[FILE_HASH(file)]);
903
1058
static void link_to_changed_list(KEY_CACHE *keycache,
904
1059
                                 BLOCK_LINK *block)
905
1060
{
906
 
  assert(block->status & BLOCK_IN_USE);
907
 
  assert(!(block->status & BLOCK_CHANGED));
908
 
  assert(block->hash_link && block->hash_link->block == block);
 
1061
  DBUG_ASSERT(block->status & BLOCK_IN_USE);
 
1062
  DBUG_ASSERT(!(block->status & BLOCK_CHANGED));
 
1063
  DBUG_ASSERT(block->hash_link && block->hash_link->block == block);
909
1064
 
910
1065
  unlink_changed(block);
911
1066
  link_changed(block,
955
1110
    not linked in the LRU ring.
956
1111
*/
957
1112
 
958
 
static void link_block(KEY_CACHE *keycache, BLOCK_LINK *block, bool hot,
959
 
                       bool at_end)
 
1113
static void link_block(KEY_CACHE *keycache, BLOCK_LINK *block, my_bool hot,
 
1114
                       my_bool at_end)
960
1115
{
961
1116
  BLOCK_LINK *ins;
962
1117
  BLOCK_LINK **pins;
963
1118
 
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);
 
1119
  DBUG_ASSERT((block->status & ~BLOCK_CHANGED) == (BLOCK_READ | BLOCK_IN_USE));
 
1120
  DBUG_ASSERT(block->hash_link); /*backptr to block NULL from free_block()*/
 
1121
  DBUG_ASSERT(!block->requests);
 
1122
  DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
 
1123
  DBUG_ASSERT(!block->next_used);
 
1124
  DBUG_ASSERT(!block->prev_used);
 
1125
#ifdef THREAD
970
1126
  if (!hot && keycache->waiting_for_block.last_thread)
971
1127
  {
972
1128
    /* Signal that in the LRU warm sub-chain an available block has appeared */
986
1142
      */
987
1143
      if ((HASH_LINK *) thread->opt_info == hash_link)
988
1144
      {
 
1145
        KEYCACHE_DBUG_PRINT("link_block: signal", ("thread %ld", thread->id));
989
1146
        keycache_pthread_cond_signal(&thread->suspend);
990
1147
        unlink_from_queue(&keycache->waiting_for_block, thread);
991
1148
        block->requests++;
1016
1173
      probably easier to read.
1017
1174
    */
1018
1175
    block->status|= BLOCK_IN_EVICTION;
 
1176
    KEYCACHE_THREAD_TRACE("link_block: after signaling");
 
1177
#if defined(KEYCACHE_DEBUG)
 
1178
    KEYCACHE_DBUG_PRINT("link_block",
 
1179
        ("linked,unlinked block %u  status=%x  #requests=%u  #available=%u",
 
1180
         BLOCK_NUMBER(block), block->status,
 
1181
         block->requests, keycache->blocks_available));
 
1182
#endif
1019
1183
    return;
1020
1184
  }
 
1185
#else /* THREAD */
 
1186
  KEYCACHE_DBUG_ASSERT(! (!hot && keycache->waiting_for_block.last_thread));
 
1187
      /* Condition not transformed using DeMorgan, to keep the text identical */
 
1188
#endif /* THREAD */
1021
1189
  pins= hot ? &keycache->used_ins : &keycache->used_last;
1022
1190
  ins= *pins;
1023
1191
  if (ins)
1035
1203
    keycache->used_last= keycache->used_ins= block->next_used= block;
1036
1204
    block->prev_used= &block->next_used;
1037
1205
  }
 
1206
  KEYCACHE_THREAD_TRACE("link_block");
 
1207
#if defined(KEYCACHE_DEBUG)
 
1208
  keycache->blocks_available++;
 
1209
  KEYCACHE_DBUG_PRINT("link_block",
 
1210
      ("linked block %u:%1u  status=%x  #requests=%u  #available=%u",
 
1211
       BLOCK_NUMBER(block), at_end, block->status,
 
1212
       block->requests, keycache->blocks_available));
 
1213
  KEYCACHE_DBUG_ASSERT((ulong) keycache->blocks_available <=
 
1214
                       keycache->blocks_used);
 
1215
#endif
1038
1216
}
1039
1217
 
1040
1218
 
1055
1233
 
1056
1234
static void unlink_block(KEY_CACHE *keycache, BLOCK_LINK *block)
1057
1235
{
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 &&
 
1236
  DBUG_ASSERT((block->status & ~BLOCK_CHANGED) == (BLOCK_READ | BLOCK_IN_USE));
 
1237
  DBUG_ASSERT(block->hash_link); /*backptr to block NULL from free_block()*/
 
1238
  DBUG_ASSERT(!block->requests);
 
1239
  DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
 
1240
  DBUG_ASSERT(block->next_used && block->prev_used &&
1063
1241
              (block->next_used->prev_used == &block->next_used) &&
1064
1242
              (*block->prev_used == block));
1065
1243
  if (block->next_used == block)
1075
1253
      keycache->used_ins=STRUCT_PTR(BLOCK_LINK, next_used, block->prev_used);
1076
1254
  }
1077
1255
  block->next_used= NULL;
 
1256
#if !defined(DBUG_OFF)
 
1257
  /*
 
1258
    This makes it easier to see it's not in a chain during debugging.
 
1259
    And some DBUG_ASSERT() rely on it.
 
1260
  */
1078
1261
  block->prev_used= NULL;
 
1262
#endif
 
1263
 
 
1264
  KEYCACHE_THREAD_TRACE("unlink_block");
 
1265
#if defined(KEYCACHE_DEBUG)
 
1266
  KEYCACHE_DBUG_ASSERT(keycache->blocks_available != 0);
 
1267
  keycache->blocks_available--;
 
1268
  KEYCACHE_DBUG_PRINT("unlink_block",
 
1269
    ("unlinked block %u  status=%x   #requests=%u  #available=%u",
 
1270
     BLOCK_NUMBER(block), block->status,
 
1271
     block->requests, keycache->blocks_available));
 
1272
#endif
1079
1273
}
1080
1274
 
1081
1275
 
1097
1291
*/
1098
1292
static void reg_requests(KEY_CACHE *keycache, BLOCK_LINK *block, int count)
1099
1293
{
1100
 
  assert(block->status & BLOCK_IN_USE);
1101
 
  assert(block->hash_link);
 
1294
  DBUG_ASSERT(block->status & BLOCK_IN_USE);
 
1295
  DBUG_ASSERT(block->hash_link);
1102
1296
 
1103
1297
  if (!block->requests)
1104
1298
    unlink_block(keycache, block);
1121
1315
 
1122
1316
  NOTES.
1123
1317
    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
 
1318
    counter (if it's positive). If the at_end parameter is TRUE the block is
1125
1319
    added either at the end of warm sub-chain or at the end of hot sub-chain.
1126
1320
    It is added to the hot subchain if its counter is zero and number of
1127
1321
    blocks in warm sub-chain is not less than some low limit (determined by
1128
1322
    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
 
1323
    sub-chain. If the at_end parameter is FALSE the block is always added
1130
1324
    at beginning of the warm sub-chain.
1131
1325
    Thus a warm block can be promoted to the hot sub-chain when its counter
1132
1326
    becomes zero for the first time.
1141
1335
static void unreg_request(KEY_CACHE *keycache,
1142
1336
                          BLOCK_LINK *block, int at_end)
1143
1337
{
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);
 
1338
  DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
1339
  DBUG_ASSERT(block->hash_link); /*backptr to block NULL from free_block()*/
 
1340
  DBUG_ASSERT(block->requests);
 
1341
  DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
 
1342
  DBUG_ASSERT(!block->next_used);
 
1343
  DBUG_ASSERT(!block->prev_used);
1150
1344
  if (! --block->requests)
1151
1345
  {
1152
 
    bool hot;
 
1346
    my_bool hot;
1153
1347
    if (block->hits_left)
1154
1348
      block->hits_left--;
1155
1349
    hot= !block->hits_left && at_end &&
1159
1353
      if (block->temperature == BLOCK_WARM)
1160
1354
        keycache->warm_blocks--;
1161
1355
      block->temperature= BLOCK_HOT;
 
1356
      KEYCACHE_DBUG_PRINT("unreg_request", ("#warm_blocks: %lu",
 
1357
                           keycache->warm_blocks));
1162
1358
    }
1163
 
    link_block(keycache, block, hot, (bool)at_end);
 
1359
    link_block(keycache, block, hot, (my_bool)at_end);
1164
1360
    block->last_hit_time= keycache->keycache_time;
1165
1361
    keycache->keycache_time++;
1166
1362
    /*
1189
1385
        keycache->warm_blocks++;
1190
1386
        block->temperature= BLOCK_WARM;
1191
1387
      }
 
1388
      KEYCACHE_DBUG_PRINT("unreg_request", ("#warm_blocks: %lu",
 
1389
                           keycache->warm_blocks));
1192
1390
    }
1193
1391
  }
1194
1392
}
1199
1397
 
1200
1398
static void remove_reader(BLOCK_LINK *block)
1201
1399
{
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);
 
1400
  DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
1401
  DBUG_ASSERT(block->hash_link && block->hash_link->block == block);
 
1402
  DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
 
1403
  DBUG_ASSERT(!block->next_used);
 
1404
  DBUG_ASSERT(!block->prev_used);
 
1405
  DBUG_ASSERT(block->hash_link->requests);
 
1406
#ifdef THREAD
1208
1407
  if (! --block->hash_link->requests && block->condvar)
1209
1408
    keycache_pthread_cond_signal(block->condvar);
 
1409
#else
 
1410
  --block->hash_link->requests;
 
1411
#endif
1210
1412
}
1211
1413
 
1212
1414
 
1218
1420
static void wait_for_readers(KEY_CACHE *keycache,
1219
1421
                             BLOCK_LINK *block)
1220
1422
{
 
1423
#ifdef THREAD
1221
1424
  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 |
 
1425
  DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
1426
  DBUG_ASSERT(!(block->status & (BLOCK_ERROR | BLOCK_IN_FLUSH |
1224
1427
                                 BLOCK_CHANGED)));
1225
 
  assert(block->hash_link);
1226
 
  assert(block->hash_link->block == block);
 
1428
  DBUG_ASSERT(block->hash_link);
 
1429
  DBUG_ASSERT(block->hash_link->block == block);
1227
1430
  /* Linked in file_blocks or changed_blocks hash. */
1228
 
  assert(block->prev_changed && *block->prev_changed == block);
 
1431
  DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
1229
1432
  /* Not linked in LRU ring. */
1230
 
  assert(!block->next_used);
1231
 
  assert(!block->prev_used);
 
1433
  DBUG_ASSERT(!block->next_used);
 
1434
  DBUG_ASSERT(!block->prev_used);
1232
1435
  while (block->hash_link->requests)
1233
1436
  {
 
1437
    KEYCACHE_DBUG_PRINT("wait_for_readers: wait",
 
1438
                        ("suspend thread %ld  block %u",
 
1439
                         thread->id, BLOCK_NUMBER(block)));
1234
1440
    /* There must be no other waiter. We have no queue here. */
1235
 
    assert(!block->condvar);
 
1441
    DBUG_ASSERT(!block->condvar);
1236
1442
    block->condvar= &thread->suspend;
1237
1443
    keycache_pthread_cond_wait(&thread->suspend, &keycache->cache_lock);
1238
1444
    block->condvar= NULL;
1239
1445
  }
 
1446
#else
 
1447
  KEYCACHE_DBUG_ASSERT(block->hash_link->requests == 0);
 
1448
#endif
1240
1449
}
1241
1450
 
1242
1451
 
1260
1469
 
1261
1470
static void unlink_hash(KEY_CACHE *keycache, HASH_LINK *hash_link)
1262
1471
{
1263
 
  assert(hash_link->requests == 0);
 
1472
  KEYCACHE_DBUG_PRINT("unlink_hash", ("fd: %u  pos_ %lu  #requests=%u",
 
1473
      (uint) hash_link->file,(ulong) hash_link->diskpos, hash_link->requests));
 
1474
  KEYCACHE_DBUG_ASSERT(hash_link->requests == 0);
1264
1475
  if ((*hash_link->prev= hash_link->next))
1265
1476
    hash_link->next->prev= hash_link->prev;
1266
1477
  hash_link->block= NULL;
 
1478
#ifdef THREAD
1267
1479
  if (keycache->waiting_for_hash_link.last_thread)
1268
1480
  {
1269
1481
    /* Signal that a free hash link has appeared */
1288
1500
      */
1289
1501
      if (page->file == hash_link->file && page->filepos == hash_link->diskpos)
1290
1502
      {
 
1503
        KEYCACHE_DBUG_PRINT("unlink_hash: signal", ("thread %ld", thread->id));
1291
1504
        keycache_pthread_cond_signal(&thread->suspend);
1292
1505
        unlink_from_queue(&keycache->waiting_for_hash_link, thread);
1293
1506
      }
1298
1511
              hash_link);
1299
1512
    return;
1300
1513
  }
 
1514
#else /* THREAD */
 
1515
  KEYCACHE_DBUG_ASSERT(! (keycache->waiting_for_hash_link.last_thread));
 
1516
#endif /* THREAD */
1301
1517
  hash_link->next= keycache->free_hash_list;
1302
1518
  keycache->free_hash_list= hash_link;
1303
1519
}
1311
1527
                                int file, my_off_t filepos)
1312
1528
{
1313
1529
  register HASH_LINK *hash_link, **start;
 
1530
#if defined(KEYCACHE_DEBUG)
 
1531
  int cnt;
 
1532
#endif
 
1533
 
 
1534
  KEYCACHE_DBUG_PRINT("get_hash_link", ("fd: %u  pos: %lu",
 
1535
                      (uint) file,(ulong) filepos));
1314
1536
 
1315
1537
restart:
1316
1538
  /*
1319
1541
     hash_link points to the first member of the list
1320
1542
  */
1321
1543
  hash_link= *(start= &keycache->hash_root[KEYCACHE_HASH(file, filepos)]);
 
1544
#if defined(KEYCACHE_DEBUG)
 
1545
  cnt= 0;
 
1546
#endif
1322
1547
  /* Look for an element for the pair (file, filepos) in the bucket chain */
1323
1548
  while (hash_link &&
1324
1549
         (hash_link->diskpos != filepos || hash_link->file != file))
1325
1550
  {
1326
1551
    hash_link= hash_link->next;
 
1552
#if defined(KEYCACHE_DEBUG)
 
1553
    cnt++;
 
1554
    if (! (cnt <= keycache->hash_links_used))
 
1555
    {
 
1556
      int i;
 
1557
      for (i=0, hash_link= *start ;
 
1558
           i < cnt ; i++, hash_link= hash_link->next)
 
1559
      {
 
1560
        KEYCACHE_DBUG_PRINT("get_hash_link", ("fd: %u  pos: %lu",
 
1561
            (uint) hash_link->file,(ulong) hash_link->diskpos));
 
1562
      }
 
1563
    }
 
1564
    KEYCACHE_DBUG_ASSERT(cnt <= keycache->hash_links_used);
 
1565
#endif
1327
1566
  }
1328
1567
  if (! hash_link)
1329
1568
  {
1339
1578
    }
1340
1579
    else
1341
1580
    {
 
1581
#ifdef THREAD
1342
1582
      /* Wait for a free hash link */
1343
1583
      struct st_my_thread_var *thread= my_thread_var;
1344
1584
      KEYCACHE_PAGE page;
 
1585
      KEYCACHE_DBUG_PRINT("get_hash_link", ("waiting"));
1345
1586
      page.file= file;
1346
1587
      page.filepos= filepos;
1347
1588
      thread->opt_info= (void *) &page;
1348
1589
      link_into_queue(&keycache->waiting_for_hash_link, thread);
 
1590
      KEYCACHE_DBUG_PRINT("get_hash_link: wait",
 
1591
                        ("suspend thread %ld", thread->id));
1349
1592
      keycache_pthread_cond_wait(&thread->suspend,
1350
1593
                                 &keycache->cache_lock);
1351
1594
      thread->opt_info= NULL;
 
1595
#else
 
1596
      KEYCACHE_DBUG_ASSERT(0);
 
1597
#endif
1352
1598
      goto restart;
1353
1599
    }
1354
1600
    hash_link->file= file;
1408
1654
  int error= 0;
1409
1655
  int page_status;
1410
1656
 
 
1657
  DBUG_ENTER("find_key_block");
 
1658
  KEYCACHE_THREAD_TRACE("find_key_block:begin");
 
1659
  DBUG_PRINT("enter", ("fd: %d  pos: %lu  wrmode: %d",
 
1660
                       file, (ulong) filepos, wrmode));
 
1661
  KEYCACHE_DBUG_PRINT("find_key_block", ("fd: %d  pos: %lu  wrmode: %d",
 
1662
                                         file, (ulong) filepos,
 
1663
                                         wrmode));
 
1664
#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
 
1665
  DBUG_EXECUTE("check_keycache2",
 
1666
               test_key_cache(keycache, "start of find_key_block", 0););
 
1667
#endif
 
1668
 
1411
1669
restart:
1412
1670
  /*
1413
1671
    If the flush phase of a resize operation fails, the cache is left
1414
1672
    unusable. This will be detected only after "goto restart".
1415
1673
  */
1416
1674
  if (!keycache->can_be_used)
1417
 
    return(0);
 
1675
    DBUG_RETURN(0);
1418
1676
 
1419
1677
  /*
1420
1678
    Find the hash_link for the requested file block (file, filepos). We
1440
1698
          - not changed (clean).
1441
1699
  */
1442
1700
  hash_link= get_hash_link(keycache, file, filepos);
1443
 
  assert((hash_link->file == file) && (hash_link->diskpos == filepos));
 
1701
  DBUG_ASSERT((hash_link->file == file) && (hash_link->diskpos == filepos));
1444
1702
 
1445
1703
  page_status= -1;
1446
1704
  if ((block= hash_link->block) &&
1479
1737
        */
1480
1738
        hash_link->requests--;
1481
1739
        unlink_hash(keycache, hash_link);
1482
 
        return(0);
 
1740
        DBUG_RETURN(0);
1483
1741
      }
1484
1742
 
1485
1743
      /*
1498
1756
      link_into_queue(&keycache->waiting_for_block, thread);
1499
1757
      do
1500
1758
      {
 
1759
        KEYCACHE_DBUG_PRINT("find_key_block: wait",
 
1760
                            ("suspend thread %ld", thread->id));
1501
1761
        keycache_pthread_cond_wait(&thread->suspend,
1502
1762
                                   &keycache->cache_lock);
1503
1763
      } while (thread->next);
1544
1804
        only. Waiting here on COND_FOR_REQUESTED works in all
1545
1805
        situations.
1546
1806
      */
1547
 
      assert(((block->hash_link != hash_link) &&
 
1807
      DBUG_ASSERT(((block->hash_link != hash_link) &&
1548
1808
                   (block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH))) ||
1549
1809
                  ((block->hash_link == hash_link) &&
1550
1810
                   !(block->status & BLOCK_READ)));
1559
1819
        again in eviction because we registered an request on it before
1560
1820
        starting to wait.
1561
1821
      */
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)));
 
1822
      DBUG_ASSERT(block->hash_link == hash_link);
 
1823
      DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
1824
      DBUG_ASSERT(!(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH)));
1565
1825
    }
1566
1826
    /*
1567
1827
      The block is in the cache. Assigned to the hash_link. Valid data.
1573
1833
    {
1574
1834
      /* A reader can just read the block. */
1575
1835
      *page_st= PAGE_READ;
1576
 
      assert((hash_link->file == file) &&
 
1836
      DBUG_ASSERT((hash_link->file == file) &&
1577
1837
                  (hash_link->diskpos == filepos) &&
1578
1838
                  (block->hash_link == hash_link));
1579
 
      return(block);
 
1839
      DBUG_RETURN(block);
1580
1840
    }
1581
1841
 
1582
1842
    /*
1583
1843
      This is a writer. No two writers for the same block can exist.
1584
1844
      This must be assured by locks outside of the key cache.
1585
1845
    */
1586
 
    assert(!(block->status & BLOCK_FOR_UPDATE));
 
1846
    DBUG_ASSERT(!(block->status & BLOCK_FOR_UPDATE) || fail_block(block));
1587
1847
 
1588
1848
    while (block->status & BLOCK_IN_FLUSH)
1589
1849
    {
1607
1867
        unreg_request(keycache, block, 1);
1608
1868
        goto restart;
1609
1869
      }
1610
 
      assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
1611
 
      assert(!(block->status & BLOCK_FOR_UPDATE));
1612
 
      assert(block->hash_link == hash_link);
 
1870
      DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
1871
      DBUG_ASSERT(!(block->status & BLOCK_FOR_UPDATE) || fail_block(block));
 
1872
      DBUG_ASSERT(block->hash_link == hash_link);
1613
1873
    }
1614
1874
 
1615
1875
    if (block->status & BLOCK_CHANGED)
1622
1882
        not yet been selected for flush, we can still add our changes.
1623
1883
      */
1624
1884
      *page_st= PAGE_READ;
1625
 
      assert((hash_link->file == file) &&
 
1885
      DBUG_ASSERT((hash_link->file == file) &&
1626
1886
                  (hash_link->diskpos == filepos) &&
1627
1887
                  (block->hash_link == hash_link));
1628
 
      return(block);
 
1888
      DBUG_RETURN(block);
1629
1889
    }
1630
1890
 
1631
1891
    /*
1693
1953
               (block->hash_link->file == file) &&
1694
1954
               (block->hash_link->diskpos == filepos));
1695
1955
    }
1696
 
    return(0);
 
1956
    DBUG_RETURN(0);
1697
1957
  }
1698
1958
 
1699
1959
  if (page_status == PAGE_READ &&
1708
1968
      (BLOCK_IN_SWITCH), readers of the block have not finished yet
1709
1969
      (BLOCK_REASSIGNED), or the evicting thread did not yet awake after
1710
1970
      the block has been selected for it (BLOCK_IN_EVICTION).
 
1971
    */
1711
1972
 
 
1973
    KEYCACHE_DBUG_PRINT("find_key_block",
 
1974
                        ("request for old page in block %u "
 
1975
                         "wrmode: %d  block->status: %d",
 
1976
                         BLOCK_NUMBER(block), wrmode, block->status));
 
1977
    /*
1712
1978
       Only reading requests can proceed until the old dirty page is flushed,
1713
1979
       all others are to be suspended, then resubmitted
1714
1980
    */
1736
2002
        as soon as possible. Again we must wait so that we don't find
1737
2003
        the same hash_link + block again and again.
1738
2004
      */
1739
 
      assert(hash_link->requests);
 
2005
      DBUG_ASSERT(hash_link->requests);
1740
2006
      hash_link->requests--;
 
2007
      KEYCACHE_DBUG_PRINT("find_key_block",
 
2008
                          ("request waiting for old page to be saved"));
1741
2009
      wait_on_queue(&block->wqueue[COND_FOR_SAVED], &keycache->cache_lock);
 
2010
      KEYCACHE_DBUG_PRINT("find_key_block",
 
2011
                          ("request for old page resubmitted"));
1742
2012
      /*
1743
2013
        The block is no longer assigned to this hash_link.
1744
2014
        Get another one.
1773
2043
        else
1774
2044
        {
1775
2045
          /* There are some never used blocks, take first of them */
1776
 
          assert(keycache->blocks_used <
1777
 
                      (uint32_t) keycache->disk_blocks);
 
2046
          DBUG_ASSERT(keycache->blocks_used <
 
2047
                      (ulong) keycache->disk_blocks);
1778
2048
          block= &keycache->block_root[keycache->blocks_used];
1779
2049
          block->buffer= ADD_TO_PTR(keycache->block_mem,
1780
 
                                    ((uint32_t) keycache->blocks_used*
 
2050
                                    ((ulong) keycache->blocks_used*
1781
2051
                                     keycache->key_cache_block_size),
1782
 
                                    unsigned char*);
 
2052
                                    uchar*);
1783
2053
          keycache->blocks_used++;
1784
 
          assert(!block->next_used);
 
2054
          DBUG_ASSERT(!block->next_used);
1785
2055
        }
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);
 
2056
        DBUG_ASSERT(!block->prev_used);
 
2057
        DBUG_ASSERT(!block->next_changed);
 
2058
        DBUG_ASSERT(!block->prev_changed);
 
2059
        DBUG_ASSERT(!block->hash_link);
 
2060
        DBUG_ASSERT(!block->status);
 
2061
        DBUG_ASSERT(!block->requests);
1792
2062
        keycache->blocks_unused--;
1793
2063
        block->status= BLOCK_IN_USE;
1794
2064
        block->length= 0;
1801
2071
        hash_link->block= block;
1802
2072
        link_to_file_list(keycache, block, file, 0);
1803
2073
        page_status= PAGE_TO_BE_READ;
 
2074
        KEYCACHE_DBUG_PRINT("find_key_block",
 
2075
                            ("got free or never used block %u",
 
2076
                             BLOCK_NUMBER(block)));
1804
2077
      }
1805
2078
      else
1806
2079
      {
1809
2082
          from the LRU ring.
1810
2083
        */
1811
2084
 
 
2085
#ifdef THREAD
1812
2086
        if (! keycache->used_last)
1813
2087
        {
1814
2088
          /*
1828
2102
          link_into_queue(&keycache->waiting_for_block, thread);
1829
2103
          do
1830
2104
          {
 
2105
            KEYCACHE_DBUG_PRINT("find_key_block: wait",
 
2106
                                ("suspend thread %ld", thread->id));
1831
2107
            keycache_pthread_cond_wait(&thread->suspend,
1832
2108
                                       &keycache->cache_lock);
1833
2109
          }
1834
2110
          while (thread->next);
1835
2111
          thread->opt_info= NULL;
1836
2112
          /* Assert that block has a request registered. */
1837
 
          assert(hash_link->block->requests);
 
2113
          DBUG_ASSERT(hash_link->block->requests);
1838
2114
          /* Assert that block is not in LRU ring. */
1839
 
          assert(!hash_link->block->next_used);
1840
 
          assert(!hash_link->block->prev_used);
 
2115
          DBUG_ASSERT(!hash_link->block->next_used);
 
2116
          DBUG_ASSERT(!hash_link->block->prev_used);
1841
2117
        }
 
2118
#else
 
2119
        KEYCACHE_DBUG_ASSERT(keycache->used_last);
 
2120
#endif
1842
2121
        /*
1843
2122
          If we waited above, hash_link->block has been assigned by
1844
2123
          link_block(). Otherwise it is still NULL. In the latter case
1856
2135
            Register a request on the block. This unlinks it from the
1857
2136
            LRU ring and protects it against eviction.
1858
2137
          */
1859
 
          assert(!block->requests);
 
2138
          DBUG_ASSERT(!block->requests);
1860
2139
          reg_requests(keycache, block,1);
1861
2140
          /*
1862
2141
            We do not need to set block->status|= BLOCK_IN_EVICTION here
1880
2159
          /* this is a primary request for a new page */
1881
2160
          block->status|= BLOCK_IN_SWITCH;
1882
2161
 
 
2162
          KEYCACHE_DBUG_PRINT("find_key_block",
 
2163
                        ("got block %u for new page", BLOCK_NUMBER(block)));
 
2164
 
1883
2165
          if (block->status & BLOCK_CHANGED)
1884
2166
          {
1885
2167
            /* The block contains a dirty page - push it out of the cache */
1886
2168
 
 
2169
            KEYCACHE_DBUG_PRINT("find_key_block", ("block is dirty"));
1887
2170
            if (block->status & BLOCK_IN_FLUSH)
1888
2171
            {
1889
2172
              /*
1899
2182
                The block is marked BLOCK_IN_SWITCH. It should be left
1900
2183
                alone except for reading. No free, no write.
1901
2184
              */
1902
 
              assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
1903
 
              assert(!(block->status & (BLOCK_REASSIGNED |
 
2185
              DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
2186
              DBUG_ASSERT(!(block->status & (BLOCK_REASSIGNED |
1904
2187
                                             BLOCK_CHANGED |
1905
2188
                                             BLOCK_FOR_UPDATE)));
1906
2189
            }
1911
2194
                BLOCK_IN_EVICTION may be true or not. Other flags must
1912
2195
                have a fixed value.
1913
2196
              */
1914
 
              assert((block->status & ~BLOCK_IN_EVICTION) ==
 
2197
              DBUG_ASSERT((block->status & ~BLOCK_IN_EVICTION) ==
1915
2198
                          (BLOCK_READ | BLOCK_IN_SWITCH |
1916
2199
                           BLOCK_IN_FLUSH | BLOCK_IN_FLUSHWRITE |
1917
2200
                           BLOCK_CHANGED | BLOCK_IN_USE));
1918
 
              assert(block->hash_link);
 
2201
              DBUG_ASSERT(block->hash_link);
1919
2202
 
1920
2203
              keycache_pthread_mutex_unlock(&keycache->cache_lock);
1921
2204
              /*
1929
2212
              keycache_pthread_mutex_lock(&keycache->cache_lock);
1930
2213
 
1931
2214
              /* Block status must not have changed. */
1932
 
              assert((block->status & ~BLOCK_IN_EVICTION) ==
 
2215
              DBUG_ASSERT((block->status & ~BLOCK_IN_EVICTION) ==
1933
2216
                          (BLOCK_READ | BLOCK_IN_SWITCH |
1934
2217
                           BLOCK_IN_FLUSH | BLOCK_IN_FLUSHWRITE |
1935
 
                           BLOCK_CHANGED | BLOCK_IN_USE));
 
2218
                           BLOCK_CHANGED | BLOCK_IN_USE) || fail_block(block));
1936
2219
              keycache->global_cache_write++;
1937
2220
            }
1938
2221
          }
1942
2225
            The block comes from the LRU ring. It must have a hash_link
1943
2226
            assigned.
1944
2227
          */
1945
 
          assert(block->hash_link);
 
2228
          DBUG_ASSERT(block->hash_link);
1946
2229
          if (block->hash_link)
1947
2230
          {
1948
2231
            /*
1969
2252
              a page in the cache in a sweep, without yielding control)
1970
2253
            */
1971
2254
            wait_for_readers(keycache, block);
1972
 
            assert(block->hash_link && block->hash_link->block == block &&
 
2255
            DBUG_ASSERT(block->hash_link && block->hash_link->block == block &&
1973
2256
                        block->prev_changed);
1974
2257
            /* The reader must not have been a writer. */
1975
 
            assert(!(block->status & BLOCK_CHANGED));
 
2258
            DBUG_ASSERT(!(block->status & BLOCK_CHANGED));
1976
2259
 
1977
2260
            /* Wake flushers that might have found the block in between. */
1978
2261
            release_whole_queue(&block->wqueue[COND_FOR_SAVED]);
1985
2268
              and hash_link refer to each other. Hence we need to assign
1986
2269
              the hash_link first, but then we would not know if it was
1987
2270
              linked before. Hence we would not know if to unlink it. So
1988
 
              unlink it here and call link_to_file_list(..., false).
 
2271
              unlink it here and call link_to_file_list(..., FALSE).
1989
2272
            */
1990
2273
            unlink_changed(block);
1991
2274
          }
1996
2279
          link_to_file_list(keycache, block, file, 0);
1997
2280
          page_status= PAGE_TO_BE_READ;
1998
2281
 
1999
 
          assert(block->hash_link->block == block);
2000
 
          assert(hash_link->block->hash_link == hash_link);
 
2282
          KEYCACHE_DBUG_ASSERT(block->hash_link->block == block);
 
2283
          KEYCACHE_DBUG_ASSERT(hash_link->block->hash_link == hash_link);
2001
2284
        }
2002
2285
        else
2003
2286
        {
2015
2298
            attached to the same hash_link and as such destined for the
2016
2299
            same file block.
2017
2300
          */
 
2301
          KEYCACHE_DBUG_PRINT("find_key_block",
 
2302
                              ("block->hash_link: %p  hash_link: %p  "
 
2303
                               "block->status: %u", block->hash_link,
 
2304
                               hash_link, block->status ));
2018
2305
          page_status= (((block->hash_link == hash_link) &&
2019
2306
                         (block->status & BLOCK_READ)) ?
2020
2307
                        PAGE_READ : PAGE_WAIT_TO_BE_READ);
2043
2330
        Register a request on the block. This is another protection
2044
2331
        against eviction.
2045
2332
      */
2046
 
      assert(((block->hash_link != hash_link) &&
 
2333
      DBUG_ASSERT(((block->hash_link != hash_link) &&
2047
2334
                   (block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH))) ||
2048
2335
                  ((block->hash_link == hash_link) &&
2049
2336
                   !(block->status & BLOCK_READ)) ||
2050
2337
                  ((block->status & BLOCK_READ) &&
2051
2338
                   !(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH))));
2052
2339
      reg_requests(keycache, block, 1);
 
2340
      KEYCACHE_DBUG_PRINT("find_key_block",
 
2341
                          ("block->hash_link: %p  hash_link: %p  "
 
2342
                           "block->status: %u", block->hash_link,
 
2343
                           hash_link, block->status ));
2053
2344
      page_status= (((block->hash_link == hash_link) &&
2054
2345
                     (block->status & BLOCK_READ)) ?
2055
2346
                    PAGE_READ : PAGE_WAIT_TO_BE_READ);
2056
2347
    }
2057
2348
  }
2058
2349
 
2059
 
  assert(page_status != -1);
 
2350
  KEYCACHE_DBUG_ASSERT(page_status != -1);
2060
2351
  /* Same assert basically, but be very sure. */
2061
 
  assert(block);
 
2352
  KEYCACHE_DBUG_ASSERT(block);
2062
2353
  /* 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);
 
2354
  DBUG_ASSERT(block->requests);
 
2355
  DBUG_ASSERT(!block->next_used);
 
2356
  DBUG_ASSERT(!block->prev_used);
2066
2357
  /* Assert that we return the correct block. */
2067
 
  assert((page_status == PAGE_WAIT_TO_BE_READ) ||
 
2358
  DBUG_ASSERT((page_status == PAGE_WAIT_TO_BE_READ) ||
2068
2359
              ((block->hash_link->file == file) &&
2069
2360
               (block->hash_link->diskpos == filepos)));
2070
2361
  *page_st=page_status;
 
2362
  KEYCACHE_DBUG_PRINT("find_key_block",
 
2363
                      ("fd: %d  pos: %lu  block->status: %u  page_status: %d",
 
2364
                       file, (ulong) filepos, block->status,
 
2365
                       page_status));
2071
2366
 
2072
 
  return(block);
 
2367
#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
 
2368
  DBUG_EXECUTE("check_keycache2",
 
2369
               test_key_cache(keycache, "end of find_key_block",0););
 
2370
#endif
 
2371
  KEYCACHE_THREAD_TRACE("find_key_block:end");
 
2372
  DBUG_RETURN(block);
2073
2373
}
2074
2374
 
2075
2375
 
2098
2398
*/
2099
2399
 
2100
2400
static void read_block(KEY_CACHE *keycache,
2101
 
                       BLOCK_LINK *block, uint32_t read_length,
2102
 
                       uint32_t min_length, bool primary)
 
2401
                       BLOCK_LINK *block, uint read_length,
 
2402
                       uint min_length, my_bool primary)
2103
2403
{
2104
 
  uint32_t got_length;
 
2404
  uint got_length;
2105
2405
 
2106
2406
  /* On entry cache_lock is locked */
2107
2407
 
 
2408
  KEYCACHE_THREAD_TRACE("read_block");
2108
2409
  if (primary)
2109
2410
  {
2110
2411
    /*
2113
2414
      request for the block become secondary requests. For a primary
2114
2415
      request the block must be properly initialized.
2115
2416
    */
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));
 
2417
    DBUG_ASSERT(((block->status & ~BLOCK_FOR_UPDATE) == BLOCK_IN_USE) ||
 
2418
                fail_block(block));
 
2419
    DBUG_ASSERT((block->length == 0) || fail_block(block));
 
2420
    DBUG_ASSERT((block->offset == keycache->key_cache_block_size) ||
 
2421
                fail_block(block));
 
2422
    DBUG_ASSERT((block->requests > 0) || fail_block(block));
 
2423
 
 
2424
    KEYCACHE_DBUG_PRINT("read_block",
 
2425
                        ("page to be read by primary request"));
2120
2426
 
2121
2427
    keycache->global_cache_read++;
2122
2428
    /* Page is not in buffer yet, is to be read from disk */
2131
2437
      The block can now have been marked for free (in case of
2132
2438
      FLUSH_RELEASE). Otherwise the state must be unchanged.
2133
2439
    */
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));
 
2440
    DBUG_ASSERT(((block->status & ~(BLOCK_REASSIGNED |
 
2441
                                    BLOCK_FOR_UPDATE)) == BLOCK_IN_USE) ||
 
2442
                fail_block(block));
 
2443
    DBUG_ASSERT((block->length == 0) || fail_block(block));
 
2444
    DBUG_ASSERT((block->offset == keycache->key_cache_block_size) ||
 
2445
                fail_block(block));
 
2446
    DBUG_ASSERT((block->requests > 0) || fail_block(block));
2139
2447
 
2140
2448
    if (got_length < min_length)
2141
2449
      block->status|= BLOCK_ERROR;
2150
2458
        keycache->key_cache_block_size.
2151
2459
      */
2152
2460
    }
 
2461
    KEYCACHE_DBUG_PRINT("read_block",
 
2462
                        ("primary request: new page in cache"));
2153
2463
    /* Signal that all pending requests for this page now can be processed */
2154
2464
    release_whole_queue(&block->wqueue[COND_FOR_REQUESTED]);
2155
2465
  }
2164
2474
      for the requested file block nor the file and position. So we have
2165
2475
      to assert this in the caller.
2166
2476
    */
 
2477
    KEYCACHE_DBUG_PRINT("read_block",
 
2478
                      ("secondary request waiting for new page to be read"));
2167
2479
    wait_on_queue(&block->wqueue[COND_FOR_REQUESTED], &keycache->cache_lock);
 
2480
    KEYCACHE_DBUG_PRINT("read_block",
 
2481
                        ("secondary request: new page in cache"));
2168
2482
  }
2169
2483
}
2170
2484
 
2191
2505
    The function ensures that a block of data of size length from file
2192
2506
    positioned at filepos is in the buffers for some key cache blocks.
2193
2507
    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
 
2508
    if return_buffer is TRUE, it just returns the pointer to the key cache
2195
2509
    buffer with the data.
2196
2510
    Filepos must be a multiple of 'block_length', but it doesn't
2197
2511
    have to be a multiple of key_cache_block_size;
2198
2512
*/
2199
2513
 
2200
 
unsigned char *key_cache_read(KEY_CACHE *keycache,
 
2514
uchar *key_cache_read(KEY_CACHE *keycache,
2201
2515
                      File file, my_off_t filepos, int level,
2202
 
                      unsigned char *buff, uint32_t length,
2203
 
                      uint32_t block_length __attribute__((unused)),
 
2516
                      uchar *buff, uint length,
 
2517
                      uint block_length __attribute__((unused)),
2204
2518
                      int return_buffer __attribute__((unused)))
2205
2519
{
2206
 
  bool locked_and_incremented= false;
 
2520
  my_bool locked_and_incremented= FALSE;
2207
2521
  int error=0;
2208
 
  unsigned char *start= buff;
 
2522
  uchar *start= buff;
 
2523
  DBUG_ENTER("key_cache_read");
 
2524
  DBUG_PRINT("enter", ("fd: %u  pos: %lu  length: %u",
 
2525
               (uint) file, (ulong) filepos, length));
2209
2526
 
2210
2527
  if (keycache->key_cache_inited)
2211
2528
  {
2212
2529
    /* Key cache is used */
2213
2530
    register BLOCK_LINK *block;
2214
 
    uint32_t read_length;
2215
 
    uint32_t offset;
2216
 
    uint32_t status;
 
2531
    uint read_length;
 
2532
    uint offset;
 
2533
    uint status;
2217
2534
    int page_st;
2218
2535
 
2219
2536
    /*
2241
2558
      wait_on_queue(&keycache->resize_queue, &keycache->cache_lock);
2242
2559
    /* Register the I/O for the next resize. */
2243
2560
    inc_counter_for_resize_op(keycache);
2244
 
    locked_and_incremented= true;
 
2561
    locked_and_incremented= TRUE;
2245
2562
    /* Requested data may not always be aligned to cache blocks. */
2246
2563
    offset= (uint) (filepos % keycache->key_cache_block_size);
2247
2564
    /* Read data in key_cache_block_size increments */
2256
2573
      /* Do not read beyond the end of the cache block. */
2257
2574
      read_length= length;
2258
2575
      set_if_smaller(read_length, keycache->key_cache_block_size-offset);
2259
 
      assert(read_length > 0);
 
2576
      KEYCACHE_DBUG_ASSERT(read_length > 0);
 
2577
 
 
2578
#ifndef THREAD
 
2579
      if (block_length > keycache->key_cache_block_size || offset)
 
2580
        return_buffer=0;
 
2581
#endif
2260
2582
 
2261
2583
      /* Request the cache block that matches file/pos. */
2262
2584
      keycache->global_cache_r_requests++;
2270
2592
        */
2271
2593
        keycache->global_cache_read++;
2272
2594
        keycache_pthread_mutex_unlock(&keycache->cache_lock);
2273
 
        error= (pread(file, (unsigned char*) buff, read_length, filepos + offset) == 0);
 
2595
        error= (pread(file, (uchar*) buff, read_length, filepos + offset) == 0);
2274
2596
        keycache_pthread_mutex_lock(&keycache->cache_lock);
2275
2597
        goto next_block;
2276
2598
      }
2281
2603
          /* The requested page is to be read into the block buffer */
2282
2604
          read_block(keycache, block,
2283
2605
                     keycache->key_cache_block_size, read_length+offset,
2284
 
                     (bool)(page_st == PAGE_TO_BE_READ));
 
2606
                     (my_bool)(page_st == PAGE_TO_BE_READ));
2285
2607
          /*
2286
2608
            A secondary request must now have the block assigned to the
2287
2609
            requested file block. It does not hurt to check it for
2288
2610
            primary requests too.
2289
2611
          */
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));
 
2612
          DBUG_ASSERT(keycache->can_be_used);
 
2613
          DBUG_ASSERT(block->hash_link->file == file);
 
2614
          DBUG_ASSERT(block->hash_link->diskpos == filepos);
 
2615
          DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
2294
2616
        }
2295
2617
        else if (block->length < read_length + offset)
2296
2618
        {
2307
2629
      /* block status may have added BLOCK_ERROR in the above 'if'. */
2308
2630
      if (!((status= block->status) & BLOCK_ERROR))
2309
2631
      {
 
2632
#ifndef THREAD
 
2633
        if (! return_buffer)
 
2634
#endif
2310
2635
        {
2311
 
          assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
2636
          DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
2312
2637
#if !defined(SERIALIZED_READ_FROM_CACHE)
2313
2638
          keycache_pthread_mutex_unlock(&keycache->cache_lock);
2314
2639
#endif
2315
2640
 
2316
2641
          /* Copy data from the cache buffer */
2317
 
          memcpy(buff, block->buffer+offset, (size_t) read_length);
 
2642
          if (!(read_length & 511))
 
2643
            bmove512(buff, block->buffer+offset, read_length);
 
2644
          else
 
2645
            memcpy(buff, block->buffer+offset, (size_t) read_length);
2318
2646
 
2319
2647
#if !defined(SERIALIZED_READ_FROM_CACHE)
2320
2648
          keycache_pthread_mutex_lock(&keycache->cache_lock);
2321
 
          assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
2649
          DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
2322
2650
#endif
2323
2651
        }
2324
2652
      }
2337
2665
        break;
2338
2666
      }
2339
2667
 
 
2668
#ifndef THREAD
 
2669
      /* This is only true if we where able to read everything in one block */
 
2670
      if (return_buffer)
 
2671
        DBUG_RETURN(block->buffer);
 
2672
#endif
2340
2673
  next_block:
2341
2674
      buff+= read_length;
2342
2675
      filepos+= read_length+offset;
2354
2687
 
2355
2688
  if (locked_and_incremented)
2356
2689
    keycache_pthread_mutex_unlock(&keycache->cache_lock);
2357
 
  if (pread(file, (unsigned char*) buff, length, filepos))
 
2690
  if (pread(file, (uchar*) buff, length, filepos))
2358
2691
    error= 1;
2359
2692
  if (locked_and_incremented)
2360
2693
    keycache_pthread_mutex_lock(&keycache->cache_lock);
2365
2698
    dec_counter_for_resize_op(keycache);
2366
2699
    keycache_pthread_mutex_unlock(&keycache->cache_lock);
2367
2700
  }
2368
 
  return(error ? (unsigned char*) 0 : start);
 
2701
  DBUG_RETURN(error ? (uchar*) 0 : start);
2369
2702
}
2370
2703
 
2371
2704
 
2391
2724
 
2392
2725
int key_cache_insert(KEY_CACHE *keycache,
2393
2726
                     File file, my_off_t filepos, int level,
2394
 
                     unsigned char *buff, uint32_t length)
 
2727
                     uchar *buff, uint length)
2395
2728
{
2396
2729
  int error= 0;
 
2730
  DBUG_ENTER("key_cache_insert");
 
2731
  DBUG_PRINT("enter", ("fd: %u  pos: %lu  length: %u",
 
2732
               (uint) file,(ulong) filepos, length));
2397
2733
 
2398
2734
  if (keycache->key_cache_inited)
2399
2735
  {
2400
2736
    /* Key cache is used */
2401
2737
    register BLOCK_LINK *block;
2402
 
    uint32_t read_length;
2403
 
    uint32_t offset;
 
2738
    uint read_length;
 
2739
    uint offset;
2404
2740
    int page_st;
2405
 
    bool locked_and_incremented= false;
 
2741
    my_bool locked_and_incremented= FALSE;
2406
2742
 
2407
2743
    /*
2408
2744
      When the keycache is once initialized, we use the cache_lock to
2419
2755
        goto no_key_cache;
2420
2756
    /* Register the pseudo I/O for the next resize. */
2421
2757
    inc_counter_for_resize_op(keycache);
2422
 
    locked_and_incremented= true;
 
2758
    locked_and_incremented= TRUE;
2423
2759
    /* Loaded data may not always be aligned to cache blocks. */
2424
2760
    offset= (uint) (filepos % keycache->key_cache_block_size);
2425
2761
    /* Load data in key_cache_block_size increments. */
2433
2769
      /* Do not load beyond the end of the cache block. */
2434
2770
      read_length= length;
2435
2771
      set_if_smaller(read_length, keycache->key_cache_block_size-offset);
2436
 
      assert(read_length > 0);
 
2772
      KEYCACHE_DBUG_ASSERT(read_length > 0);
2437
2773
 
2438
2774
      /* The block has been read by the caller already. */
2439
2775
      keycache->global_cache_read++;
2464
2800
            hash_link). So we cannot call remove_reader() on the block.
2465
2801
            And we cannot access the hash_link directly here. We need to
2466
2802
            wait until the assignment is complete. read_block() executes
2467
 
            the correct wait when called with primary == false.
 
2803
            the correct wait when called with primary == FALSE.
2468
2804
 
2469
2805
            Or
2470
2806
 
2489
2825
            requested file block. It does not hurt to check it for
2490
2826
            primary requests too.
2491
2827
          */
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));
 
2828
          DBUG_ASSERT(keycache->can_be_used);
 
2829
          DBUG_ASSERT(block->hash_link->file == file);
 
2830
          DBUG_ASSERT(block->hash_link->diskpos == filepos);
 
2831
          DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
2496
2832
        }
2497
2833
        else if (page_st == PAGE_TO_BE_READ)
2498
2834
        {
2500
2836
            This is a new block in the cache. If we come here, we have
2501
2837
            data for the whole block.
2502
2838
          */
2503
 
          assert(block->hash_link->requests);
2504
 
          assert(block->status & BLOCK_IN_USE);
2505
 
          assert((page_st == PAGE_TO_BE_READ) ||
 
2839
          DBUG_ASSERT(block->hash_link->requests);
 
2840
          DBUG_ASSERT(block->status & BLOCK_IN_USE);
 
2841
          DBUG_ASSERT((page_st == PAGE_TO_BE_READ) ||
2506
2842
                      (block->status & BLOCK_READ));
2507
2843
 
2508
2844
#if !defined(SERIALIZED_READ_FROM_CACHE)
2514
2850
#endif
2515
2851
 
2516
2852
          /* Copy data from buff */
2517
 
          memcpy(block->buffer+offset, buff, (size_t) read_length);
 
2853
          if (!(read_length & 511))
 
2854
            bmove512(block->buffer+offset, buff, read_length);
 
2855
          else
 
2856
            memcpy(block->buffer+offset, buff, (size_t) read_length);
2518
2857
 
2519
2858
#if !defined(SERIALIZED_READ_FROM_CACHE)
2520
2859
          keycache_pthread_mutex_lock(&keycache->cache_lock);
2521
 
          assert(block->status & BLOCK_IN_USE);
2522
 
          assert((page_st == PAGE_TO_BE_READ) ||
 
2860
          DBUG_ASSERT(block->status & BLOCK_IN_USE);
 
2861
          DBUG_ASSERT((page_st == PAGE_TO_BE_READ) ||
2523
2862
                      (block->status & BLOCK_READ));
2524
2863
#endif
2525
2864
          /*
2536
2875
            only a writer may set block->offset down from
2537
2876
            keycache->key_cache_block_size.
2538
2877
          */
 
2878
          KEYCACHE_DBUG_PRINT("key_cache_insert",
 
2879
                              ("primary request: new page in cache"));
2539
2880
          /* Signal all pending requests. */
2540
2881
          release_whole_queue(&block->wqueue[COND_FOR_REQUESTED]);
2541
2882
        }
2551
2892
            with the new data. If the condition is met, we can simply
2552
2893
            ignore the block.
2553
2894
          */
2554
 
          assert((page_st == PAGE_READ) &&
 
2895
          DBUG_ASSERT((page_st == PAGE_READ) &&
2555
2896
                      (read_length + offset <= block->length));
2556
2897
        }
2557
2898
 
2560
2901
          requested file block. It does not hurt to check it for primary
2561
2902
          requests too.
2562
2903
        */
2563
 
        assert(block->hash_link->file == file);
2564
 
        assert(block->hash_link->diskpos == filepos);
2565
 
        assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
2904
        DBUG_ASSERT(block->hash_link->file == file);
 
2905
        DBUG_ASSERT(block->hash_link->diskpos == filepos);
 
2906
        DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
2566
2907
      } /* end of if (!(block->status & BLOCK_ERROR)) */
2567
2908
 
2568
2909
 
2590
2931
      dec_counter_for_resize_op(keycache);
2591
2932
    keycache_pthread_mutex_unlock(&keycache->cache_lock);
2592
2933
  }
2593
 
  return(error);
 
2934
  DBUG_RETURN(error);
2594
2935
}
2595
2936
 
2596
2937
 
2616
2957
    The function copies the data of size length from buff into buffers
2617
2958
    for key cache blocks that are  assigned to contain the portion of
2618
2959
    the file starting with position filepos.
2619
 
    It ensures that this data is flushed to the file if dont_write is false.
 
2960
    It ensures that this data is flushed to the file if dont_write is FALSE.
2620
2961
    Filepos must be a multiple of 'block_length', but it doesn't
2621
2962
    have to be a multiple of key_cache_block_size;
2622
2963
 
2623
 
    dont_write is always true in the server (info->lock_type is never F_UNLCK).
 
2964
    dont_write is always TRUE in the server (info->lock_type is never F_UNLCK).
2624
2965
*/
2625
2966
 
2626
2967
int key_cache_write(KEY_CACHE *keycache,
2627
2968
                    File file, my_off_t filepos, int level,
2628
 
                    unsigned char *buff, uint32_t length,
2629
 
                    uint32_t block_length  __attribute__((unused)),
 
2969
                    uchar *buff, uint length,
 
2970
                    uint block_length  __attribute__((unused)),
2630
2971
                    int dont_write)
2631
2972
{
2632
 
  bool locked_and_incremented= false;
 
2973
  my_bool locked_and_incremented= FALSE;
2633
2974
  int error=0;
 
2975
  DBUG_ENTER("key_cache_write");
 
2976
  DBUG_PRINT("enter",
 
2977
             ("fd: %u  pos: %lu  length: %u  block_length: %u"
 
2978
              "  key_block_length: %u",
 
2979
              (uint) file, (ulong) filepos, length, block_length,
 
2980
              keycache ? keycache->key_cache_block_size : 0));
2634
2981
 
2635
2982
  if (!dont_write)
2636
2983
  {
2640
2987
    keycache->global_cache_w_requests++;
2641
2988
    keycache->global_cache_write++;
2642
2989
    if (pwrite(file, buff, length, filepos) == 0)
2643
 
      return(1);
 
2990
      DBUG_RETURN(1);
2644
2991
    /* purecov: end */
2645
2992
  }
2646
2993
 
 
2994
#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
 
2995
  DBUG_EXECUTE("check_keycache",
 
2996
               test_key_cache(keycache, "start of key_cache_write", 1););
 
2997
#endif
 
2998
 
2647
2999
  if (keycache->key_cache_inited)
2648
3000
  {
2649
3001
    /* Key cache is used */
2650
3002
    register BLOCK_LINK *block;
2651
 
    uint32_t read_length;
2652
 
    uint32_t offset;
 
3003
    uint read_length;
 
3004
    uint offset;
2653
3005
    int page_st;
2654
3006
 
2655
3007
    /*
2678
3030
      wait_on_queue(&keycache->resize_queue, &keycache->cache_lock);
2679
3031
    /* Register the I/O for the next resize. */
2680
3032
    inc_counter_for_resize_op(keycache);
2681
 
    locked_and_incremented= true;
 
3033
    locked_and_incremented= TRUE;
2682
3034
    /* Requested data may not always be aligned to cache blocks. */
2683
3035
    offset= (uint) (filepos % keycache->key_cache_block_size);
2684
3036
    /* Write data in key_cache_block_size increments. */
2692
3044
      /* Do not write beyond the end of the cache block. */
2693
3045
      read_length= length;
2694
3046
      set_if_smaller(read_length, keycache->key_cache_block_size-offset);
2695
 
      assert(read_length > 0);
 
3047
      KEYCACHE_DBUG_ASSERT(read_length > 0);
2696
3048
 
2697
3049
      /* Request the cache block that matches file/pos. */
2698
3050
      keycache->global_cache_w_requests++;
2709
3061
          /* Used in the server. */
2710
3062
          keycache->global_cache_write++;
2711
3063
          keycache_pthread_mutex_unlock(&keycache->cache_lock);
2712
 
          if (pwrite(file, (unsigned char*) buff, read_length, filepos + offset) == 0)
 
3064
          if (pwrite(file, (uchar*) buff, read_length, filepos + offset) == 0)
2713
3065
            error=1;
2714
3066
          keycache_pthread_mutex_lock(&keycache->cache_lock);
2715
3067
        }
2744
3096
                   offset + read_length >= keycache->key_cache_block_size?
2745
3097
                   offset : keycache->key_cache_block_size,
2746
3098
                   offset, (page_st == PAGE_TO_BE_READ));
2747
 
        assert(keycache->can_be_used);
2748
 
        assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
 
3099
        DBUG_ASSERT(keycache->can_be_used);
 
3100
        DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
2749
3101
        /*
2750
3102
          Prevent block from flushing and from being selected for to be
2751
3103
          freed. This must be set when we release the cache_lock.
2757
3109
        The block should always be assigned to the requested file block
2758
3110
        here. It need not be BLOCK_READ when overwriting the whole block.
2759
3111
      */
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));
 
3112
      DBUG_ASSERT(block->hash_link->file == file);
 
3113
      DBUG_ASSERT(block->hash_link->diskpos == filepos);
 
3114
      DBUG_ASSERT(block->status & BLOCK_IN_USE);
 
3115
      DBUG_ASSERT((page_st == PAGE_TO_BE_READ) || (block->status & BLOCK_READ));
2764
3116
      /*
2765
3117
        The block to be written must not be marked BLOCK_REASSIGNED.
2766
3118
        Otherwise it could be freed in dirty state or reused without
2769
3121
        the flusher could clear BLOCK_CHANGED without flushing the
2770
3122
        new changes again.
2771
3123
      */
2772
 
      assert(!(block->status & BLOCK_REASSIGNED));
 
3124
      DBUG_ASSERT(!(block->status & BLOCK_REASSIGNED));
2773
3125
 
2774
3126
      while (block->status & BLOCK_IN_FLUSHWRITE)
2775
3127
      {
2783
3135
          another hash_link until we release our request on it.
2784
3136
        */
2785
3137
        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));
 
3138
        DBUG_ASSERT(keycache->can_be_used);
 
3139
        DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
2788
3140
        /* Still must not be marked for free. */
2789
 
        assert(!(block->status & BLOCK_REASSIGNED));
2790
 
        assert(block->hash_link && (block->hash_link->block == block));
 
3141
        DBUG_ASSERT(!(block->status & BLOCK_REASSIGNED));
 
3142
        DBUG_ASSERT(block->hash_link && (block->hash_link->block == block));
2791
3143
      }
2792
3144
 
2793
3145
      /*
2804
3156
#if !defined(SERIALIZED_READ_FROM_CACHE)
2805
3157
        keycache_pthread_mutex_unlock(&keycache->cache_lock);
2806
3158
#endif
2807
 
        memcpy(block->buffer+offset, buff, (size_t) read_length);
 
3159
        if (!(read_length & 511))
 
3160
          bmove512(block->buffer+offset, buff, read_length);
 
3161
        else
 
3162
          memcpy(block->buffer+offset, buff, (size_t) read_length);
2808
3163
 
2809
3164
#if !defined(SERIALIZED_READ_FROM_CACHE)
2810
3165
        keycache_pthread_mutex_lock(&keycache->cache_lock);
2873
3228
    keycache->global_cache_write++;
2874
3229
    if (locked_and_incremented)
2875
3230
      keycache_pthread_mutex_unlock(&keycache->cache_lock);
2876
 
    if (pwrite(file, (unsigned char*) buff, length, filepos) == 0)
 
3231
    if (pwrite(file, (uchar*) buff, length, filepos) == 0)
2877
3232
      error=1;
2878
3233
    if (locked_and_incremented)
2879
3234
      keycache_pthread_mutex_lock(&keycache->cache_lock);
2885
3240
    dec_counter_for_resize_op(keycache);
2886
3241
    keycache_pthread_mutex_unlock(&keycache->cache_lock);
2887
3242
  }
2888
 
  return(error);
 
3243
#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
 
3244
  DBUG_EXECUTE("exec",
 
3245
               test_key_cache(keycache, "end of key_cache_write", 1););
 
3246
#endif
 
3247
  DBUG_RETURN(error);
2889
3248
}
2890
3249
 
2891
3250
 
2918
3277
 
2919
3278
static void free_block(KEY_CACHE *keycache, BLOCK_LINK *block)
2920
3279
{
 
3280
  KEYCACHE_THREAD_TRACE("free block");
 
3281
  KEYCACHE_DBUG_PRINT("free_block",
 
3282
                      ("block %u to be freed, hash_link %p",
 
3283
                       BLOCK_NUMBER(block), block->hash_link));
2921
3284
  /*
2922
3285
    Assert that the block is not free already. And that it is in a clean
2923
3286
    state. Note that the block might just be assigned to a hash_link and
2925
3288
    is registered in the hash_link and free_block() will wait for it
2926
3289
    below.
2927
3290
  */
2928
 
  assert((block->status & BLOCK_IN_USE) &&
 
3291
  DBUG_ASSERT((block->status & BLOCK_IN_USE) &&
2929
3292
              !(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH |
2930
3293
                                 BLOCK_REASSIGNED | BLOCK_IN_FLUSH |
2931
3294
                                 BLOCK_CHANGED | BLOCK_FOR_UPDATE)));
2932
3295
  /* Assert that the block is in a file_blocks chain. */
2933
 
  assert(block->prev_changed && *block->prev_changed == block);
 
3296
  DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
2934
3297
  /* Assert that the block is not in the LRU ring. */
2935
 
  assert(!block->next_used && !block->prev_used);
 
3298
  DBUG_ASSERT(!block->next_used && !block->prev_used);
2936
3299
  /*
2937
3300
    IMHO the below condition (if()) makes no sense. I can't see how it
2938
3301
    could be possible that free_block() is entered with a NULL hash_link
2939
3302
    pointer. The only place where it can become NULL is in free_block()
2940
3303
    (or before its first use ever, but for those blocks free_block() is
2941
3304
    not called). I don't remove the conditional as it cannot harm, but
2942
 
    place an assert to confirm my hypothesis. Eventually the
 
3305
    place an DBUG_ASSERT to confirm my hypothesis. Eventually the
2943
3306
    condition (if()) can be removed.
2944
3307
  */
2945
 
  assert(block->hash_link && block->hash_link->block == block);
 
3308
  DBUG_ASSERT(block->hash_link && block->hash_link->block == block);
2946
3309
  if (block->hash_link)
2947
3310
  {
2948
3311
    /*
2958
3321
      checks. An additional requirement is that it must be read now
2959
3322
      (BLOCK_READ).
2960
3323
    */
2961
 
    assert(block->hash_link && block->hash_link->block == block);
2962
 
    assert((block->status & (BLOCK_READ | BLOCK_IN_USE |
 
3324
    DBUG_ASSERT(block->hash_link && block->hash_link->block == block);
 
3325
    DBUG_ASSERT((block->status & (BLOCK_READ | BLOCK_IN_USE |
2963
3326
                                  BLOCK_REASSIGNED)) &&
2964
3327
                !(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH |
2965
3328
                                   BLOCK_IN_FLUSH | BLOCK_CHANGED |
2966
3329
                                   BLOCK_FOR_UPDATE)));
2967
 
    assert(block->prev_changed && *block->prev_changed == block);
2968
 
    assert(!block->prev_used);
 
3330
    DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
 
3331
    DBUG_ASSERT(!block->prev_used);
2969
3332
    /*
2970
3333
      Unset BLOCK_REASSIGNED again. If we hand the block to an evicting
2971
3334
      thread (through unreg_request() below), other threads must not see
2988
3351
    operation in this case. Assert that there are no other requests
2989
3352
    registered.
2990
3353
  */
2991
 
  assert(block->requests == 1);
 
3354
  DBUG_ASSERT(block->requests == 1);
2992
3355
  unreg_request(keycache, block, 0);
2993
3356
  /*
2994
3357
    Note that even without releasing the cache lock it is possible that
3000
3363
    return;
3001
3364
 
3002
3365
  /* Here the block must be in the LRU ring. Unlink it again. */
3003
 
  assert(block->next_used && block->prev_used &&
 
3366
  DBUG_ASSERT(block->next_used && block->prev_used &&
3004
3367
              *block->prev_used == block);
3005
3368
  unlink_block(keycache, block);
3006
3369
  if (block->temperature == BLOCK_WARM)
3017
3380
  block->status= 0;
3018
3381
  block->length= 0;
3019
3382
  block->offset= keycache->key_cache_block_size;
 
3383
  KEYCACHE_THREAD_TRACE("free block");
 
3384
  KEYCACHE_DBUG_PRINT("free_block", ("block is freed"));
3020
3385
 
3021
3386
  /* Enforced by unlink_changed(), but just to be sure. */
3022
 
  assert(!block->next_changed && !block->prev_changed);
 
3387
  DBUG_ASSERT(!block->next_changed && !block->prev_changed);
3023
3388
  /* Enforced by unlink_block(): not in LRU ring nor in free_block_list. */
3024
 
  assert(!block->next_used && !block->prev_used);
 
3389
  DBUG_ASSERT(!block->next_used && !block->prev_used);
3025
3390
  /* Insert the free block in the free list. */
3026
3391
  block->next_used= keycache->free_block_list;
3027
3392
  keycache->free_block_list= block;
3052
3417
{
3053
3418
  int error;
3054
3419
  int last_errno= 0;
3055
 
  uint32_t count= (uint) (end-cache);
 
3420
  uint count= (uint) (end-cache);
3056
3421
 
3057
3422
  /* Don't lock the cache during the flush */
3058
3423
  keycache_pthread_mutex_unlock(&keycache->cache_lock);
3060
3425
     As all blocks referred in 'cache' are marked by BLOCK_IN_FLUSH
3061
3426
     we are guarunteed no thread will change them
3062
3427
  */
3063
 
  my_qsort((unsigned char*) cache, count, sizeof(*cache), (qsort_cmp) cmp_sec_link);
 
3428
  my_qsort((uchar*) cache, count, sizeof(*cache), (qsort_cmp) cmp_sec_link);
3064
3429
 
3065
3430
  keycache_pthread_mutex_lock(&keycache->cache_lock);
3066
3431
  /*
3071
3436
  for ( ; cache != end ; cache++)
3072
3437
  {
3073
3438
    BLOCK_LINK *block= *cache;
 
3439
 
 
3440
    KEYCACHE_DBUG_PRINT("flush_cached_blocks",
 
3441
                        ("block %u to be flushed", BLOCK_NUMBER(block)));
3074
3442
    /*
3075
3443
      If the block contents is going to be changed, we abandon the flush
3076
3444
      for this block. flush_key_blocks_int() will restart its search and
3079
3447
    if (!(block->status & BLOCK_FOR_UPDATE))
3080
3448
    {
3081
3449
      /* 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) ==
 
3450
      DBUG_ASSERT(block->hash_link);
 
3451
      DBUG_ASSERT(block->hash_link->block == block);
 
3452
      DBUG_ASSERT(block->hash_link->file == file);
 
3453
      DBUG_ASSERT((block->status & ~BLOCK_IN_EVICTION) ==
3086
3454
                  (BLOCK_READ | BLOCK_IN_FLUSH | BLOCK_CHANGED | BLOCK_IN_USE));
3087
3455
      block->status|= BLOCK_IN_FLUSHWRITE;
3088
3456
      keycache_pthread_mutex_unlock(&keycache->cache_lock);
3100
3468
      }
3101
3469
      block->status&= ~BLOCK_IN_FLUSHWRITE;
3102
3470
      /* 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)) ==
 
3471
      DBUG_ASSERT(block->hash_link);
 
3472
      DBUG_ASSERT(block->hash_link->block == block);
 
3473
      DBUG_ASSERT(block->hash_link->file == file);
 
3474
      DBUG_ASSERT((block->status & ~(BLOCK_FOR_UPDATE | BLOCK_IN_EVICTION)) ==
3107
3475
                  (BLOCK_READ | BLOCK_IN_FLUSH | BLOCK_CHANGED | BLOCK_IN_USE));
3108
3476
      /*
3109
3477
        Set correct status and link in right queue for free or later use.
3177
3545
  BLOCK_LINK *cache_buff[FLUSH_CACHE],**cache;
3178
3546
  int last_errno= 0;
3179
3547
  int last_errcnt= 0;
 
3548
  DBUG_ENTER("flush_key_blocks_int");
 
3549
  DBUG_PRINT("enter",("file: %d  blocks_used: %lu  blocks_changed: %lu",
 
3550
              file, keycache->blocks_used, keycache->blocks_changed));
 
3551
 
 
3552
#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
 
3553
    DBUG_EXECUTE("check_keycache",
 
3554
                 test_key_cache(keycache, "start of flush_key_blocks", 0););
 
3555
#endif
3180
3556
 
3181
3557
  cache= cache_buff;
3182
3558
  if (keycache->disk_blocks > 0 &&
3184
3560
  {
3185
3561
    /* Key cache exists and flush is not disabled */
3186
3562
    int error= 0;
3187
 
    uint32_t count= FLUSH_CACHE;
 
3563
    uint count= FLUSH_CACHE;
3188
3564
    BLOCK_LINK **pos,**end;
3189
3565
    BLOCK_LINK *first_in_switch= NULL;
3190
3566
    BLOCK_LINK *last_in_flush;
3191
3567
    BLOCK_LINK *last_for_update;
3192
3568
    BLOCK_LINK *block, *next;
 
3569
#if defined(KEYCACHE_DEBUG)
 
3570
    uint cnt=0;
 
3571
#endif
3193
3572
 
3194
3573
    if (type != FLUSH_IGNORE_CHANGED)
3195
3574
    {
3206
3585
            !(block->status & BLOCK_IN_FLUSH))
3207
3586
        {
3208
3587
          count++;
3209
 
          assert(count<= keycache->blocks_used);
 
3588
          KEYCACHE_DBUG_ASSERT(count<= keycache->blocks_used);
3210
3589
        }
3211
3590
      }
3212
3591
      /*
3235
3614
         block ;
3236
3615
         block= next)
3237
3616
    {
 
3617
#if defined(KEYCACHE_DEBUG)
 
3618
      cnt++;
 
3619
      KEYCACHE_DBUG_ASSERT(cnt <= keycache->blocks_used);
 
3620
#endif
3238
3621
      next= block->next_changed;
3239
3622
      if (block->hash_link->file == file)
3240
3623
      {
3298
3681
            else
3299
3682
            {
3300
3683
              /* It's a temporary file */
3301
 
              assert(!(block->status & BLOCK_REASSIGNED));
 
3684
              DBUG_ASSERT(!(block->status & BLOCK_REASSIGNED));
3302
3685
 
3303
3686
              /*
3304
3687
                free_block() must not be called with BLOCK_CHANGED. Note
3419
3802
    */
3420
3803
    while (first_in_switch)
3421
3804
    {
 
3805
#if defined(KEYCACHE_DEBUG)
 
3806
      cnt= 0;
 
3807
#endif
3422
3808
      wait_on_queue(&first_in_switch->wqueue[COND_FOR_SAVED],
3423
3809
                    &keycache->cache_lock);
 
3810
#if defined(KEYCACHE_DEBUG)
 
3811
      cnt++;
 
3812
      KEYCACHE_DBUG_ASSERT(cnt <= keycache->blocks_used);
 
3813
#endif
3424
3814
      /*
3425
3815
        Do not restart here. We have flushed all blocks that were
3426
3816
        changed when entering this function and were not marked for
3433
3823
    {
3434
3824
      BLOCK_LINK *last_for_update= NULL;
3435
3825
      BLOCK_LINK *last_in_switch= NULL;
3436
 
      uint32_t total_found= 0;
3437
 
      uint32_t found;
 
3826
      uint total_found= 0;
 
3827
      uint found;
3438
3828
 
3439
3829
      /*
3440
3830
        Finally free all clean blocks for this file.
3451
3841
          next= block->next_changed;
3452
3842
 
3453
3843
          /* Changed blocks cannot appear in the file_blocks hash. */
3454
 
          assert(!(block->status & BLOCK_CHANGED));
 
3844
          DBUG_ASSERT(!(block->status & BLOCK_CHANGED));
3455
3845
          if (block->hash_link->file == file)
3456
3846
          {
3457
3847
            /* We must skip blocks that will be changed. */
3469
3859
            if (!(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH |
3470
3860
                                   BLOCK_REASSIGNED)))
3471
3861
            {
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;
 
3862
              struct st_hash_link *next_hash_link;
 
3863
              my_off_t            next_diskpos;
 
3864
              File                next_file;
 
3865
              uint                next_status;
 
3866
              uint                hash_requests;
3477
3867
 
3478
3868
              total_found++;
3479
3869
              found++;
3480
 
              assert(found <= keycache->blocks_used);
 
3870
              KEYCACHE_DBUG_ASSERT(found <= keycache->blocks_used);
3481
3871
 
3482
3872
              /*
3483
3873
                Register a request. This unlinks the block from the LRU
3499
3889
                next_hash_link= next->hash_link;
3500
3890
                next_diskpos=   next_hash_link->diskpos;
3501
3891
                next_file=      next_hash_link->file;
3502
 
                assert(next == next_hash_link->block);
 
3892
                DBUG_ASSERT(next == next_hash_link->block);
3503
3893
              }
3504
3894
 
3505
3895
              free_block(keycache, block);
3546
3936
      if (last_for_update)
3547
3937
      {
3548
3938
        /* We did not wait. Block must not have changed status. */
3549
 
        assert(last_for_update->status & BLOCK_FOR_UPDATE);
 
3939
        DBUG_ASSERT(last_for_update->status & BLOCK_FOR_UPDATE);
3550
3940
        wait_on_queue(&last_for_update->wqueue[COND_FOR_REQUESTED],
3551
3941
                      &keycache->cache_lock);
3552
3942
        goto restart;
3559
3949
      if (last_in_switch)
3560
3950
      {
3561
3951
        /* We did not wait. Block must not have changed status. */
3562
 
        assert(last_in_switch->status & (BLOCK_IN_EVICTION |
 
3952
        DBUG_ASSERT(last_in_switch->status & (BLOCK_IN_EVICTION |
3563
3953
                                              BLOCK_IN_SWITCH |
3564
3954
                                              BLOCK_REASSIGNED));
3565
3955
        wait_on_queue(&last_in_switch->wqueue[COND_FOR_SAVED],
3571
3961
 
3572
3962
  } /* if (keycache->disk_blocks > 0 */
3573
3963
 
 
3964
#ifndef DBUG_OFF
 
3965
  DBUG_EXECUTE("check_keycache",
 
3966
               test_key_cache(keycache, "end of flush_key_blocks", 0););
 
3967
#endif
3574
3968
err:
3575
3969
  if (cache != cache_buff)
3576
 
    free((unsigned char*) cache);
 
3970
    my_free((uchar*) cache, MYF(0));
3577
3971
  if (last_errno)
3578
3972
    errno=last_errno;                /* Return first error */
3579
 
  return(last_errno != 0);
 
3973
  DBUG_RETURN(last_errno != 0);
3580
3974
}
3581
3975
 
3582
3976
 
3599
3993
                     File file, enum flush_type type)
3600
3994
{
3601
3995
  int res= 0;
 
3996
  DBUG_ENTER("flush_key_blocks");
 
3997
  DBUG_PRINT("enter", ("keycache: 0x%lx", (long) keycache));
3602
3998
 
3603
3999
  if (!keycache->key_cache_inited)
3604
 
    return(0);
 
4000
    DBUG_RETURN(0);
3605
4001
 
3606
4002
  keycache_pthread_mutex_lock(&keycache->cache_lock);
3607
4003
  /* While waiting for lock, keycache could have been ended. */
3612
4008
    dec_counter_for_resize_op(keycache);
3613
4009
  }
3614
4010
  keycache_pthread_mutex_unlock(&keycache->cache_lock);
3615
 
  return(res);
 
4011
  DBUG_RETURN(res);
3616
4012
}
3617
4013
 
3618
4014
 
3651
4047
static int flush_all_key_blocks(KEY_CACHE *keycache)
3652
4048
{
3653
4049
  BLOCK_LINK    *block;
3654
 
  uint32_t          total_found;
3655
 
  uint32_t          found;
3656
 
  uint32_t          idx;
 
4050
  uint          total_found;
 
4051
  uint          found;
 
4052
  uint          idx;
 
4053
  DBUG_ENTER("flush_all_key_blocks");
3657
4054
 
3658
4055
  do
3659
4056
  {
3688
4085
          */
3689
4086
          if (flush_key_blocks_int(keycache, block->hash_link->file,
3690
4087
                                   FLUSH_FORCE_WRITE))
3691
 
            return(1);
 
4088
            DBUG_RETURN(1);
3692
4089
        }
3693
4090
      }
3694
4091
 
3722
4119
          found++;
3723
4120
          if (flush_key_blocks_int(keycache, block->hash_link->file,
3724
4121
                                   FLUSH_RELEASE))
3725
 
            return(1);
 
4122
            DBUG_RETURN(1);
3726
4123
        }
3727
4124
      }
3728
4125
 
3735
4132
      before the resize started (BLOCK_FOR_UPDATE). Re-check the hashes.
3736
4133
    */
3737
4134
  } while (total_found);
3738
 
  return(0);
 
4135
 
 
4136
#ifndef DBUG_OFF
 
4137
  /* Now there should not exist any block any more. */
 
4138
  for (idx= 0; idx < CHANGED_BLOCKS_HASH; idx++)
 
4139
  {
 
4140
    DBUG_ASSERT(!keycache->changed_blocks[idx]);
 
4141
    DBUG_ASSERT(!keycache->file_blocks[idx]);
 
4142
  }
 
4143
#endif
 
4144
 
 
4145
  DBUG_RETURN(0);
3739
4146
}
3740
4147
 
3741
4148
 
3758
4165
int reset_key_cache_counters(const char *name __attribute__((unused)),
3759
4166
                             KEY_CACHE *key_cache)
3760
4167
{
 
4168
  DBUG_ENTER("reset_key_cache_counters");
3761
4169
  if (!key_cache->key_cache_inited)
3762
4170
  {
3763
 
    return(0);
 
4171
    DBUG_PRINT("info", ("Key cache %s not initialized.", name));
 
4172
    DBUG_RETURN(0);
3764
4173
  }
 
4174
  DBUG_PRINT("info", ("Resetting counters for key cache %s.", name));
 
4175
 
3765
4176
  key_cache->global_blocks_changed= 0;   /* Key_blocks_not_flushed */
3766
4177
  key_cache->global_cache_r_requests= 0; /* Key_read_requests */
3767
4178
  key_cache->global_cache_read= 0;       /* Key_reads */
3768
4179
  key_cache->global_cache_w_requests= 0; /* Key_write_requests */
3769
4180
  key_cache->global_cache_write= 0;      /* Key_writes */
3770
 
  return(0);
3771
 
}
 
4181
  DBUG_RETURN(0);
 
4182
}
 
4183
 
 
4184
 
 
4185
#ifndef DBUG_OFF
 
4186
/*
 
4187
  Test if disk-cache is ok
 
4188
*/
 
4189
static void test_key_cache(KEY_CACHE *keycache __attribute__((unused)),
 
4190
                           const char *where __attribute__((unused)),
 
4191
                           my_bool lock __attribute__((unused)))
 
4192
{
 
4193
  /* TODO */
 
4194
}
 
4195
#endif
3772
4196
 
3773
4197
#if defined(KEYCACHE_TIMEOUT)
3774
4198
 
3784
4208
  BLOCK_LINK *block;
3785
4209
  HASH_LINK *hash_link;
3786
4210
  KEYCACHE_PAGE *page;
3787
 
  uint32_t i;
 
4211
  uint i;
3788
4212
 
3789
4213
  fprintf(keycache_dump_file, "thread:%u\n", thread->id);
3790
4214
 
3798
4222
      page= (KEYCACHE_PAGE *) thread->opt_info;
3799
4223
      fprintf(keycache_dump_file,
3800
4224
              "thread:%u, (file,filepos)=(%u,%lu)\n",
3801
 
              thread->id,(uint) page->file,(uint32_t) page->filepos);
 
4225
              thread->id,(uint) page->file,(ulong) page->filepos);
3802
4226
      if (++i == MAX_QUEUE_LEN)
3803
4227
        break;
3804
4228
    }
3813
4237
      thread=thread->next;
3814
4238
      hash_link= (HASH_LINK *) thread->opt_info;
3815
4239
      fprintf(keycache_dump_file,
3816
 
        "thread:%u hash_link:%u (file,filepos)=(%u,%u)\n",
 
4240
        "thread:%u hash_link:%u (file,filepos)=(%u,%lu)\n",
3817
4241
        thread->id, (uint) HASH_LINK_NUMBER(hash_link),
3818
 
        (uint) hash_link->file,(uint32_t) hash_link->diskpos);
 
4242
        (uint) hash_link->file,(ulong) hash_link->diskpos);
3819
4243
      if (++i == MAX_QUEUE_LEN)
3820
4244
        break;
3821
4245
    }
3866
4290
  fclose(keycache_dump_file);
3867
4291
}
3868
4292
 
 
4293
#endif /* defined(KEYCACHE_TIMEOUT) */
 
4294
 
 
4295
#if defined(KEYCACHE_TIMEOUT)
 
4296
 
 
4297
 
3869
4298
static int keycache_pthread_cond_wait(pthread_cond_t *cond,
3870
4299
                                      pthread_mutex_t *mutex)
3871
4300
{
3873
4302
  struct timeval  now;            /* time when we started waiting        */
3874
4303
  struct timespec timeout;        /* timeout value for the wait function */
3875
4304
  struct timezone tz;
 
4305
#if defined(KEYCACHE_DEBUG)
 
4306
  int cnt=0;
 
4307
#endif
3876
4308
 
3877
4309
  /* Get current time */
3878
4310
  gettimeofday(&now, &tz);
3884
4316
   1 nanosecond = 1000 micro seconds
3885
4317
 */
3886
4318
  timeout.tv_nsec= now.tv_usec * 1000;
 
4319
  KEYCACHE_THREAD_TRACE_END("started waiting");
 
4320
#if defined(KEYCACHE_DEBUG)
 
4321
  cnt++;
 
4322
  if (cnt % 100 == 0)
 
4323
    fprintf(keycache_debug_log, "waiting...\n");
 
4324
    fflush(keycache_debug_log);
 
4325
#endif
3887
4326
  rc= pthread_cond_timedwait(cond, mutex, &timeout);
 
4327
  KEYCACHE_THREAD_TRACE_BEGIN("finished waiting");
3888
4328
  if (rc == ETIMEDOUT || rc == ETIME)
3889
4329
  {
 
4330
#if defined(KEYCACHE_DEBUG)
 
4331
    fprintf(keycache_debug_log,"aborted by keycache timeout\n");
 
4332
    fclose(keycache_debug_log);
 
4333
    abort();
 
4334
#endif
3890
4335
    keycache_dump();
3891
4336
  }
3892
4337
 
 
4338
#if defined(KEYCACHE_DEBUG)
 
4339
  KEYCACHE_DBUG_ASSERT(rc != ETIMEDOUT);
 
4340
#else
3893
4341
  assert(rc != ETIMEDOUT);
3894
 
  return rc;
3895
 
}
 
4342
#endif
 
4343
  return rc;
 
4344
}
 
4345
#else
 
4346
#if defined(KEYCACHE_DEBUG)
 
4347
static int keycache_pthread_cond_wait(pthread_cond_t *cond,
 
4348
                                      pthread_mutex_t *mutex)
 
4349
{
 
4350
  int rc;
 
4351
  KEYCACHE_THREAD_TRACE_END("started waiting");
 
4352
  rc= pthread_cond_wait(cond, mutex);
 
4353
  KEYCACHE_THREAD_TRACE_BEGIN("finished waiting");
 
4354
  return rc;
 
4355
}
 
4356
#endif
3896
4357
#endif /* defined(KEYCACHE_TIMEOUT) */
 
4358
 
 
4359
#if defined(KEYCACHE_DEBUG)
 
4360
 
 
4361
 
 
4362
static int keycache_pthread_mutex_lock(pthread_mutex_t *mutex)
 
4363
{
 
4364
  int rc;
 
4365
  rc= pthread_mutex_lock(mutex);
 
4366
  KEYCACHE_THREAD_TRACE_BEGIN("");
 
4367
  return rc;
 
4368
}
 
4369
 
 
4370
 
 
4371
static void keycache_pthread_mutex_unlock(pthread_mutex_t *mutex)
 
4372
{
 
4373
  KEYCACHE_THREAD_TRACE_END("");
 
4374
  pthread_mutex_unlock(mutex);
 
4375
}
 
4376
 
 
4377
 
 
4378
static int keycache_pthread_cond_signal(pthread_cond_t *cond)
 
4379
{
 
4380
  int rc;
 
4381
  KEYCACHE_THREAD_TRACE("signal");
 
4382
  rc= pthread_cond_signal(cond);
 
4383
  return rc;
 
4384
}
 
4385
 
 
4386
 
 
4387
#if defined(KEYCACHE_DEBUG_LOG)
 
4388
 
 
4389
 
 
4390
static void keycache_debug_print(const char * fmt,...)
 
4391
{
 
4392
  va_list args;
 
4393
  va_start(args,fmt);
 
4394
  if (keycache_debug_log)
 
4395
  {
 
4396
    VOID(vfprintf(keycache_debug_log, fmt, args));
 
4397
    VOID(fputc('\n',keycache_debug_log));
 
4398
  }
 
4399
  va_end(args);
 
4400
}
 
4401
#endif /* defined(KEYCACHE_DEBUG_LOG) */
 
4402
 
 
4403
#if defined(KEYCACHE_DEBUG_LOG)
 
4404
 
 
4405
 
 
4406
void keycache_debug_log_close(void)
 
4407
{
 
4408
  if (keycache_debug_log)
 
4409
    fclose(keycache_debug_log);
 
4410
}
 
4411
#endif /* defined(KEYCACHE_DEBUG_LOG) */
 
4412
 
 
4413
#endif /* defined(KEYCACHE_DEBUG) */
 
4414
 
 
4415
#if !defined(DBUG_OFF)
 
4416
#define F_B_PRT(_f_, _v_) DBUG_PRINT("assert_fail", (_f_, _v_))
 
4417
 
 
4418
static int fail_block(BLOCK_LINK *block)
 
4419
{
 
4420
  F_B_PRT("block->next_used:    %lx\n", (ulong) block->next_used);
 
4421
  F_B_PRT("block->prev_used:    %lx\n", (ulong) block->prev_used);
 
4422
  F_B_PRT("block->next_changed: %lx\n", (ulong) block->next_changed);
 
4423
  F_B_PRT("block->prev_changed: %lx\n", (ulong) block->prev_changed);
 
4424
  F_B_PRT("block->hash_link:    %lx\n", (ulong) block->hash_link);
 
4425
  F_B_PRT("block->status:       %u\n", block->status);
 
4426
  F_B_PRT("block->length:       %u\n", block->length);
 
4427
  F_B_PRT("block->offset:       %u\n", block->offset);
 
4428
  F_B_PRT("block->requests:     %u\n", block->requests);
 
4429
  F_B_PRT("block->temperature:  %u\n", block->temperature);
 
4430
  return 0; /* Let the assert fail. */
 
4431
}
 
4432
 
 
4433
static int fail_hlink(HASH_LINK *hlink)
 
4434
{
 
4435
  F_B_PRT("hlink->next:    %lx\n", (ulong) hlink->next);
 
4436
  F_B_PRT("hlink->prev:    %lx\n", (ulong) hlink->prev);
 
4437
  F_B_PRT("hlink->block:   %lx\n", (ulong) hlink->block);
 
4438
  F_B_PRT("hlink->diskpos: %lu\n", (ulong) hlink->diskpos);
 
4439
  F_B_PRT("hlink->file:    %d\n", hlink->file);
 
4440
  return 0; /* Let the assert fail. */
 
4441
}
 
4442
 
 
4443
static int cache_empty(KEY_CACHE *keycache)
 
4444
{
 
4445
  int errcnt= 0;
 
4446
  int idx;
 
4447
  if (keycache->disk_blocks <= 0)
 
4448
    return 1;
 
4449
  for (idx= 0; idx < keycache->disk_blocks; idx++)
 
4450
  {
 
4451
    BLOCK_LINK *block= keycache->block_root + idx;
 
4452
    if (block->status || block->requests || block->hash_link)
 
4453
    {
 
4454
      fprintf(stderr, "block index: %u\n", idx);
 
4455
      fail_block(block);
 
4456
      errcnt++;
 
4457
    }
 
4458
  }
 
4459
  for (idx= 0; idx < keycache->hash_links; idx++)
 
4460
  {
 
4461
    HASH_LINK *hash_link= keycache->hash_link_root + idx;
 
4462
    if (hash_link->requests || hash_link->block)
 
4463
    {
 
4464
      fprintf(stderr, "hash_link index: %u\n", idx);
 
4465
      fail_hlink(hash_link);
 
4466
      errcnt++;
 
4467
    }
 
4468
  }
 
4469
  if (errcnt)
 
4470
  {
 
4471
    fprintf(stderr, "blocks: %d  used: %lu\n",
 
4472
            keycache->disk_blocks, keycache->blocks_used);
 
4473
    fprintf(stderr, "hash_links: %d  used: %d\n",
 
4474
            keycache->hash_links, keycache->hash_links_used);
 
4475
    fprintf(stderr, "\n");
 
4476
  }
 
4477
  return !errcnt;
 
4478
}
 
4479
#endif
 
4480