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>
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
using namespace drizzled;
115
static void change_key_cache_param(KEY_CACHE *keycache, uint32_t division_limit,
116
uint32_t age_threshold);
114
119
Some compilation flags have been added specifically for this module
115
120
to control the following:
151
155
struct st_keycache_page
153
157
int file; /* file to which the page belongs to */
154
my_off_t filepos; /* position of the page in the file */
158
internal::my_off_t filepos; /* position of the page in the file */
157
161
/* element in the chain of a hash table bucket */
160
164
struct st_hash_link *next, **prev; /* to connect links in the same bucket */
161
165
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 */
166
int file; /* from such a file */
167
internal::my_off_t diskpos; /* with such an offset */
168
uint32_t requests; /* number of requests for the page */
167
171
/* simple states of a block */
193
197
*next_changed, **prev_changed; /* for lists of file dirty/clean blocks */
194
198
struct st_hash_link *hash_link; /* backward ptr to referring hash_link */
195
199
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 */
200
uint32_t requests; /* number of requests for the block */
201
unsigned char *buffer; /* buffer for the block page */
202
uint32_t offset; /* beginning of modified data in the buffer */
203
uint32_t length; /* end of data in the buffer */
204
uint32_t status; /* state of the block */
201
205
enum BLOCK_TEMPERATURE temperature; /* block temperature: cold, warm, hot */
202
uint hits_left; /* number of hits left until promotion */
206
uint32_t hits_left; /* number of hits left until promotion */
203
207
uint64_t last_hit_time; /* timestamp of the last hit */
204
208
KEYCACHE_CONDVAR *condvar; /* condition variable for 'no readers' event */
220
224
(uint32_t) (f)) & (keycache->hash_entries-1))
221
225
#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
228
#ifdef KEYCACHE_TIMEOUT
229
229
static int keycache_pthread_cond_wait(pthread_cond_t *cond,
236
236
#define keycache_pthread_mutex_unlock pthread_mutex_unlock
237
237
#define keycache_pthread_cond_signal pthread_cond_signal
239
static inline uint next_power(uint value)
239
static inline uint32_t next_power(uint32_t value)
241
return (uint) my_round_up_to_next_power((uint32_t) value) << 1;
241
return my_round_up_to_next_power(value) << 1;
270
int init_key_cache(KEY_CACHE *keycache, uint key_cache_block_size,
271
size_t use_mem, uint division_limit,
270
int init_key_cache(KEY_CACHE *keycache, uint32_t key_cache_block_size,
271
size_t use_mem, uint32_t division_limit,
272
uint32_t age_threshold)
274
274
uint32_t blocks, hash_links;
325
325
((size_t) blocks * keycache->key_cache_block_size) > use_mem)
327
327
/* Allocate memory for cache page buffers */
328
if ((keycache->block_mem= malloc((size_t) blocks * keycache->key_cache_block_size)))
328
if ((keycache->block_mem= (unsigned char *)malloc((size_t) blocks * keycache->key_cache_block_size)))
331
331
Allocate memory for blocks, hash_links and hash entries;
332
332
For each block 2 hash links are allocated
334
if ((keycache->block_root= (BLOCK_LINK*) my_malloc(length,
334
if ((keycache->block_root= (BLOCK_LINK*) malloc(length)))
337
336
free(keycache->block_mem);
338
337
keycache->block_mem= 0;
343
342
my_error(EE_OUTOFMEMORY, MYF(0), blocks * keycache->key_cache_block_size);
409
408
if (keycache->block_root)
411
my_free((uchar*) keycache->block_root, MYF(0));
410
free((unsigned char*) keycache->block_root);
412
411
keycache->block_root= NULL;
415
414
keycache->can_be_used= 0;
446
445
(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,
448
int resize_key_cache(KEY_CACHE *keycache, uint32_t key_cache_block_size,
449
size_t use_mem, uint32_t division_limit,
450
uint32_t age_threshold)
583
void change_key_cache_param(KEY_CACHE *keycache, uint division_limit,
580
static void change_key_cache_param(KEY_CACHE *keycache, uint32_t division_limit,
581
uint32_t age_threshold)
586
583
keycache_pthread_mutex_lock(&keycache->cache_lock);
587
584
if (division_limit)
619
616
free(keycache->block_mem);
620
617
keycache->block_mem= NULL;
621
my_free((uchar*) keycache->block_root, MYF(0));
618
free((unsigned char*) keycache->block_root);
622
619
keycache->block_root= NULL;
624
621
keycache->disk_blocks= -1;
655
652
static void link_into_queue(KEYCACHE_WQUEUE *wqueue,
656
struct st_my_thread_var *thread)
653
internal::st_my_thread_var *thread)
658
struct st_my_thread_var *last;
655
internal::st_my_thread_var *last;
660
657
assert(!thread->next && !thread->prev);
661
658
if (! (last= wqueue->last_thread))
692
689
static void unlink_from_queue(KEYCACHE_WQUEUE *wqueue,
693
struct st_my_thread_var *thread)
690
internal::st_my_thread_var *thread)
695
692
assert(thread->next && thread->prev);
696
693
if (thread->next == thread)
701
698
thread->next->prev= thread->prev;
702
699
*thread->prev=thread->next;
703
700
if (wqueue->last_thread == thread)
704
wqueue->last_thread= STRUCT_PTR(struct st_my_thread_var, next,
701
wqueue->last_thread= STRUCT_PTR(internal::st_my_thread_var, next,
707
704
thread->next= NULL;
735
732
static void wait_on_queue(KEYCACHE_WQUEUE *wqueue,
736
733
pthread_mutex_t *mutex)
738
struct st_my_thread_var *last;
739
struct st_my_thread_var *thread= my_thread_var;
735
internal::st_my_thread_var *last;
736
internal::st_my_thread_var *thread= my_thread_var;
741
738
/* Add to queue. */
742
739
assert(!thread->next);
781
778
static void release_whole_queue(KEYCACHE_WQUEUE *wqueue)
783
struct st_my_thread_var *last;
784
struct st_my_thread_var *next;
785
struct st_my_thread_var *thread;
780
internal::st_my_thread_var *last;
781
internal::st_my_thread_var *next;
782
internal::st_my_thread_var *thread;
787
784
/* Queue may be empty. */
788
785
if (!(last= wqueue->last_thread))
809
806
Unlink a block from the chain of dirty/clean blocks
811
static inline void unlink_changed(BLOCK_LINK *block)
808
static void unlink_changed(BLOCK_LINK *block)
813
810
assert(block->prev_changed && *block->prev_changed == block);
814
811
if (block->next_changed)
823
820
Link a block into the chain of dirty/clean blocks
826
static inline void link_changed(BLOCK_LINK *block, BLOCK_LINK **phead)
823
static void link_changed(BLOCK_LINK *block, BLOCK_LINK **phead)
828
825
assert(!block->next_changed);
829
826
assert(!block->prev_changed);
970
967
if (!hot && keycache->waiting_for_block.last_thread)
972
969
/* Signal that in the LRU warm sub-chain an available block has appeared */
973
struct st_my_thread_var *last_thread=
970
internal::st_my_thread_var *last_thread=
974
971
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;
972
internal::st_my_thread_var *first_thread= last_thread->next;
973
internal::st_my_thread_var *next_thread= first_thread;
977
974
HASH_LINK *hash_link= (HASH_LINK *) first_thread->opt_info;
978
struct st_my_thread_var *thread;
975
internal::st_my_thread_var *thread;
981
978
thread= next_thread;
1218
1215
static void wait_for_readers(KEY_CACHE *keycache,
1219
1216
BLOCK_LINK *block)
1221
struct st_my_thread_var *thread= my_thread_var;
1218
internal::st_my_thread_var *thread= my_thread_var;
1222
1219
assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
1223
1220
assert(!(block->status & (BLOCK_ERROR | BLOCK_IN_FLUSH |
1224
1221
BLOCK_CHANGED)));
1267
1264
if (keycache->waiting_for_hash_link.last_thread)
1269
1266
/* Signal that a free hash link has appeared */
1270
struct st_my_thread_var *last_thread=
1267
internal::st_my_thread_var *last_thread=
1271
1268
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;
1269
internal::st_my_thread_var *first_thread= last_thread->next;
1270
internal::st_my_thread_var *next_thread= first_thread;
1274
1271
KEYCACHE_PAGE *first_page= (KEYCACHE_PAGE *) (first_thread->opt_info);
1275
struct st_my_thread_var *thread;
1272
internal::st_my_thread_var *thread;
1277
1274
hash_link->file= first_page->file;
1278
1275
hash_link->diskpos= first_page->filepos;
1310
1307
static HASH_LINK *get_hash_link(KEY_CACHE *keycache,
1311
int file, my_off_t filepos)
1308
int file, internal::my_off_t filepos)
1313
1310
register HASH_LINK *hash_link, **start;
1401
1398
static BLOCK_LINK *find_key_block(KEY_CACHE *keycache,
1402
File file, my_off_t filepos,
1399
int file, internal::my_off_t filepos,
1403
1400
int init_hits_left,
1404
1401
int wrmode, int *page_st)
1779
1776
block->buffer= ADD_TO_PTR(keycache->block_mem,
1780
1777
((uint32_t) keycache->blocks_used*
1781
1778
keycache->key_cache_block_size),
1783
1780
keycache->blocks_used++;
1784
1781
assert(!block->next_used);
1823
1820
it is marked BLOCK_IN_EVICTION.
1826
struct st_my_thread_var *thread= my_thread_var;
1823
internal::st_my_thread_var *thread= my_thread_var;
1827
1824
thread->opt_info= (void *) hash_link;
1828
1825
link_into_queue(&keycache->waiting_for_block, thread);
2100
2097
static void read_block(KEY_CACHE *keycache,
2101
BLOCK_LINK *block, uint read_length,
2102
uint min_length, bool primary)
2098
BLOCK_LINK *block, uint32_t read_length,
2099
uint32_t min_length, bool primary)
2101
uint32_t got_length;
2106
2103
/* On entry cache_lock is locked */
2197
2194
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)))
2197
unsigned char *key_cache_read(KEY_CACHE *keycache,
2198
int file, internal::my_off_t filepos, int level,
2199
unsigned char *buff, uint32_t length,
2200
uint32_t block_length,
2204
(void)return_buffer;
2206
2205
bool locked_and_incremented= false;
2207
unsigned char *start= buff;
2210
2209
if (keycache->key_cache_inited)
2212
2211
/* Key cache is used */
2213
2212
register BLOCK_LINK *block;
2213
uint32_t read_length;
2271
2270
keycache->global_cache_read++;
2272
2271
keycache_pthread_mutex_unlock(&keycache->cache_lock);
2273
error= (pread(file, (uchar*) buff, read_length, filepos + offset) == 0);
2272
error= (pread(file, (unsigned char*) buff, read_length, filepos + offset) == 0);
2274
2273
keycache_pthread_mutex_lock(&keycache->cache_lock);
2275
2274
goto next_block;
2355
2354
if (locked_and_incremented)
2356
2355
keycache_pthread_mutex_unlock(&keycache->cache_lock);
2357
if (pread(file, (uchar*) buff, length, filepos))
2356
if (!pread(file, (unsigned char*) buff, length, filepos))
2359
2358
if (locked_and_incremented)
2360
2359
keycache_pthread_mutex_lock(&keycache->cache_lock);
2392
2391
int key_cache_insert(KEY_CACHE *keycache,
2393
File file, my_off_t filepos, int level,
2394
uchar *buff, uint length)
2392
int file, internal::my_off_t filepos, int level,
2393
unsigned char *buff, uint32_t length)
2626
2625
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)),
2626
int file, internal::my_off_t filepos, int level,
2627
unsigned char *buff, uint32_t length,
2628
uint32_t block_length,
2630
2629
int dont_write)
2632
2632
bool locked_and_incremented= false;
2635
2635
if (!dont_write)
2637
/* purecov: begin inspected */
2638
2637
/* Not used in the server. */
2639
2638
/* Force writing from buff into disk. */
2640
2639
keycache->global_cache_w_requests++;
2641
2640
keycache->global_cache_write++;
2642
2641
if (pwrite(file, buff, length, filepos) == 0)
2647
2645
if (keycache->key_cache_inited)
2649
2647
/* Key cache is used */
2650
2648
register BLOCK_LINK *block;
2649
uint32_t read_length;
2709
2707
/* Used in the server. */
2710
2708
keycache->global_cache_write++;
2711
2709
keycache_pthread_mutex_unlock(&keycache->cache_lock);
2712
if (pwrite(file, (uchar*) buff, read_length, filepos + offset) == 0)
2710
if (pwrite(file, (unsigned char*) buff, read_length, filepos + offset) == 0)
2714
2712
keycache_pthread_mutex_lock(&keycache->cache_lock);
2873
2871
keycache->global_cache_write++;
2874
2872
if (locked_and_incremented)
2875
2873
keycache_pthread_mutex_unlock(&keycache->cache_lock);
2876
if (pwrite(file, (uchar*) buff, length, filepos) == 0)
2874
if (pwrite(file, (unsigned char*) buff, length, filepos) == 0)
2878
2876
if (locked_and_incremented)
2879
2877
keycache_pthread_mutex_lock(&keycache->cache_lock);
3048
3046
static int flush_cached_blocks(KEY_CACHE *keycache,
3049
File file, BLOCK_LINK **cache,
3047
int file, BLOCK_LINK **cache,
3050
3048
BLOCK_LINK **end,
3051
3049
enum flush_type type)
3054
3052
int last_errno= 0;
3055
uint count= (uint) (end-cache);
3053
uint32_t count= (uint) (end-cache);
3057
3055
/* Don't lock the cache during the flush */
3058
3056
keycache_pthread_mutex_unlock(&keycache->cache_lock);
3060
3058
As all blocks referred in 'cache' are marked by BLOCK_IN_FLUSH
3061
3059
we are guarunteed no thread will change them
3063
my_qsort((uchar*) cache, count, sizeof(*cache), (qsort_cmp) cmp_sec_link);
3061
internal::my_qsort((unsigned char*) cache, count, sizeof(*cache), (qsort_cmp) cmp_sec_link);
3065
3063
keycache_pthread_mutex_lock(&keycache->cache_lock);
3174
3172
static int flush_key_blocks_int(KEY_CACHE *keycache,
3175
File file, enum flush_type type)
3173
int file, enum flush_type type)
3177
3175
BLOCK_LINK *cache_buff[FLUSH_CACHE],**cache;
3178
3176
int last_errno= 0;
3181
3179
cache= cache_buff;
3182
3180
if (keycache->disk_blocks > 0 &&
3183
(!my_disable_flush_key_blocks || type != FLUSH_KEEP))
3181
(!internal::my_disable_flush_key_blocks || type != FLUSH_KEEP))
3185
3183
/* Key cache exists and flush is not disabled */
3187
uint count= FLUSH_CACHE;
3185
uint32_t count= FLUSH_CACHE;
3188
3186
BLOCK_LINK **pos,**end;
3189
3187
BLOCK_LINK *first_in_switch= NULL;
3190
3188
BLOCK_LINK *last_in_flush;
3191
3189
BLOCK_LINK *last_for_update;
3190
BLOCK_LINK *last_in_switch;
3192
3191
BLOCK_LINK *block, *next;
3194
3193
if (type != FLUSH_IGNORE_CHANGED)
3215
3214
changed blocks appear while we need to wait for something.
3217
3216
if ((count > FLUSH_CACHE) &&
3218
!(cache= (BLOCK_LINK**) my_malloc(sizeof(BLOCK_LINK*)*count,
3217
!(cache= (BLOCK_LINK**) malloc(sizeof(BLOCK_LINK*)*count)))
3220
3218
cache= cache_buff;
3222
3220
After a restart there could be more changed blocks than now.
3598
3596
int flush_key_blocks(KEY_CACHE *keycache,
3599
File file, enum flush_type type)
3597
int file, enum flush_type type)
3746
3744
reset_key_cache_counters()
3747
name the name of a key cache
3748
key_cache pointer to the key kache to be reset
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.
3747
This procedure is used by process_key_caches() to reset the key_cache.
3755
3750
0 on success (always because it can't fail)
3758
int reset_key_cache_counters(const char *name __attribute__((unused)),
3759
KEY_CACHE *key_cache)
3753
void reset_key_cache_counters()
3761
if (!key_cache->key_cache_inited)
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 */
3755
dflt_key_cache->global_blocks_changed= 0; /* Key_blocks_not_flushed */
3756
dflt_key_cache->global_cache_r_requests= 0; /* Key_read_requests */
3757
dflt_key_cache->global_cache_read= 0; /* Key_reads */
3758
dflt_key_cache->global_cache_w_requests= 0; /* Key_write_requests */
3759
dflt_key_cache->global_cache_write= 0; /* Key_writes */
3773
3762
#if defined(KEYCACHE_TIMEOUT)
3766
unsigned int hash_link_number(HASH_LINK *hash_link, KEY_CACHE *keycache)
3768
return ((unsigned int) (((char*)hash_link-(char *) keycache->hash_link_root)/
3769
sizeof(HASH_LINK)));
3773
unsigned int block_number(BLOCK_LINK *block, KEY_CACHE *keycache)
3775
return ((unsigned int) (((char*)block-(char *)keycache->block_root)/
3776
sizeof(BLOCK_LINK)));
3775
3780
#define KEYCACHE_DUMP_FILE "keycache_dump.txt"
3776
3781
#define MAX_QUEUE_LEN 100
3779
3784
static void keycache_dump(KEY_CACHE *keycache)
3781
3786
FILE *keycache_dump_file=fopen(KEYCACHE_DUMP_FILE, "w");
3782
struct st_my_thread_var *last;
3783
struct st_my_thread_var *thread;
3787
internal::st_my_thread_var *last;
3788
internal::st_my_thread_var *thread;
3784
3789
BLOCK_LINK *block;
3785
3790
HASH_LINK *hash_link;
3786
3791
KEYCACHE_PAGE *page;
3789
3794
fprintf(keycache_dump_file, "thread:%u\n", thread->id);
3813
3818
thread=thread->next;
3814
3819
hash_link= (HASH_LINK *) thread->opt_info;
3815
3820
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);
3821
"thread:%u hash_link:%u (file,filepos)=(%u,%u)\n",
3822
thread->id, (uint) hash_link_number(hash_link, keycache),
3823
(uint) hash_link->file,(uint32_t) hash_link->diskpos);
3819
3824
if (++i == MAX_QUEUE_LEN)
3827
3832
block= &keycache->block_root[i];
3828
3833
hash_link= block->hash_link;
3829
3834
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);
3835
"block:%u hash_link:%d status:%x #requests=%u "
3836
"waiting_for_readers:%d\n",
3837
i, (int) (hash_link ? hash_link_number(hash_link, keycache) : -1),
3838
block->status, block->requests, block->condvar ? 1 : 0);
3833
3839
for (j=0 ; j < 2; j++)
3835
3841
KEYCACHE_WQUEUE *wqueue=&block->wqueue[j];
3858
3864
block= block->next_used;
3859
3865
fprintf(keycache_dump_file,
3860
"block:%u, ", BLOCK_NUMBER(block));
3866
"block:%u, ", block_number(block, keycache));
3862
3868
while (block != keycache->used_last);