104
#include "my_global.h"
105
#include "mysys_err.h"
107
#include <keycache.h>
108
#include <m_string.h>
105
#include "drizzled/my_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>
113
static void change_key_cache_param(KEY_CACHE *keycache, uint32_t division_limit,
114
uint32_t age_threshold);
114
117
Some compilation flags have been added specifically for this module
115
118
to control the following:
160
162
struct st_hash_link *next, **prev; /* to connect links in the same bucket */
161
163
struct st_block_link *block; /* reference to the block for the page: */
162
File file; /* from such a file */
164
int file; /* from such a file */
163
165
my_off_t diskpos; /* with such an offset */
164
uint requests; /* number of requests for the page */
166
uint32_t requests; /* number of requests for the page */
167
169
/* simple states of a block */
193
195
*next_changed, **prev_changed; /* for lists of file dirty/clean blocks */
194
196
struct st_hash_link *hash_link; /* backward ptr to referring hash_link */
195
197
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 */
198
uint32_t requests; /* number of requests for the block */
199
unsigned char *buffer; /* buffer for the block page */
200
uint32_t offset; /* beginning of modified data in the buffer */
201
uint32_t length; /* end of data in the buffer */
202
uint32_t status; /* state of the block */
201
203
enum BLOCK_TEMPERATURE temperature; /* block temperature: cold, warm, hot */
202
uint hits_left; /* number of hits left until promotion */
204
uint32_t hits_left; /* number of hits left until promotion */
203
205
uint64_t last_hit_time; /* timestamp of the last hit */
204
206
KEYCACHE_CONDVAR *condvar; /* condition variable for 'no readers' event */
216
218
static void free_block(KEY_CACHE *keycache, BLOCK_LINK *block);
218
220
#define KEYCACHE_HASH(f, pos) \
219
(((ulong) ((pos) / keycache->key_cache_block_size) + \
220
(ulong) (f)) & (keycache->hash_entries-1))
221
(((uint32_t) ((pos) / keycache->key_cache_block_size) + \
222
(uint32_t) (f)) & (keycache->hash_entries-1))
221
223
#define FILE_HASH(f) ((uint) (f) & (CHANGED_BLOCKS_HASH-1))
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)))
228
226
#ifdef KEYCACHE_TIMEOUT
229
227
static int keycache_pthread_cond_wait(pthread_cond_t *cond,
236
234
#define keycache_pthread_mutex_unlock pthread_mutex_unlock
237
235
#define keycache_pthread_cond_signal pthread_cond_signal
239
static inline uint next_power(uint value)
237
static inline uint32_t next_power(uint32_t value)
241
239
return (uint) my_round_up_to_next_power((uint32_t) value) << 1;
270
int init_key_cache(KEY_CACHE *keycache, uint key_cache_block_size,
271
size_t use_mem, uint division_limit,
268
int init_key_cache(KEY_CACHE *keycache, uint32_t key_cache_block_size,
269
size_t use_mem, uint32_t division_limit,
270
uint32_t age_threshold)
274
ulong blocks, hash_links;
272
uint32_t blocks, hash_links;
277
275
assert(key_cache_block_size >= 512);
303
301
keycache->key_cache_mem_size= use_mem;
304
302
keycache->key_cache_block_size= key_cache_block_size;
306
blocks= (ulong) (use_mem / (sizeof(BLOCK_LINK) + 2 * sizeof(HASH_LINK) +
304
blocks= (uint32_t) (use_mem / (sizeof(BLOCK_LINK) + 2 * sizeof(HASH_LINK) +
307
305
sizeof(HASH_LINK*) * 5/4 + key_cache_block_size));
308
306
/* It doesn't make sense to have too few blocks (less than 8) */
325
323
((size_t) blocks * keycache->key_cache_block_size) > use_mem)
327
325
/* Allocate memory for cache page buffers */
328
if ((keycache->block_mem= malloc((size_t) blocks * keycache->key_cache_block_size)))
326
if ((keycache->block_mem= (unsigned char *)malloc((size_t) blocks * keycache->key_cache_block_size)))
331
329
Allocate memory for blocks, hash_links and hash entries;
332
330
For each block 2 hash links are allocated
334
if ((keycache->block_root= (BLOCK_LINK*) my_malloc(length,
332
if ((keycache->block_root= (BLOCK_LINK*) malloc(length)))
337
334
free(keycache->block_mem);
338
335
keycache->block_mem= 0;
343
340
my_error(EE_OUTOFMEMORY, MYF(0), blocks * keycache->key_cache_block_size);
353
350
keycache->hash_link_root= (HASH_LINK*) ((char*) keycache->hash_root +
354
351
ALIGN_SIZE((sizeof(HASH_LINK*) *
355
352
keycache->hash_entries)));
356
bzero((uchar*) keycache->block_root,
357
keycache->disk_blocks * sizeof(BLOCK_LINK));
358
bzero((uchar*) keycache->hash_root,
359
keycache->hash_entries * sizeof(HASH_LINK*));
360
bzero((uchar*) keycache->hash_link_root,
361
keycache->hash_links * sizeof(HASH_LINK));
353
memset(keycache->block_root, 0,
354
keycache->disk_blocks * sizeof(BLOCK_LINK));
355
memset(keycache->hash_root, 0,
356
keycache->hash_entries * sizeof(HASH_LINK*));
357
memset(keycache->hash_link_root, 0,
358
keycache->hash_links * sizeof(HASH_LINK));
362
359
keycache->hash_links_used= 0;
363
360
keycache->free_hash_list= NULL;
364
361
keycache->blocks_used= keycache->blocks_changed= 0;
384
381
keycache->waiting_for_hash_link.last_thread= NULL;
385
382
keycache->waiting_for_block.last_thread= NULL;
386
bzero((uchar*) keycache->changed_blocks,
387
sizeof(keycache->changed_blocks[0]) * CHANGED_BLOCKS_HASH);
388
bzero((uchar*) keycache->file_blocks,
389
sizeof(keycache->file_blocks[0]) * CHANGED_BLOCKS_HASH);
383
memset(keycache->changed_blocks, 0,
384
sizeof(keycache->changed_blocks[0]) * CHANGED_BLOCKS_HASH);
385
memset(keycache->file_blocks, 0,
386
sizeof(keycache->file_blocks[0]) * CHANGED_BLOCKS_HASH);
409
406
if (keycache->block_root)
411
my_free((uchar*) keycache->block_root, MYF(0));
408
free((unsigned char*) keycache->block_root);
412
409
keycache->block_root= NULL;
415
412
keycache->can_be_used= 0;
446
443
(when cnt_for_resize=0).
449
int resize_key_cache(KEY_CACHE *keycache, uint key_cache_block_size,
450
size_t use_mem, uint division_limit,
446
int resize_key_cache(KEY_CACHE *keycache, uint32_t key_cache_block_size,
447
size_t use_mem, uint32_t division_limit,
448
uint32_t age_threshold)
583
void change_key_cache_param(KEY_CACHE *keycache, uint division_limit,
578
static void change_key_cache_param(KEY_CACHE *keycache, uint32_t division_limit,
579
uint32_t age_threshold)
586
581
keycache_pthread_mutex_lock(&keycache->cache_lock);
587
582
if (division_limit)
619
614
free(keycache->block_mem);
620
615
keycache->block_mem= NULL;
621
my_free((uchar*) keycache->block_root, MYF(0));
616
free((unsigned char*) keycache->block_root);
622
617
keycache->block_root= NULL;
624
619
keycache->disk_blocks= -1;
809
804
Unlink a block from the chain of dirty/clean blocks
811
static inline void unlink_changed(BLOCK_LINK *block)
806
static void unlink_changed(BLOCK_LINK *block)
813
808
assert(block->prev_changed && *block->prev_changed == block);
814
809
if (block->next_changed)
823
818
Link a block into the chain of dirty/clean blocks
826
static inline void link_changed(BLOCK_LINK *block, BLOCK_LINK **phead)
821
static void link_changed(BLOCK_LINK *block, BLOCK_LINK **phead)
828
823
assert(!block->next_changed);
829
824
assert(!block->prev_changed);
862
857
static void link_to_file_list(KEY_CACHE *keycache,
863
858
BLOCK_LINK *block, int file,
864
my_bool unlink_block)
866
861
assert(block->status & BLOCK_IN_USE);
867
862
assert(block->hash_link && block->hash_link->block == block);
955
950
not linked in the LRU ring.
958
static void link_block(KEY_CACHE *keycache, BLOCK_LINK *block, my_bool hot,
953
static void link_block(KEY_CACHE *keycache, BLOCK_LINK *block, bool hot,
962
957
BLOCK_LINK **pins;
1160
1155
keycache->warm_blocks--;
1161
1156
block->temperature= BLOCK_HOT;
1163
link_block(keycache, block, hot, (my_bool)at_end);
1158
link_block(keycache, block, hot, (bool)at_end);
1164
1159
block->last_hit_time= keycache->keycache_time;
1165
1160
keycache->keycache_time++;
1401
1396
static BLOCK_LINK *find_key_block(KEY_CACHE *keycache,
1402
File file, my_off_t filepos,
1397
int file, my_off_t filepos,
1403
1398
int init_hits_left,
1404
1399
int wrmode, int *page_st)
1775
1770
/* There are some never used blocks, take first of them */
1776
1771
assert(keycache->blocks_used <
1777
(ulong) keycache->disk_blocks);
1772
(uint32_t) keycache->disk_blocks);
1778
1773
block= &keycache->block_root[keycache->blocks_used];
1779
1774
block->buffer= ADD_TO_PTR(keycache->block_mem,
1780
((ulong) keycache->blocks_used*
1775
((uint32_t) keycache->blocks_used*
1781
1776
keycache->key_cache_block_size),
1783
1778
keycache->blocks_used++;
1784
1779
assert(!block->next_used);
2100
2095
static void read_block(KEY_CACHE *keycache,
2101
BLOCK_LINK *block, uint read_length,
2102
uint min_length, my_bool primary)
2096
BLOCK_LINK *block, uint32_t read_length,
2097
uint32_t min_length, bool primary)
2099
uint32_t got_length;
2106
2101
/* On entry cache_lock is locked */
2197
2192
have to be a multiple of key_cache_block_size;
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)))
2195
unsigned char *key_cache_read(KEY_CACHE *keycache,
2196
int file, my_off_t filepos, int level,
2197
unsigned char *buff, uint32_t length,
2198
uint32_t block_length,
2206
my_bool locked_and_incremented= false;
2202
(void)return_buffer;
2203
bool locked_and_incremented= false;
2205
unsigned char *start= buff;
2210
2207
if (keycache->key_cache_inited)
2212
2209
/* Key cache is used */
2213
2210
register BLOCK_LINK *block;
2211
uint32_t read_length;
2271
2268
keycache->global_cache_read++;
2272
2269
keycache_pthread_mutex_unlock(&keycache->cache_lock);
2273
error= (pread(file, (uchar*) buff, read_length, filepos + offset) == 0);
2270
error= (pread(file, (unsigned char*) buff, read_length, filepos + offset) == 0);
2274
2271
keycache_pthread_mutex_lock(&keycache->cache_lock);
2275
2272
goto next_block;
2281
2278
/* The requested page is to be read into the block buffer */
2282
2279
read_block(keycache, block,
2283
2280
keycache->key_cache_block_size, read_length+offset,
2284
(my_bool)(page_st == PAGE_TO_BE_READ));
2281
(bool)(page_st == PAGE_TO_BE_READ));
2286
2283
A secondary request must now have the block assigned to the
2287
2284
requested file block. It does not hurt to check it for
2316
2313
/* Copy data from the cache buffer */
2317
if (!(read_length & 511))
2318
bmove512(buff, block->buffer+offset, read_length);
2320
memcpy(buff, block->buffer+offset, (size_t) read_length);
2314
memcpy(buff, block->buffer+offset, (size_t) read_length);
2322
2316
#if !defined(SERIALIZED_READ_FROM_CACHE)
2323
2317
keycache_pthread_mutex_lock(&keycache->cache_lock);
2358
2352
if (locked_and_incremented)
2359
2353
keycache_pthread_mutex_unlock(&keycache->cache_lock);
2360
if (pread(file, (uchar*) buff, length, filepos))
2354
if (!pread(file, (unsigned char*) buff, length, filepos))
2362
2356
if (locked_and_incremented)
2363
2357
keycache_pthread_mutex_lock(&keycache->cache_lock);
2395
2389
int key_cache_insert(KEY_CACHE *keycache,
2396
File file, my_off_t filepos, int level,
2397
uchar *buff, uint length)
2390
int file, my_off_t filepos, int level,
2391
unsigned char *buff, uint32_t length)
2403
2397
/* Key cache is used */
2404
2398
register BLOCK_LINK *block;
2399
uint32_t read_length;
2408
my_bool locked_and_incremented= false;
2402
bool locked_and_incremented= false;
2411
2405
When the keycache is once initialized, we use the cache_lock to
2519
2513
/* Copy data from buff */
2520
if (!(read_length & 511))
2521
bmove512(block->buffer+offset, buff, read_length);
2523
memcpy(block->buffer+offset, buff, (size_t) read_length);
2514
memcpy(block->buffer+offset, buff, (size_t) read_length);
2525
2516
#if !defined(SERIALIZED_READ_FROM_CACHE)
2526
2517
keycache_pthread_mutex_lock(&keycache->cache_lock);
2632
2623
int key_cache_write(KEY_CACHE *keycache,
2633
File file, my_off_t filepos, int level,
2634
uchar *buff, uint length,
2635
uint block_length __attribute__((unused)),
2624
int file, my_off_t filepos, int level,
2625
unsigned char *buff, uint32_t length,
2626
uint32_t block_length,
2636
2627
int dont_write)
2638
my_bool locked_and_incremented= false;
2630
bool locked_and_incremented= false;
2641
2633
if (!dont_write)
2643
/* purecov: begin inspected */
2644
2635
/* Not used in the server. */
2645
2636
/* Force writing from buff into disk. */
2646
2637
keycache->global_cache_w_requests++;
2647
2638
keycache->global_cache_write++;
2648
2639
if (pwrite(file, buff, length, filepos) == 0)
2653
2643
if (keycache->key_cache_inited)
2655
2645
/* Key cache is used */
2656
2646
register BLOCK_LINK *block;
2647
uint32_t read_length;
2715
2705
/* Used in the server. */
2716
2706
keycache->global_cache_write++;
2717
2707
keycache_pthread_mutex_unlock(&keycache->cache_lock);
2718
if (pwrite(file, (uchar*) buff, read_length, filepos + offset) == 0)
2708
if (pwrite(file, (unsigned char*) buff, read_length, filepos + offset) == 0)
2720
2710
keycache_pthread_mutex_lock(&keycache->cache_lock);
2810
2800
#if !defined(SERIALIZED_READ_FROM_CACHE)
2811
2801
keycache_pthread_mutex_unlock(&keycache->cache_lock);
2813
if (!(read_length & 511))
2814
bmove512(block->buffer+offset, buff, read_length);
2816
memcpy(block->buffer+offset, buff, (size_t) read_length);
2803
memcpy(block->buffer+offset, buff, (size_t) read_length);
2818
2805
#if !defined(SERIALIZED_READ_FROM_CACHE)
2819
2806
keycache_pthread_mutex_lock(&keycache->cache_lock);
2882
2869
keycache->global_cache_write++;
2883
2870
if (locked_and_incremented)
2884
2871
keycache_pthread_mutex_unlock(&keycache->cache_lock);
2885
if (pwrite(file, (uchar*) buff, length, filepos) == 0)
2872
if (pwrite(file, (unsigned char*) buff, length, filepos) == 0)
2887
2874
if (locked_and_incremented)
2888
2875
keycache_pthread_mutex_lock(&keycache->cache_lock);
3057
3044
static int flush_cached_blocks(KEY_CACHE *keycache,
3058
File file, BLOCK_LINK **cache,
3045
int file, BLOCK_LINK **cache,
3059
3046
BLOCK_LINK **end,
3060
3047
enum flush_type type)
3063
3050
int last_errno= 0;
3064
uint count= (uint) (end-cache);
3051
uint32_t count= (uint) (end-cache);
3066
3053
/* Don't lock the cache during the flush */
3067
3054
keycache_pthread_mutex_unlock(&keycache->cache_lock);
3069
3056
As all blocks referred in 'cache' are marked by BLOCK_IN_FLUSH
3070
3057
we are guarunteed no thread will change them
3072
my_qsort((uchar*) cache, count, sizeof(*cache), (qsort_cmp) cmp_sec_link);
3059
my_qsort((unsigned char*) cache, count, sizeof(*cache), (qsort_cmp) cmp_sec_link);
3074
3061
keycache_pthread_mutex_lock(&keycache->cache_lock);
3183
3170
static int flush_key_blocks_int(KEY_CACHE *keycache,
3184
File file, enum flush_type type)
3171
int file, enum flush_type type)
3186
3173
BLOCK_LINK *cache_buff[FLUSH_CACHE],**cache;
3187
3174
int last_errno= 0;
3194
3181
/* Key cache exists and flush is not disabled */
3196
uint count= FLUSH_CACHE;
3183
uint32_t count= FLUSH_CACHE;
3197
3184
BLOCK_LINK **pos,**end;
3198
3185
BLOCK_LINK *first_in_switch= NULL;
3199
3186
BLOCK_LINK *last_in_flush;
3200
3187
BLOCK_LINK *last_for_update;
3188
BLOCK_LINK *last_in_switch;
3201
3189
BLOCK_LINK *block, *next;
3203
3191
if (type != FLUSH_IGNORE_CHANGED)
3224
3212
changed blocks appear while we need to wait for something.
3226
3214
if ((count > FLUSH_CACHE) &&
3227
!(cache= (BLOCK_LINK**) my_malloc(sizeof(BLOCK_LINK*)*count,
3215
!(cache= (BLOCK_LINK**) malloc(sizeof(BLOCK_LINK*)*count)))
3229
3216
cache= cache_buff;
3231
3218
After a restart there could be more changed blocks than now.
3478
3465
if (!(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH |
3479
3466
BLOCK_REASSIGNED)))
3481
struct st_hash_link *next_hash_link;
3482
my_off_t next_diskpos;
3468
struct st_hash_link *next_hash_link= NULL;
3469
my_off_t next_diskpos= 0;
3471
uint32_t next_status= 0;
3472
uint32_t hash_requests= 0;
3607
3594
int flush_key_blocks(KEY_CACHE *keycache,
3608
File file, enum flush_type type)
3595
int file, enum flush_type type)
3755
3742
reset_key_cache_counters()
3756
name the name of a key cache
3757
key_cache pointer to the key kache to be reset
3760
This procedure is used by process_key_caches() to reset the counters of all
3761
currently used key caches, both the default one and the named ones.
3745
This procedure is used by process_key_caches() to reset the key_cache.
3764
3748
0 on success (always because it can't fail)
3767
int reset_key_cache_counters(const char *name __attribute__((unused)),
3768
KEY_CACHE *key_cache)
3751
void reset_key_cache_counters()
3770
if (!key_cache->key_cache_inited)
3774
key_cache->global_blocks_changed= 0; /* Key_blocks_not_flushed */
3775
key_cache->global_cache_r_requests= 0; /* Key_read_requests */
3776
key_cache->global_cache_read= 0; /* Key_reads */
3777
key_cache->global_cache_w_requests= 0; /* Key_write_requests */
3778
key_cache->global_cache_write= 0; /* Key_writes */
3753
dflt_key_cache->global_blocks_changed= 0; /* Key_blocks_not_flushed */
3754
dflt_key_cache->global_cache_r_requests= 0; /* Key_read_requests */
3755
dflt_key_cache->global_cache_read= 0; /* Key_reads */
3756
dflt_key_cache->global_cache_w_requests= 0; /* Key_write_requests */
3757
dflt_key_cache->global_cache_write= 0; /* Key_writes */
3782
3760
#if defined(KEYCACHE_TIMEOUT)
3764
unsigned int hash_link_number(HASH_LINK *hash_link, KEY_CACHE *keycache)
3766
return ((unsigned int) (((char*)hash_link-(char *) keycache->hash_link_root)/
3767
sizeof(HASH_LINK)));
3771
unsigned int block_number(BLOCK_LINK *block, KEY_CACHE *keycache)
3773
return ((unsigned int) (((char*)block-(char *)keycache->block_root)/
3774
sizeof(BLOCK_LINK)));
3784
3778
#define KEYCACHE_DUMP_FILE "keycache_dump.txt"
3785
3779
#define MAX_QUEUE_LEN 100
3807
3801
page= (KEYCACHE_PAGE *) thread->opt_info;
3808
3802
fprintf(keycache_dump_file,
3809
3803
"thread:%u, (file,filepos)=(%u,%lu)\n",
3810
thread->id,(uint) page->file,(ulong) page->filepos);
3804
thread->id,(uint) page->file,(uint32_t) page->filepos);
3811
3805
if (++i == MAX_QUEUE_LEN)
3822
3816
thread=thread->next;
3823
3817
hash_link= (HASH_LINK *) thread->opt_info;
3824
3818
fprintf(keycache_dump_file,
3825
"thread:%u hash_link:%u (file,filepos)=(%u,%lu)\n",
3826
thread->id, (uint) HASH_LINK_NUMBER(hash_link),
3827
(uint) hash_link->file,(ulong) hash_link->diskpos);
3819
"thread:%u hash_link:%u (file,filepos)=(%u,%u)\n",
3820
thread->id, (uint) hash_link_number(hash_link, keycache),
3821
(uint) hash_link->file,(uint32_t) hash_link->diskpos);
3828
3822
if (++i == MAX_QUEUE_LEN)
3836
3830
block= &keycache->block_root[i];
3837
3831
hash_link= block->hash_link;
3838
3832
fprintf(keycache_dump_file,
3839
"block:%u hash_link:%d status:%x #requests=%u waiting_for_readers:%d\n",
3840
i, (int) (hash_link ? HASH_LINK_NUMBER(hash_link) : -1),
3841
block->status, block->requests, block->condvar ? 1 : 0);
3833
"block:%u hash_link:%d status:%x #requests=%u "
3834
"waiting_for_readers:%d\n",
3835
i, (int) (hash_link ? hash_link_number(hash_link, keycache) : -1),
3836
block->status, block->requests, block->condvar ? 1 : 0);
3842
3837
for (j=0 ; j < 2; j++)
3844
3839
KEYCACHE_WQUEUE *wqueue=&block->wqueue[j];
3867
3862
block= block->next_used;
3868
3863
fprintf(keycache_dump_file,
3869
"block:%u, ", BLOCK_NUMBER(block));
3864
"block:%u, ", block_number(block, keycache));
3871
3866
while (block != keycache->used_last);