~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/myisam/mf_keycache.cc

  • Committer: Brian Aker
  • Date: 2010-12-18 18:24:57 UTC
  • mfrom: (1999.6.3 trunk)
  • Revision ID: brian@tangent.org-20101218182457-yi1wd0so2hml1k1w
Merge in Lee's copyright header fix

Show diffs side-by-side

added added

removed removed

Lines of Context:
11
11
 
12
12
   You should have received a copy of the GNU General Public License
13
13
   along with this program; if not, write to the Free Software
14
 
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
 
14
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
15
15
 
16
16
/*
17
17
  These functions handle keyblock cacheing for ISAM and MyISAM tables.
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>
107
 
#include <keycache.h>
108
 
#include <mystrings/m_string.h>
109
 
#include <mysys/my_bit.h>
 
104
#include "config.h"
 
105
#include "drizzled/error.h"
 
106
#include "drizzled/internal/my_sys.h"
 
107
#include "keycache.h"
 
108
#include "drizzled/internal/m_string.h"
 
109
#include "drizzled/internal/my_bit.h"
110
110
#include <errno.h>
111
111
#include <stdarg.h>
112
112
 
 
113
using namespace drizzled;
 
114
 
113
115
/*
114
116
  Some compilation flags have been added specifically for this module
115
117
  to control the following:
124
126
    accessing it;
125
127
    to set this number equal to <N> add
126
128
      #define MAX_THREADS <N>
127
 
  - to substitute calls of pthread_cond_wait for calls of
128
 
    pthread_cond_timedwait (wait with timeout set up);
129
 
    this setting should be used only when you want to trap a deadlock
130
 
    situation, which theoretically should not happen;
131
 
    to set timeout equal to <T> seconds add
132
 
      #define KEYCACHE_TIMEOUT <T>
133
129
 
134
130
  Example of the settings:
135
131
    #define SERIALIZED_READ_FROM_CACHE
136
132
    #define MAX_THREADS   100
137
 
    #define KEYCACHE_TIMEOUT  1
138
133
*/
139
134
 
140
135
#define STRUCT_PTR(TYPE, MEMBER, a)                                           \
143
138
/* types of condition variables */
144
139
#define  COND_FOR_REQUESTED 0
145
140
#define  COND_FOR_SAVED     1
146
 
#define  COND_FOR_READERS   2
147
141
 
148
142
typedef pthread_cond_t KEYCACHE_CONDVAR;
149
143
 
151
145
struct st_keycache_page
152
146
{
153
147
  int file;               /* file to which the page belongs to  */
154
 
  my_off_t filepos;       /* position of the page in the file   */
 
148
  internal::my_off_t filepos;       /* position of the page in the file   */
155
149
};
156
150
 
157
151
/* element in the chain of a hash table bucket */
159
153
{
160
154
  struct st_hash_link *next, **prev; /* to connect links in the same bucket  */
161
155
  struct st_block_link *block;       /* reference to the block for the page: */
162
 
  File file;                         /* from such a file                     */
163
 
  my_off_t diskpos;                  /* with such an offset                  */
164
 
  uint requests;                     /* number of requests for the page      */
 
156
  int file;                         /* from such a file                     */
 
157
  internal::my_off_t diskpos;                  /* with such an offset                  */
 
158
  uint32_t requests;                     /* number of requests for the page      */
165
159
};
166
160
 
167
161
/* simple states of a block */
193
187
    *next_changed, **prev_changed; /* for lists of file dirty/clean blocks   */
194
188
  struct st_hash_link *hash_link; /* backward ptr to referring hash_link     */
195
189
  KEYCACHE_WQUEUE wqueue[2]; /* queues on waiting requests for new/old pages */
196
 
  uint requests;          /* number of requests for the block                */
197
 
  uchar *buffer;           /* buffer for the block page                       */
198
 
  uint offset;            /* beginning of modified data in the buffer        */
199
 
  uint length;            /* end of data in the buffer                       */
200
 
  uint status;            /* state of the block                              */
 
190
  uint32_t requests;          /* number of requests for the block                */
 
191
  unsigned char *buffer;           /* buffer for the block page                       */
 
192
  uint32_t offset;            /* beginning of modified data in the buffer        */
 
193
  uint32_t length;            /* end of data in the buffer                       */
 
194
  uint32_t status;            /* state of the block                              */
201
195
  enum BLOCK_TEMPERATURE temperature; /* block temperature: cold, warm, hot */
202
 
  uint hits_left;         /* number of hits left until promotion             */
 
196
  uint32_t hits_left;         /* number of hits left until promotion             */
203
197
  uint64_t last_hit_time; /* timestamp of the last hit                      */
204
198
  KEYCACHE_CONDVAR *condvar; /* condition variable for 'no readers' event    */
205
199
};
206
200
 
207
 
KEY_CACHE dflt_key_cache_var;
208
 
KEY_CACHE *dflt_key_cache= &dflt_key_cache_var;
209
 
 
210
201
#define FLUSH_CACHE         2000            /* sort this many blocks at once */
211
202
 
212
 
static int flush_all_key_blocks(KEY_CACHE *keycache);
213
 
static void wait_on_queue(KEYCACHE_WQUEUE *wqueue,
214
 
                          pthread_mutex_t *mutex);
215
 
static void release_whole_queue(KEYCACHE_WQUEUE *wqueue);
216
 
static void free_block(KEY_CACHE *keycache, BLOCK_LINK *block);
217
 
 
218
203
#define KEYCACHE_HASH(f, pos)                                                 \
219
204
(((uint32_t) ((pos) / keycache->key_cache_block_size) +                          \
220
205
                                     (uint32_t) (f)) & (keycache->hash_entries-1))
221
206
#define FILE_HASH(f)                 ((uint) (f) & (CHANGED_BLOCKS_HASH-1))
222
207
 
223
 
#define BLOCK_NUMBER(b)                                                       \
224
 
  ((uint) (((char*)(b)-(char *) keycache->block_root)/sizeof(BLOCK_LINK)))
225
 
#define HASH_LINK_NUMBER(h)                                                   \
226
 
  ((uint) (((char*)(h)-(char *) keycache->hash_link_root)/sizeof(HASH_LINK)))
227
 
 
228
 
#ifdef KEYCACHE_TIMEOUT
229
 
static int keycache_pthread_cond_wait(pthread_cond_t *cond,
230
 
                                      pthread_mutex_t *mutex);
231
 
#else
232
 
#define  keycache_pthread_cond_wait pthread_cond_wait
233
 
#endif
234
 
 
235
 
#define keycache_pthread_mutex_lock pthread_mutex_lock
236
 
#define keycache_pthread_mutex_unlock pthread_mutex_unlock
237
 
#define keycache_pthread_cond_signal pthread_cond_signal
238
 
 
239
 
static inline uint next_power(uint value)
 
208
 
 
209
#define  keycache_pthread_cond_wait(A,B) (void)A;
 
210
#define keycache_pthread_mutex_lock(A) (void)A;
 
211
#define keycache_pthread_mutex_unlock(A) (void)A;
 
212
#define keycache_pthread_cond_signal(A) (void)A;
 
213
 
 
214
static inline uint32_t next_power(uint32_t value)
240
215
{
241
 
  return (uint) my_round_up_to_next_power((uint32_t) value) << 1;
 
216
  return my_round_up_to_next_power(value) << 1;
242
217
}
243
218
 
244
219
 
267
242
 
268
243
*/
269
244
 
270
 
int init_key_cache(KEY_CACHE *keycache, uint key_cache_block_size,
271
 
                   size_t use_mem, uint division_limit,
272
 
                   uint age_threshold)
273
 
{
274
 
  uint32_t blocks, hash_links;
275
 
  size_t length;
276
 
  int error;
277
 
  assert(key_cache_block_size >= 512);
278
 
 
279
 
  if (keycache->key_cache_inited && keycache->disk_blocks > 0)
280
 
  {
281
 
    return(0);
282
 
  }
283
 
 
284
 
  keycache->global_cache_w_requests= keycache->global_cache_r_requests= 0;
285
 
  keycache->global_cache_read= keycache->global_cache_write= 0;
286
 
  keycache->disk_blocks= -1;
287
 
  if (! keycache->key_cache_inited)
288
 
  {
289
 
    keycache->key_cache_inited= 1;
290
 
    /*
291
 
      Initialize these variables once only.
292
 
      Their value must survive re-initialization during resizing.
293
 
    */
294
 
    keycache->in_resize= 0;
295
 
    keycache->resize_in_flush= 0;
296
 
    keycache->cnt_for_resize_op= 0;
297
 
    keycache->waiting_for_resize_cnt.last_thread= NULL;
298
 
    keycache->in_init= 0;
299
 
    pthread_mutex_init(&keycache->cache_lock, MY_MUTEX_INIT_FAST);
300
 
    keycache->resize_queue.last_thread= NULL;
301
 
  }
302
 
 
303
 
  keycache->key_cache_mem_size= use_mem;
304
 
  keycache->key_cache_block_size= key_cache_block_size;
305
 
 
306
 
  blocks= (uint32_t) (use_mem / (sizeof(BLOCK_LINK) + 2 * sizeof(HASH_LINK) +
307
 
                              sizeof(HASH_LINK*) * 5/4 + key_cache_block_size));
308
 
  /* It doesn't make sense to have too few blocks (less than 8) */
309
 
  if (blocks >= 8)
310
 
  {
311
 
    for ( ; ; )
312
 
    {
313
 
      /* Set my_hash_entries to the next bigger 2 power */
314
 
      if ((keycache->hash_entries= next_power(blocks)) < blocks * 5/4)
315
 
        keycache->hash_entries<<= 1;
316
 
      hash_links= 2 * blocks;
317
 
#if defined(MAX_THREADS)
318
 
      if (hash_links < MAX_THREADS + blocks - 1)
319
 
        hash_links= MAX_THREADS + blocks - 1;
320
 
#endif
321
 
      while ((length= (ALIGN_SIZE(blocks * sizeof(BLOCK_LINK)) +
322
 
                       ALIGN_SIZE(hash_links * sizeof(HASH_LINK)) +
323
 
                       ALIGN_SIZE(sizeof(HASH_LINK*) *
324
 
                                  keycache->hash_entries))) +
325
 
             ((size_t) blocks * keycache->key_cache_block_size) > use_mem)
326
 
        blocks--;
327
 
      /* Allocate memory for cache page buffers */
328
 
      if ((keycache->block_mem= malloc((size_t) blocks * keycache->key_cache_block_size)))
329
 
      {
330
 
        /*
331
 
          Allocate memory for blocks, hash_links and hash entries;
332
 
          For each block 2 hash links are allocated
333
 
        */
334
 
        if ((keycache->block_root= (BLOCK_LINK*) my_malloc(length,
335
 
                                                           MYF(0))))
336
 
          break;
337
 
        free(keycache->block_mem);
338
 
        keycache->block_mem= 0;
339
 
      }
340
 
      if (blocks < 8)
341
 
      {
342
 
        my_errno= ENOMEM;
343
 
        my_error(EE_OUTOFMEMORY, MYF(0), blocks * keycache->key_cache_block_size);
344
 
        goto err;
345
 
      }
346
 
      blocks= blocks / 4*3;
347
 
    }
348
 
    keycache->blocks_unused= blocks;
349
 
    keycache->disk_blocks= (int) blocks;
350
 
    keycache->hash_links= hash_links;
351
 
    keycache->hash_root= (HASH_LINK**) ((char*) keycache->block_root +
352
 
                                        ALIGN_SIZE(blocks*sizeof(BLOCK_LINK)));
353
 
    keycache->hash_link_root= (HASH_LINK*) ((char*) keycache->hash_root +
354
 
                                            ALIGN_SIZE((sizeof(HASH_LINK*) *
355
 
                                                        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));
362
 
    keycache->hash_links_used= 0;
363
 
    keycache->free_hash_list= NULL;
364
 
    keycache->blocks_used= keycache->blocks_changed= 0;
365
 
 
366
 
    keycache->global_blocks_changed= 0;
367
 
    keycache->blocks_available=0;               /* For debugging */
368
 
 
369
 
    /* The LRU chain is empty after initialization */
370
 
    keycache->used_last= NULL;
371
 
    keycache->used_ins= NULL;
372
 
    keycache->free_block_list= NULL;
373
 
    keycache->keycache_time= 0;
374
 
    keycache->warm_blocks= 0;
375
 
    keycache->min_warm_blocks= (division_limit ?
376
 
                                blocks * division_limit / 100 + 1 :
377
 
                                blocks);
378
 
    keycache->age_threshold= (age_threshold ?
379
 
                              blocks * age_threshold / 100 :
380
 
                              blocks);
381
 
 
382
 
    keycache->can_be_used= 1;
383
 
 
384
 
    keycache->waiting_for_hash_link.last_thread= NULL;
385
 
    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);
390
 
  }
391
 
  else
392
 
  {
393
 
    /* key_buffer_size is specified too small. Disable the cache. */
394
 
    keycache->can_be_used= 0;
395
 
  }
396
 
 
397
 
  keycache->blocks= keycache->disk_blocks > 0 ? keycache->disk_blocks : 0;
398
 
  return((int) keycache->disk_blocks);
399
 
 
400
 
err:
401
 
  error= my_errno;
402
 
  keycache->disk_blocks= 0;
403
 
  keycache->blocks=  0;
404
 
  if (keycache->block_mem)
405
 
  {
406
 
    free(keycache->block_mem);
407
 
    keycache->block_mem= NULL;
408
 
  }
409
 
  if (keycache->block_root)
410
 
  {
411
 
    my_free((uchar*) keycache->block_root, MYF(0));
412
 
    keycache->block_root= NULL;
413
 
  }
414
 
  my_errno= error;
415
 
  keycache->can_be_used= 0;
416
 
  return(0);
417
 
}
418
 
 
419
 
 
420
 
/*
421
 
  Resize a key cache
422
 
 
423
 
  SYNOPSIS
424
 
    resize_key_cache()
425
 
    keycache                    pointer to a key cache data structure
426
 
    key_cache_block_size        size of blocks to keep cached data
427
 
    use_mem                     total memory to use for the new key cache
428
 
    division_limit              new division limit (if not zero)
429
 
    age_threshold               new age threshold (if not zero)
430
 
 
431
 
  RETURN VALUE
432
 
    number of blocks in the key cache, if successful,
433
 
    0 - otherwise.
434
 
 
435
 
  NOTES.
436
 
    The function first compares the memory size and the block size parameters
437
 
    with the key cache values.
438
 
 
439
 
    If they differ the function free the the memory allocated for the
440
 
    old key cache blocks by calling the end_key_cache function and
441
 
    then rebuilds the key cache with new blocks by calling
442
 
    init_key_cache.
443
 
 
444
 
    The function starts the operation only when all other threads
445
 
    performing operations with the key cache let her to proceed
446
 
    (when cnt_for_resize=0).
447
 
*/
448
 
 
449
 
int resize_key_cache(KEY_CACHE *keycache, uint key_cache_block_size,
450
 
                     size_t use_mem, uint division_limit,
451
 
                     uint age_threshold)
452
 
{
453
 
  int blocks;
454
 
 
455
 
  if (!keycache->key_cache_inited)
456
 
    return(keycache->disk_blocks);
457
 
 
458
 
  if(key_cache_block_size == keycache->key_cache_block_size &&
459
 
     use_mem == keycache->key_cache_mem_size)
460
 
  {
461
 
    change_key_cache_param(keycache, division_limit, age_threshold);
462
 
    return(keycache->disk_blocks);
463
 
  }
464
 
 
465
 
  keycache_pthread_mutex_lock(&keycache->cache_lock);
466
 
 
467
 
  /*
468
 
    We may need to wait for another thread which is doing a resize
469
 
    already. This cannot happen in the MySQL server though. It allows
470
 
    one resizer only. In set_var.cc keycache->in_init is used to block
471
 
    multiple attempts.
472
 
  */
473
 
  while (keycache->in_resize)
474
 
  {
475
 
    /* purecov: begin inspected */
476
 
    wait_on_queue(&keycache->resize_queue, &keycache->cache_lock);
477
 
    /* purecov: end */
478
 
  }
479
 
 
480
 
  /*
481
 
    Mark the operation in progress. This blocks other threads from doing
482
 
    a resize in parallel. It prohibits new blocks to enter the cache.
483
 
    Read/write requests can bypass the cache during the flush phase.
484
 
  */
485
 
  keycache->in_resize= 1;
486
 
 
487
 
  /* Need to flush only if keycache is enabled. */
488
 
  if (keycache->can_be_used)
489
 
  {
490
 
    /* Start the flush phase. */
491
 
    keycache->resize_in_flush= 1;
492
 
 
493
 
    if (flush_all_key_blocks(keycache))
494
 
    {
495
 
      /* TODO: if this happens, we should write a warning in the log file ! */
496
 
      keycache->resize_in_flush= 0;
497
 
      blocks= 0;
498
 
      keycache->can_be_used= 0;
499
 
      goto finish;
500
 
    }
501
 
 
502
 
    /* End the flush phase. */
503
 
    keycache->resize_in_flush= 0;
504
 
  }
505
 
 
506
 
  /*
507
 
    Some direct read/write operations (bypassing the cache) may still be
508
 
    unfinished. Wait until they are done. If the key cache can be used,
509
 
    direct I/O is done in increments of key_cache_block_size. That is,
510
 
    every block is checked if it is in the cache. We need to wait for
511
 
    pending I/O before re-initializing the cache, because we may change
512
 
    the block size. Otherwise they could check for blocks at file
513
 
    positions where the new block division has none. We do also want to
514
 
    wait for I/O done when (if) the cache was disabled. It must not
515
 
    run in parallel with normal cache operation.
516
 
  */
517
 
  while (keycache->cnt_for_resize_op)
518
 
    wait_on_queue(&keycache->waiting_for_resize_cnt, &keycache->cache_lock);
519
 
 
520
 
  /*
521
 
    Free old cache structures, allocate new structures, and initialize
522
 
    them. Note that the cache_lock mutex and the resize_queue are left
523
 
    untouched. We do not lose the cache_lock and will release it only at
524
 
    the end of this function.
525
 
  */
526
 
  end_key_cache(keycache, 0);                   /* Don't free mutex */
527
 
  /* The following will work even if use_mem is 0 */
528
 
  blocks= init_key_cache(keycache, key_cache_block_size, use_mem,
529
 
                         division_limit, age_threshold);
530
 
 
531
 
finish:
532
 
  /*
533
 
    Mark the resize finished. This allows other threads to start a
534
 
    resize or to request new cache blocks.
535
 
  */
536
 
  keycache->in_resize= 0;
537
 
 
538
 
  /* Signal waiting threads. */
539
 
  release_whole_queue(&keycache->resize_queue);
540
 
 
541
 
  keycache_pthread_mutex_unlock(&keycache->cache_lock);
542
 
  return(blocks);
543
 
}
544
 
 
545
 
 
546
 
/*
547
 
  Increment counter blocking resize key cache operation
548
 
*/
549
 
static inline void inc_counter_for_resize_op(KEY_CACHE *keycache)
550
 
{
551
 
  keycache->cnt_for_resize_op++;
552
 
}
553
 
 
554
 
 
555
 
/*
556
 
  Decrement counter blocking resize key cache operation;
557
 
  Signal the operation to proceed when counter becomes equal zero
558
 
*/
559
 
static inline void dec_counter_for_resize_op(KEY_CACHE *keycache)
560
 
{
561
 
  if (!--keycache->cnt_for_resize_op)
562
 
    release_whole_queue(&keycache->waiting_for_resize_cnt);
563
 
}
564
 
 
565
 
/*
566
 
  Change the key cache parameters
567
 
 
568
 
  SYNOPSIS
569
 
    change_key_cache_param()
570
 
    keycache                    pointer to a key cache data structure
571
 
    division_limit              new division limit (if not zero)
572
 
    age_threshold               new age threshold (if not zero)
573
 
 
574
 
  RETURN VALUE
575
 
    none
576
 
 
577
 
  NOTES.
578
 
    Presently the function resets the key cache parameters
579
 
    concerning midpoint insertion strategy - division_limit and
580
 
    age_threshold.
581
 
*/
582
 
 
583
 
void change_key_cache_param(KEY_CACHE *keycache, uint division_limit,
584
 
                            uint age_threshold)
585
 
{
586
 
  keycache_pthread_mutex_lock(&keycache->cache_lock);
587
 
  if (division_limit)
588
 
    keycache->min_warm_blocks= (keycache->disk_blocks *
589
 
                                division_limit / 100 + 1);
590
 
  if (age_threshold)
591
 
    keycache->age_threshold=   (keycache->disk_blocks *
592
 
                                age_threshold / 100);
593
 
  keycache_pthread_mutex_unlock(&keycache->cache_lock);
594
 
  return;
 
245
int init_key_cache(KEY_CACHE *keycache, uint32_t key_cache_block_size,
 
246
                   size_t use_mem, uint32_t division_limit,
 
247
                   uint32_t age_threshold)
 
248
{
 
249
  (void)keycache;
 
250
  (void)key_cache_block_size;
 
251
  (void)use_mem;
 
252
  (void)division_limit;
 
253
  (void)age_threshold;
 
254
  memset(keycache, 0, sizeof(KEY_CACHE));
 
255
  
 
256
  return 0;
595
257
}
596
258
 
597
259
 
609
271
 
610
272
void end_key_cache(KEY_CACHE *keycache, bool cleanup)
611
273
{
612
 
  if (!keycache->key_cache_inited)
613
 
    return;
614
 
 
615
 
  if (keycache->disk_blocks > 0)
616
 
  {
617
 
    if (keycache->block_mem)
618
 
    {
619
 
      free(keycache->block_mem);
620
 
      keycache->block_mem= NULL;
621
 
      my_free((uchar*) keycache->block_root, MYF(0));
622
 
      keycache->block_root= NULL;
623
 
    }
624
 
    keycache->disk_blocks= -1;
625
 
    /* Reset blocks_changed to be safe if flush_all_key_blocks is called */
626
 
    keycache->blocks_changed= 0;
627
 
  }
628
 
 
629
 
  if (cleanup)
630
 
  {
631
 
    pthread_mutex_destroy(&keycache->cache_lock);
632
 
    keycache->key_cache_inited= keycache->can_be_used= 0;
633
 
  }
634
 
  return;
 
274
  (void)keycache;
 
275
  (void)cleanup;
635
276
} /* end_key_cache */
636
277
 
637
278
 
638
279
/*
639
 
  Link a thread into double-linked queue of waiting threads.
640
 
 
641
 
  SYNOPSIS
642
 
    link_into_queue()
643
 
      wqueue              pointer to the queue structure
644
 
      thread              pointer to the thread to be added to the queue
645
 
 
646
 
  RETURN VALUE
647
 
    none
648
 
 
649
 
  NOTES.
650
 
    Queue is represented by a circular list of the thread structures
651
 
    The list is double-linked of the type (**prev,*next), accessed by
652
 
    a pointer to the last element.
653
 
*/
654
 
 
655
 
static void link_into_queue(KEYCACHE_WQUEUE *wqueue,
656
 
                                   struct st_my_thread_var *thread)
657
 
{
658
 
  struct st_my_thread_var *last;
659
 
 
660
 
  assert(!thread->next && !thread->prev);
661
 
  if (! (last= wqueue->last_thread))
662
 
  {
663
 
    /* Queue is empty */
664
 
    thread->next= thread;
665
 
    thread->prev= &thread->next;
666
 
  }
667
 
  else
668
 
  {
669
 
    thread->prev= last->next->prev;
670
 
    last->next->prev= &thread->next;
671
 
    thread->next= last->next;
672
 
    last->next= thread;
673
 
  }
674
 
  wqueue->last_thread= thread;
675
 
}
676
 
 
677
 
/*
678
 
  Unlink a thread from double-linked queue of waiting threads
679
 
 
680
 
  SYNOPSIS
681
 
    unlink_from_queue()
682
 
      wqueue              pointer to the queue structure
683
 
      thread              pointer to the thread to be removed from the queue
684
 
 
685
 
  RETURN VALUE
686
 
    none
687
 
 
688
 
  NOTES.
689
 
    See NOTES for link_into_queue
690
 
*/
691
 
 
692
 
static void unlink_from_queue(KEYCACHE_WQUEUE *wqueue,
693
 
                                     struct st_my_thread_var *thread)
694
 
{
695
 
  assert(thread->next && thread->prev);
696
 
  if (thread->next == thread)
697
 
    /* The queue contains only one member */
698
 
    wqueue->last_thread= NULL;
699
 
  else
700
 
  {
701
 
    thread->next->prev= thread->prev;
702
 
    *thread->prev=thread->next;
703
 
    if (wqueue->last_thread == thread)
704
 
      wqueue->last_thread= STRUCT_PTR(struct st_my_thread_var, next,
705
 
                                      thread->prev);
706
 
  }
707
 
  thread->next= NULL;
708
 
  thread->prev= NULL;
709
 
}
710
 
 
711
 
 
712
 
/*
713
 
  Add a thread to single-linked queue of waiting threads
714
 
 
715
 
  SYNOPSIS
716
 
    wait_on_queue()
717
 
      wqueue            Pointer to the queue structure.
718
 
      mutex             Cache_lock to acquire after awake.
719
 
 
720
 
  RETURN VALUE
721
 
    none
722
 
 
723
 
  NOTES.
724
 
    Queue is represented by a circular list of the thread structures
725
 
    The list is single-linked of the type (*next), accessed by a pointer
726
 
    to the last element.
727
 
 
728
 
    The function protects against stray signals by verifying that the
729
 
    current thread is unlinked from the queue when awaking. However,
730
 
    since several threads can wait for the same event, it might be
731
 
    necessary for the caller of the function to check again if the
732
 
    condition for awake is indeed matched.
733
 
*/
734
 
 
735
 
static void wait_on_queue(KEYCACHE_WQUEUE *wqueue,
736
 
                          pthread_mutex_t *mutex)
737
 
{
738
 
  struct st_my_thread_var *last;
739
 
  struct st_my_thread_var *thread= my_thread_var;
740
 
 
741
 
  /* Add to queue. */
742
 
  assert(!thread->next);
743
 
  assert(!thread->prev); /* Not required, but must be true anyway. */
744
 
  if (! (last= wqueue->last_thread))
745
 
    thread->next= thread;
746
 
  else
747
 
  {
748
 
    thread->next= last->next;
749
 
    last->next= thread;
750
 
  }
751
 
  wqueue->last_thread= thread;
752
 
 
753
 
  /*
754
 
    Wait until thread is removed from queue by the signalling thread.
755
 
    The loop protects against stray signals.
756
 
  */
757
 
  do
758
 
  {
759
 
    keycache_pthread_cond_wait(&thread->suspend, mutex);
760
 
  }
761
 
  while (thread->next);
762
 
}
763
 
 
764
 
 
765
 
/*
766
 
  Remove all threads from queue signaling them to proceed
767
 
 
768
 
  SYNOPSIS
769
 
    release_whole_queue()
770
 
      wqueue            pointer to the queue structure
771
 
 
772
 
  RETURN VALUE
773
 
    none
774
 
 
775
 
  NOTES.
776
 
    See notes for wait_on_queue().
777
 
    When removed from the queue each thread is signaled via condition
778
 
    variable thread->suspend.
779
 
*/
780
 
 
781
 
static void release_whole_queue(KEYCACHE_WQUEUE *wqueue)
782
 
{
783
 
  struct st_my_thread_var *last;
784
 
  struct st_my_thread_var *next;
785
 
  struct st_my_thread_var *thread;
786
 
 
787
 
  /* Queue may be empty. */
788
 
  if (!(last= wqueue->last_thread))
789
 
    return;
790
 
 
791
 
  next= last->next;
792
 
  do
793
 
  {
794
 
    thread=next;
795
 
    /* Signal the thread. */
796
 
    keycache_pthread_cond_signal(&thread->suspend);
797
 
    /* Take thread from queue. */
798
 
    next=thread->next;
799
 
    thread->next= NULL;
800
 
  }
801
 
  while (thread != last);
802
 
 
803
 
  /* Now queue is definitely empty. */
804
 
  wqueue->last_thread= NULL;
805
 
}
806
 
 
807
 
 
808
 
/*
809
 
  Unlink a block from the chain of dirty/clean blocks
810
 
*/
811
 
static inline void unlink_changed(BLOCK_LINK *block)
812
 
{
813
 
  assert(block->prev_changed && *block->prev_changed == block);
814
 
  if (block->next_changed)
815
 
    block->next_changed->prev_changed= block->prev_changed;
816
 
  *block->prev_changed= block->next_changed;
817
 
  block->next_changed= NULL;
818
 
  block->prev_changed= NULL;
819
 
}
820
 
 
821
 
 
822
 
/*
823
 
  Link a block into the chain of dirty/clean blocks
824
 
*/
825
 
 
826
 
static inline void link_changed(BLOCK_LINK *block, BLOCK_LINK **phead)
827
 
{
828
 
  assert(!block->next_changed);
829
 
  assert(!block->prev_changed);
830
 
  block->prev_changed= phead;
831
 
  if ((block->next_changed= *phead))
832
 
    (*phead)->prev_changed= &block->next_changed;
833
 
  *phead= block;
834
 
}
835
 
 
836
 
 
837
 
/*
838
 
  Link a block in a chain of clean blocks of a file.
839
 
 
840
 
  SYNOPSIS
841
 
    link_to_file_list()
842
 
      keycache          Key cache handle
843
 
      block             Block to relink
844
 
      file              File to be linked to
845
 
      unlink            If to unlink first
846
 
 
847
 
  DESCRIPTION
848
 
    Unlink a block from whichever chain it is linked in, if it's
849
 
    asked for, and link it to the chain of clean blocks of the
850
 
    specified file.
851
 
 
852
 
  NOTE
853
 
    Please do never set/clear BLOCK_CHANGED outside of
854
 
    link_to_file_list() or link_to_changed_list().
855
 
    You would risk to damage correct counting of changed blocks
856
 
    and to find blocks in the wrong hash.
857
 
 
858
 
  RETURN
859
 
    void
860
 
*/
861
 
 
862
 
static void link_to_file_list(KEY_CACHE *keycache,
863
 
                              BLOCK_LINK *block, int file,
864
 
                              bool unlink_block)
865
 
{
866
 
  assert(block->status & BLOCK_IN_USE);
867
 
  assert(block->hash_link && block->hash_link->block == block);
868
 
  assert(block->hash_link->file == file);
869
 
  if (unlink_block)
870
 
    unlink_changed(block);
871
 
  link_changed(block, &keycache->file_blocks[FILE_HASH(file)]);
872
 
  if (block->status & BLOCK_CHANGED)
873
 
  {
874
 
    block->status&= ~BLOCK_CHANGED;
875
 
    keycache->blocks_changed--;
876
 
    keycache->global_blocks_changed--;
877
 
  }
878
 
}
879
 
 
880
 
 
881
 
/*
882
 
  Re-link a block from the clean chain to the dirty chain of a file.
883
 
 
884
 
  SYNOPSIS
885
 
    link_to_changed_list()
886
 
      keycache          key cache handle
887
 
      block             block to relink
888
 
 
889
 
  DESCRIPTION
890
 
    Unlink a block from the chain of clean blocks of a file
891
 
    and link it to the chain of dirty blocks of the same file.
892
 
 
893
 
  NOTE
894
 
    Please do never set/clear BLOCK_CHANGED outside of
895
 
    link_to_file_list() or link_to_changed_list().
896
 
    You would risk to damage correct counting of changed blocks
897
 
    and to find blocks in the wrong hash.
898
 
 
899
 
  RETURN
900
 
    void
901
 
*/
902
 
 
903
 
static void link_to_changed_list(KEY_CACHE *keycache,
904
 
                                 BLOCK_LINK *block)
905
 
{
906
 
  assert(block->status & BLOCK_IN_USE);
907
 
  assert(!(block->status & BLOCK_CHANGED));
908
 
  assert(block->hash_link && block->hash_link->block == block);
909
 
 
910
 
  unlink_changed(block);
911
 
  link_changed(block,
912
 
               &keycache->changed_blocks[FILE_HASH(block->hash_link->file)]);
913
 
  block->status|=BLOCK_CHANGED;
914
 
  keycache->blocks_changed++;
915
 
  keycache->global_blocks_changed++;
916
 
}
917
 
 
918
 
 
919
 
/*
920
 
  Link a block to the LRU chain at the beginning or at the end of
921
 
  one of two parts.
922
 
 
923
 
  SYNOPSIS
924
 
    link_block()
925
 
      keycache            pointer to a key cache data structure
926
 
      block               pointer to the block to link to the LRU chain
927
 
      hot                 <-> to link the block into the hot subchain
928
 
      at_end              <-> to link the block at the end of the subchain
929
 
 
930
 
  RETURN VALUE
931
 
    none
932
 
 
933
 
  NOTES.
934
 
    The LRU ring is represented by a circular list of block structures.
935
 
    The list is double-linked of the type (**prev,*next) type.
936
 
    The LRU ring is divided into two parts - hot and warm.
937
 
    There are two pointers to access the last blocks of these two
938
 
    parts. The beginning of the warm part follows right after the
939
 
    end of the hot part.
940
 
    Only blocks of the warm part can be used for eviction.
941
 
    The first block from the beginning of this subchain is always
942
 
    taken for eviction (keycache->last_used->next)
943
 
 
944
 
    LRU chain:       +------+   H O T    +------+
945
 
                +----| end  |----...<----| beg  |----+
946
 
                |    +------+last        +------+    |
947
 
                v<-link in latest hot (new end)      |
948
 
                |     link in latest warm (new end)->^
949
 
                |    +------+  W A R M   +------+    |
950
 
                +----| beg  |---->...----| end  |----+
951
 
                     +------+            +------+ins
952
 
                  first for eviction
953
 
 
954
 
    It is also possible that the block is selected for eviction and thus
955
 
    not linked in the LRU ring.
956
 
*/
957
 
 
958
 
static void link_block(KEY_CACHE *keycache, BLOCK_LINK *block, bool hot,
959
 
                       bool at_end)
960
 
{
961
 
  BLOCK_LINK *ins;
962
 
  BLOCK_LINK **pins;
963
 
 
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);
970
 
  if (!hot && keycache->waiting_for_block.last_thread)
971
 
  {
972
 
    /* Signal that in the LRU warm sub-chain an available block has appeared */
973
 
    struct st_my_thread_var *last_thread=
974
 
                               keycache->waiting_for_block.last_thread;
975
 
    struct st_my_thread_var *first_thread= last_thread->next;
976
 
    struct st_my_thread_var *next_thread= first_thread;
977
 
    HASH_LINK *hash_link= (HASH_LINK *) first_thread->opt_info;
978
 
    struct st_my_thread_var *thread;
979
 
    do
980
 
    {
981
 
      thread= next_thread;
982
 
      next_thread= thread->next;
983
 
      /*
984
 
         We notify about the event all threads that ask
985
 
         for the same page as the first thread in the queue
986
 
      */
987
 
      if ((HASH_LINK *) thread->opt_info == hash_link)
988
 
      {
989
 
        keycache_pthread_cond_signal(&thread->suspend);
990
 
        unlink_from_queue(&keycache->waiting_for_block, thread);
991
 
        block->requests++;
992
 
      }
993
 
    }
994
 
    while (thread != last_thread);
995
 
    hash_link->block= block;
996
 
    /*
997
 
      NOTE: We assigned the block to the hash_link and signalled the
998
 
      requesting thread(s). But it is possible that other threads runs
999
 
      first. These threads see the hash_link assigned to a block which
1000
 
      is assigned to another hash_link and not marked BLOCK_IN_SWITCH.
1001
 
      This can be a problem for functions that do not select the block
1002
 
      via its hash_link: flush and free. They do only see a block which
1003
 
      is in a "normal" state and don't know that it will be evicted soon.
1004
 
 
1005
 
      We cannot set BLOCK_IN_SWITCH here because only one of the
1006
 
      requesting threads must handle the eviction. All others must wait
1007
 
      for it to complete. If we set the flag here, the threads would not
1008
 
      know who is in charge of the eviction. Without the flag, the first
1009
 
      thread takes the stick and sets the flag.
1010
 
 
1011
 
      But we need to note in the block that is has been selected for
1012
 
      eviction. It must not be freed. The evicting thread will not
1013
 
      expect the block in the free list. Before freeing we could also
1014
 
      check if block->requests > 1. But I think including another flag
1015
 
      in the check of block->status is slightly more efficient and
1016
 
      probably easier to read.
1017
 
    */
1018
 
    block->status|= BLOCK_IN_EVICTION;
1019
 
    return;
1020
 
  }
1021
 
  pins= hot ? &keycache->used_ins : &keycache->used_last;
1022
 
  ins= *pins;
1023
 
  if (ins)
1024
 
  {
1025
 
    ins->next_used->prev_used= &block->next_used;
1026
 
    block->next_used= ins->next_used;
1027
 
    block->prev_used= &ins->next_used;
1028
 
    ins->next_used= block;
1029
 
    if (at_end)
1030
 
      *pins= block;
1031
 
  }
1032
 
  else
1033
 
  {
1034
 
    /* The LRU ring is empty. Let the block point to itself. */
1035
 
    keycache->used_last= keycache->used_ins= block->next_used= block;
1036
 
    block->prev_used= &block->next_used;
1037
 
  }
1038
 
}
1039
 
 
1040
 
 
1041
 
/*
1042
 
  Unlink a block from the LRU chain
1043
 
 
1044
 
  SYNOPSIS
1045
 
    unlink_block()
1046
 
      keycache            pointer to a key cache data structure
1047
 
      block               pointer to the block to unlink from the LRU chain
1048
 
 
1049
 
  RETURN VALUE
1050
 
    none
1051
 
 
1052
 
  NOTES.
1053
 
    See NOTES for link_block
1054
 
*/
1055
 
 
1056
 
static void unlink_block(KEY_CACHE *keycache, BLOCK_LINK *block)
1057
 
{
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 &&
1063
 
              (block->next_used->prev_used == &block->next_used) &&
1064
 
              (*block->prev_used == block));
1065
 
  if (block->next_used == block)
1066
 
    /* The list contains only one member */
1067
 
    keycache->used_last= keycache->used_ins= NULL;
1068
 
  else
1069
 
  {
1070
 
    block->next_used->prev_used= block->prev_used;
1071
 
    *block->prev_used= block->next_used;
1072
 
    if (keycache->used_last == block)
1073
 
      keycache->used_last= STRUCT_PTR(BLOCK_LINK, next_used, block->prev_used);
1074
 
    if (keycache->used_ins == block)
1075
 
      keycache->used_ins=STRUCT_PTR(BLOCK_LINK, next_used, block->prev_used);
1076
 
  }
1077
 
  block->next_used= NULL;
1078
 
  block->prev_used= NULL;
1079
 
}
1080
 
 
1081
 
 
1082
 
/*
1083
 
  Register requests for a block.
1084
 
 
1085
 
  SYNOPSIS
1086
 
    reg_requests()
1087
 
      keycache          Pointer to a key cache data structure.
1088
 
      block             Pointer to the block to register a request on.
1089
 
      count             Number of requests. Always 1.
1090
 
 
1091
 
  NOTE
1092
 
    The first request unlinks the block from the LRU ring. This means
1093
 
    that it is protected against eveiction.
1094
 
 
1095
 
  RETURN
1096
 
    void
1097
 
*/
1098
 
static void reg_requests(KEY_CACHE *keycache, BLOCK_LINK *block, int count)
1099
 
{
1100
 
  assert(block->status & BLOCK_IN_USE);
1101
 
  assert(block->hash_link);
1102
 
 
1103
 
  if (!block->requests)
1104
 
    unlink_block(keycache, block);
1105
 
  block->requests+=count;
1106
 
}
1107
 
 
1108
 
 
1109
 
/*
1110
 
  Unregister request for a block
1111
 
  linking it to the LRU chain if it's the last request
1112
 
 
1113
 
  SYNOPSIS
1114
 
    unreg_request()
1115
 
    keycache            pointer to a key cache data structure
1116
 
    block               pointer to the block to link to the LRU chain
1117
 
    at_end              <-> to link the block at the end of the LRU chain
1118
 
 
1119
 
  RETURN VALUE
1120
 
    none
1121
 
 
1122
 
  NOTES.
1123
 
    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
1125
 
    added either at the end of warm sub-chain or at the end of hot sub-chain.
1126
 
    It is added to the hot subchain if its counter is zero and number of
1127
 
    blocks in warm sub-chain is not less than some low limit (determined by
1128
 
    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
1130
 
    at beginning of the warm sub-chain.
1131
 
    Thus a warm block can be promoted to the hot sub-chain when its counter
1132
 
    becomes zero for the first time.
1133
 
    At the same time  the block at the very beginning of the hot subchain
1134
 
    might be moved to the beginning of the warm subchain if it stays untouched
1135
 
    for a too long time (this time is determined by parameter age_threshold).
1136
 
 
1137
 
    It is also possible that the block is selected for eviction and thus
1138
 
    not linked in the LRU ring.
1139
 
*/
1140
 
 
1141
 
static void unreg_request(KEY_CACHE *keycache,
1142
 
                          BLOCK_LINK *block, int at_end)
1143
 
{
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);
1150
 
  if (! --block->requests)
1151
 
  {
1152
 
    bool hot;
1153
 
    if (block->hits_left)
1154
 
      block->hits_left--;
1155
 
    hot= !block->hits_left && at_end &&
1156
 
      keycache->warm_blocks > keycache->min_warm_blocks;
1157
 
    if (hot)
1158
 
    {
1159
 
      if (block->temperature == BLOCK_WARM)
1160
 
        keycache->warm_blocks--;
1161
 
      block->temperature= BLOCK_HOT;
1162
 
    }
1163
 
    link_block(keycache, block, hot, (bool)at_end);
1164
 
    block->last_hit_time= keycache->keycache_time;
1165
 
    keycache->keycache_time++;
1166
 
    /*
1167
 
      At this place, the block might be in the LRU ring or not. If an
1168
 
      evicter was waiting for a block, it was selected for eviction and
1169
 
      not linked in the LRU ring.
1170
 
    */
1171
 
 
1172
 
    /*
1173
 
      Check if we should link a hot block to the warm block sub-chain.
1174
 
      It is possible that we select the same block as above. But it can
1175
 
      also be another block. In any case a block from the LRU ring is
1176
 
      selected. In other words it works even if the above block was
1177
 
      selected for eviction and not linked in the LRU ring. Since this
1178
 
      happens only if the LRU ring is empty, the block selected below
1179
 
      would be NULL and the rest of the function skipped.
1180
 
    */
1181
 
    block= keycache->used_ins;
1182
 
    if (block && keycache->keycache_time - block->last_hit_time >
1183
 
        keycache->age_threshold)
1184
 
    {
1185
 
      unlink_block(keycache, block);
1186
 
      link_block(keycache, block, 0, 0);
1187
 
      if (block->temperature != BLOCK_WARM)
1188
 
      {
1189
 
        keycache->warm_blocks++;
1190
 
        block->temperature= BLOCK_WARM;
1191
 
      }
1192
 
    }
1193
 
  }
1194
 
}
1195
 
 
1196
 
/*
1197
 
  Remove a reader of the page in block
1198
 
*/
1199
 
 
1200
 
static void remove_reader(BLOCK_LINK *block)
1201
 
{
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);
1208
 
  if (! --block->hash_link->requests && block->condvar)
1209
 
    keycache_pthread_cond_signal(block->condvar);
1210
 
}
1211
 
 
1212
 
 
1213
 
/*
1214
 
  Wait until the last reader of the page in block
1215
 
  signals on its termination
1216
 
*/
1217
 
 
1218
 
static void wait_for_readers(KEY_CACHE *keycache,
1219
 
                             BLOCK_LINK *block)
1220
 
{
1221
 
  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 |
1224
 
                                 BLOCK_CHANGED)));
1225
 
  assert(block->hash_link);
1226
 
  assert(block->hash_link->block == block);
1227
 
  /* Linked in file_blocks or changed_blocks hash. */
1228
 
  assert(block->prev_changed && *block->prev_changed == block);
1229
 
  /* Not linked in LRU ring. */
1230
 
  assert(!block->next_used);
1231
 
  assert(!block->prev_used);
1232
 
  while (block->hash_link->requests)
1233
 
  {
1234
 
    /* There must be no other waiter. We have no queue here. */
1235
 
    assert(!block->condvar);
1236
 
    block->condvar= &thread->suspend;
1237
 
    keycache_pthread_cond_wait(&thread->suspend, &keycache->cache_lock);
1238
 
    block->condvar= NULL;
1239
 
  }
1240
 
}
1241
 
 
1242
 
 
1243
 
/*
1244
280
  Add a hash link to a bucket in the hash_table
1245
281
*/
1246
282
 
1255
291
 
1256
292
 
1257
293
/*
1258
 
  Remove a hash link from the hash table
1259
 
*/
1260
 
 
1261
 
static void unlink_hash(KEY_CACHE *keycache, HASH_LINK *hash_link)
1262
 
{
1263
 
  assert(hash_link->requests == 0);
1264
 
  if ((*hash_link->prev= hash_link->next))
1265
 
    hash_link->next->prev= hash_link->prev;
1266
 
  hash_link->block= NULL;
1267
 
  if (keycache->waiting_for_hash_link.last_thread)
1268
 
  {
1269
 
    /* Signal that a free hash link has appeared */
1270
 
    struct st_my_thread_var *last_thread=
1271
 
                               keycache->waiting_for_hash_link.last_thread;
1272
 
    struct st_my_thread_var *first_thread= last_thread->next;
1273
 
    struct st_my_thread_var *next_thread= first_thread;
1274
 
    KEYCACHE_PAGE *first_page= (KEYCACHE_PAGE *) (first_thread->opt_info);
1275
 
    struct st_my_thread_var *thread;
1276
 
 
1277
 
    hash_link->file= first_page->file;
1278
 
    hash_link->diskpos= first_page->filepos;
1279
 
    do
1280
 
    {
1281
 
      KEYCACHE_PAGE *page;
1282
 
      thread= next_thread;
1283
 
      page= (KEYCACHE_PAGE *) thread->opt_info;
1284
 
      next_thread= thread->next;
1285
 
      /*
1286
 
         We notify about the event all threads that ask
1287
 
         for the same page as the first thread in the queue
1288
 
      */
1289
 
      if (page->file == hash_link->file && page->filepos == hash_link->diskpos)
1290
 
      {
1291
 
        keycache_pthread_cond_signal(&thread->suspend);
1292
 
        unlink_from_queue(&keycache->waiting_for_hash_link, thread);
1293
 
      }
1294
 
    }
1295
 
    while (thread != last_thread);
1296
 
    link_hash(&keycache->hash_root[KEYCACHE_HASH(hash_link->file,
1297
 
                                                 hash_link->diskpos)],
1298
 
              hash_link);
1299
 
    return;
1300
 
  }
1301
 
  hash_link->next= keycache->free_hash_list;
1302
 
  keycache->free_hash_list= hash_link;
1303
 
}
1304
 
 
1305
 
 
1306
 
/*
1307
 
  Get the hash link for a page
1308
 
*/
1309
 
 
1310
 
static HASH_LINK *get_hash_link(KEY_CACHE *keycache,
1311
 
                                int file, my_off_t filepos)
1312
 
{
1313
 
  register HASH_LINK *hash_link, **start;
1314
 
 
1315
 
restart:
1316
 
  /*
1317
 
     Find the bucket in the hash table for the pair (file, filepos);
1318
 
     start contains the head of the bucket list,
1319
 
     hash_link points to the first member of the list
1320
 
  */
1321
 
  hash_link= *(start= &keycache->hash_root[KEYCACHE_HASH(file, filepos)]);
1322
 
  /* Look for an element for the pair (file, filepos) in the bucket chain */
1323
 
  while (hash_link &&
1324
 
         (hash_link->diskpos != filepos || hash_link->file != file))
1325
 
  {
1326
 
    hash_link= hash_link->next;
1327
 
  }
1328
 
  if (! hash_link)
1329
 
  {
1330
 
    /* There is no hash link in the hash table for the pair (file, filepos) */
1331
 
    if (keycache->free_hash_list)
1332
 
    {
1333
 
      hash_link= keycache->free_hash_list;
1334
 
      keycache->free_hash_list= hash_link->next;
1335
 
    }
1336
 
    else if (keycache->hash_links_used < keycache->hash_links)
1337
 
    {
1338
 
      hash_link= &keycache->hash_link_root[keycache->hash_links_used++];
1339
 
    }
1340
 
    else
1341
 
    {
1342
 
      /* Wait for a free hash link */
1343
 
      struct st_my_thread_var *thread= my_thread_var;
1344
 
      KEYCACHE_PAGE page;
1345
 
      page.file= file;
1346
 
      page.filepos= filepos;
1347
 
      thread->opt_info= (void *) &page;
1348
 
      link_into_queue(&keycache->waiting_for_hash_link, thread);
1349
 
      keycache_pthread_cond_wait(&thread->suspend,
1350
 
                                 &keycache->cache_lock);
1351
 
      thread->opt_info= NULL;
1352
 
      goto restart;
1353
 
    }
1354
 
    hash_link->file= file;
1355
 
    hash_link->diskpos= filepos;
1356
 
    link_hash(start, hash_link);
1357
 
  }
1358
 
  /* Register the request for the page */
1359
 
  hash_link->requests++;
1360
 
 
1361
 
  return hash_link;
1362
 
}
1363
 
 
1364
 
 
1365
 
/*
1366
 
  Get a block for the file page requested by a keycache read/write operation;
1367
 
  If the page is not in the cache return a free block, if there is none
1368
 
  return the lru block after saving its buffer if the page is dirty.
1369
 
 
1370
 
  SYNOPSIS
1371
 
 
1372
 
    find_key_block()
1373
 
      keycache            pointer to a key cache data structure
1374
 
      file                handler for the file to read page from
1375
 
      filepos             position of the page in the file
1376
 
      init_hits_left      how initialize the block counter for the page
1377
 
      wrmode              <-> get for writing
1378
 
      page_st        out  {PAGE_READ,PAGE_TO_BE_READ,PAGE_WAIT_TO_BE_READ}
1379
 
 
1380
 
  RETURN VALUE
1381
 
    Pointer to the found block if successful, 0 - otherwise
1382
 
 
1383
 
  NOTES.
1384
 
    For the page from file positioned at filepos the function checks whether
1385
 
    the page is in the key cache specified by the first parameter.
1386
 
    If this is the case it immediately returns the block.
1387
 
    If not, the function first chooses  a block for this page. If there is
1388
 
    no not used blocks in the key cache yet, the function takes the block
1389
 
    at the very beginning of the warm sub-chain. It saves the page in that
1390
 
    block if it's dirty before returning the pointer to it.
1391
 
    The function returns in the page_st parameter the following values:
1392
 
      PAGE_READ         - if page already in the block,
1393
 
      PAGE_TO_BE_READ   - if it is to be read yet by the current thread
1394
 
      WAIT_TO_BE_READ   - if it is to be read by another thread
1395
 
    If an error occurs THE BLOCK_ERROR bit is set in the block status.
1396
 
    It might happen that there are no blocks in LRU chain (in warm part) -
1397
 
    all blocks  are unlinked for some read/write operations. Then the function
1398
 
    waits until first of this operations links any block back.
1399
 
*/
1400
 
 
1401
 
static BLOCK_LINK *find_key_block(KEY_CACHE *keycache,
1402
 
                                  File file, my_off_t filepos,
1403
 
                                  int init_hits_left,
1404
 
                                  int wrmode, int *page_st)
1405
 
{
1406
 
  HASH_LINK *hash_link;
1407
 
  BLOCK_LINK *block;
1408
 
  int error= 0;
1409
 
  int page_status;
1410
 
 
1411
 
restart:
1412
 
  /*
1413
 
    If the flush phase of a resize operation fails, the cache is left
1414
 
    unusable. This will be detected only after "goto restart".
1415
 
  */
1416
 
  if (!keycache->can_be_used)
1417
 
    return(0);
1418
 
 
1419
 
  /*
1420
 
    Find the hash_link for the requested file block (file, filepos). We
1421
 
    do always get a hash_link here. It has registered our request so
1422
 
    that no other thread can use it for another file block until we
1423
 
    release the request (which is done by remove_reader() usually). The
1424
 
    hash_link can have a block assigned to it or not. If there is a
1425
 
    block, it may be assigned to this hash_link or not. In cases where a
1426
 
    block is evicted from the cache, it is taken from the LRU ring and
1427
 
    referenced by the new hash_link. But the block can still be assigned
1428
 
    to its old hash_link for some time if it needs to be flushed first,
1429
 
    or if there are other threads still reading it.
1430
 
 
1431
 
    Summary:
1432
 
      hash_link is always returned.
1433
 
      hash_link->block can be:
1434
 
      - NULL or
1435
 
      - not assigned to this hash_link or
1436
 
      - assigned to this hash_link. If assigned, the block can have
1437
 
        - invalid data (when freshly assigned) or
1438
 
        - valid data. Valid data can be
1439
 
          - changed over the file contents (dirty) or
1440
 
          - not changed (clean).
1441
 
  */
1442
 
  hash_link= get_hash_link(keycache, file, filepos);
1443
 
  assert((hash_link->file == file) && (hash_link->diskpos == filepos));
1444
 
 
1445
 
  page_status= -1;
1446
 
  if ((block= hash_link->block) &&
1447
 
      block->hash_link == hash_link && (block->status & BLOCK_READ))
1448
 
  {
1449
 
    /* Assigned block with valid (changed or unchanged) contents. */
1450
 
    page_status= PAGE_READ;
1451
 
  }
1452
 
  /*
1453
 
    else (page_status == -1)
1454
 
      - block == NULL or
1455
 
      - block not assigned to this hash_link or
1456
 
      - block assigned but not yet read from file (invalid data).
1457
 
  */
1458
 
 
1459
 
  if (keycache->in_resize)
1460
 
  {
1461
 
    /* This is a request during a resize operation */
1462
 
 
1463
 
    if (!block)
1464
 
    {
1465
 
      struct st_my_thread_var *thread;
1466
 
 
1467
 
      /*
1468
 
        The file block is not in the cache. We don't need it in the
1469
 
        cache: we are going to read or write directly to file. Cancel
1470
 
        the request. We can simply decrement hash_link->requests because
1471
 
        we did not release cache_lock since increasing it. So no other
1472
 
        thread can wait for our request to become released.
1473
 
      */
1474
 
      if (hash_link->requests == 1)
1475
 
      {
1476
 
        /*
1477
 
          We are the only one to request this hash_link (this file/pos).
1478
 
          Free the hash_link.
1479
 
        */
1480
 
        hash_link->requests--;
1481
 
        unlink_hash(keycache, hash_link);
1482
 
        return(0);
1483
 
      }
1484
 
 
1485
 
      /*
1486
 
        More requests on the hash_link. Someone tries to evict a block
1487
 
        for this hash_link (could have started before resizing started).
1488
 
        This means that the LRU ring is empty. Otherwise a block could
1489
 
        be assigned immediately. Behave like a thread that wants to
1490
 
        evict a block for this file/pos. Add to the queue of threads
1491
 
        waiting for a block. Wait until there is one assigned.
1492
 
 
1493
 
        Refresh the request on the hash-link so that it cannot be reused
1494
 
        for another file/pos.
1495
 
      */
1496
 
      thread= my_thread_var;
1497
 
      thread->opt_info= (void *) hash_link;
1498
 
      link_into_queue(&keycache->waiting_for_block, thread);
1499
 
      do
1500
 
      {
1501
 
        keycache_pthread_cond_wait(&thread->suspend,
1502
 
                                   &keycache->cache_lock);
1503
 
      } while (thread->next);
1504
 
      thread->opt_info= NULL;
1505
 
      /*
1506
 
        A block should now be assigned to the hash_link. But it may
1507
 
        still need to be evicted. Anyway, we should re-check the
1508
 
        situation. page_status must be set correctly.
1509
 
      */
1510
 
      hash_link->requests--;
1511
 
      goto restart;
1512
 
    } /* end of if (!block) */
1513
 
 
1514
 
    /*
1515
 
      There is a block for this file/pos in the cache. Register a
1516
 
      request on it. This unlinks it from the LRU ring (if it is there)
1517
 
      and hence protects it against eviction (if not already in
1518
 
      eviction). We need this for returning the block to the caller, for
1519
 
      calling remove_reader() (for debugging purposes), and for calling
1520
 
      free_block(). The only case where we don't need the request is if
1521
 
      the block is in eviction. In that case we have to unregister the
1522
 
      request later.
1523
 
    */
1524
 
    reg_requests(keycache, block, 1);
1525
 
 
1526
 
    if (page_status != PAGE_READ)
1527
 
    {
1528
 
      /*
1529
 
        - block not assigned to this hash_link or
1530
 
        - block assigned but not yet read from file (invalid data).
1531
 
 
1532
 
        This must be a block in eviction. It will be read soon. We need
1533
 
        to wait here until this happened. Otherwise the caller could
1534
 
        access a wrong block or a block which is in read. While waiting
1535
 
        we cannot lose hash_link nor block. We have registered a request
1536
 
        on the hash_link. Everything can happen to the block but changes
1537
 
        in the hash_link -> block relationship. In other words:
1538
 
        everything can happen to the block but free or another completed
1539
 
        eviction.
1540
 
 
1541
 
        Note that we bahave like a secondary requestor here. We just
1542
 
        cannot return with PAGE_WAIT_TO_BE_READ. This would work for
1543
 
        read requests and writes on dirty blocks that are not in flush
1544
 
        only. Waiting here on COND_FOR_REQUESTED works in all
1545
 
        situations.
1546
 
      */
1547
 
      assert(((block->hash_link != hash_link) &&
1548
 
                   (block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH))) ||
1549
 
                  ((block->hash_link == hash_link) &&
1550
 
                   !(block->status & BLOCK_READ)));
1551
 
      wait_on_queue(&block->wqueue[COND_FOR_REQUESTED], &keycache->cache_lock);
1552
 
      /*
1553
 
        Here we can trust that the block has been assigned to this
1554
 
        hash_link (block->hash_link == hash_link) and read into the
1555
 
        buffer (BLOCK_READ). The worst things possible here are that the
1556
 
        block is in free (BLOCK_REASSIGNED). But the block is still
1557
 
        assigned to the hash_link. The freeing thread waits until we
1558
 
        release our request on the hash_link. The block must not be
1559
 
        again in eviction because we registered an request on it before
1560
 
        starting to wait.
1561
 
      */
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)));
1565
 
    }
1566
 
    /*
1567
 
      The block is in the cache. Assigned to the hash_link. Valid data.
1568
 
      Note that in case of page_st == PAGE_READ, the block can be marked
1569
 
      for eviction. In any case it can be marked for freeing.
1570
 
    */
1571
 
 
1572
 
    if (!wrmode)
1573
 
    {
1574
 
      /* A reader can just read the block. */
1575
 
      *page_st= PAGE_READ;
1576
 
      assert((hash_link->file == file) &&
1577
 
                  (hash_link->diskpos == filepos) &&
1578
 
                  (block->hash_link == hash_link));
1579
 
      return(block);
1580
 
    }
1581
 
 
1582
 
    /*
1583
 
      This is a writer. No two writers for the same block can exist.
1584
 
      This must be assured by locks outside of the key cache.
1585
 
    */
1586
 
    assert(!(block->status & BLOCK_FOR_UPDATE));
1587
 
 
1588
 
    while (block->status & BLOCK_IN_FLUSH)
1589
 
    {
1590
 
      /*
1591
 
        Wait until the block is flushed to file. Do not release the
1592
 
        request on the hash_link yet to prevent that the block is freed
1593
 
        or reassigned while we wait. While we wait, several things can
1594
 
        happen to the block, including another flush. But the block
1595
 
        cannot be reassigned to another hash_link until we release our
1596
 
        request on it. But it can be marked BLOCK_REASSIGNED from free
1597
 
        or eviction, while they wait for us to release the hash_link.
1598
 
      */
1599
 
      wait_on_queue(&block->wqueue[COND_FOR_SAVED], &keycache->cache_lock);
1600
 
      /*
1601
 
        If the flush phase failed, the resize could have finished while
1602
 
        we waited here.
1603
 
      */
1604
 
      if (!keycache->in_resize)
1605
 
      {
1606
 
        remove_reader(block);
1607
 
        unreg_request(keycache, block, 1);
1608
 
        goto restart;
1609
 
      }
1610
 
      assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
1611
 
      assert(!(block->status & BLOCK_FOR_UPDATE));
1612
 
      assert(block->hash_link == hash_link);
1613
 
    }
1614
 
 
1615
 
    if (block->status & BLOCK_CHANGED)
1616
 
    {
1617
 
      /*
1618
 
        We want to write a block with changed contents. If the cache
1619
 
        block size is bigger than the callers block size (e.g. MyISAM),
1620
 
        the caller may replace part of the block only. Changes of the
1621
 
        other part of the block must be preserved. Since the block has
1622
 
        not yet been selected for flush, we can still add our changes.
1623
 
      */
1624
 
      *page_st= PAGE_READ;
1625
 
      assert((hash_link->file == file) &&
1626
 
                  (hash_link->diskpos == filepos) &&
1627
 
                  (block->hash_link == hash_link));
1628
 
      return(block);
1629
 
    }
1630
 
 
1631
 
    /*
1632
 
      This is a write request for a clean block. We do not want to have
1633
 
      new dirty blocks in the cache while resizing. We will free the
1634
 
      block and write directly to file. If the block is in eviction or
1635
 
      in free, we just let it go.
1636
 
 
1637
 
      Unregister from the hash_link. This must be done before freeing
1638
 
      the block. And it must be done if not freeing the block. Because
1639
 
      we could have waited above, we need to call remove_reader(). Other
1640
 
      threads could wait for us to release our request on the hash_link.
1641
 
    */
1642
 
    remove_reader(block);
1643
 
 
1644
 
    /* If the block is not in eviction and not in free, we can free it. */
1645
 
    if (!(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH |
1646
 
                           BLOCK_REASSIGNED)))
1647
 
    {
1648
 
      /*
1649
 
        Free block as we are going to write directly to file.
1650
 
        Although we have an exlusive lock for the updated key part,
1651
 
        the control can be yielded by the current thread as we might
1652
 
        have unfinished readers of other key parts in the block
1653
 
        buffer. Still we are guaranteed not to have any readers
1654
 
        of the key part we are writing into until the block is
1655
 
        removed from the cache as we set the BLOCK_REASSIGNED
1656
 
        flag (see the code below that handles reading requests).
1657
 
      */
1658
 
      free_block(keycache, block);
1659
 
    }
1660
 
    else
1661
 
    {
1662
 
      /*
1663
 
        The block will be evicted/freed soon. Don't touch it in any way.
1664
 
        Unregister the request that we registered above.
1665
 
      */
1666
 
      unreg_request(keycache, block, 1);
1667
 
 
1668
 
      /*
1669
 
        The block is still assigned to the hash_link (the file/pos that
1670
 
        we are going to write to). Wait until the eviction/free is
1671
 
        complete. Otherwise the direct write could complete before all
1672
 
        readers are done with the block. So they could read outdated
1673
 
        data.
1674
 
 
1675
 
        Since we released our request on the hash_link, it can be reused
1676
 
        for another file/pos. Hence we cannot just check for
1677
 
        block->hash_link == hash_link. As long as the resize is
1678
 
        proceeding the block cannot be reassigned to the same file/pos
1679
 
        again. So we can terminate the loop when the block is no longer
1680
 
        assigned to this file/pos.
1681
 
      */
1682
 
      do
1683
 
      {
1684
 
        wait_on_queue(&block->wqueue[COND_FOR_SAVED],
1685
 
                      &keycache->cache_lock);
1686
 
        /*
1687
 
          If the flush phase failed, the resize could have finished
1688
 
          while we waited here.
1689
 
        */
1690
 
        if (!keycache->in_resize)
1691
 
          goto restart;
1692
 
      } while (block->hash_link &&
1693
 
               (block->hash_link->file == file) &&
1694
 
               (block->hash_link->diskpos == filepos));
1695
 
    }
1696
 
    return(0);
1697
 
  }
1698
 
 
1699
 
  if (page_status == PAGE_READ &&
1700
 
      (block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH |
1701
 
                        BLOCK_REASSIGNED)))
1702
 
  {
1703
 
    /*
1704
 
      This is a request for a block to be removed from cache. The block
1705
 
      is assigned to this hash_link and contains valid data, but is
1706
 
      marked for eviction or to be freed. Possible reasons why it has
1707
 
      not yet been evicted/freed can be a flush before reassignment
1708
 
      (BLOCK_IN_SWITCH), readers of the block have not finished yet
1709
 
      (BLOCK_REASSIGNED), or the evicting thread did not yet awake after
1710
 
      the block has been selected for it (BLOCK_IN_EVICTION).
1711
 
 
1712
 
       Only reading requests can proceed until the old dirty page is flushed,
1713
 
       all others are to be suspended, then resubmitted
1714
 
    */
1715
 
    if (!wrmode && !(block->status & BLOCK_REASSIGNED))
1716
 
    {
1717
 
      /*
1718
 
        This is a read request and the block not yet reassigned. We can
1719
 
        register our request and proceed. This unlinks the block from
1720
 
        the LRU ring and protects it against eviction.
1721
 
      */
1722
 
      reg_requests(keycache, block, 1);
1723
 
    }
1724
 
    else
1725
 
    {
1726
 
      /*
1727
 
        Either this is a write request for a block that is in eviction
1728
 
        or in free. We must not use it any more. Instead we must evict
1729
 
        another block. But we cannot do this before the eviction/free is
1730
 
        done. Otherwise we would find the same hash_link + block again
1731
 
        and again.
1732
 
 
1733
 
        Or this is a read request for a block in eviction/free that does
1734
 
        not require a flush, but waits for readers to finish with the
1735
 
        block. We do not read this block to let the eviction/free happen
1736
 
        as soon as possible. Again we must wait so that we don't find
1737
 
        the same hash_link + block again and again.
1738
 
      */
1739
 
      assert(hash_link->requests);
1740
 
      hash_link->requests--;
1741
 
      wait_on_queue(&block->wqueue[COND_FOR_SAVED], &keycache->cache_lock);
1742
 
      /*
1743
 
        The block is no longer assigned to this hash_link.
1744
 
        Get another one.
1745
 
      */
1746
 
      goto restart;
1747
 
    }
1748
 
  }
1749
 
  else
1750
 
  {
1751
 
    /*
1752
 
      This is a request for a new block or for a block not to be removed.
1753
 
      Either
1754
 
      - block == NULL or
1755
 
      - block not assigned to this hash_link or
1756
 
      - block assigned but not yet read from file,
1757
 
      or
1758
 
      - block assigned with valid (changed or unchanged) data and
1759
 
      - it will not be reassigned/freed.
1760
 
    */
1761
 
    if (! block)
1762
 
    {
1763
 
      /* No block is assigned to the hash_link yet. */
1764
 
      if (keycache->blocks_unused)
1765
 
      {
1766
 
        if (keycache->free_block_list)
1767
 
        {
1768
 
          /* There is a block in the free list. */
1769
 
          block= keycache->free_block_list;
1770
 
          keycache->free_block_list= block->next_used;
1771
 
          block->next_used= NULL;
1772
 
        }
1773
 
        else
1774
 
        {
1775
 
          /* There are some never used blocks, take first of them */
1776
 
          assert(keycache->blocks_used <
1777
 
                      (uint32_t) keycache->disk_blocks);
1778
 
          block= &keycache->block_root[keycache->blocks_used];
1779
 
          block->buffer= ADD_TO_PTR(keycache->block_mem,
1780
 
                                    ((uint32_t) keycache->blocks_used*
1781
 
                                     keycache->key_cache_block_size),
1782
 
                                    uchar*);
1783
 
          keycache->blocks_used++;
1784
 
          assert(!block->next_used);
1785
 
        }
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);
1792
 
        keycache->blocks_unused--;
1793
 
        block->status= BLOCK_IN_USE;
1794
 
        block->length= 0;
1795
 
        block->offset= keycache->key_cache_block_size;
1796
 
        block->requests= 1;
1797
 
        block->temperature= BLOCK_COLD;
1798
 
        block->hits_left= init_hits_left;
1799
 
        block->last_hit_time= 0;
1800
 
        block->hash_link= hash_link;
1801
 
        hash_link->block= block;
1802
 
        link_to_file_list(keycache, block, file, 0);
1803
 
        page_status= PAGE_TO_BE_READ;
1804
 
      }
1805
 
      else
1806
 
      {
1807
 
        /*
1808
 
          There are no free blocks and no never used blocks, use a block
1809
 
          from the LRU ring.
1810
 
        */
1811
 
 
1812
 
        if (! keycache->used_last)
1813
 
        {
1814
 
          /*
1815
 
            The LRU ring is empty. Wait until a new block is added to
1816
 
            it. Several threads might wait here for the same hash_link,
1817
 
            all of them must get the same block. While waiting for a
1818
 
            block, after a block is selected for this hash_link, other
1819
 
            threads can run first before this one awakes. During this
1820
 
            time interval other threads find this hash_link pointing to
1821
 
            the block, which is still assigned to another hash_link. In
1822
 
            this case the block is not marked BLOCK_IN_SWITCH yet, but
1823
 
            it is marked BLOCK_IN_EVICTION.
1824
 
          */
1825
 
 
1826
 
          struct st_my_thread_var *thread= my_thread_var;
1827
 
          thread->opt_info= (void *) hash_link;
1828
 
          link_into_queue(&keycache->waiting_for_block, thread);
1829
 
          do
1830
 
          {
1831
 
            keycache_pthread_cond_wait(&thread->suspend,
1832
 
                                       &keycache->cache_lock);
1833
 
          }
1834
 
          while (thread->next);
1835
 
          thread->opt_info= NULL;
1836
 
          /* Assert that block has a request registered. */
1837
 
          assert(hash_link->block->requests);
1838
 
          /* Assert that block is not in LRU ring. */
1839
 
          assert(!hash_link->block->next_used);
1840
 
          assert(!hash_link->block->prev_used);
1841
 
        }
1842
 
        /*
1843
 
          If we waited above, hash_link->block has been assigned by
1844
 
          link_block(). Otherwise it is still NULL. In the latter case
1845
 
          we need to grab a block from the LRU ring ourselves.
1846
 
        */
1847
 
        block= hash_link->block;
1848
 
        if (! block)
1849
 
        {
1850
 
          /* Select the last block from the LRU ring. */
1851
 
          block= keycache->used_last->next_used;
1852
 
          block->hits_left= init_hits_left;
1853
 
          block->last_hit_time= 0;
1854
 
          hash_link->block= block;
1855
 
          /*
1856
 
            Register a request on the block. This unlinks it from the
1857
 
            LRU ring and protects it against eviction.
1858
 
          */
1859
 
          assert(!block->requests);
1860
 
          reg_requests(keycache, block,1);
1861
 
          /*
1862
 
            We do not need to set block->status|= BLOCK_IN_EVICTION here
1863
 
            because we will set block->status|= BLOCK_IN_SWITCH
1864
 
            immediately without releasing the lock in between. This does
1865
 
            also support debugging. When looking at the block, one can
1866
 
            see if the block has been selected by link_block() after the
1867
 
            LRU ring was empty, or if it was grabbed directly from the
1868
 
            LRU ring in this branch.
1869
 
          */
1870
 
        }
1871
 
 
1872
 
        /*
1873
 
          If we had to wait above, there is a small chance that another
1874
 
          thread grabbed this block for the same file block already. But
1875
 
          in most cases the first condition is true.
1876
 
        */
1877
 
        if (block->hash_link != hash_link &&
1878
 
            ! (block->status & BLOCK_IN_SWITCH) )
1879
 
        {
1880
 
          /* this is a primary request for a new page */
1881
 
          block->status|= BLOCK_IN_SWITCH;
1882
 
 
1883
 
          if (block->status & BLOCK_CHANGED)
1884
 
          {
1885
 
            /* The block contains a dirty page - push it out of the cache */
1886
 
 
1887
 
            if (block->status & BLOCK_IN_FLUSH)
1888
 
            {
1889
 
              /*
1890
 
                The block is marked for flush. If we do not wait here,
1891
 
                it could happen that we write the block, reassign it to
1892
 
                another file block, then, before the new owner can read
1893
 
                the new file block, the flusher writes the cache block
1894
 
                (which still has the old contents) to the new file block!
1895
 
              */
1896
 
              wait_on_queue(&block->wqueue[COND_FOR_SAVED],
1897
 
                            &keycache->cache_lock);
1898
 
              /*
1899
 
                The block is marked BLOCK_IN_SWITCH. It should be left
1900
 
                alone except for reading. No free, no write.
1901
 
              */
1902
 
              assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
1903
 
              assert(!(block->status & (BLOCK_REASSIGNED |
1904
 
                                             BLOCK_CHANGED |
1905
 
                                             BLOCK_FOR_UPDATE)));
1906
 
            }
1907
 
            else
1908
 
            {
1909
 
              block->status|= BLOCK_IN_FLUSH | BLOCK_IN_FLUSHWRITE;
1910
 
              /*
1911
 
                BLOCK_IN_EVICTION may be true or not. Other flags must
1912
 
                have a fixed value.
1913
 
              */
1914
 
              assert((block->status & ~BLOCK_IN_EVICTION) ==
1915
 
                          (BLOCK_READ | BLOCK_IN_SWITCH |
1916
 
                           BLOCK_IN_FLUSH | BLOCK_IN_FLUSHWRITE |
1917
 
                           BLOCK_CHANGED | BLOCK_IN_USE));
1918
 
              assert(block->hash_link);
1919
 
 
1920
 
              keycache_pthread_mutex_unlock(&keycache->cache_lock);
1921
 
              /*
1922
 
                The call is thread safe because only the current
1923
 
                thread might change the block->hash_link value
1924
 
              */
1925
 
              error= (pwrite(block->hash_link->file,
1926
 
                             block->buffer+block->offset,
1927
 
                             block->length - block->offset,
1928
 
                             block->hash_link->diskpos+ block->offset) == 0);
1929
 
              keycache_pthread_mutex_lock(&keycache->cache_lock);
1930
 
 
1931
 
              /* Block status must not have changed. */
1932
 
              assert((block->status & ~BLOCK_IN_EVICTION) ==
1933
 
                          (BLOCK_READ | BLOCK_IN_SWITCH |
1934
 
                           BLOCK_IN_FLUSH | BLOCK_IN_FLUSHWRITE |
1935
 
                           BLOCK_CHANGED | BLOCK_IN_USE));
1936
 
              keycache->global_cache_write++;
1937
 
            }
1938
 
          }
1939
 
 
1940
 
          block->status|= BLOCK_REASSIGNED;
1941
 
          /*
1942
 
            The block comes from the LRU ring. It must have a hash_link
1943
 
            assigned.
1944
 
          */
1945
 
          assert(block->hash_link);
1946
 
          if (block->hash_link)
1947
 
          {
1948
 
            /*
1949
 
              All pending requests for this page must be resubmitted.
1950
 
              This must be done before waiting for readers. They could
1951
 
              wait for the flush to complete. And we must also do it
1952
 
              after the wait. Flushers might try to free the block while
1953
 
              we wait. They would wait until the reassignment is
1954
 
              complete. Also the block status must reflect the correct
1955
 
              situation: The block is not changed nor in flush any more.
1956
 
              Note that we must not change the BLOCK_CHANGED flag
1957
 
              outside of link_to_file_list() so that it is always in the
1958
 
              correct queue and the *blocks_changed counters are
1959
 
              correct.
1960
 
            */
1961
 
            block->status&= ~(BLOCK_IN_FLUSH | BLOCK_IN_FLUSHWRITE);
1962
 
            link_to_file_list(keycache, block, block->hash_link->file, 1);
1963
 
            release_whole_queue(&block->wqueue[COND_FOR_SAVED]);
1964
 
            /*
1965
 
              The block is still assigned to its old hash_link.
1966
 
              Wait until all pending read requests
1967
 
              for this page are executed
1968
 
              (we could have avoided this waiting, if we had read
1969
 
              a page in the cache in a sweep, without yielding control)
1970
 
            */
1971
 
            wait_for_readers(keycache, block);
1972
 
            assert(block->hash_link && block->hash_link->block == block &&
1973
 
                        block->prev_changed);
1974
 
            /* The reader must not have been a writer. */
1975
 
            assert(!(block->status & BLOCK_CHANGED));
1976
 
 
1977
 
            /* Wake flushers that might have found the block in between. */
1978
 
            release_whole_queue(&block->wqueue[COND_FOR_SAVED]);
1979
 
 
1980
 
            /* Remove the hash link for the old file block from the hash. */
1981
 
            unlink_hash(keycache, block->hash_link);
1982
 
 
1983
 
            /*
1984
 
              For sanity checks link_to_file_list() asserts that block
1985
 
              and hash_link refer to each other. Hence we need to assign
1986
 
              the hash_link first, but then we would not know if it was
1987
 
              linked before. Hence we would not know if to unlink it. So
1988
 
              unlink it here and call link_to_file_list(..., false).
1989
 
            */
1990
 
            unlink_changed(block);
1991
 
          }
1992
 
          block->status= error ? BLOCK_ERROR : BLOCK_IN_USE ;
1993
 
          block->length= 0;
1994
 
          block->offset= keycache->key_cache_block_size;
1995
 
          block->hash_link= hash_link;
1996
 
          link_to_file_list(keycache, block, file, 0);
1997
 
          page_status= PAGE_TO_BE_READ;
1998
 
 
1999
 
          assert(block->hash_link->block == block);
2000
 
          assert(hash_link->block->hash_link == hash_link);
2001
 
        }
2002
 
        else
2003
 
        {
2004
 
          /*
2005
 
            Either (block->hash_link == hash_link),
2006
 
            or     (block->status & BLOCK_IN_SWITCH).
2007
 
 
2008
 
            This is for secondary requests for a new file block only.
2009
 
            Either it is already assigned to the new hash_link meanwhile
2010
 
            (if we had to wait due to empty LRU), or it is already in
2011
 
            eviction by another thread. Since this block has been
2012
 
            grabbed from the LRU ring and attached to this hash_link,
2013
 
            another thread cannot grab the same block from the LRU ring
2014
 
            anymore. If the block is in eviction already, it must become
2015
 
            attached to the same hash_link and as such destined for the
2016
 
            same file block.
2017
 
          */
2018
 
          page_status= (((block->hash_link == hash_link) &&
2019
 
                         (block->status & BLOCK_READ)) ?
2020
 
                        PAGE_READ : PAGE_WAIT_TO_BE_READ);
2021
 
        }
2022
 
      }
2023
 
    }
2024
 
    else
2025
 
    {
2026
 
      /*
2027
 
        Block is not NULL. This hash_link points to a block.
2028
 
        Either
2029
 
        - block not assigned to this hash_link (yet) or
2030
 
        - block assigned but not yet read from file,
2031
 
        or
2032
 
        - block assigned with valid (changed or unchanged) data and
2033
 
        - it will not be reassigned/freed.
2034
 
 
2035
 
        The first condition means hash_link points to a block in
2036
 
        eviction. This is not necessarily marked by BLOCK_IN_SWITCH yet.
2037
 
        But then it is marked BLOCK_IN_EVICTION. See the NOTE in
2038
 
        link_block(). In both cases it is destined for this hash_link
2039
 
        and its file block address. When this hash_link got its block
2040
 
        address, the block was removed from the LRU ring and cannot be
2041
 
        selected for eviction (for another hash_link) again.
2042
 
 
2043
 
        Register a request on the block. This is another protection
2044
 
        against eviction.
2045
 
      */
2046
 
      assert(((block->hash_link != hash_link) &&
2047
 
                   (block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH))) ||
2048
 
                  ((block->hash_link == hash_link) &&
2049
 
                   !(block->status & BLOCK_READ)) ||
2050
 
                  ((block->status & BLOCK_READ) &&
2051
 
                   !(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH))));
2052
 
      reg_requests(keycache, block, 1);
2053
 
      page_status= (((block->hash_link == hash_link) &&
2054
 
                     (block->status & BLOCK_READ)) ?
2055
 
                    PAGE_READ : PAGE_WAIT_TO_BE_READ);
2056
 
    }
2057
 
  }
2058
 
 
2059
 
  assert(page_status != -1);
2060
 
  /* Same assert basically, but be very sure. */
2061
 
  assert(block);
2062
 
  /* 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);
2066
 
  /* Assert that we return the correct block. */
2067
 
  assert((page_status == PAGE_WAIT_TO_BE_READ) ||
2068
 
              ((block->hash_link->file == file) &&
2069
 
               (block->hash_link->diskpos == filepos)));
2070
 
  *page_st=page_status;
2071
 
 
2072
 
  return(block);
2073
 
}
2074
 
 
2075
 
 
2076
 
/*
2077
 
  Read into a key cache block buffer from disk.
2078
 
 
2079
 
  SYNOPSIS
2080
 
 
2081
 
    read_block()
2082
 
      keycache            pointer to a key cache data structure
2083
 
      block               block to which buffer the data is to be read
2084
 
      read_length         size of data to be read
2085
 
      min_length          at least so much data must be read
2086
 
      primary             <-> the current thread will read the data
2087
 
 
2088
 
  RETURN VALUE
2089
 
    None
2090
 
 
2091
 
  NOTES.
2092
 
    The function either reads a page data from file to the block buffer,
2093
 
    or waits until another thread reads it. What page to read is determined
2094
 
    by a block parameter - reference to a hash link for this page.
2095
 
    If an error occurs THE BLOCK_ERROR bit is set in the block status.
2096
 
    We do not report error when the size of successfully read
2097
 
    portion is less than read_length, but not less than min_length.
2098
 
*/
2099
 
 
2100
 
static void read_block(KEY_CACHE *keycache,
2101
 
                       BLOCK_LINK *block, uint read_length,
2102
 
                       uint min_length, bool primary)
2103
 
{
2104
 
  uint got_length;
2105
 
 
2106
 
  /* On entry cache_lock is locked */
2107
 
 
2108
 
  if (primary)
2109
 
  {
2110
 
    /*
2111
 
      This code is executed only by threads that submitted primary
2112
 
      requests. Until block->status contains BLOCK_READ, all other
2113
 
      request for the block become secondary requests. For a primary
2114
 
      request the block must be properly initialized.
2115
 
    */
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));
2120
 
 
2121
 
    keycache->global_cache_read++;
2122
 
    /* Page is not in buffer yet, is to be read from disk */
2123
 
    keycache_pthread_mutex_unlock(&keycache->cache_lock);
2124
 
    /*
2125
 
      Here other threads may step in and register as secondary readers.
2126
 
      They will register in block->wqueue[COND_FOR_REQUESTED].
2127
 
    */
2128
 
    got_length= pread(block->hash_link->file, block->buffer, read_length, block->hash_link->diskpos);
2129
 
    keycache_pthread_mutex_lock(&keycache->cache_lock);
2130
 
    /*
2131
 
      The block can now have been marked for free (in case of
2132
 
      FLUSH_RELEASE). Otherwise the state must be unchanged.
2133
 
    */
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));
2139
 
 
2140
 
    if (got_length < min_length)
2141
 
      block->status|= BLOCK_ERROR;
2142
 
    else
2143
 
    {
2144
 
      block->status|= BLOCK_READ;
2145
 
      block->length= got_length;
2146
 
      /*
2147
 
        Do not set block->offset here. If this block is marked
2148
 
        BLOCK_CHANGED later, we want to flush only the modified part. So
2149
 
        only a writer may set block->offset down from
2150
 
        keycache->key_cache_block_size.
2151
 
      */
2152
 
    }
2153
 
    /* Signal that all pending requests for this page now can be processed */
2154
 
    release_whole_queue(&block->wqueue[COND_FOR_REQUESTED]);
2155
 
  }
2156
 
  else
2157
 
  {
2158
 
    /*
2159
 
      This code is executed only by threads that submitted secondary
2160
 
      requests. At this point it could happen that the cache block is
2161
 
      not yet assigned to the hash_link for the requested file block.
2162
 
      But at awake from the wait this should be the case. Unfortunately
2163
 
      we cannot assert this here because we do not know the hash_link
2164
 
      for the requested file block nor the file and position. So we have
2165
 
      to assert this in the caller.
2166
 
    */
2167
 
    wait_on_queue(&block->wqueue[COND_FOR_REQUESTED], &keycache->cache_lock);
2168
 
  }
2169
 
}
2170
 
 
2171
 
 
2172
 
/*
2173
294
  Read a block of data from a cached file into a buffer;
2174
295
 
2175
296
  SYNOPSIS
2197
318
    have to be a multiple of key_cache_block_size;
2198
319
*/
2199
320
 
2200
 
uchar *key_cache_read(KEY_CACHE *keycache,
2201
 
                      File file, my_off_t filepos, int level,
2202
 
                      uchar *buff, uint length,
2203
 
                      uint block_length __attribute__((unused)),
2204
 
                      int return_buffer __attribute__((unused)))
 
321
unsigned char *key_cache_read(KEY_CACHE *keycache,
 
322
                      int file, internal::my_off_t filepos, int level,
 
323
                      unsigned char *buff, uint32_t length,
 
324
                      uint32_t block_length,
 
325
                      int return_buffer)
2205
326
{
2206
 
  bool locked_and_incremented= false;
 
327
  (void)block_length;
 
328
  (void)return_buffer;
 
329
  (void)level;
2207
330
  int error=0;
2208
 
  uchar *start= buff;
2209
 
 
2210
 
  if (keycache->key_cache_inited)
2211
 
  {
2212
 
    /* Key cache is used */
2213
 
    register BLOCK_LINK *block;
2214
 
    uint read_length;
2215
 
    uint offset;
2216
 
    uint status;
2217
 
    int page_st;
2218
 
 
2219
 
    /*
2220
 
      When the key cache is once initialized, we use the cache_lock to
2221
 
      reliably distinguish the cases of normal operation, resizing, and
2222
 
      disabled cache. We always increment and decrement
2223
 
      'cnt_for_resize_op' so that a resizer can wait for pending I/O.
2224
 
    */
2225
 
    keycache_pthread_mutex_lock(&keycache->cache_lock);
2226
 
    /*
2227
 
      Cache resizing has two phases: Flushing and re-initializing. In
2228
 
      the flush phase read requests are allowed to bypass the cache for
2229
 
      blocks not in the cache. find_key_block() returns NULL in this
2230
 
      case.
2231
 
 
2232
 
      After the flush phase new I/O requests must wait until the
2233
 
      re-initialization is done. The re-initialization can be done only
2234
 
      if no I/O request is in progress. The reason is that
2235
 
      key_cache_block_size can change. With enabled cache, I/O is done
2236
 
      in chunks of key_cache_block_size. Every chunk tries to use a
2237
 
      cache block first. If the block size changes in the middle, a
2238
 
      block could be missed and old data could be read.
2239
 
    */
2240
 
    while (keycache->in_resize && !keycache->resize_in_flush)
2241
 
      wait_on_queue(&keycache->resize_queue, &keycache->cache_lock);
2242
 
    /* Register the I/O for the next resize. */
2243
 
    inc_counter_for_resize_op(keycache);
2244
 
    locked_and_incremented= true;
2245
 
    /* Requested data may not always be aligned to cache blocks. */
2246
 
    offset= (uint) (filepos % keycache->key_cache_block_size);
2247
 
    /* Read data in key_cache_block_size increments */
2248
 
    do
2249
 
    {
2250
 
      /* Cache could be disabled in a later iteration. */
2251
 
 
2252
 
      if (!keycache->can_be_used)
2253
 
        goto no_key_cache;
2254
 
      /* Start reading at the beginning of the cache block. */
2255
 
      filepos-= offset;
2256
 
      /* Do not read beyond the end of the cache block. */
2257
 
      read_length= length;
2258
 
      set_if_smaller(read_length, keycache->key_cache_block_size-offset);
2259
 
      assert(read_length > 0);
2260
 
 
2261
 
      /* Request the cache block that matches file/pos. */
2262
 
      keycache->global_cache_r_requests++;
2263
 
      block=find_key_block(keycache, file, filepos, level, 0, &page_st);
2264
 
      if (!block)
2265
 
      {
2266
 
        /*
2267
 
          This happens only for requests submitted during key cache
2268
 
          resize. The block is not in the cache and shall not go in.
2269
 
          Read directly from file.
2270
 
        */
2271
 
        keycache->global_cache_read++;
2272
 
        keycache_pthread_mutex_unlock(&keycache->cache_lock);
2273
 
        error= (pread(file, (uchar*) buff, read_length, filepos + offset) == 0);
2274
 
        keycache_pthread_mutex_lock(&keycache->cache_lock);
2275
 
        goto next_block;
2276
 
      }
2277
 
      if (!(block->status & BLOCK_ERROR))
2278
 
      {
2279
 
        if (page_st != PAGE_READ)
2280
 
        {
2281
 
          /* The requested page is to be read into the block buffer */
2282
 
          read_block(keycache, block,
2283
 
                     keycache->key_cache_block_size, read_length+offset,
2284
 
                     (bool)(page_st == PAGE_TO_BE_READ));
2285
 
          /*
2286
 
            A secondary request must now have the block assigned to the
2287
 
            requested file block. It does not hurt to check it for
2288
 
            primary requests too.
2289
 
          */
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));
2294
 
        }
2295
 
        else if (block->length < read_length + offset)
2296
 
        {
2297
 
          /*
2298
 
            Impossible if nothing goes wrong:
2299
 
            this could only happen if we are using a file with
2300
 
            small key blocks and are trying to read outside the file
2301
 
          */
2302
 
          my_errno= -1;
2303
 
          block->status|= BLOCK_ERROR;
2304
 
        }
2305
 
      }
2306
 
 
2307
 
      /* block status may have added BLOCK_ERROR in the above 'if'. */
2308
 
      if (!((status= block->status) & BLOCK_ERROR))
2309
 
      {
2310
 
        {
2311
 
          assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
2312
 
#if !defined(SERIALIZED_READ_FROM_CACHE)
2313
 
          keycache_pthread_mutex_unlock(&keycache->cache_lock);
2314
 
#endif
2315
 
 
2316
 
          /* Copy data from the cache buffer */
2317
 
          memcpy(buff, block->buffer+offset, (size_t) read_length);
2318
 
 
2319
 
#if !defined(SERIALIZED_READ_FROM_CACHE)
2320
 
          keycache_pthread_mutex_lock(&keycache->cache_lock);
2321
 
          assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
2322
 
#endif
2323
 
        }
2324
 
      }
2325
 
 
2326
 
      remove_reader(block);
2327
 
 
2328
 
      /*
2329
 
         Link the block into the LRU ring if it's the last submitted
2330
 
         request for the block. This enables eviction for the block.
2331
 
           */
2332
 
      unreg_request(keycache, block, 1);
2333
 
 
2334
 
      if (status & BLOCK_ERROR)
2335
 
      {
2336
 
        error= 1;
2337
 
        break;
2338
 
      }
2339
 
 
2340
 
  next_block:
2341
 
      buff+= read_length;
2342
 
      filepos+= read_length+offset;
2343
 
      offset= 0;
2344
 
 
2345
 
    } while ((length-= read_length));
2346
 
    goto end;
2347
 
  }
2348
 
 
2349
 
no_key_cache:
2350
 
  /* Key cache is not used */
2351
 
 
2352
 
  keycache->global_cache_r_requests++;
2353
 
  keycache->global_cache_read++;
2354
 
 
2355
 
  if (locked_and_incremented)
2356
 
    keycache_pthread_mutex_unlock(&keycache->cache_lock);
2357
 
  if (pread(file, (uchar*) buff, length, filepos))
 
331
  unsigned char *start= buff;
 
332
 
 
333
  assert (! keycache->key_cache_inited);
 
334
 
 
335
  if (!pread(file, (unsigned char*) buff, length, filepos))
2358
336
    error= 1;
2359
 
  if (locked_and_incremented)
2360
 
    keycache_pthread_mutex_lock(&keycache->cache_lock);
2361
 
 
2362
 
end:
2363
 
  if (locked_and_incremented)
2364
 
  {
2365
 
    dec_counter_for_resize_op(keycache);
2366
 
    keycache_pthread_mutex_unlock(&keycache->cache_lock);
2367
 
  }
2368
 
  return(error ? (uchar*) 0 : start);
 
337
  return(error ? (unsigned char*) 0 : start);
2369
338
}
2370
339
 
2371
340
 
2390
359
*/
2391
360
 
2392
361
int key_cache_insert(KEY_CACHE *keycache,
2393
 
                     File file, my_off_t filepos, int level,
2394
 
                     uchar *buff, uint length)
 
362
                     int file, internal::my_off_t filepos, int level,
 
363
                     unsigned char *buff, uint32_t length)
2395
364
{
2396
 
  int error= 0;
2397
 
 
2398
 
  if (keycache->key_cache_inited)
2399
 
  {
2400
 
    /* Key cache is used */
2401
 
    register BLOCK_LINK *block;
2402
 
    uint read_length;
2403
 
    uint offset;
2404
 
    int page_st;
2405
 
    bool locked_and_incremented= false;
2406
 
 
2407
 
    /*
2408
 
      When the keycache is once initialized, we use the cache_lock to
2409
 
      reliably distinguish the cases of normal operation, resizing, and
2410
 
      disabled cache. We always increment and decrement
2411
 
      'cnt_for_resize_op' so that a resizer can wait for pending I/O.
2412
 
    */
2413
 
    keycache_pthread_mutex_lock(&keycache->cache_lock);
2414
 
    /*
2415
 
      We do not load index data into a disabled cache nor into an
2416
 
      ongoing resize.
2417
 
    */
2418
 
    if (!keycache->can_be_used || keycache->in_resize)
2419
 
        goto no_key_cache;
2420
 
    /* Register the pseudo I/O for the next resize. */
2421
 
    inc_counter_for_resize_op(keycache);
2422
 
    locked_and_incremented= true;
2423
 
    /* Loaded data may not always be aligned to cache blocks. */
2424
 
    offset= (uint) (filepos % keycache->key_cache_block_size);
2425
 
    /* Load data in key_cache_block_size increments. */
2426
 
    do
2427
 
    {
2428
 
      /* Cache could be disabled or resizing in a later iteration. */
2429
 
      if (!keycache->can_be_used || keycache->in_resize)
2430
 
        goto no_key_cache;
2431
 
      /* Start loading at the beginning of the cache block. */
2432
 
      filepos-= offset;
2433
 
      /* Do not load beyond the end of the cache block. */
2434
 
      read_length= length;
2435
 
      set_if_smaller(read_length, keycache->key_cache_block_size-offset);
2436
 
      assert(read_length > 0);
2437
 
 
2438
 
      /* The block has been read by the caller already. */
2439
 
      keycache->global_cache_read++;
2440
 
      /* Request the cache block that matches file/pos. */
2441
 
      keycache->global_cache_r_requests++;
2442
 
      block= find_key_block(keycache, file, filepos, level, 0, &page_st);
2443
 
      if (!block)
2444
 
      {
2445
 
        /*
2446
 
          This happens only for requests submitted during key cache
2447
 
          resize. The block is not in the cache and shall not go in.
2448
 
          Stop loading index data.
2449
 
        */
2450
 
        goto no_key_cache;
2451
 
      }
2452
 
      if (!(block->status & BLOCK_ERROR))
2453
 
      {
2454
 
        if ((page_st == PAGE_WAIT_TO_BE_READ) ||
2455
 
            ((page_st == PAGE_TO_BE_READ) &&
2456
 
             (offset || (read_length < keycache->key_cache_block_size))))
2457
 
        {
2458
 
          /*
2459
 
            Either
2460
 
 
2461
 
            this is a secondary request for a block to be read into the
2462
 
            cache. The block is in eviction. It is not yet assigned to
2463
 
            the requested file block (It does not point to the right
2464
 
            hash_link). So we cannot call remove_reader() on the block.
2465
 
            And we cannot access the hash_link directly here. We need to
2466
 
            wait until the assignment is complete. read_block() executes
2467
 
            the correct wait when called with primary == false.
2468
 
 
2469
 
            Or
2470
 
 
2471
 
            this is a primary request for a block to be read into the
2472
 
            cache and the supplied data does not fill the whole block.
2473
 
 
2474
 
            This function is called on behalf of a LOAD INDEX INTO CACHE
2475
 
            statement, which is a read-only task and allows other
2476
 
            readers. It is possible that a parallel running reader tries
2477
 
            to access this block. If it needs more data than has been
2478
 
            supplied here, it would report an error. To be sure that we
2479
 
            have all data in the block that is available in the file, we
2480
 
            read the block ourselves.
2481
 
 
2482
 
            Though reading again what the caller did read already is an
2483
 
            expensive operation, we need to do this for correctness.
2484
 
          */
2485
 
          read_block(keycache, block, keycache->key_cache_block_size,
2486
 
                     read_length + offset, (page_st == PAGE_TO_BE_READ));
2487
 
          /*
2488
 
            A secondary request must now have the block assigned to the
2489
 
            requested file block. It does not hurt to check it for
2490
 
            primary requests too.
2491
 
          */
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));
2496
 
        }
2497
 
        else if (page_st == PAGE_TO_BE_READ)
2498
 
        {
2499
 
          /*
2500
 
            This is a new block in the cache. If we come here, we have
2501
 
            data for the whole block.
2502
 
          */
2503
 
          assert(block->hash_link->requests);
2504
 
          assert(block->status & BLOCK_IN_USE);
2505
 
          assert((page_st == PAGE_TO_BE_READ) ||
2506
 
                      (block->status & BLOCK_READ));
2507
 
 
2508
 
#if !defined(SERIALIZED_READ_FROM_CACHE)
2509
 
          keycache_pthread_mutex_unlock(&keycache->cache_lock);
2510
 
          /*
2511
 
            Here other threads may step in and register as secondary readers.
2512
 
            They will register in block->wqueue[COND_FOR_REQUESTED].
2513
 
          */
2514
 
#endif
2515
 
 
2516
 
          /* Copy data from buff */
2517
 
          memcpy(block->buffer+offset, buff, (size_t) read_length);
2518
 
 
2519
 
#if !defined(SERIALIZED_READ_FROM_CACHE)
2520
 
          keycache_pthread_mutex_lock(&keycache->cache_lock);
2521
 
          assert(block->status & BLOCK_IN_USE);
2522
 
          assert((page_st == PAGE_TO_BE_READ) ||
2523
 
                      (block->status & BLOCK_READ));
2524
 
#endif
2525
 
          /*
2526
 
            After the data is in the buffer, we can declare the block
2527
 
            valid. Now other threads do not need to register as
2528
 
            secondary readers any more. They can immediately access the
2529
 
            block.
2530
 
          */
2531
 
          block->status|= BLOCK_READ;
2532
 
          block->length= read_length+offset;
2533
 
          /*
2534
 
            Do not set block->offset here. If this block is marked
2535
 
            BLOCK_CHANGED later, we want to flush only the modified part. So
2536
 
            only a writer may set block->offset down from
2537
 
            keycache->key_cache_block_size.
2538
 
          */
2539
 
          /* Signal all pending requests. */
2540
 
          release_whole_queue(&block->wqueue[COND_FOR_REQUESTED]);
2541
 
        }
2542
 
        else
2543
 
        {
2544
 
          /*
2545
 
            page_st == PAGE_READ. The block is in the buffer. All data
2546
 
            must already be present. Blocks are always read with all
2547
 
            data available on file. Assert that the block does not have
2548
 
            less contents than the preloader supplies. If the caller has
2549
 
            data beyond block->length, it means that a file write has
2550
 
            been done while this block was in cache and not extended
2551
 
            with the new data. If the condition is met, we can simply
2552
 
            ignore the block.
2553
 
          */
2554
 
          assert((page_st == PAGE_READ) &&
2555
 
                      (read_length + offset <= block->length));
2556
 
        }
2557
 
 
2558
 
        /*
2559
 
          A secondary request must now have the block assigned to the
2560
 
          requested file block. It does not hurt to check it for primary
2561
 
          requests too.
2562
 
        */
2563
 
        assert(block->hash_link->file == file);
2564
 
        assert(block->hash_link->diskpos == filepos);
2565
 
        assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
2566
 
      } /* end of if (!(block->status & BLOCK_ERROR)) */
2567
 
 
2568
 
 
2569
 
      remove_reader(block);
2570
 
 
2571
 
      /*
2572
 
         Link the block into the LRU ring if it's the last submitted
2573
 
         request for the block. This enables eviction for the block.
2574
 
      */
2575
 
      unreg_request(keycache, block, 1);
2576
 
 
2577
 
      error= (block->status & BLOCK_ERROR);
2578
 
 
2579
 
      if (error)
2580
 
        break;
2581
 
 
2582
 
      buff+= read_length;
2583
 
      filepos+= read_length+offset;
2584
 
      offset= 0;
2585
 
 
2586
 
    } while ((length-= read_length));
2587
 
 
2588
 
  no_key_cache:
2589
 
    if (locked_and_incremented)
2590
 
      dec_counter_for_resize_op(keycache);
2591
 
    keycache_pthread_mutex_unlock(&keycache->cache_lock);
2592
 
  }
2593
 
  return(error);
 
365
  (void)file;
 
366
  (void)filepos;
 
367
  (void)level;
 
368
  (void)buff;
 
369
  (void)length;
 
370
 
 
371
  assert (!keycache->key_cache_inited);
 
372
  return 0;
2594
373
}
2595
374
 
2596
375
 
2624
403
*/
2625
404
 
2626
405
int key_cache_write(KEY_CACHE *keycache,
2627
 
                    File file, my_off_t filepos, int level,
2628
 
                    uchar *buff, uint length,
2629
 
                    uint block_length  __attribute__((unused)),
 
406
                    int file, internal::my_off_t filepos, int level,
 
407
                    unsigned char *buff, uint32_t length,
 
408
                    uint32_t block_length,
2630
409
                    int dont_write)
2631
410
{
2632
 
  bool locked_and_incremented= false;
 
411
  (void)block_length;
 
412
  (void)level;
2633
413
  int error=0;
2634
414
 
2635
415
  if (!dont_write)
2636
416
  {
2637
 
    /* purecov: begin inspected */
2638
417
    /* Not used in the server. */
2639
418
    /* Force writing from buff into disk. */
2640
 
    keycache->global_cache_w_requests++;
2641
 
    keycache->global_cache_write++;
2642
419
    if (pwrite(file, buff, length, filepos) == 0)
2643
420
      return(1);
2644
 
    /* purecov: end */
2645
 
  }
2646
 
 
2647
 
  if (keycache->key_cache_inited)
2648
 
  {
2649
 
    /* Key cache is used */
2650
 
    register BLOCK_LINK *block;
2651
 
    uint read_length;
2652
 
    uint offset;
2653
 
    int page_st;
2654
 
 
2655
 
    /*
2656
 
      When the key cache is once initialized, we use the cache_lock to
2657
 
      reliably distinguish the cases of normal operation, resizing, and
2658
 
      disabled cache. We always increment and decrement
2659
 
      'cnt_for_resize_op' so that a resizer can wait for pending I/O.
2660
 
    */
2661
 
    keycache_pthread_mutex_lock(&keycache->cache_lock);
2662
 
    /*
2663
 
      Cache resizing has two phases: Flushing and re-initializing. In
2664
 
      the flush phase write requests can modify dirty blocks that are
2665
 
      not yet in flush. Otherwise they are allowed to bypass the cache.
2666
 
      find_key_block() returns NULL in both cases (clean blocks and
2667
 
      non-cached blocks).
2668
 
 
2669
 
      After the flush phase new I/O requests must wait until the
2670
 
      re-initialization is done. The re-initialization can be done only
2671
 
      if no I/O request is in progress. The reason is that
2672
 
      key_cache_block_size can change. With enabled cache I/O is done in
2673
 
      chunks of key_cache_block_size. Every chunk tries to use a cache
2674
 
      block first. If the block size changes in the middle, a block
2675
 
      could be missed and data could be written below a cached block.
2676
 
    */
2677
 
    while (keycache->in_resize && !keycache->resize_in_flush)
2678
 
      wait_on_queue(&keycache->resize_queue, &keycache->cache_lock);
2679
 
    /* Register the I/O for the next resize. */
2680
 
    inc_counter_for_resize_op(keycache);
2681
 
    locked_and_incremented= true;
2682
 
    /* Requested data may not always be aligned to cache blocks. */
2683
 
    offset= (uint) (filepos % keycache->key_cache_block_size);
2684
 
    /* Write data in key_cache_block_size increments. */
2685
 
    do
2686
 
    {
2687
 
      /* Cache could be disabled in a later iteration. */
2688
 
      if (!keycache->can_be_used)
2689
 
        goto no_key_cache;
2690
 
      /* Start writing at the beginning of the cache block. */
2691
 
      filepos-= offset;
2692
 
      /* Do not write beyond the end of the cache block. */
2693
 
      read_length= length;
2694
 
      set_if_smaller(read_length, keycache->key_cache_block_size-offset);
2695
 
      assert(read_length > 0);
2696
 
 
2697
 
      /* Request the cache block that matches file/pos. */
2698
 
      keycache->global_cache_w_requests++;
2699
 
      block= find_key_block(keycache, file, filepos, level, 1, &page_st);
2700
 
      if (!block)
2701
 
      {
2702
 
        /*
2703
 
          This happens only for requests submitted during key cache
2704
 
          resize. The block is not in the cache and shall not go in.
2705
 
          Write directly to file.
2706
 
        */
2707
 
        if (dont_write)
2708
 
        {
2709
 
          /* Used in the server. */
2710
 
          keycache->global_cache_write++;
2711
 
          keycache_pthread_mutex_unlock(&keycache->cache_lock);
2712
 
          if (pwrite(file, (uchar*) buff, read_length, filepos + offset) == 0)
2713
 
            error=1;
2714
 
          keycache_pthread_mutex_lock(&keycache->cache_lock);
2715
 
        }
2716
 
        goto next_block;
2717
 
      }
2718
 
      /*
2719
 
        Prevent block from flushing and from being selected for to be
2720
 
        freed. This must be set when we release the cache_lock.
2721
 
        However, we must not set the status of the block before it is
2722
 
        assigned to this file/pos.
2723
 
      */
2724
 
      if (page_st != PAGE_WAIT_TO_BE_READ)
2725
 
        block->status|= BLOCK_FOR_UPDATE;
2726
 
      /*
2727
 
        We must read the file block first if it is not yet in the cache
2728
 
        and we do not replace all of its contents.
2729
 
 
2730
 
        In cases where the cache block is big enough to contain (parts
2731
 
        of) index blocks of different indexes, our request can be
2732
 
        secondary (PAGE_WAIT_TO_BE_READ). In this case another thread is
2733
 
        reading the file block. If the read completes after us, it
2734
 
        overwrites our new contents with the old contents. So we have to
2735
 
        wait for the other thread to complete the read of this block.
2736
 
        read_block() takes care for the wait.
2737
 
      */
2738
 
      if (!(block->status & BLOCK_ERROR) &&
2739
 
          ((page_st == PAGE_TO_BE_READ &&
2740
 
            (offset || read_length < keycache->key_cache_block_size)) ||
2741
 
           (page_st == PAGE_WAIT_TO_BE_READ)))
2742
 
      {
2743
 
        read_block(keycache, block,
2744
 
                   offset + read_length >= keycache->key_cache_block_size?
2745
 
                   offset : keycache->key_cache_block_size,
2746
 
                   offset, (page_st == PAGE_TO_BE_READ));
2747
 
        assert(keycache->can_be_used);
2748
 
        assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
2749
 
        /*
2750
 
          Prevent block from flushing and from being selected for to be
2751
 
          freed. This must be set when we release the cache_lock.
2752
 
          Here we set it in case we could not set it above.
2753
 
        */
2754
 
        block->status|= BLOCK_FOR_UPDATE;
2755
 
      }
2756
 
      /*
2757
 
        The block should always be assigned to the requested file block
2758
 
        here. It need not be BLOCK_READ when overwriting the whole block.
2759
 
      */
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));
2764
 
      /*
2765
 
        The block to be written must not be marked BLOCK_REASSIGNED.
2766
 
        Otherwise it could be freed in dirty state or reused without
2767
 
        another flush during eviction. It must also not be in flush.
2768
 
        Otherwise the old contens may have been flushed already and
2769
 
        the flusher could clear BLOCK_CHANGED without flushing the
2770
 
        new changes again.
2771
 
      */
2772
 
      assert(!(block->status & BLOCK_REASSIGNED));
2773
 
 
2774
 
      while (block->status & BLOCK_IN_FLUSHWRITE)
2775
 
      {
2776
 
        /*
2777
 
          Another thread is flushing the block. It was dirty already.
2778
 
          Wait until the block is flushed to file. Otherwise we could
2779
 
          modify the buffer contents just while it is written to file.
2780
 
          An unpredictable file block contents would be the result.
2781
 
          While we wait, several things can happen to the block,
2782
 
          including another flush. But the block cannot be reassigned to
2783
 
          another hash_link until we release our request on it.
2784
 
        */
2785
 
        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));
2788
 
        /* Still must not be marked for free. */
2789
 
        assert(!(block->status & BLOCK_REASSIGNED));
2790
 
        assert(block->hash_link && (block->hash_link->block == block));
2791
 
      }
2792
 
 
2793
 
      /*
2794
 
        We could perhaps release the cache_lock during access of the
2795
 
        data like in the other functions. Locks outside of the key cache
2796
 
        assure that readers and a writer do not access the same range of
2797
 
        data. Parallel accesses should happen only if the cache block
2798
 
        contains multiple index block(fragment)s. So different parts of
2799
 
        the buffer would be read/written. An attempt to flush during
2800
 
        memcpy() is prevented with BLOCK_FOR_UPDATE.
2801
 
      */
2802
 
      if (!(block->status & BLOCK_ERROR))
2803
 
      {
2804
 
#if !defined(SERIALIZED_READ_FROM_CACHE)
2805
 
        keycache_pthread_mutex_unlock(&keycache->cache_lock);
2806
 
#endif
2807
 
        memcpy(block->buffer+offset, buff, (size_t) read_length);
2808
 
 
2809
 
#if !defined(SERIALIZED_READ_FROM_CACHE)
2810
 
        keycache_pthread_mutex_lock(&keycache->cache_lock);
2811
 
#endif
2812
 
      }
2813
 
 
2814
 
      if (!dont_write)
2815
 
      {
2816
 
        /* Not used in the server. buff has been written to disk at start. */
2817
 
        if ((block->status & BLOCK_CHANGED) &&
2818
 
            (!offset && read_length >= keycache->key_cache_block_size))
2819
 
             link_to_file_list(keycache, block, block->hash_link->file, 1);
2820
 
      }
2821
 
      else if (! (block->status & BLOCK_CHANGED))
2822
 
        link_to_changed_list(keycache, block);
2823
 
      block->status|=BLOCK_READ;
2824
 
      /*
2825
 
        Allow block to be selected for to be freed. Since it is marked
2826
 
        BLOCK_CHANGED too, it won't be selected for to be freed without
2827
 
        a flush.
2828
 
      */
2829
 
      block->status&= ~BLOCK_FOR_UPDATE;
2830
 
      set_if_smaller(block->offset, offset);
2831
 
      set_if_bigger(block->length, read_length+offset);
2832
 
 
2833
 
      /* Threads may be waiting for the changes to be complete. */
2834
 
      release_whole_queue(&block->wqueue[COND_FOR_REQUESTED]);
2835
 
 
2836
 
      /*
2837
 
        If only a part of the cache block is to be replaced, and the
2838
 
        rest has been read from file, then the cache lock has been
2839
 
        released for I/O and it could be possible that another thread
2840
 
        wants to evict or free the block and waits for it to be
2841
 
        released. So we must not just decrement hash_link->requests, but
2842
 
        also wake a waiting thread.
2843
 
      */
2844
 
      remove_reader(block);
2845
 
 
2846
 
      /*
2847
 
         Link the block into the LRU ring if it's the last submitted
2848
 
         request for the block. This enables eviction for the block.
2849
 
      */
2850
 
      unreg_request(keycache, block, 1);
2851
 
 
2852
 
      if (block->status & BLOCK_ERROR)
2853
 
      {
2854
 
        error= 1;
2855
 
        break;
2856
 
      }
2857
 
 
2858
 
    next_block:
2859
 
      buff+= read_length;
2860
 
      filepos+= read_length+offset;
2861
 
      offset= 0;
2862
 
 
2863
 
    } while ((length-= read_length));
2864
 
    goto end;
2865
 
  }
2866
 
 
2867
 
no_key_cache:
 
421
  }
 
422
 
 
423
  assert (!keycache->key_cache_inited);
 
424
 
2868
425
  /* Key cache is not used */
2869
426
  if (dont_write)
2870
427
  {
2871
428
    /* Used in the server. */
2872
 
    keycache->global_cache_w_requests++;
2873
 
    keycache->global_cache_write++;
2874
 
    if (locked_and_incremented)
2875
 
      keycache_pthread_mutex_unlock(&keycache->cache_lock);
2876
 
    if (pwrite(file, (uchar*) buff, length, filepos) == 0)
 
429
    if (pwrite(file, (unsigned char*) buff, length, filepos) == 0)
2877
430
      error=1;
2878
 
    if (locked_and_incremented)
2879
 
      keycache_pthread_mutex_lock(&keycache->cache_lock);
2880
431
  }
2881
432
 
2882
 
end:
2883
 
  if (locked_and_incremented)
2884
 
  {
2885
 
    dec_counter_for_resize_op(keycache);
2886
 
    keycache_pthread_mutex_unlock(&keycache->cache_lock);
2887
 
  }
2888
433
  return(error);
2889
434
}
2890
435
 
2891
436
 
2892
437
/*
2893
 
  Free block.
2894
 
 
2895
 
  SYNOPSIS
2896
 
    free_block()
2897
 
      keycache          Pointer to a key cache data structure
2898
 
      block             Pointer to the block to free
2899
 
 
2900
 
  DESCRIPTION
2901
 
    Remove reference to block from hash table.
2902
 
    Remove block from the chain of clean blocks.
2903
 
    Add block to the free list.
2904
 
 
2905
 
  NOTE
2906
 
    Block must not be free (status == 0).
2907
 
    Block must not be in free_block_list.
2908
 
    Block must not be in the LRU ring.
2909
 
    Block must not be in eviction (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH).
2910
 
    Block must not be in free (BLOCK_REASSIGNED).
2911
 
    Block must not be in flush (BLOCK_IN_FLUSH).
2912
 
    Block must not be dirty (BLOCK_CHANGED).
2913
 
    Block must not be in changed_blocks (dirty) hash.
2914
 
    Block must be in file_blocks (clean) hash.
2915
 
    Block must refer to a hash_link.
2916
 
    Block must have a request registered on it.
2917
 
*/
2918
 
 
2919
 
static void free_block(KEY_CACHE *keycache, BLOCK_LINK *block)
2920
 
{
2921
 
  /*
2922
 
    Assert that the block is not free already. And that it is in a clean
2923
 
    state. Note that the block might just be assigned to a hash_link and
2924
 
    not yet read (BLOCK_READ may not be set here). In this case a reader
2925
 
    is registered in the hash_link and free_block() will wait for it
2926
 
    below.
2927
 
  */
2928
 
  assert((block->status & BLOCK_IN_USE) &&
2929
 
              !(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH |
2930
 
                                 BLOCK_REASSIGNED | BLOCK_IN_FLUSH |
2931
 
                                 BLOCK_CHANGED | BLOCK_FOR_UPDATE)));
2932
 
  /* Assert that the block is in a file_blocks chain. */
2933
 
  assert(block->prev_changed && *block->prev_changed == block);
2934
 
  /* Assert that the block is not in the LRU ring. */
2935
 
  assert(!block->next_used && !block->prev_used);
2936
 
  /*
2937
 
    IMHO the below condition (if()) makes no sense. I can't see how it
2938
 
    could be possible that free_block() is entered with a NULL hash_link
2939
 
    pointer. The only place where it can become NULL is in free_block()
2940
 
    (or before its first use ever, but for those blocks free_block() is
2941
 
    not called). I don't remove the conditional as it cannot harm, but
2942
 
    place an assert to confirm my hypothesis. Eventually the
2943
 
    condition (if()) can be removed.
2944
 
  */
2945
 
  assert(block->hash_link && block->hash_link->block == block);
2946
 
  if (block->hash_link)
2947
 
  {
2948
 
    /*
2949
 
      While waiting for readers to finish, new readers might request the
2950
 
      block. But since we set block->status|= BLOCK_REASSIGNED, they
2951
 
      will wait on block->wqueue[COND_FOR_SAVED]. They must be signalled
2952
 
      later.
2953
 
    */
2954
 
    block->status|= BLOCK_REASSIGNED;
2955
 
    wait_for_readers(keycache, block);
2956
 
    /*
2957
 
      The block must not have been freed by another thread. Repeat some
2958
 
      checks. An additional requirement is that it must be read now
2959
 
      (BLOCK_READ).
2960
 
    */
2961
 
    assert(block->hash_link && block->hash_link->block == block);
2962
 
    assert((block->status & (BLOCK_READ | BLOCK_IN_USE |
2963
 
                                  BLOCK_REASSIGNED)) &&
2964
 
                !(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH |
2965
 
                                   BLOCK_IN_FLUSH | BLOCK_CHANGED |
2966
 
                                   BLOCK_FOR_UPDATE)));
2967
 
    assert(block->prev_changed && *block->prev_changed == block);
2968
 
    assert(!block->prev_used);
2969
 
    /*
2970
 
      Unset BLOCK_REASSIGNED again. If we hand the block to an evicting
2971
 
      thread (through unreg_request() below), other threads must not see
2972
 
      this flag. They could become confused.
2973
 
    */
2974
 
    block->status&= ~BLOCK_REASSIGNED;
2975
 
    /*
2976
 
      Do not release the hash_link until the block is off all lists.
2977
 
      At least not if we hand it over for eviction in unreg_request().
2978
 
    */
2979
 
  }
2980
 
 
2981
 
  /*
2982
 
    Unregister the block request and link the block into the LRU ring.
2983
 
    This enables eviction for the block. If the LRU ring was empty and
2984
 
    threads are waiting for a block, then the block wil be handed over
2985
 
    for eviction immediately. Otherwise we will unlink it from the LRU
2986
 
    ring again, without releasing the lock in between. So decrementing
2987
 
    the request counter and updating statistics are the only relevant
2988
 
    operation in this case. Assert that there are no other requests
2989
 
    registered.
2990
 
  */
2991
 
  assert(block->requests == 1);
2992
 
  unreg_request(keycache, block, 0);
2993
 
  /*
2994
 
    Note that even without releasing the cache lock it is possible that
2995
 
    the block is immediately selected for eviction by link_block() and
2996
 
    thus not added to the LRU ring. In this case we must not touch the
2997
 
    block any more.
2998
 
  */
2999
 
  if (block->status & BLOCK_IN_EVICTION)
3000
 
    return;
3001
 
 
3002
 
  /* Here the block must be in the LRU ring. Unlink it again. */
3003
 
  assert(block->next_used && block->prev_used &&
3004
 
              *block->prev_used == block);
3005
 
  unlink_block(keycache, block);
3006
 
  if (block->temperature == BLOCK_WARM)
3007
 
    keycache->warm_blocks--;
3008
 
  block->temperature= BLOCK_COLD;
3009
 
 
3010
 
  /* Remove from file_blocks hash. */
3011
 
  unlink_changed(block);
3012
 
 
3013
 
  /* Remove reference to block from hash table. */
3014
 
  unlink_hash(keycache, block->hash_link);
3015
 
  block->hash_link= NULL;
3016
 
 
3017
 
  block->status= 0;
3018
 
  block->length= 0;
3019
 
  block->offset= keycache->key_cache_block_size;
3020
 
 
3021
 
  /* Enforced by unlink_changed(), but just to be sure. */
3022
 
  assert(!block->next_changed && !block->prev_changed);
3023
 
  /* Enforced by unlink_block(): not in LRU ring nor in free_block_list. */
3024
 
  assert(!block->next_used && !block->prev_used);
3025
 
  /* Insert the free block in the free list. */
3026
 
  block->next_used= keycache->free_block_list;
3027
 
  keycache->free_block_list= block;
3028
 
  /* Keep track of the number of currently unused blocks. */
3029
 
  keycache->blocks_unused++;
3030
 
 
3031
 
  /* All pending requests for this page must be resubmitted. */
3032
 
  release_whole_queue(&block->wqueue[COND_FOR_SAVED]);
3033
 
}
3034
 
 
3035
 
 
3036
 
static int cmp_sec_link(BLOCK_LINK **a, BLOCK_LINK **b)
3037
 
{
3038
 
  return (((*a)->hash_link->diskpos < (*b)->hash_link->diskpos) ? -1 :
3039
 
      ((*a)->hash_link->diskpos > (*b)->hash_link->diskpos) ? 1 : 0);
3040
 
}
3041
 
 
3042
 
 
3043
 
/*
3044
 
  Flush a portion of changed blocks to disk,
3045
 
  free used blocks if requested
3046
 
*/
3047
 
 
3048
 
static int flush_cached_blocks(KEY_CACHE *keycache,
3049
 
                               File file, BLOCK_LINK **cache,
3050
 
                               BLOCK_LINK **end,
3051
 
                               enum flush_type type)
3052
 
{
3053
 
  int error;
3054
 
  int last_errno= 0;
3055
 
  uint count= (uint) (end-cache);
3056
 
 
3057
 
  /* Don't lock the cache during the flush */
3058
 
  keycache_pthread_mutex_unlock(&keycache->cache_lock);
3059
 
  /*
3060
 
     As all blocks referred in 'cache' are marked by BLOCK_IN_FLUSH
3061
 
     we are guarunteed no thread will change them
3062
 
  */
3063
 
  my_qsort((uchar*) cache, count, sizeof(*cache), (qsort_cmp) cmp_sec_link);
3064
 
 
3065
 
  keycache_pthread_mutex_lock(&keycache->cache_lock);
3066
 
  /*
3067
 
    Note: Do not break the loop. We have registered a request on every
3068
 
    block in 'cache'. These must be unregistered by free_block() or
3069
 
    unreg_request().
3070
 
  */
3071
 
  for ( ; cache != end ; cache++)
3072
 
  {
3073
 
    BLOCK_LINK *block= *cache;
3074
 
    /*
3075
 
      If the block contents is going to be changed, we abandon the flush
3076
 
      for this block. flush_key_blocks_int() will restart its search and
3077
 
      handle the block properly.
3078
 
    */
3079
 
    if (!(block->status & BLOCK_FOR_UPDATE))
3080
 
    {
3081
 
      /* 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) ==
3086
 
                  (BLOCK_READ | BLOCK_IN_FLUSH | BLOCK_CHANGED | BLOCK_IN_USE));
3087
 
      block->status|= BLOCK_IN_FLUSHWRITE;
3088
 
      keycache_pthread_mutex_unlock(&keycache->cache_lock);
3089
 
      error= (pwrite(file,
3090
 
                     block->buffer+block->offset,
3091
 
                     block->length - block->offset,
3092
 
                     block->hash_link->diskpos+ block->offset) == 0);
3093
 
      keycache_pthread_mutex_lock(&keycache->cache_lock);
3094
 
      keycache->global_cache_write++;
3095
 
      if (error)
3096
 
      {
3097
 
        block->status|= BLOCK_ERROR;
3098
 
        if (!last_errno)
3099
 
          last_errno= errno ? errno : -1;
3100
 
      }
3101
 
      block->status&= ~BLOCK_IN_FLUSHWRITE;
3102
 
      /* 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)) ==
3107
 
                  (BLOCK_READ | BLOCK_IN_FLUSH | BLOCK_CHANGED | BLOCK_IN_USE));
3108
 
      /*
3109
 
        Set correct status and link in right queue for free or later use.
3110
 
        free_block() must not see BLOCK_CHANGED and it may need to wait
3111
 
        for readers of the block. These should not see the block in the
3112
 
        wrong hash. If not freeing the block, we need to have it in the
3113
 
        right queue anyway.
3114
 
      */
3115
 
      link_to_file_list(keycache, block, file, 1);
3116
 
 
3117
 
    }
3118
 
    block->status&= ~BLOCK_IN_FLUSH;
3119
 
    /*
3120
 
      Let to proceed for possible waiting requests to write to the block page.
3121
 
      It might happen only during an operation to resize the key cache.
3122
 
    */
3123
 
    release_whole_queue(&block->wqueue[COND_FOR_SAVED]);
3124
 
    /* type will never be FLUSH_IGNORE_CHANGED here */
3125
 
    if (!(type == FLUSH_KEEP || type == FLUSH_FORCE_WRITE) &&
3126
 
        !(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH |
3127
 
                           BLOCK_FOR_UPDATE)))
3128
 
    {
3129
 
      /*
3130
 
        Note that a request has been registered against the block in
3131
 
        flush_key_blocks_int().
3132
 
      */
3133
 
      free_block(keycache, block);
3134
 
    }
3135
 
    else
3136
 
    {
3137
 
      /*
3138
 
        Link the block into the LRU ring if it's the last submitted
3139
 
        request for the block. This enables eviction for the block.
3140
 
        Note that a request has been registered against the block in
3141
 
        flush_key_blocks_int().
3142
 
      */
3143
 
      unreg_request(keycache, block, 1);
3144
 
    }
3145
 
 
3146
 
  } /* end of for ( ; cache != end ; cache++) */
3147
 
  return last_errno;
3148
 
}
3149
 
 
3150
 
 
3151
 
/*
3152
 
  flush all key blocks for a file to disk, but don't do any mutex locks.
3153
 
 
3154
 
  SYNOPSIS
3155
 
    flush_key_blocks_int()
3156
 
      keycache            pointer to a key cache data structure
3157
 
      file                handler for the file to flush to
3158
 
      flush_type          type of the flush
3159
 
 
3160
 
  NOTES
3161
 
    This function doesn't do any mutex locks because it needs to be called both
3162
 
    from flush_key_blocks and flush_all_key_blocks (the later one does the
3163
 
    mutex lock in the resize_key_cache() function).
3164
 
 
3165
 
    We do only care about changed blocks that exist when the function is
3166
 
    entered. We do not guarantee that all changed blocks of the file are
3167
 
    flushed if more blocks change while this function is running.
3168
 
 
3169
 
  RETURN
3170
 
    0   ok
3171
 
    1  error
3172
 
*/
3173
 
 
3174
 
static int flush_key_blocks_int(KEY_CACHE *keycache,
3175
 
                                File file, enum flush_type type)
3176
 
{
3177
 
  BLOCK_LINK *cache_buff[FLUSH_CACHE],**cache;
3178
 
  int last_errno= 0;
3179
 
  int last_errcnt= 0;
3180
 
 
3181
 
  cache= cache_buff;
3182
 
  if (keycache->disk_blocks > 0 &&
3183
 
      (!my_disable_flush_key_blocks || type != FLUSH_KEEP))
3184
 
  {
3185
 
    /* Key cache exists and flush is not disabled */
3186
 
    int error= 0;
3187
 
    uint count= FLUSH_CACHE;
3188
 
    BLOCK_LINK **pos,**end;
3189
 
    BLOCK_LINK *first_in_switch= NULL;
3190
 
    BLOCK_LINK *last_in_flush;
3191
 
    BLOCK_LINK *last_for_update;
3192
 
    BLOCK_LINK *block, *next;
3193
 
 
3194
 
    if (type != FLUSH_IGNORE_CHANGED)
3195
 
    {
3196
 
      /*
3197
 
         Count how many key blocks we have to cache to be able
3198
 
         to flush all dirty pages with minimum seek moves
3199
 
      */
3200
 
      count= 0;
3201
 
      for (block= keycache->changed_blocks[FILE_HASH(file)] ;
3202
 
           block ;
3203
 
           block= block->next_changed)
3204
 
      {
3205
 
        if ((block->hash_link->file == file) &&
3206
 
            !(block->status & BLOCK_IN_FLUSH))
3207
 
        {
3208
 
          count++;
3209
 
          assert(count<= keycache->blocks_used);
3210
 
        }
3211
 
      }
3212
 
      /*
3213
 
        Allocate a new buffer only if its bigger than the one we have.
3214
 
        Assure that we always have some entries for the case that new
3215
 
        changed blocks appear while we need to wait for something.
3216
 
      */
3217
 
      if ((count > FLUSH_CACHE) &&
3218
 
          !(cache= (BLOCK_LINK**) my_malloc(sizeof(BLOCK_LINK*)*count,
3219
 
                                            MYF(0))))
3220
 
        cache= cache_buff;
3221
 
      /*
3222
 
        After a restart there could be more changed blocks than now.
3223
 
        So we should not let count become smaller than the fixed buffer.
3224
 
      */
3225
 
      if (cache == cache_buff)
3226
 
        count= FLUSH_CACHE;
3227
 
    }
3228
 
 
3229
 
    /* Retrieve the blocks and write them to a buffer to be flushed */
3230
 
restart:
3231
 
    last_in_flush= NULL;
3232
 
    last_for_update= NULL;
3233
 
    end= (pos= cache)+count;
3234
 
    for (block= keycache->changed_blocks[FILE_HASH(file)] ;
3235
 
         block ;
3236
 
         block= next)
3237
 
    {
3238
 
      next= block->next_changed;
3239
 
      if (block->hash_link->file == file)
3240
 
      {
3241
 
        if (!(block->status & (BLOCK_IN_FLUSH | BLOCK_FOR_UPDATE)))
3242
 
        {
3243
 
          /*
3244
 
            Note: The special handling of BLOCK_IN_SWITCH is obsolete
3245
 
            since we set BLOCK_IN_FLUSH if the eviction includes a
3246
 
            flush. It can be removed in a later version.
3247
 
          */
3248
 
          if (!(block->status & BLOCK_IN_SWITCH))
3249
 
          {
3250
 
            /*
3251
 
              We care only for the blocks for which flushing was not
3252
 
              initiated by another thread and which are not in eviction.
3253
 
              Registering a request on the block unlinks it from the LRU
3254
 
              ring and protects against eviction.
3255
 
            */
3256
 
            reg_requests(keycache, block, 1);
3257
 
            if (type != FLUSH_IGNORE_CHANGED)
3258
 
            {
3259
 
              /* It's not a temporary file */
3260
 
              if (pos == end)
3261
 
              {
3262
 
                /*
3263
 
                  This should happen relatively seldom. Remove the
3264
 
                  request because we won't do anything with the block
3265
 
                  but restart and pick it again in the next iteration.
3266
 
                */
3267
 
                unreg_request(keycache, block, 0);
3268
 
                /*
3269
 
                  This happens only if there is not enough
3270
 
                  memory for the big block
3271
 
                */
3272
 
                if ((error= flush_cached_blocks(keycache, file, cache,
3273
 
                                                end,type)))
3274
 
                {
3275
 
                  /* Do not loop infinitely trying to flush in vain. */
3276
 
                  if ((last_errno == error) && (++last_errcnt > 5))
3277
 
                    goto err;
3278
 
                  last_errno= error;
3279
 
                }
3280
 
                /*
3281
 
                  Restart the scan as some other thread might have changed
3282
 
                  the changed blocks chain: the blocks that were in switch
3283
 
                  state before the flush started have to be excluded
3284
 
                */
3285
 
                goto restart;
3286
 
              }
3287
 
              /*
3288
 
                Mark the block with BLOCK_IN_FLUSH in order not to let
3289
 
                other threads to use it for new pages and interfere with
3290
 
                our sequence of flushing dirty file pages. We must not
3291
 
                set this flag before actually putting the block on the
3292
 
                write burst array called 'cache'.
3293
 
              */
3294
 
              block->status|= BLOCK_IN_FLUSH;
3295
 
              /* Add block to the array for a write burst. */
3296
 
              *pos++= block;
3297
 
            }
3298
 
            else
3299
 
            {
3300
 
              /* It's a temporary file */
3301
 
              assert(!(block->status & BLOCK_REASSIGNED));
3302
 
 
3303
 
              /*
3304
 
                free_block() must not be called with BLOCK_CHANGED. Note
3305
 
                that we must not change the BLOCK_CHANGED flag outside of
3306
 
                link_to_file_list() so that it is always in the correct
3307
 
                queue and the *blocks_changed counters are correct.
3308
 
              */
3309
 
              link_to_file_list(keycache, block, file, 1);
3310
 
              if (!(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH)))
3311
 
              {
3312
 
                /* A request has been registered against the block above. */
3313
 
                free_block(keycache, block);
3314
 
              }
3315
 
              else
3316
 
              {
3317
 
                /*
3318
 
                  Link the block into the LRU ring if it's the last
3319
 
                  submitted request for the block. This enables eviction
3320
 
                  for the block. A request has been registered against
3321
 
                  the block above.
3322
 
                */
3323
 
                unreg_request(keycache, block, 1);
3324
 
              }
3325
 
            }
3326
 
          }
3327
 
          else
3328
 
          {
3329
 
            /*
3330
 
              Link the block into a list of blocks 'in switch'.
3331
 
 
3332
 
              WARNING: Here we introduce a place where a changed block
3333
 
              is not in the changed_blocks hash! This is acceptable for
3334
 
              a BLOCK_IN_SWITCH. Never try this for another situation.
3335
 
              Other parts of the key cache code rely on changed blocks
3336
 
              being in the changed_blocks hash.
3337
 
            */
3338
 
            unlink_changed(block);
3339
 
            link_changed(block, &first_in_switch);
3340
 
          }
3341
 
        }
3342
 
        else if (type != FLUSH_KEEP)
3343
 
        {
3344
 
          /*
3345
 
            During the normal flush at end of statement (FLUSH_KEEP) we
3346
 
            do not need to ensure that blocks in flush or update by
3347
 
            other threads are flushed. They will be flushed by them
3348
 
            later. In all other cases we must assure that we do not have
3349
 
            any changed block of this file in the cache when this
3350
 
            function returns.
3351
 
          */
3352
 
          if (block->status & BLOCK_IN_FLUSH)
3353
 
          {
3354
 
            /* Remember the last block found to be in flush. */
3355
 
            last_in_flush= block;
3356
 
          }
3357
 
          else
3358
 
          {
3359
 
            /* Remember the last block found to be selected for update. */
3360
 
            last_for_update= block;
3361
 
          }
3362
 
        }
3363
 
      }
3364
 
    }
3365
 
    if (pos != cache)
3366
 
    {
3367
 
      if ((error= flush_cached_blocks(keycache, file, cache, pos, type)))
3368
 
      {
3369
 
        /* Do not loop inifnitely trying to flush in vain. */
3370
 
        if ((last_errno == error) && (++last_errcnt > 5))
3371
 
          goto err;
3372
 
        last_errno= error;
3373
 
      }
3374
 
      /*
3375
 
        Do not restart here during the normal flush at end of statement
3376
 
        (FLUSH_KEEP). We have now flushed at least all blocks that were
3377
 
        changed when entering this function. In all other cases we must
3378
 
        assure that we do not have any changed block of this file in the
3379
 
        cache when this function returns.
3380
 
      */
3381
 
      if (type != FLUSH_KEEP)
3382
 
        goto restart;
3383
 
    }
3384
 
    if (last_in_flush)
3385
 
    {
3386
 
      /*
3387
 
        There are no blocks to be flushed by this thread, but blocks in
3388
 
        flush by other threads. Wait until one of the blocks is flushed.
3389
 
        Re-check the condition for last_in_flush. We may have unlocked
3390
 
        the cache_lock in flush_cached_blocks(). The state of the block
3391
 
        could have changed.
3392
 
      */
3393
 
      if (last_in_flush->status & BLOCK_IN_FLUSH)
3394
 
        wait_on_queue(&last_in_flush->wqueue[COND_FOR_SAVED],
3395
 
                      &keycache->cache_lock);
3396
 
      /* Be sure not to lose a block. They may be flushed in random order. */
3397
 
      goto restart;
3398
 
    }
3399
 
    if (last_for_update)
3400
 
    {
3401
 
      /*
3402
 
        There are no blocks to be flushed by this thread, but blocks for
3403
 
        update by other threads. Wait until one of the blocks is updated.
3404
 
        Re-check the condition for last_for_update. We may have unlocked
3405
 
        the cache_lock in flush_cached_blocks(). The state of the block
3406
 
        could have changed.
3407
 
      */
3408
 
      if (last_for_update->status & BLOCK_FOR_UPDATE)
3409
 
        wait_on_queue(&last_for_update->wqueue[COND_FOR_REQUESTED],
3410
 
                      &keycache->cache_lock);
3411
 
      /* The block is now changed. Flush it. */
3412
 
      goto restart;
3413
 
    }
3414
 
 
3415
 
    /*
3416
 
      Wait until the list of blocks in switch is empty. The threads that
3417
 
      are switching these blocks will relink them to clean file chains
3418
 
      while we wait and thus empty the 'first_in_switch' chain.
3419
 
    */
3420
 
    while (first_in_switch)
3421
 
    {
3422
 
      wait_on_queue(&first_in_switch->wqueue[COND_FOR_SAVED],
3423
 
                    &keycache->cache_lock);
3424
 
      /*
3425
 
        Do not restart here. We have flushed all blocks that were
3426
 
        changed when entering this function and were not marked for
3427
 
        eviction. Other threads have now flushed all remaining blocks in
3428
 
        the course of their eviction.
3429
 
      */
3430
 
    }
3431
 
 
3432
 
    if (! (type == FLUSH_KEEP || type == FLUSH_FORCE_WRITE))
3433
 
    {
3434
 
      BLOCK_LINK *last_for_update= NULL;
3435
 
      BLOCK_LINK *last_in_switch= NULL;
3436
 
      uint total_found= 0;
3437
 
      uint found;
3438
 
 
3439
 
      /*
3440
 
        Finally free all clean blocks for this file.
3441
 
        During resize this may be run by two threads in parallel.
3442
 
      */
3443
 
      do
3444
 
      {
3445
 
        found= 0;
3446
 
        for (block= keycache->file_blocks[FILE_HASH(file)] ;
3447
 
             block ;
3448
 
             block= next)
3449
 
        {
3450
 
          /* Remember the next block. After freeing we cannot get at it. */
3451
 
          next= block->next_changed;
3452
 
 
3453
 
          /* Changed blocks cannot appear in the file_blocks hash. */
3454
 
          assert(!(block->status & BLOCK_CHANGED));
3455
 
          if (block->hash_link->file == file)
3456
 
          {
3457
 
            /* We must skip blocks that will be changed. */
3458
 
            if (block->status & BLOCK_FOR_UPDATE)
3459
 
            {
3460
 
              last_for_update= block;
3461
 
              continue;
3462
 
            }
3463
 
 
3464
 
            /*
3465
 
              We must not free blocks in eviction (BLOCK_IN_EVICTION |
3466
 
              BLOCK_IN_SWITCH) or blocks intended to be freed
3467
 
              (BLOCK_REASSIGNED).
3468
 
            */
3469
 
            if (!(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH |
3470
 
                                   BLOCK_REASSIGNED)))
3471
 
            {
3472
 
              struct st_hash_link *next_hash_link= NULL;
3473
 
              my_off_t            next_diskpos= 0;
3474
 
              File                next_file= 0;
3475
 
              uint                next_status= 0;
3476
 
              uint                hash_requests= 0;
3477
 
 
3478
 
              total_found++;
3479
 
              found++;
3480
 
              assert(found <= keycache->blocks_used);
3481
 
 
3482
 
              /*
3483
 
                Register a request. This unlinks the block from the LRU
3484
 
                ring and protects it against eviction. This is required
3485
 
                by free_block().
3486
 
              */
3487
 
              reg_requests(keycache, block, 1);
3488
 
 
3489
 
              /*
3490
 
                free_block() may need to wait for readers of the block.
3491
 
                This is the moment where the other thread can move the
3492
 
                'next' block from the chain. free_block() needs to wait
3493
 
                if there are requests for the block pending.
3494
 
              */
3495
 
              if (next && (hash_requests= block->hash_link->requests))
3496
 
              {
3497
 
                /* Copy values from the 'next' block and its hash_link. */
3498
 
                next_status=    next->status;
3499
 
                next_hash_link= next->hash_link;
3500
 
                next_diskpos=   next_hash_link->diskpos;
3501
 
                next_file=      next_hash_link->file;
3502
 
                assert(next == next_hash_link->block);
3503
 
              }
3504
 
 
3505
 
              free_block(keycache, block);
3506
 
              /*
3507
 
                If we had to wait and the state of the 'next' block
3508
 
                changed, break the inner loop. 'next' may no longer be
3509
 
                part of the current chain.
3510
 
 
3511
 
                We do not want to break the loop after every free_block(),
3512
 
                not even only after waits. The chain might be quite long
3513
 
                and contain blocks for many files. Traversing it again and
3514
 
                again to find more blocks for this file could become quite
3515
 
                inefficient.
3516
 
              */
3517
 
              if (next && hash_requests &&
3518
 
                  ((next_status    != next->status) ||
3519
 
                   (next_hash_link != next->hash_link) ||
3520
 
                   (next_file      != next_hash_link->file) ||
3521
 
                   (next_diskpos   != next_hash_link->diskpos) ||
3522
 
                   (next           != next_hash_link->block)))
3523
 
                break;
3524
 
            }
3525
 
            else
3526
 
            {
3527
 
              last_in_switch= block;
3528
 
            }
3529
 
          }
3530
 
        } /* end for block in file_blocks */
3531
 
      } while (found);
3532
 
 
3533
 
      /*
3534
 
        If any clean block has been found, we may have waited for it to
3535
 
        become free. In this case it could be possible that another clean
3536
 
        block became dirty. This is possible if the write request existed
3537
 
        before the flush started (BLOCK_FOR_UPDATE). Re-check the hashes.
3538
 
      */
3539
 
      if (total_found)
3540
 
        goto restart;
3541
 
 
3542
 
      /*
3543
 
        To avoid an infinite loop, wait until one of the blocks marked
3544
 
        for update is updated.
3545
 
      */
3546
 
      if (last_for_update)
3547
 
      {
3548
 
        /* We did not wait. Block must not have changed status. */
3549
 
        assert(last_for_update->status & BLOCK_FOR_UPDATE);
3550
 
        wait_on_queue(&last_for_update->wqueue[COND_FOR_REQUESTED],
3551
 
                      &keycache->cache_lock);
3552
 
        goto restart;
3553
 
      }
3554
 
 
3555
 
      /*
3556
 
        To avoid an infinite loop wait until one of the blocks marked
3557
 
        for eviction is switched.
3558
 
      */
3559
 
      if (last_in_switch)
3560
 
      {
3561
 
        /* We did not wait. Block must not have changed status. */
3562
 
        assert(last_in_switch->status & (BLOCK_IN_EVICTION |
3563
 
                                              BLOCK_IN_SWITCH |
3564
 
                                              BLOCK_REASSIGNED));
3565
 
        wait_on_queue(&last_in_switch->wqueue[COND_FOR_SAVED],
3566
 
                      &keycache->cache_lock);
3567
 
        goto restart;
3568
 
      }
3569
 
 
3570
 
    } /* if (! (type == FLUSH_KEEP || type == FLUSH_FORCE_WRITE)) */
3571
 
 
3572
 
  } /* if (keycache->disk_blocks > 0 */
3573
 
 
3574
 
err:
3575
 
  if (cache != cache_buff)
3576
 
    my_free((uchar*) cache, MYF(0));
3577
 
  if (last_errno)
3578
 
    errno=last_errno;                /* Return first error */
3579
 
  return(last_errno != 0);
3580
 
}
3581
 
 
3582
 
 
3583
 
/*
3584
438
  Flush all blocks for a file to disk
3585
439
 
3586
440
  SYNOPSIS
3596
450
*/
3597
451
 
3598
452
int flush_key_blocks(KEY_CACHE *keycache,
3599
 
                     File file, enum flush_type type)
3600
 
{
3601
 
  int res= 0;
3602
 
 
3603
 
  if (!keycache->key_cache_inited)
3604
 
    return(0);
3605
 
 
3606
 
  keycache_pthread_mutex_lock(&keycache->cache_lock);
3607
 
  /* While waiting for lock, keycache could have been ended. */
3608
 
  if (keycache->disk_blocks > 0)
3609
 
  {
3610
 
    inc_counter_for_resize_op(keycache);
3611
 
    res= flush_key_blocks_int(keycache, file, type);
3612
 
    dec_counter_for_resize_op(keycache);
3613
 
  }
3614
 
  keycache_pthread_mutex_unlock(&keycache->cache_lock);
3615
 
  return(res);
3616
 
}
3617
 
 
3618
 
 
3619
 
/*
3620
 
  Flush all blocks in the key cache to disk.
3621
 
 
3622
 
  SYNOPSIS
3623
 
    flush_all_key_blocks()
3624
 
      keycache                  pointer to key cache root structure
3625
 
 
3626
 
  DESCRIPTION
3627
 
 
3628
 
    Flushing of the whole key cache is done in two phases.
3629
 
 
3630
 
    1. Flush all changed blocks, waiting for them if necessary. Loop
3631
 
    until there is no changed block left in the cache.
3632
 
 
3633
 
    2. Free all clean blocks. Normally this means free all blocks. The
3634
 
    changed blocks were flushed in phase 1 and became clean. However we
3635
 
    may need to wait for blocks that are read by other threads. While we
3636
 
    wait, a clean block could become changed if that operation started
3637
 
    before the resize operation started. To be safe we must restart at
3638
 
    phase 1.
3639
 
 
3640
 
    When we can run through the changed_blocks and file_blocks hashes
3641
 
    without finding a block any more, then we are done.
3642
 
 
3643
 
    Note that we hold keycache->cache_lock all the time unless we need
3644
 
    to wait for something.
3645
 
 
3646
 
  RETURN
3647
 
    0           OK
3648
 
    != 0        Error
3649
 
*/
3650
 
 
3651
 
static int flush_all_key_blocks(KEY_CACHE *keycache)
3652
 
{
3653
 
  BLOCK_LINK    *block;
3654
 
  uint          total_found;
3655
 
  uint          found;
3656
 
  uint          idx;
3657
 
 
3658
 
  do
3659
 
  {
3660
 
    safe_mutex_assert_owner(&keycache->cache_lock);
3661
 
    total_found= 0;
3662
 
 
3663
 
    /*
3664
 
      Phase1: Flush all changed blocks, waiting for them if necessary.
3665
 
      Loop until there is no changed block left in the cache.
3666
 
    */
3667
 
    do
3668
 
    {
3669
 
      found= 0;
3670
 
      /* Step over the whole changed_blocks hash array. */
3671
 
      for (idx= 0; idx < CHANGED_BLOCKS_HASH; idx++)
3672
 
      {
3673
 
        /*
3674
 
          If an array element is non-empty, use the first block from its
3675
 
          chain to find a file for flush. All changed blocks for this
3676
 
          file are flushed. So the same block will not appear at this
3677
 
          place again with the next iteration. New writes for blocks are
3678
 
          not accepted during the flush. If multiple files share the
3679
 
          same hash bucket, one of them will be flushed per iteration
3680
 
          of the outer loop of phase 1.
3681
 
        */
3682
 
        if ((block= keycache->changed_blocks[idx]))
3683
 
        {
3684
 
          found++;
3685
 
          /*
3686
 
            Flush dirty blocks but do not free them yet. They can be used
3687
 
            for reading until all other blocks are flushed too.
3688
 
          */
3689
 
          if (flush_key_blocks_int(keycache, block->hash_link->file,
3690
 
                                   FLUSH_FORCE_WRITE))
3691
 
            return(1);
3692
 
        }
3693
 
      }
3694
 
 
3695
 
    } while (found);
3696
 
 
3697
 
    /*
3698
 
      Phase 2: Free all clean blocks. Normally this means free all
3699
 
      blocks. The changed blocks were flushed in phase 1 and became
3700
 
      clean. However we may need to wait for blocks that are read by
3701
 
      other threads. While we wait, a clean block could become changed
3702
 
      if that operation started before the resize operation started. To
3703
 
      be safe we must restart at phase 1.
3704
 
    */
3705
 
    do
3706
 
    {
3707
 
      found= 0;
3708
 
      /* Step over the whole file_blocks hash array. */
3709
 
      for (idx= 0; idx < CHANGED_BLOCKS_HASH; idx++)
3710
 
      {
3711
 
        /*
3712
 
          If an array element is non-empty, use the first block from its
3713
 
          chain to find a file for flush. All blocks for this file are
3714
 
          freed. So the same block will not appear at this place again
3715
 
          with the next iteration. If multiple files share the
3716
 
          same hash bucket, one of them will be flushed per iteration
3717
 
          of the outer loop of phase 2.
3718
 
        */
3719
 
        if ((block= keycache->file_blocks[idx]))
3720
 
        {
3721
 
          total_found++;
3722
 
          found++;
3723
 
          if (flush_key_blocks_int(keycache, block->hash_link->file,
3724
 
                                   FLUSH_RELEASE))
3725
 
            return(1);
3726
 
        }
3727
 
      }
3728
 
 
3729
 
    } while (found);
3730
 
 
3731
 
    /*
3732
 
      If any clean block has been found, we may have waited for it to
3733
 
      become free. In this case it could be possible that another clean
3734
 
      block became dirty. This is possible if the write request existed
3735
 
      before the resize started (BLOCK_FOR_UPDATE). Re-check the hashes.
3736
 
    */
3737
 
  } while (total_found);
3738
 
  return(0);
3739
 
}
3740
 
 
3741
 
 
3742
 
/*
3743
 
  Reset the counters of a key cache.
3744
 
 
3745
 
  SYNOPSIS
3746
 
    reset_key_cache_counters()
3747
 
    name       the name of a key cache
3748
 
    key_cache  pointer to the key kache to be reset
3749
 
 
3750
 
  DESCRIPTION
3751
 
   This procedure is used by process_key_caches() to reset the counters of all
3752
 
   currently used key caches, both the default one and the named ones.
3753
 
 
3754
 
  RETURN
3755
 
    0 on success (always because it can't fail)
3756
 
*/
3757
 
 
3758
 
int reset_key_cache_counters(const char *name __attribute__((unused)),
3759
 
                             KEY_CACHE *key_cache)
3760
 
{
3761
 
  if (!key_cache->key_cache_inited)
3762
 
  {
3763
 
    return(0);
3764
 
  }
3765
 
  key_cache->global_blocks_changed= 0;   /* Key_blocks_not_flushed */
3766
 
  key_cache->global_cache_r_requests= 0; /* Key_read_requests */
3767
 
  key_cache->global_cache_read= 0;       /* Key_reads */
3768
 
  key_cache->global_cache_w_requests= 0; /* Key_write_requests */
3769
 
  key_cache->global_cache_write= 0;      /* Key_writes */
3770
 
  return(0);
3771
 
}
3772
 
 
3773
 
#if defined(KEYCACHE_TIMEOUT)
3774
 
 
3775
 
#define KEYCACHE_DUMP_FILE  "keycache_dump.txt"
3776
 
#define MAX_QUEUE_LEN  100
3777
 
 
3778
 
 
3779
 
static void keycache_dump(KEY_CACHE *keycache)
3780
 
{
3781
 
  FILE *keycache_dump_file=fopen(KEYCACHE_DUMP_FILE, "w");
3782
 
  struct st_my_thread_var *last;
3783
 
  struct st_my_thread_var *thread;
3784
 
  BLOCK_LINK *block;
3785
 
  HASH_LINK *hash_link;
3786
 
  KEYCACHE_PAGE *page;
3787
 
  uint i;
3788
 
 
3789
 
  fprintf(keycache_dump_file, "thread:%u\n", thread->id);
3790
 
 
3791
 
  i=0;
3792
 
  thread=last=waiting_for_hash_link.last_thread;
3793
 
  fprintf(keycache_dump_file, "queue of threads waiting for hash link\n");
3794
 
  if (thread)
3795
 
    do
3796
 
    {
3797
 
      thread=thread->next;
3798
 
      page= (KEYCACHE_PAGE *) thread->opt_info;
3799
 
      fprintf(keycache_dump_file,
3800
 
              "thread:%u, (file,filepos)=(%u,%lu)\n",
3801
 
              thread->id,(uint) page->file,(uint32_t) page->filepos);
3802
 
      if (++i == MAX_QUEUE_LEN)
3803
 
        break;
3804
 
    }
3805
 
    while (thread != last);
3806
 
 
3807
 
  i=0;
3808
 
  thread=last=waiting_for_block.last_thread;
3809
 
  fprintf(keycache_dump_file, "queue of threads waiting for block\n");
3810
 
  if (thread)
3811
 
    do
3812
 
    {
3813
 
      thread=thread->next;
3814
 
      hash_link= (HASH_LINK *) thread->opt_info;
3815
 
      fprintf(keycache_dump_file,
3816
 
        "thread:%u hash_link:%u (file,filepos)=(%u,%u)\n",
3817
 
        thread->id, (uint) HASH_LINK_NUMBER(hash_link),
3818
 
        (uint) hash_link->file,(uint32_t) hash_link->diskpos);
3819
 
      if (++i == MAX_QUEUE_LEN)
3820
 
        break;
3821
 
    }
3822
 
    while (thread != last);
3823
 
 
3824
 
  for (i=0 ; i< keycache->blocks_used ; i++)
3825
 
  {
3826
 
    int j;
3827
 
    block= &keycache->block_root[i];
3828
 
    hash_link= block->hash_link;
3829
 
    fprintf(keycache_dump_file,
3830
 
            "block:%u hash_link:%d status:%x #requests=%u waiting_for_readers:%d\n",
3831
 
            i, (int) (hash_link ? HASH_LINK_NUMBER(hash_link) : -1),
3832
 
            block->status, block->requests, block->condvar ? 1 : 0);
3833
 
    for (j=0 ; j < 2; j++)
3834
 
    {
3835
 
      KEYCACHE_WQUEUE *wqueue=&block->wqueue[j];
3836
 
      thread= last= wqueue->last_thread;
3837
 
      fprintf(keycache_dump_file, "queue #%d\n", j);
3838
 
      if (thread)
3839
 
      {
3840
 
        do
3841
 
        {
3842
 
          thread=thread->next;
3843
 
          fprintf(keycache_dump_file,
3844
 
                  "thread:%u\n", thread->id);
3845
 
          if (++i == MAX_QUEUE_LEN)
3846
 
            break;
3847
 
        }
3848
 
        while (thread != last);
3849
 
      }
3850
 
    }
3851
 
  }
3852
 
  fprintf(keycache_dump_file, "LRU chain:");
3853
 
  block= keycache= used_last;
3854
 
  if (block)
3855
 
  {
3856
 
    do
3857
 
    {
3858
 
      block= block->next_used;
3859
 
      fprintf(keycache_dump_file,
3860
 
              "block:%u, ", BLOCK_NUMBER(block));
3861
 
    }
3862
 
    while (block != keycache->used_last);
3863
 
  }
3864
 
  fprintf(keycache_dump_file, "\n");
3865
 
 
3866
 
  fclose(keycache_dump_file);
3867
 
}
3868
 
 
3869
 
static int keycache_pthread_cond_wait(pthread_cond_t *cond,
3870
 
                                      pthread_mutex_t *mutex)
3871
 
{
3872
 
  int rc;
3873
 
  struct timeval  now;            /* time when we started waiting        */
3874
 
  struct timespec timeout;        /* timeout value for the wait function */
3875
 
  struct timezone tz;
3876
 
 
3877
 
  /* Get current time */
3878
 
  gettimeofday(&now, &tz);
3879
 
  /* Prepare timeout value */
3880
 
  timeout.tv_sec= now.tv_sec + KEYCACHE_TIMEOUT;
3881
 
 /*
3882
 
   timeval uses microseconds.
3883
 
   timespec uses nanoseconds.
3884
 
   1 nanosecond = 1000 micro seconds
3885
 
 */
3886
 
  timeout.tv_nsec= now.tv_usec * 1000;
3887
 
  rc= pthread_cond_timedwait(cond, mutex, &timeout);
3888
 
  if (rc == ETIMEDOUT || rc == ETIME)
3889
 
  {
3890
 
    keycache_dump();
3891
 
  }
3892
 
 
3893
 
  assert(rc != ETIMEDOUT);
3894
 
  return rc;
3895
 
}
3896
 
#endif /* defined(KEYCACHE_TIMEOUT) */
 
453
                     int file, enum flush_type type)
 
454
{
 
455
  (void)file;
 
456
  (void)type;
 
457
  assert (!keycache->key_cache_inited);
 
458
  return 0;
 
459
}