130
130
situation, which theoretically should not happen;
131
131
to set timeout equal to <T> seconds add
132
132
#define KEYCACHE_TIMEOUT <T>
133
- to enable the module traps and to send debug information from
134
key cache module to a special debug log add:
135
#define KEYCACHE_DEBUG
136
the name of this debug log file <LOG NAME> can be set through:
137
#define KEYCACHE_DEBUG_LOG <LOG NAME>
138
if the name is not defined, it's set by default;
139
if the KEYCACHE_DEBUG flag is not set up and we are in a debug
140
mode, i.e. when ! defined(DBUG_OFF), the debug information from the
141
module is sent to the regular debug log.
134
143
Example of the settings:
135
144
#define SERIALIZED_READ_FROM_CACHE
136
145
#define MAX_THREADS 100
137
146
#define KEYCACHE_TIMEOUT 1
147
#define KEYCACHE_DEBUG
148
#define KEYCACHE_DEBUG_LOG "my_key_cache_debug.log"
140
151
#define STRUCT_PTR(TYPE, MEMBER, a) \
193
204
*next_changed, **prev_changed; /* for lists of file dirty/clean blocks */
194
205
struct st_hash_link *hash_link; /* backward ptr to referring hash_link */
195
206
KEYCACHE_WQUEUE wqueue[2]; /* queues on waiting requests for new/old pages */
196
uint32_t requests; /* number of requests for the block */
197
unsigned char *buffer; /* buffer for the block page */
198
uint32_t offset; /* beginning of modified data in the buffer */
199
uint32_t length; /* end of data in the buffer */
200
uint32_t status; /* state of the block */
207
uint requests; /* number of requests for the block */
208
uchar *buffer; /* buffer for the block page */
209
uint offset; /* beginning of modified data in the buffer */
210
uint length; /* end of data in the buffer */
211
uint status; /* state of the block */
201
212
enum BLOCK_TEMPERATURE temperature; /* block temperature: cold, warm, hot */
202
uint32_t hits_left; /* number of hits left until promotion */
203
uint64_t last_hit_time; /* timestamp of the last hit */
213
uint hits_left; /* number of hits left until promotion */
214
ulonglong last_hit_time; /* timestamp of the last hit */
204
215
KEYCACHE_CONDVAR *condvar; /* condition variable for 'no readers' event */
214
225
pthread_mutex_t *mutex);
215
226
static void release_whole_queue(KEYCACHE_WQUEUE *wqueue);
216
227
static void free_block(KEY_CACHE *keycache, BLOCK_LINK *block);
228
#if !defined(DBUG_OFF)
229
static void test_key_cache(KEY_CACHE *keycache,
230
const char *where, my_bool lock);
218
233
#define KEYCACHE_HASH(f, pos) \
219
(((uint32_t) ((pos) / keycache->key_cache_block_size) + \
220
(uint32_t) (f)) & (keycache->hash_entries-1))
234
(((ulong) ((pos) / keycache->key_cache_block_size) + \
235
(ulong) (f)) & (keycache->hash_entries-1))
221
236
#define FILE_HASH(f) ((uint) (f) & (CHANGED_BLOCKS_HASH-1))
238
#define DEFAULT_KEYCACHE_DEBUG_LOG "keycache_debug.log"
240
#if defined(KEYCACHE_DEBUG) && ! defined(KEYCACHE_DEBUG_LOG)
241
#define KEYCACHE_DEBUG_LOG DEFAULT_KEYCACHE_DEBUG_LOG
244
#if defined(KEYCACHE_DEBUG_LOG)
245
static FILE *keycache_debug_log=NULL;
246
static void keycache_debug_print _VARARGS((const char *fmt,...));
247
#define KEYCACHE_DEBUG_OPEN \
248
if (!keycache_debug_log) \
250
keycache_debug_log= fopen(KEYCACHE_DEBUG_LOG, "w"); \
251
(void) setvbuf(keycache_debug_log, NULL, _IOLBF, BUFSIZ); \
254
#define KEYCACHE_DEBUG_CLOSE \
255
if (keycache_debug_log) \
257
fclose(keycache_debug_log); \
258
keycache_debug_log= 0; \
261
#define KEYCACHE_DEBUG_OPEN
262
#define KEYCACHE_DEBUG_CLOSE
263
#endif /* defined(KEYCACHE_DEBUG_LOG) */
265
#if defined(KEYCACHE_DEBUG_LOG) && defined(KEYCACHE_DEBUG)
266
#define KEYCACHE_DBUG_PRINT(l, m) \
267
{ if (keycache_debug_log) fprintf(keycache_debug_log, "%s: ", l); \
268
keycache_debug_print m; }
270
#define KEYCACHE_DBUG_ASSERT(a) \
271
{ if (! (a) && keycache_debug_log) fclose(keycache_debug_log); \
274
#define KEYCACHE_DBUG_PRINT(l, m) DBUG_PRINT(l, m)
275
#define KEYCACHE_DBUG_ASSERT(a) DBUG_ASSERT(a)
276
#endif /* defined(KEYCACHE_DEBUG_LOG) && defined(KEYCACHE_DEBUG) */
278
#if defined(KEYCACHE_DEBUG) || !defined(DBUG_OFF)
279
static long keycache_thread_id;
280
#define KEYCACHE_THREAD_TRACE(l) \
281
KEYCACHE_DBUG_PRINT(l,("|thread %ld",keycache_thread_id))
283
#define KEYCACHE_THREAD_TRACE_BEGIN(l) \
284
{ struct st_my_thread_var *thread_var= my_thread_var; \
285
keycache_thread_id= thread_var->id; \
286
KEYCACHE_DBUG_PRINT(l,("[thread %ld",keycache_thread_id)) }
288
#define KEYCACHE_THREAD_TRACE_END(l) \
289
KEYCACHE_DBUG_PRINT(l,("]thread %ld",keycache_thread_id))
291
#define KEYCACHE_THREAD_TRACE_BEGIN(l)
292
#define KEYCACHE_THREAD_TRACE_END(l)
293
#define KEYCACHE_THREAD_TRACE(l)
294
#endif /* defined(KEYCACHE_DEBUG) || !defined(DBUG_OFF) */
223
296
#define BLOCK_NUMBER(b) \
224
297
((uint) (((char*)(b)-(char *) keycache->block_root)/sizeof(BLOCK_LINK)))
225
298
#define HASH_LINK_NUMBER(h) \
226
299
((uint) (((char*)(h)-(char *) keycache->hash_link_root)/sizeof(HASH_LINK)))
228
#ifdef KEYCACHE_TIMEOUT
301
#if (defined(KEYCACHE_TIMEOUT)) || defined(KEYCACHE_DEBUG)
229
302
static int keycache_pthread_cond_wait(pthread_cond_t *cond,
230
303
pthread_mutex_t *mutex);
232
305
#define keycache_pthread_cond_wait pthread_cond_wait
308
#if defined(KEYCACHE_DEBUG)
309
static int keycache_pthread_mutex_lock(pthread_mutex_t *mutex);
310
static void keycache_pthread_mutex_unlock(pthread_mutex_t *mutex);
311
static int keycache_pthread_cond_signal(pthread_cond_t *cond);
235
313
#define keycache_pthread_mutex_lock pthread_mutex_lock
236
314
#define keycache_pthread_mutex_unlock pthread_mutex_unlock
237
315
#define keycache_pthread_cond_signal pthread_cond_signal
239
static inline uint32_t next_power(uint32_t value)
316
#endif /* defined(KEYCACHE_DEBUG) */
318
#if !defined(DBUG_OFF)
322
#define inline /* disabled inline for easier debugging */
323
static int fail_block(BLOCK_LINK *block);
324
static int fail_hlink(HASH_LINK *hlink);
325
static int cache_empty(KEY_CACHE *keycache);
328
static inline uint next_power(uint value)
241
return (uint) my_round_up_to_next_power((uint32_t) value) << 1;
330
return (uint) my_round_up_to_next_power((uint32) value) << 1;
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)
359
int init_key_cache(KEY_CACHE *keycache, uint key_cache_block_size,
360
size_t use_mem, uint division_limit,
274
uint32_t blocks, hash_links;
363
ulong blocks, hash_links;
277
assert(key_cache_block_size >= 512);
366
DBUG_ENTER("init_key_cache");
367
DBUG_ASSERT(key_cache_block_size >= 512);
279
370
if (keycache->key_cache_inited && keycache->disk_blocks > 0)
372
DBUG_PRINT("warning",("key cache already in use"));
284
376
keycache->global_cache_w_requests= keycache->global_cache_r_requests= 0;
353
447
keycache->hash_link_root= (HASH_LINK*) ((char*) keycache->hash_root +
354
448
ALIGN_SIZE((sizeof(HASH_LINK*) *
355
449
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));
450
bzero((uchar*) keycache->block_root,
451
keycache->disk_blocks * sizeof(BLOCK_LINK));
452
bzero((uchar*) keycache->hash_root,
453
keycache->hash_entries * sizeof(HASH_LINK*));
454
bzero((uchar*) keycache->hash_link_root,
455
keycache->hash_links * sizeof(HASH_LINK));
362
456
keycache->hash_links_used= 0;
363
457
keycache->free_hash_list= NULL;
364
458
keycache->blocks_used= keycache->blocks_changed= 0;
384
478
keycache->waiting_for_hash_link.last_thread= NULL;
385
479
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);
481
("disk_blocks: %d block_root: 0x%lx hash_entries: %d\
482
hash_root: 0x%lx hash_links: %d hash_link_root: 0x%lx",
483
keycache->disk_blocks, (long) keycache->block_root,
484
keycache->hash_entries, (long) keycache->hash_root,
485
keycache->hash_links, (long) keycache->hash_link_root));
486
bzero((uchar*) keycache->changed_blocks,
487
sizeof(keycache->changed_blocks[0]) * CHANGED_BLOCKS_HASH);
488
bzero((uchar*) keycache->file_blocks,
489
sizeof(keycache->file_blocks[0]) * CHANGED_BLOCKS_HASH);
446
546
(when cnt_for_resize=0).
449
int resize_key_cache(KEY_CACHE *keycache, uint32_t key_cache_block_size,
450
size_t use_mem, uint32_t division_limit,
451
uint32_t age_threshold)
549
int resize_key_cache(KEY_CACHE *keycache, uint key_cache_block_size,
550
size_t use_mem, uint division_limit,
554
DBUG_ENTER("resize_key_cache");
455
556
if (!keycache->key_cache_inited)
456
return(keycache->disk_blocks);
557
DBUG_RETURN(keycache->disk_blocks);
458
559
if(key_cache_block_size == keycache->key_cache_block_size &&
459
560
use_mem == keycache->key_cache_mem_size)
461
562
change_key_cache_param(keycache, division_limit, age_threshold);
462
return(keycache->disk_blocks);
563
DBUG_RETURN(keycache->disk_blocks);
465
566
keycache_pthread_mutex_lock(&keycache->cache_lock);
955
1089
not linked in the LRU ring.
958
static void link_block(KEY_CACHE *keycache, BLOCK_LINK *block, bool hot,
1092
static void link_block(KEY_CACHE *keycache, BLOCK_LINK *block, my_bool hot,
961
1095
BLOCK_LINK *ins;
962
1096
BLOCK_LINK **pins;
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);
1098
DBUG_ASSERT((block->status & ~BLOCK_CHANGED) == (BLOCK_READ | BLOCK_IN_USE));
1099
DBUG_ASSERT(block->hash_link); /*backptr to block NULL from free_block()*/
1100
DBUG_ASSERT(!block->requests);
1101
DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
1102
DBUG_ASSERT(!block->next_used);
1103
DBUG_ASSERT(!block->prev_used);
970
1104
if (!hot && keycache->waiting_for_block.last_thread)
972
1106
/* Signal that in the LRU warm sub-chain an available block has appeared */
1056
1208
static void unlink_block(KEY_CACHE *keycache, BLOCK_LINK *block)
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 &&
1210
DBUG_ASSERT((block->status & ~BLOCK_CHANGED) == (BLOCK_READ | BLOCK_IN_USE));
1211
DBUG_ASSERT(block->hash_link); /*backptr to block NULL from free_block()*/
1212
DBUG_ASSERT(!block->requests);
1213
DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
1214
DBUG_ASSERT(block->next_used && block->prev_used &&
1063
1215
(block->next_used->prev_used == &block->next_used) &&
1064
1216
(*block->prev_used == block));
1065
1217
if (block->next_used == block)
1141
1309
static void unreg_request(KEY_CACHE *keycache,
1142
1310
BLOCK_LINK *block, int at_end)
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);
1312
DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
1313
DBUG_ASSERT(block->hash_link); /*backptr to block NULL from free_block()*/
1314
DBUG_ASSERT(block->requests);
1315
DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
1316
DBUG_ASSERT(!block->next_used);
1317
DBUG_ASSERT(!block->prev_used);
1150
1318
if (! --block->requests)
1153
1321
if (block->hits_left)
1154
1322
block->hits_left--;
1155
1323
hot= !block->hits_left && at_end &&
1200
1372
static void remove_reader(BLOCK_LINK *block)
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);
1374
DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
1375
DBUG_ASSERT(block->hash_link && block->hash_link->block == block);
1376
DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
1377
DBUG_ASSERT(!block->next_used);
1378
DBUG_ASSERT(!block->prev_used);
1379
DBUG_ASSERT(block->hash_link->requests);
1208
1380
if (! --block->hash_link->requests && block->condvar)
1209
1381
keycache_pthread_cond_signal(block->condvar);
1219
1391
BLOCK_LINK *block)
1221
1393
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 |
1394
DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
1395
DBUG_ASSERT(!(block->status & (BLOCK_ERROR | BLOCK_IN_FLUSH |
1224
1396
BLOCK_CHANGED)));
1225
assert(block->hash_link);
1226
assert(block->hash_link->block == block);
1397
DBUG_ASSERT(block->hash_link);
1398
DBUG_ASSERT(block->hash_link->block == block);
1227
1399
/* Linked in file_blocks or changed_blocks hash. */
1228
assert(block->prev_changed && *block->prev_changed == block);
1400
DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
1229
1401
/* Not linked in LRU ring. */
1230
assert(!block->next_used);
1231
assert(!block->prev_used);
1402
DBUG_ASSERT(!block->next_used);
1403
DBUG_ASSERT(!block->prev_used);
1232
1404
while (block->hash_link->requests)
1406
KEYCACHE_DBUG_PRINT("wait_for_readers: wait",
1407
("suspend thread %ld block %u",
1408
thread->id, BLOCK_NUMBER(block)));
1234
1409
/* There must be no other waiter. We have no queue here. */
1235
assert(!block->condvar);
1410
DBUG_ASSERT(!block->condvar);
1236
1411
block->condvar= &thread->suspend;
1237
1412
keycache_pthread_cond_wait(&thread->suspend, &keycache->cache_lock);
1238
1413
block->condvar= NULL;
1319
1503
hash_link points to the first member of the list
1321
1505
hash_link= *(start= &keycache->hash_root[KEYCACHE_HASH(file, filepos)]);
1506
#if defined(KEYCACHE_DEBUG)
1322
1509
/* Look for an element for the pair (file, filepos) in the bucket chain */
1323
1510
while (hash_link &&
1324
1511
(hash_link->diskpos != filepos || hash_link->file != file))
1326
1513
hash_link= hash_link->next;
1514
#if defined(KEYCACHE_DEBUG)
1516
if (! (cnt <= keycache->hash_links_used))
1519
for (i=0, hash_link= *start ;
1520
i < cnt ; i++, hash_link= hash_link->next)
1522
KEYCACHE_DBUG_PRINT("get_hash_link", ("fd: %u pos: %lu",
1523
(uint) hash_link->file,(ulong) hash_link->diskpos));
1526
KEYCACHE_DBUG_ASSERT(cnt <= keycache->hash_links_used);
1328
1529
if (! hash_link)
1409
1613
int page_status;
1615
DBUG_ENTER("find_key_block");
1616
KEYCACHE_THREAD_TRACE("find_key_block:begin");
1617
DBUG_PRINT("enter", ("fd: %d pos: %lu wrmode: %d",
1618
file, (ulong) filepos, wrmode));
1619
KEYCACHE_DBUG_PRINT("find_key_block", ("fd: %d pos: %lu wrmode: %d",
1620
file, (ulong) filepos,
1622
#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
1623
DBUG_EXECUTE("check_keycache2",
1624
test_key_cache(keycache, "start of find_key_block", 0););
1413
1629
If the flush phase of a resize operation fails, the cache is left
1414
1630
unusable. This will be detected only after "goto restart".
1416
1632
if (!keycache->can_be_used)
1420
1636
Find the hash_link for the requested file block (file, filepos). We
1775
2003
/* There are some never used blocks, take first of them */
1776
assert(keycache->blocks_used <
1777
(uint32_t) keycache->disk_blocks);
2004
DBUG_ASSERT(keycache->blocks_used <
2005
(ulong) keycache->disk_blocks);
1778
2006
block= &keycache->block_root[keycache->blocks_used];
1779
2007
block->buffer= ADD_TO_PTR(keycache->block_mem,
1780
((uint32_t) keycache->blocks_used*
2008
((ulong) keycache->blocks_used*
1781
2009
keycache->key_cache_block_size),
1783
2011
keycache->blocks_used++;
1784
assert(!block->next_used);
2012
DBUG_ASSERT(!block->next_used);
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);
2014
DBUG_ASSERT(!block->prev_used);
2015
DBUG_ASSERT(!block->next_changed);
2016
DBUG_ASSERT(!block->prev_changed);
2017
DBUG_ASSERT(!block->hash_link);
2018
DBUG_ASSERT(!block->status);
2019
DBUG_ASSERT(!block->requests);
1792
2020
keycache->blocks_unused--;
1793
2021
block->status= BLOCK_IN_USE;
1794
2022
block->length= 0;
1828
2059
link_into_queue(&keycache->waiting_for_block, thread);
2062
KEYCACHE_DBUG_PRINT("find_key_block: wait",
2063
("suspend thread %ld", thread->id));
1831
2064
keycache_pthread_cond_wait(&thread->suspend,
1832
2065
&keycache->cache_lock);
1834
2067
while (thread->next);
1835
2068
thread->opt_info= NULL;
1836
2069
/* Assert that block has a request registered. */
1837
assert(hash_link->block->requests);
2070
DBUG_ASSERT(hash_link->block->requests);
1838
2071
/* Assert that block is not in LRU ring. */
1839
assert(!hash_link->block->next_used);
1840
assert(!hash_link->block->prev_used);
2072
DBUG_ASSERT(!hash_link->block->next_used);
2073
DBUG_ASSERT(!hash_link->block->prev_used);
1843
2076
If we waited above, hash_link->block has been assigned by
2043
2284
Register a request on the block. This is another protection
2044
2285
against eviction.
2046
assert(((block->hash_link != hash_link) &&
2287
DBUG_ASSERT(((block->hash_link != hash_link) &&
2047
2288
(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH))) ||
2048
2289
((block->hash_link == hash_link) &&
2049
2290
!(block->status & BLOCK_READ)) ||
2050
2291
((block->status & BLOCK_READ) &&
2051
2292
!(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH))));
2052
2293
reg_requests(keycache, block, 1);
2294
KEYCACHE_DBUG_PRINT("find_key_block",
2295
("block->hash_link: %p hash_link: %p "
2296
"block->status: %u", block->hash_link,
2297
hash_link, block->status ));
2053
2298
page_status= (((block->hash_link == hash_link) &&
2054
2299
(block->status & BLOCK_READ)) ?
2055
2300
PAGE_READ : PAGE_WAIT_TO_BE_READ);
2059
assert(page_status != -1);
2304
KEYCACHE_DBUG_ASSERT(page_status != -1);
2060
2305
/* Same assert basically, but be very sure. */
2306
KEYCACHE_DBUG_ASSERT(block);
2062
2307
/* 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);
2308
DBUG_ASSERT(block->requests);
2309
DBUG_ASSERT(!block->next_used);
2310
DBUG_ASSERT(!block->prev_used);
2066
2311
/* Assert that we return the correct block. */
2067
assert((page_status == PAGE_WAIT_TO_BE_READ) ||
2312
DBUG_ASSERT((page_status == PAGE_WAIT_TO_BE_READ) ||
2068
2313
((block->hash_link->file == file) &&
2069
2314
(block->hash_link->diskpos == filepos)));
2070
2315
*page_st=page_status;
2316
KEYCACHE_DBUG_PRINT("find_key_block",
2317
("fd: %d pos: %lu block->status: %u page_status: %d",
2318
file, (ulong) filepos, block->status,
2321
#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
2322
DBUG_EXECUTE("check_keycache2",
2323
test_key_cache(keycache, "end of find_key_block",0););
2325
KEYCACHE_THREAD_TRACE("find_key_block:end");
2113
2368
request for the block become secondary requests. For a primary
2114
2369
request the block must be properly initialized.
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));
2371
DBUG_ASSERT(((block->status & ~BLOCK_FOR_UPDATE) == BLOCK_IN_USE) ||
2373
DBUG_ASSERT((block->length == 0) || fail_block(block));
2374
DBUG_ASSERT((block->offset == keycache->key_cache_block_size) ||
2376
DBUG_ASSERT((block->requests > 0) || fail_block(block));
2378
KEYCACHE_DBUG_PRINT("read_block",
2379
("page to be read by primary request"));
2121
2381
keycache->global_cache_read++;
2122
2382
/* Page is not in buffer yet, is to be read from disk */
2191
2459
The function ensures that a block of data of size length from file
2192
2460
positioned at filepos is in the buffers for some key cache blocks.
2193
2461
Then the function either copies the data into the buffer buff, or,
2194
if return_buffer is true, it just returns the pointer to the key cache
2462
if return_buffer is TRUE, it just returns the pointer to the key cache
2195
2463
buffer with the data.
2196
2464
Filepos must be a multiple of 'block_length', but it doesn't
2197
2465
have to be a multiple of key_cache_block_size;
2200
unsigned char *key_cache_read(KEY_CACHE *keycache,
2468
uchar *key_cache_read(KEY_CACHE *keycache,
2201
2469
File file, my_off_t filepos, int level,
2202
unsigned char *buff, uint32_t length,
2203
uint32_t block_length __attribute__((unused)),
2470
uchar *buff, uint length,
2471
uint block_length __attribute__((unused)),
2204
2472
int return_buffer __attribute__((unused)))
2206
bool locked_and_incremented= false;
2474
my_bool locked_and_incremented= FALSE;
2208
unsigned char *start= buff;
2477
DBUG_ENTER("key_cache_read");
2478
DBUG_PRINT("enter", ("fd: %u pos: %lu length: %u",
2479
(uint) file, (ulong) filepos, length));
2210
2481
if (keycache->key_cache_inited)
2212
2483
/* Key cache is used */
2213
2484
register BLOCK_LINK *block;
2214
uint32_t read_length;
2281
2552
/* The requested page is to be read into the block buffer */
2282
2553
read_block(keycache, block,
2283
2554
keycache->key_cache_block_size, read_length+offset,
2284
(bool)(page_st == PAGE_TO_BE_READ));
2555
(my_bool)(page_st == PAGE_TO_BE_READ));
2286
2557
A secondary request must now have the block assigned to the
2287
2558
requested file block. It does not hurt to check it for
2288
2559
primary requests too.
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));
2561
DBUG_ASSERT(keycache->can_be_used);
2562
DBUG_ASSERT(block->hash_link->file == file);
2563
DBUG_ASSERT(block->hash_link->diskpos == filepos);
2564
DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
2295
2566
else if (block->length < read_length + offset)
2308
2579
if (!((status= block->status) & BLOCK_ERROR))
2311
assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
2582
DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
2312
2583
#if !defined(SERIALIZED_READ_FROM_CACHE)
2313
2584
keycache_pthread_mutex_unlock(&keycache->cache_lock);
2316
2587
/* Copy data from the cache buffer */
2317
memcpy(buff, block->buffer+offset, (size_t) read_length);
2588
if (!(read_length & 511))
2589
bmove512(buff, block->buffer+offset, read_length);
2591
memcpy(buff, block->buffer+offset, (size_t) read_length);
2319
2593
#if !defined(SERIALIZED_READ_FROM_CACHE)
2320
2594
keycache_pthread_mutex_lock(&keycache->cache_lock);
2321
assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
2595
DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
2392
2666
int key_cache_insert(KEY_CACHE *keycache,
2393
2667
File file, my_off_t filepos, int level,
2394
unsigned char *buff, uint32_t length)
2668
uchar *buff, uint length)
2671
DBUG_ENTER("key_cache_insert");
2672
DBUG_PRINT("enter", ("fd: %u pos: %lu length: %u",
2673
(uint) file,(ulong) filepos, length));
2398
2675
if (keycache->key_cache_inited)
2400
2677
/* Key cache is used */
2401
2678
register BLOCK_LINK *block;
2402
uint32_t read_length;
2405
bool locked_and_incremented= false;
2682
my_bool locked_and_incremented= FALSE;
2408
2685
When the keycache is once initialized, we use the cache_lock to
2616
2898
The function copies the data of size length from buff into buffers
2617
2899
for key cache blocks that are assigned to contain the portion of
2618
2900
the file starting with position filepos.
2619
It ensures that this data is flushed to the file if dont_write is false.
2901
It ensures that this data is flushed to the file if dont_write is FALSE.
2620
2902
Filepos must be a multiple of 'block_length', but it doesn't
2621
2903
have to be a multiple of key_cache_block_size;
2623
dont_write is always true in the server (info->lock_type is never F_UNLCK).
2905
dont_write is always TRUE in the server (info->lock_type is never F_UNLCK).
2626
2908
int key_cache_write(KEY_CACHE *keycache,
2627
2909
File file, my_off_t filepos, int level,
2628
unsigned char *buff, uint32_t length,
2629
uint32_t block_length __attribute__((unused)),
2910
uchar *buff, uint length,
2911
uint block_length __attribute__((unused)),
2630
2912
int dont_write)
2632
bool locked_and_incremented= false;
2914
my_bool locked_and_incremented= FALSE;
2916
DBUG_ENTER("key_cache_write");
2918
("fd: %u pos: %lu length: %u block_length: %u"
2919
" key_block_length: %u",
2920
(uint) file, (ulong) filepos, length, block_length,
2921
keycache ? keycache->key_cache_block_size : 0));
2635
2923
if (!dont_write)
2925
3229
is registered in the hash_link and free_block() will wait for it
2928
assert((block->status & BLOCK_IN_USE) &&
3232
DBUG_ASSERT((block->status & BLOCK_IN_USE) &&
2929
3233
!(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH |
2930
3234
BLOCK_REASSIGNED | BLOCK_IN_FLUSH |
2931
3235
BLOCK_CHANGED | BLOCK_FOR_UPDATE)));
2932
3236
/* Assert that the block is in a file_blocks chain. */
2933
assert(block->prev_changed && *block->prev_changed == block);
3237
DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
2934
3238
/* Assert that the block is not in the LRU ring. */
2935
assert(!block->next_used && !block->prev_used);
3239
DBUG_ASSERT(!block->next_used && !block->prev_used);
2937
3241
IMHO the below condition (if()) makes no sense. I can't see how it
2938
3242
could be possible that free_block() is entered with a NULL hash_link
2939
3243
pointer. The only place where it can become NULL is in free_block()
2940
3244
(or before its first use ever, but for those blocks free_block() is
2941
3245
not called). I don't remove the conditional as it cannot harm, but
2942
place an assert to confirm my hypothesis. Eventually the
3246
place an DBUG_ASSERT to confirm my hypothesis. Eventually the
2943
3247
condition (if()) can be removed.
2945
assert(block->hash_link && block->hash_link->block == block);
3249
DBUG_ASSERT(block->hash_link && block->hash_link->block == block);
2946
3250
if (block->hash_link)
3758
4106
int reset_key_cache_counters(const char *name __attribute__((unused)),
3759
4107
KEY_CACHE *key_cache)
4109
DBUG_ENTER("reset_key_cache_counters");
3761
4110
if (!key_cache->key_cache_inited)
4112
DBUG_PRINT("info", ("Key cache %s not initialized.", name));
4115
DBUG_PRINT("info", ("Resetting counters for key cache %s.", name));
3765
4117
key_cache->global_blocks_changed= 0; /* Key_blocks_not_flushed */
3766
4118
key_cache->global_cache_r_requests= 0; /* Key_read_requests */
3767
4119
key_cache->global_cache_read= 0; /* Key_reads */
3768
4120
key_cache->global_cache_w_requests= 0; /* Key_write_requests */
3769
4121
key_cache->global_cache_write= 0; /* Key_writes */
4128
Test if disk-cache is ok
4130
static void test_key_cache(KEY_CACHE *keycache __attribute__((unused)),
4131
const char *where __attribute__((unused)),
4132
my_bool lock __attribute__((unused)))
3773
4138
#if defined(KEYCACHE_TIMEOUT)
3884
4257
1 nanosecond = 1000 micro seconds
3886
4259
timeout.tv_nsec= now.tv_usec * 1000;
4260
KEYCACHE_THREAD_TRACE_END("started waiting");
4261
#if defined(KEYCACHE_DEBUG)
4264
fprintf(keycache_debug_log, "waiting...\n");
4265
fflush(keycache_debug_log);
3887
4267
rc= pthread_cond_timedwait(cond, mutex, &timeout);
4268
KEYCACHE_THREAD_TRACE_BEGIN("finished waiting");
3888
4269
if (rc == ETIMEDOUT || rc == ETIME)
4271
#if defined(KEYCACHE_DEBUG)
4272
fprintf(keycache_debug_log,"aborted by keycache timeout\n");
4273
fclose(keycache_debug_log);
3890
4276
keycache_dump();
4279
#if defined(KEYCACHE_DEBUG)
4280
KEYCACHE_DBUG_ASSERT(rc != ETIMEDOUT);
3893
4282
assert(rc != ETIMEDOUT);
4287
#if defined(KEYCACHE_DEBUG)
4288
static int keycache_pthread_cond_wait(pthread_cond_t *cond,
4289
pthread_mutex_t *mutex)
4292
KEYCACHE_THREAD_TRACE_END("started waiting");
4293
rc= pthread_cond_wait(cond, mutex);
4294
KEYCACHE_THREAD_TRACE_BEGIN("finished waiting");
3896
4298
#endif /* defined(KEYCACHE_TIMEOUT) */
4300
#if defined(KEYCACHE_DEBUG)
4303
static int keycache_pthread_mutex_lock(pthread_mutex_t *mutex)
4306
rc= pthread_mutex_lock(mutex);
4307
KEYCACHE_THREAD_TRACE_BEGIN("");
4312
static void keycache_pthread_mutex_unlock(pthread_mutex_t *mutex)
4314
KEYCACHE_THREAD_TRACE_END("");
4315
pthread_mutex_unlock(mutex);
4319
static int keycache_pthread_cond_signal(pthread_cond_t *cond)
4322
KEYCACHE_THREAD_TRACE("signal");
4323
rc= pthread_cond_signal(cond);
4328
#if defined(KEYCACHE_DEBUG_LOG)
4331
static void keycache_debug_print(const char * fmt,...)
4335
if (keycache_debug_log)
4337
VOID(vfprintf(keycache_debug_log, fmt, args));
4338
VOID(fputc('\n',keycache_debug_log));
4342
#endif /* defined(KEYCACHE_DEBUG_LOG) */
4344
#if defined(KEYCACHE_DEBUG_LOG)
4347
void keycache_debug_log_close(void)
4349
if (keycache_debug_log)
4350
fclose(keycache_debug_log);
4352
#endif /* defined(KEYCACHE_DEBUG_LOG) */
4354
#endif /* defined(KEYCACHE_DEBUG) */
4356
#if !defined(DBUG_OFF)
4357
#define F_B_PRT(_f_, _v_) DBUG_PRINT("assert_fail", (_f_, _v_))
4359
static int fail_block(BLOCK_LINK *block)
4361
F_B_PRT("block->next_used: %lx\n", (ulong) block->next_used);
4362
F_B_PRT("block->prev_used: %lx\n", (ulong) block->prev_used);
4363
F_B_PRT("block->next_changed: %lx\n", (ulong) block->next_changed);
4364
F_B_PRT("block->prev_changed: %lx\n", (ulong) block->prev_changed);
4365
F_B_PRT("block->hash_link: %lx\n", (ulong) block->hash_link);
4366
F_B_PRT("block->status: %u\n", block->status);
4367
F_B_PRT("block->length: %u\n", block->length);
4368
F_B_PRT("block->offset: %u\n", block->offset);
4369
F_B_PRT("block->requests: %u\n", block->requests);
4370
F_B_PRT("block->temperature: %u\n", block->temperature);
4371
return 0; /* Let the assert fail. */
4374
static int fail_hlink(HASH_LINK *hlink)
4376
F_B_PRT("hlink->next: %lx\n", (ulong) hlink->next);
4377
F_B_PRT("hlink->prev: %lx\n", (ulong) hlink->prev);
4378
F_B_PRT("hlink->block: %lx\n", (ulong) hlink->block);
4379
F_B_PRT("hlink->diskpos: %lu\n", (ulong) hlink->diskpos);
4380
F_B_PRT("hlink->file: %d\n", hlink->file);
4381
return 0; /* Let the assert fail. */
4384
static int cache_empty(KEY_CACHE *keycache)
4388
if (keycache->disk_blocks <= 0)
4390
for (idx= 0; idx < keycache->disk_blocks; idx++)
4392
BLOCK_LINK *block= keycache->block_root + idx;
4393
if (block->status || block->requests || block->hash_link)
4395
fprintf(stderr, "block index: %u\n", idx);
4400
for (idx= 0; idx < keycache->hash_links; idx++)
4402
HASH_LINK *hash_link= keycache->hash_link_root + idx;
4403
if (hash_link->requests || hash_link->block)
4405
fprintf(stderr, "hash_link index: %u\n", idx);
4406
fail_hlink(hash_link);
4412
fprintf(stderr, "blocks: %d used: %lu\n",
4413
keycache->disk_blocks, keycache->blocks_used);
4414
fprintf(stderr, "hash_links: %d used: %d\n",
4415
keycache->hash_links, keycache->hash_links_used);
4416
fprintf(stderr, "\n");