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 */
210
221
#define FLUSH_CACHE 2000 /* sort this many blocks at once */
212
223
static int flush_all_key_blocks(KEY_CACHE *keycache);
213
225
static void wait_on_queue(KEYCACHE_WQUEUE *wqueue,
214
226
pthread_mutex_t *mutex);
215
227
static void release_whole_queue(KEYCACHE_WQUEUE *wqueue);
229
#define wait_on_queue(wqueue, mutex) do {} while (0)
230
#define release_whole_queue(wqueue) do {} while (0)
216
232
static void free_block(KEY_CACHE *keycache, BLOCK_LINK *block);
233
#if !defined(DBUG_OFF)
234
static void test_key_cache(KEY_CACHE *keycache,
235
const char *where, my_bool lock);
218
238
#define KEYCACHE_HASH(f, pos) \
219
(((uint32_t) ((pos) / keycache->key_cache_block_size) + \
220
(uint32_t) (f)) & (keycache->hash_entries-1))
239
(((ulong) ((pos) / keycache->key_cache_block_size) + \
240
(ulong) (f)) & (keycache->hash_entries-1))
221
241
#define FILE_HASH(f) ((uint) (f) & (CHANGED_BLOCKS_HASH-1))
243
#define DEFAULT_KEYCACHE_DEBUG_LOG "keycache_debug.log"
245
#if defined(KEYCACHE_DEBUG) && ! defined(KEYCACHE_DEBUG_LOG)
246
#define KEYCACHE_DEBUG_LOG DEFAULT_KEYCACHE_DEBUG_LOG
249
#if defined(KEYCACHE_DEBUG_LOG)
250
static FILE *keycache_debug_log=NULL;
251
static void keycache_debug_print _VARARGS((const char *fmt,...));
252
#define KEYCACHE_DEBUG_OPEN \
253
if (!keycache_debug_log) \
255
keycache_debug_log= fopen(KEYCACHE_DEBUG_LOG, "w"); \
256
(void) setvbuf(keycache_debug_log, NULL, _IOLBF, BUFSIZ); \
259
#define KEYCACHE_DEBUG_CLOSE \
260
if (keycache_debug_log) \
262
fclose(keycache_debug_log); \
263
keycache_debug_log= 0; \
266
#define KEYCACHE_DEBUG_OPEN
267
#define KEYCACHE_DEBUG_CLOSE
268
#endif /* defined(KEYCACHE_DEBUG_LOG) */
270
#if defined(KEYCACHE_DEBUG_LOG) && defined(KEYCACHE_DEBUG)
271
#define KEYCACHE_DBUG_PRINT(l, m) \
272
{ if (keycache_debug_log) fprintf(keycache_debug_log, "%s: ", l); \
273
keycache_debug_print m; }
275
#define KEYCACHE_DBUG_ASSERT(a) \
276
{ if (! (a) && keycache_debug_log) fclose(keycache_debug_log); \
279
#define KEYCACHE_DBUG_PRINT(l, m) DBUG_PRINT(l, m)
280
#define KEYCACHE_DBUG_ASSERT(a) DBUG_ASSERT(a)
281
#endif /* defined(KEYCACHE_DEBUG_LOG) && defined(KEYCACHE_DEBUG) */
283
#if defined(KEYCACHE_DEBUG) || !defined(DBUG_OFF)
285
static long keycache_thread_id;
286
#define KEYCACHE_THREAD_TRACE(l) \
287
KEYCACHE_DBUG_PRINT(l,("|thread %ld",keycache_thread_id))
289
#define KEYCACHE_THREAD_TRACE_BEGIN(l) \
290
{ struct st_my_thread_var *thread_var= my_thread_var; \
291
keycache_thread_id= thread_var->id; \
292
KEYCACHE_DBUG_PRINT(l,("[thread %ld",keycache_thread_id)) }
294
#define KEYCACHE_THREAD_TRACE_END(l) \
295
KEYCACHE_DBUG_PRINT(l,("]thread %ld",keycache_thread_id))
297
#define KEYCACHE_THREAD_TRACE(l) KEYCACHE_DBUG_PRINT(l,(""))
298
#define KEYCACHE_THREAD_TRACE_BEGIN(l) KEYCACHE_DBUG_PRINT(l,(""))
299
#define KEYCACHE_THREAD_TRACE_END(l) KEYCACHE_DBUG_PRINT(l,(""))
302
#define KEYCACHE_THREAD_TRACE_BEGIN(l)
303
#define KEYCACHE_THREAD_TRACE_END(l)
304
#define KEYCACHE_THREAD_TRACE(l)
305
#endif /* defined(KEYCACHE_DEBUG) || !defined(DBUG_OFF) */
223
307
#define BLOCK_NUMBER(b) \
224
308
((uint) (((char*)(b)-(char *) keycache->block_root)/sizeof(BLOCK_LINK)))
225
309
#define HASH_LINK_NUMBER(h) \
226
310
((uint) (((char*)(h)-(char *) keycache->hash_link_root)/sizeof(HASH_LINK)))
228
#ifdef KEYCACHE_TIMEOUT
312
#if (defined(KEYCACHE_TIMEOUT)) || defined(KEYCACHE_DEBUG)
229
313
static int keycache_pthread_cond_wait(pthread_cond_t *cond,
230
314
pthread_mutex_t *mutex);
232
316
#define keycache_pthread_cond_wait pthread_cond_wait
319
#if defined(KEYCACHE_DEBUG)
320
static int keycache_pthread_mutex_lock(pthread_mutex_t *mutex);
321
static void keycache_pthread_mutex_unlock(pthread_mutex_t *mutex);
322
static int keycache_pthread_cond_signal(pthread_cond_t *cond);
235
324
#define keycache_pthread_mutex_lock pthread_mutex_lock
236
325
#define keycache_pthread_mutex_unlock pthread_mutex_unlock
237
326
#define keycache_pthread_cond_signal pthread_cond_signal
239
static inline uint32_t next_power(uint32_t value)
327
#endif /* defined(KEYCACHE_DEBUG) */
329
#if !defined(DBUG_OFF)
333
#define inline /* disabled inline for easier debugging */
334
static int fail_block(BLOCK_LINK *block);
335
static int fail_hlink(HASH_LINK *hlink);
336
static int cache_empty(KEY_CACHE *keycache);
339
static inline uint next_power(uint value)
241
return (uint) my_round_up_to_next_power((uint32_t) value) << 1;
341
return (uint) my_round_up_to_next_power((uint32) value) << 1;
270
int init_key_cache(KEY_CACHE *keycache, uint32_t key_cache_block_size,
271
size_t use_mem, uint32_t division_limit,
272
uint32_t age_threshold)
370
int init_key_cache(KEY_CACHE *keycache, uint key_cache_block_size,
371
size_t use_mem, uint division_limit,
274
uint32_t blocks, hash_links;
374
ulong blocks, hash_links;
277
assert(key_cache_block_size >= 512);
377
DBUG_ENTER("init_key_cache");
378
DBUG_ASSERT(key_cache_block_size >= 512);
279
381
if (keycache->key_cache_inited && keycache->disk_blocks > 0)
383
DBUG_PRINT("warning",("key cache already in use"));
284
387
keycache->global_cache_w_requests= keycache->global_cache_r_requests= 0;
353
458
keycache->hash_link_root= (HASH_LINK*) ((char*) keycache->hash_root +
354
459
ALIGN_SIZE((sizeof(HASH_LINK*) *
355
460
keycache->hash_entries)));
356
memset(keycache->block_root, 0,
357
keycache->disk_blocks * sizeof(BLOCK_LINK));
358
memset(keycache->hash_root, 0,
359
keycache->hash_entries * sizeof(HASH_LINK*));
360
memset(keycache->hash_link_root, 0,
361
keycache->hash_links * sizeof(HASH_LINK));
461
bzero((uchar*) keycache->block_root,
462
keycache->disk_blocks * sizeof(BLOCK_LINK));
463
bzero((uchar*) keycache->hash_root,
464
keycache->hash_entries * sizeof(HASH_LINK*));
465
bzero((uchar*) keycache->hash_link_root,
466
keycache->hash_links * sizeof(HASH_LINK));
362
467
keycache->hash_links_used= 0;
363
468
keycache->free_hash_list= NULL;
364
469
keycache->blocks_used= keycache->blocks_changed= 0;
384
489
keycache->waiting_for_hash_link.last_thread= NULL;
385
490
keycache->waiting_for_block.last_thread= NULL;
386
memset(keycache->changed_blocks, 0,
387
sizeof(keycache->changed_blocks[0]) * CHANGED_BLOCKS_HASH);
388
memset(keycache->file_blocks, 0,
389
sizeof(keycache->file_blocks[0]) * CHANGED_BLOCKS_HASH);
492
("disk_blocks: %d block_root: 0x%lx hash_entries: %d\
493
hash_root: 0x%lx hash_links: %d hash_link_root: 0x%lx",
494
keycache->disk_blocks, (long) keycache->block_root,
495
keycache->hash_entries, (long) keycache->hash_root,
496
keycache->hash_links, (long) keycache->hash_link_root));
497
bzero((uchar*) keycache->changed_blocks,
498
sizeof(keycache->changed_blocks[0]) * CHANGED_BLOCKS_HASH);
499
bzero((uchar*) keycache->file_blocks,
500
sizeof(keycache->file_blocks[0]) * CHANGED_BLOCKS_HASH);
446
557
(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)
560
int resize_key_cache(KEY_CACHE *keycache, uint key_cache_block_size,
561
size_t use_mem, uint division_limit,
565
DBUG_ENTER("resize_key_cache");
455
567
if (!keycache->key_cache_inited)
456
return(keycache->disk_blocks);
568
DBUG_RETURN(keycache->disk_blocks);
458
570
if(key_cache_block_size == keycache->key_cache_block_size &&
459
571
use_mem == keycache->key_cache_mem_size)
461
573
change_key_cache_param(keycache, division_limit, age_threshold);
462
return(keycache->disk_blocks);
574
DBUG_RETURN(keycache->disk_blocks);
465
577
keycache_pthread_mutex_lock(&keycache->cache_lock);
468
581
We may need to wait for another thread which is doing a resize
469
582
already. This cannot happen in the MySQL server though. It allows
955
1110
not linked in the LRU ring.
958
static void link_block(KEY_CACHE *keycache, BLOCK_LINK *block, bool hot,
1113
static void link_block(KEY_CACHE *keycache, BLOCK_LINK *block, my_bool hot,
961
1116
BLOCK_LINK *ins;
962
1117
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);
1119
DBUG_ASSERT((block->status & ~BLOCK_CHANGED) == (BLOCK_READ | BLOCK_IN_USE));
1120
DBUG_ASSERT(block->hash_link); /*backptr to block NULL from free_block()*/
1121
DBUG_ASSERT(!block->requests);
1122
DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
1123
DBUG_ASSERT(!block->next_used);
1124
DBUG_ASSERT(!block->prev_used);
970
1126
if (!hot && keycache->waiting_for_block.last_thread)
972
1128
/* Signal that in the LRU warm sub-chain an available block has appeared */
1200
1398
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);
1400
DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
1401
DBUG_ASSERT(block->hash_link && block->hash_link->block == block);
1402
DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
1403
DBUG_ASSERT(!block->next_used);
1404
DBUG_ASSERT(!block->prev_used);
1405
DBUG_ASSERT(block->hash_link->requests);
1208
1407
if (! --block->hash_link->requests && block->condvar)
1209
1408
keycache_pthread_cond_signal(block->condvar);
1410
--block->hash_link->requests;
1218
1420
static void wait_for_readers(KEY_CACHE *keycache,
1219
1421
BLOCK_LINK *block)
1221
1424
struct st_my_thread_var *thread= my_thread_var;
1222
assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
1223
assert(!(block->status & (BLOCK_ERROR | BLOCK_IN_FLUSH |
1425
DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
1426
DBUG_ASSERT(!(block->status & (BLOCK_ERROR | BLOCK_IN_FLUSH |
1224
1427
BLOCK_CHANGED)));
1225
assert(block->hash_link);
1226
assert(block->hash_link->block == block);
1428
DBUG_ASSERT(block->hash_link);
1429
DBUG_ASSERT(block->hash_link->block == block);
1227
1430
/* Linked in file_blocks or changed_blocks hash. */
1228
assert(block->prev_changed && *block->prev_changed == block);
1431
DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
1229
1432
/* Not linked in LRU ring. */
1230
assert(!block->next_used);
1231
assert(!block->prev_used);
1433
DBUG_ASSERT(!block->next_used);
1434
DBUG_ASSERT(!block->prev_used);
1232
1435
while (block->hash_link->requests)
1437
KEYCACHE_DBUG_PRINT("wait_for_readers: wait",
1438
("suspend thread %ld block %u",
1439
thread->id, BLOCK_NUMBER(block)));
1234
1440
/* There must be no other waiter. We have no queue here. */
1235
assert(!block->condvar);
1441
DBUG_ASSERT(!block->condvar);
1236
1442
block->condvar= &thread->suspend;
1237
1443
keycache_pthread_cond_wait(&thread->suspend, &keycache->cache_lock);
1238
1444
block->condvar= NULL;
1447
KEYCACHE_DBUG_ASSERT(block->hash_link->requests == 0);
1319
1541
hash_link points to the first member of the list
1321
1543
hash_link= *(start= &keycache->hash_root[KEYCACHE_HASH(file, filepos)]);
1544
#if defined(KEYCACHE_DEBUG)
1322
1547
/* Look for an element for the pair (file, filepos) in the bucket chain */
1323
1548
while (hash_link &&
1324
1549
(hash_link->diskpos != filepos || hash_link->file != file))
1326
1551
hash_link= hash_link->next;
1552
#if defined(KEYCACHE_DEBUG)
1554
if (! (cnt <= keycache->hash_links_used))
1557
for (i=0, hash_link= *start ;
1558
i < cnt ; i++, hash_link= hash_link->next)
1560
KEYCACHE_DBUG_PRINT("get_hash_link", ("fd: %u pos: %lu",
1561
(uint) hash_link->file,(ulong) hash_link->diskpos));
1564
KEYCACHE_DBUG_ASSERT(cnt <= keycache->hash_links_used);
1328
1567
if (! hash_link)
1409
1655
int page_status;
1657
DBUG_ENTER("find_key_block");
1658
KEYCACHE_THREAD_TRACE("find_key_block:begin");
1659
DBUG_PRINT("enter", ("fd: %d pos: %lu wrmode: %d",
1660
file, (ulong) filepos, wrmode));
1661
KEYCACHE_DBUG_PRINT("find_key_block", ("fd: %d pos: %lu wrmode: %d",
1662
file, (ulong) filepos,
1664
#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
1665
DBUG_EXECUTE("check_keycache2",
1666
test_key_cache(keycache, "start of find_key_block", 0););
1413
1671
If the flush phase of a resize operation fails, the cache is left
1414
1672
unusable. This will be detected only after "goto restart".
1416
1674
if (!keycache->can_be_used)
1420
1678
Find the hash_link for the requested file block (file, filepos). We
1775
2045
/* There are some never used blocks, take first of them */
1776
assert(keycache->blocks_used <
1777
(uint32_t) keycache->disk_blocks);
2046
DBUG_ASSERT(keycache->blocks_used <
2047
(ulong) keycache->disk_blocks);
1778
2048
block= &keycache->block_root[keycache->blocks_used];
1779
2049
block->buffer= ADD_TO_PTR(keycache->block_mem,
1780
((uint32_t) keycache->blocks_used*
2050
((ulong) keycache->blocks_used*
1781
2051
keycache->key_cache_block_size),
1783
2053
keycache->blocks_used++;
1784
assert(!block->next_used);
2054
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);
2056
DBUG_ASSERT(!block->prev_used);
2057
DBUG_ASSERT(!block->next_changed);
2058
DBUG_ASSERT(!block->prev_changed);
2059
DBUG_ASSERT(!block->hash_link);
2060
DBUG_ASSERT(!block->status);
2061
DBUG_ASSERT(!block->requests);
1792
2062
keycache->blocks_unused--;
1793
2063
block->status= BLOCK_IN_USE;
1794
2064
block->length= 0;
1828
2102
link_into_queue(&keycache->waiting_for_block, thread);
2105
KEYCACHE_DBUG_PRINT("find_key_block: wait",
2106
("suspend thread %ld", thread->id));
1831
2107
keycache_pthread_cond_wait(&thread->suspend,
1832
2108
&keycache->cache_lock);
1834
2110
while (thread->next);
1835
2111
thread->opt_info= NULL;
1836
2112
/* Assert that block has a request registered. */
1837
assert(hash_link->block->requests);
2113
DBUG_ASSERT(hash_link->block->requests);
1838
2114
/* Assert that block is not in LRU ring. */
1839
assert(!hash_link->block->next_used);
1840
assert(!hash_link->block->prev_used);
2115
DBUG_ASSERT(!hash_link->block->next_used);
2116
DBUG_ASSERT(!hash_link->block->prev_used);
2119
KEYCACHE_DBUG_ASSERT(keycache->used_last);
1843
2122
If we waited above, hash_link->block has been assigned by
1844
2123
link_block(). Otherwise it is still NULL. In the latter case
2043
2330
Register a request on the block. This is another protection
2044
2331
against eviction.
2046
assert(((block->hash_link != hash_link) &&
2333
DBUG_ASSERT(((block->hash_link != hash_link) &&
2047
2334
(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH))) ||
2048
2335
((block->hash_link == hash_link) &&
2049
2336
!(block->status & BLOCK_READ)) ||
2050
2337
((block->status & BLOCK_READ) &&
2051
2338
!(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH))));
2052
2339
reg_requests(keycache, block, 1);
2340
KEYCACHE_DBUG_PRINT("find_key_block",
2341
("block->hash_link: %p hash_link: %p "
2342
"block->status: %u", block->hash_link,
2343
hash_link, block->status ));
2053
2344
page_status= (((block->hash_link == hash_link) &&
2054
2345
(block->status & BLOCK_READ)) ?
2055
2346
PAGE_READ : PAGE_WAIT_TO_BE_READ);
2059
assert(page_status != -1);
2350
KEYCACHE_DBUG_ASSERT(page_status != -1);
2060
2351
/* Same assert basically, but be very sure. */
2352
KEYCACHE_DBUG_ASSERT(block);
2062
2353
/* Assert that block has a request and is not in LRU ring. */
2063
assert(block->requests);
2064
assert(!block->next_used);
2065
assert(!block->prev_used);
2354
DBUG_ASSERT(block->requests);
2355
DBUG_ASSERT(!block->next_used);
2356
DBUG_ASSERT(!block->prev_used);
2066
2357
/* Assert that we return the correct block. */
2067
assert((page_status == PAGE_WAIT_TO_BE_READ) ||
2358
DBUG_ASSERT((page_status == PAGE_WAIT_TO_BE_READ) ||
2068
2359
((block->hash_link->file == file) &&
2069
2360
(block->hash_link->diskpos == filepos)));
2070
2361
*page_st=page_status;
2362
KEYCACHE_DBUG_PRINT("find_key_block",
2363
("fd: %d pos: %lu block->status: %u page_status: %d",
2364
file, (ulong) filepos, block->status,
2367
#if !defined(DBUG_OFF) && defined(EXTRA_DEBUG)
2368
DBUG_EXECUTE("check_keycache2",
2369
test_key_cache(keycache, "end of find_key_block",0););
2371
KEYCACHE_THREAD_TRACE("find_key_block:end");
2113
2414
request for the block become secondary requests. For a primary
2114
2415
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));
2417
DBUG_ASSERT(((block->status & ~BLOCK_FOR_UPDATE) == BLOCK_IN_USE) ||
2419
DBUG_ASSERT((block->length == 0) || fail_block(block));
2420
DBUG_ASSERT((block->offset == keycache->key_cache_block_size) ||
2422
DBUG_ASSERT((block->requests > 0) || fail_block(block));
2424
KEYCACHE_DBUG_PRINT("read_block",
2425
("page to be read by primary request"));
2121
2427
keycache->global_cache_read++;
2122
2428
/* Page is not in buffer yet, is to be read from disk */
2191
2505
The function ensures that a block of data of size length from file
2192
2506
positioned at filepos is in the buffers for some key cache blocks.
2193
2507
Then the function either copies the data into the buffer buff, or,
2194
if return_buffer is true, it just returns the pointer to the key cache
2508
if return_buffer is TRUE, it just returns the pointer to the key cache
2195
2509
buffer with the data.
2196
2510
Filepos must be a multiple of 'block_length', but it doesn't
2197
2511
have to be a multiple of key_cache_block_size;
2200
unsigned char *key_cache_read(KEY_CACHE *keycache,
2514
uchar *key_cache_read(KEY_CACHE *keycache,
2201
2515
File file, my_off_t filepos, int level,
2202
unsigned char *buff, uint32_t length,
2203
uint32_t block_length __attribute__((unused)),
2516
uchar *buff, uint length,
2517
uint block_length __attribute__((unused)),
2204
2518
int return_buffer __attribute__((unused)))
2206
bool locked_and_incremented= false;
2520
my_bool locked_and_incremented= FALSE;
2208
unsigned char *start= buff;
2523
DBUG_ENTER("key_cache_read");
2524
DBUG_PRINT("enter", ("fd: %u pos: %lu length: %u",
2525
(uint) file, (ulong) filepos, length));
2210
2527
if (keycache->key_cache_inited)
2212
2529
/* Key cache is used */
2213
2530
register BLOCK_LINK *block;
2214
uint32_t read_length;
2281
2603
/* The requested page is to be read into the block buffer */
2282
2604
read_block(keycache, block,
2283
2605
keycache->key_cache_block_size, read_length+offset,
2284
(bool)(page_st == PAGE_TO_BE_READ));
2606
(my_bool)(page_st == PAGE_TO_BE_READ));
2286
2608
A secondary request must now have the block assigned to the
2287
2609
requested file block. It does not hurt to check it for
2288
2610
primary requests too.
2290
assert(keycache->can_be_used);
2291
assert(block->hash_link->file == file);
2292
assert(block->hash_link->diskpos == filepos);
2293
assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
2612
DBUG_ASSERT(keycache->can_be_used);
2613
DBUG_ASSERT(block->hash_link->file == file);
2614
DBUG_ASSERT(block->hash_link->diskpos == filepos);
2615
DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
2295
2617
else if (block->length < read_length + offset)
2307
2629
/* block status may have added BLOCK_ERROR in the above 'if'. */
2308
2630
if (!((status= block->status) & BLOCK_ERROR))
2633
if (! return_buffer)
2311
assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
2636
DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
2312
2637
#if !defined(SERIALIZED_READ_FROM_CACHE)
2313
2638
keycache_pthread_mutex_unlock(&keycache->cache_lock);
2316
2641
/* Copy data from the cache buffer */
2317
memcpy(buff, block->buffer+offset, (size_t) read_length);
2642
if (!(read_length & 511))
2643
bmove512(buff, block->buffer+offset, read_length);
2645
memcpy(buff, block->buffer+offset, (size_t) read_length);
2319
2647
#if !defined(SERIALIZED_READ_FROM_CACHE)
2320
2648
keycache_pthread_mutex_lock(&keycache->cache_lock);
2321
assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
2649
DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
2392
2725
int key_cache_insert(KEY_CACHE *keycache,
2393
2726
File file, my_off_t filepos, int level,
2394
unsigned char *buff, uint32_t length)
2727
uchar *buff, uint length)
2730
DBUG_ENTER("key_cache_insert");
2731
DBUG_PRINT("enter", ("fd: %u pos: %lu length: %u",
2732
(uint) file,(ulong) filepos, length));
2398
2734
if (keycache->key_cache_inited)
2400
2736
/* Key cache is used */
2401
2737
register BLOCK_LINK *block;
2402
uint32_t read_length;
2405
bool locked_and_incremented= false;
2741
my_bool locked_and_incremented= FALSE;
2408
2744
When the keycache is once initialized, we use the cache_lock to
2616
2957
The function copies the data of size length from buff into buffers
2617
2958
for key cache blocks that are assigned to contain the portion of
2618
2959
the file starting with position filepos.
2619
It ensures that this data is flushed to the file if dont_write is false.
2960
It ensures that this data is flushed to the file if dont_write is FALSE.
2620
2961
Filepos must be a multiple of 'block_length', but it doesn't
2621
2962
have to be a multiple of key_cache_block_size;
2623
dont_write is always true in the server (info->lock_type is never F_UNLCK).
2964
dont_write is always TRUE in the server (info->lock_type is never F_UNLCK).
2626
2967
int key_cache_write(KEY_CACHE *keycache,
2627
2968
File file, my_off_t filepos, int level,
2628
unsigned char *buff, uint32_t length,
2629
uint32_t block_length __attribute__((unused)),
2969
uchar *buff, uint length,
2970
uint block_length __attribute__((unused)),
2630
2971
int dont_write)
2632
bool locked_and_incremented= false;
2973
my_bool locked_and_incremented= FALSE;
2975
DBUG_ENTER("key_cache_write");
2977
("fd: %u pos: %lu length: %u block_length: %u"
2978
" key_block_length: %u",
2979
(uint) file, (ulong) filepos, length, block_length,
2980
keycache ? keycache->key_cache_block_size : 0));
2635
2982
if (!dont_write)
2925
3288
is registered in the hash_link and free_block() will wait for it
2928
assert((block->status & BLOCK_IN_USE) &&
3291
DBUG_ASSERT((block->status & BLOCK_IN_USE) &&
2929
3292
!(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH |
2930
3293
BLOCK_REASSIGNED | BLOCK_IN_FLUSH |
2931
3294
BLOCK_CHANGED | BLOCK_FOR_UPDATE)));
2932
3295
/* Assert that the block is in a file_blocks chain. */
2933
assert(block->prev_changed && *block->prev_changed == block);
3296
DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
2934
3297
/* Assert that the block is not in the LRU ring. */
2935
assert(!block->next_used && !block->prev_used);
3298
DBUG_ASSERT(!block->next_used && !block->prev_used);
2937
3300
IMHO the below condition (if()) makes no sense. I can't see how it
2938
3301
could be possible that free_block() is entered with a NULL hash_link
2939
3302
pointer. The only place where it can become NULL is in free_block()
2940
3303
(or before its first use ever, but for those blocks free_block() is
2941
3304
not called). I don't remove the conditional as it cannot harm, but
2942
place an assert to confirm my hypothesis. Eventually the
3305
place an DBUG_ASSERT to confirm my hypothesis. Eventually the
2943
3306
condition (if()) can be removed.
2945
assert(block->hash_link && block->hash_link->block == block);
3308
DBUG_ASSERT(block->hash_link && block->hash_link->block == block);
2946
3309
if (block->hash_link)
3758
4165
int reset_key_cache_counters(const char *name __attribute__((unused)),
3759
4166
KEY_CACHE *key_cache)
4168
DBUG_ENTER("reset_key_cache_counters");
3761
4169
if (!key_cache->key_cache_inited)
4171
DBUG_PRINT("info", ("Key cache %s not initialized.", name));
4174
DBUG_PRINT("info", ("Resetting counters for key cache %s.", name));
3765
4176
key_cache->global_blocks_changed= 0; /* Key_blocks_not_flushed */
3766
4177
key_cache->global_cache_r_requests= 0; /* Key_read_requests */
3767
4178
key_cache->global_cache_read= 0; /* Key_reads */
3768
4179
key_cache->global_cache_w_requests= 0; /* Key_write_requests */
3769
4180
key_cache->global_cache_write= 0; /* Key_writes */
4187
Test if disk-cache is ok
4189
static void test_key_cache(KEY_CACHE *keycache __attribute__((unused)),
4190
const char *where __attribute__((unused)),
4191
my_bool lock __attribute__((unused)))
3773
4197
#if defined(KEYCACHE_TIMEOUT)
3884
4316
1 nanosecond = 1000 micro seconds
3886
4318
timeout.tv_nsec= now.tv_usec * 1000;
4319
KEYCACHE_THREAD_TRACE_END("started waiting");
4320
#if defined(KEYCACHE_DEBUG)
4323
fprintf(keycache_debug_log, "waiting...\n");
4324
fflush(keycache_debug_log);
3887
4326
rc= pthread_cond_timedwait(cond, mutex, &timeout);
4327
KEYCACHE_THREAD_TRACE_BEGIN("finished waiting");
3888
4328
if (rc == ETIMEDOUT || rc == ETIME)
4330
#if defined(KEYCACHE_DEBUG)
4331
fprintf(keycache_debug_log,"aborted by keycache timeout\n");
4332
fclose(keycache_debug_log);
3890
4335
keycache_dump();
4338
#if defined(KEYCACHE_DEBUG)
4339
KEYCACHE_DBUG_ASSERT(rc != ETIMEDOUT);
3893
4341
assert(rc != ETIMEDOUT);
4346
#if defined(KEYCACHE_DEBUG)
4347
static int keycache_pthread_cond_wait(pthread_cond_t *cond,
4348
pthread_mutex_t *mutex)
4351
KEYCACHE_THREAD_TRACE_END("started waiting");
4352
rc= pthread_cond_wait(cond, mutex);
4353
KEYCACHE_THREAD_TRACE_BEGIN("finished waiting");
3896
4357
#endif /* defined(KEYCACHE_TIMEOUT) */
4359
#if defined(KEYCACHE_DEBUG)
4362
static int keycache_pthread_mutex_lock(pthread_mutex_t *mutex)
4365
rc= pthread_mutex_lock(mutex);
4366
KEYCACHE_THREAD_TRACE_BEGIN("");
4371
static void keycache_pthread_mutex_unlock(pthread_mutex_t *mutex)
4373
KEYCACHE_THREAD_TRACE_END("");
4374
pthread_mutex_unlock(mutex);
4378
static int keycache_pthread_cond_signal(pthread_cond_t *cond)
4381
KEYCACHE_THREAD_TRACE("signal");
4382
rc= pthread_cond_signal(cond);
4387
#if defined(KEYCACHE_DEBUG_LOG)
4390
static void keycache_debug_print(const char * fmt,...)
4394
if (keycache_debug_log)
4396
VOID(vfprintf(keycache_debug_log, fmt, args));
4397
VOID(fputc('\n',keycache_debug_log));
4401
#endif /* defined(KEYCACHE_DEBUG_LOG) */
4403
#if defined(KEYCACHE_DEBUG_LOG)
4406
void keycache_debug_log_close(void)
4408
if (keycache_debug_log)
4409
fclose(keycache_debug_log);
4411
#endif /* defined(KEYCACHE_DEBUG_LOG) */
4413
#endif /* defined(KEYCACHE_DEBUG) */
4415
#if !defined(DBUG_OFF)
4416
#define F_B_PRT(_f_, _v_) DBUG_PRINT("assert_fail", (_f_, _v_))
4418
static int fail_block(BLOCK_LINK *block)
4420
F_B_PRT("block->next_used: %lx\n", (ulong) block->next_used);
4421
F_B_PRT("block->prev_used: %lx\n", (ulong) block->prev_used);
4422
F_B_PRT("block->next_changed: %lx\n", (ulong) block->next_changed);
4423
F_B_PRT("block->prev_changed: %lx\n", (ulong) block->prev_changed);
4424
F_B_PRT("block->hash_link: %lx\n", (ulong) block->hash_link);
4425
F_B_PRT("block->status: %u\n", block->status);
4426
F_B_PRT("block->length: %u\n", block->length);
4427
F_B_PRT("block->offset: %u\n", block->offset);
4428
F_B_PRT("block->requests: %u\n", block->requests);
4429
F_B_PRT("block->temperature: %u\n", block->temperature);
4430
return 0; /* Let the assert fail. */
4433
static int fail_hlink(HASH_LINK *hlink)
4435
F_B_PRT("hlink->next: %lx\n", (ulong) hlink->next);
4436
F_B_PRT("hlink->prev: %lx\n", (ulong) hlink->prev);
4437
F_B_PRT("hlink->block: %lx\n", (ulong) hlink->block);
4438
F_B_PRT("hlink->diskpos: %lu\n", (ulong) hlink->diskpos);
4439
F_B_PRT("hlink->file: %d\n", hlink->file);
4440
return 0; /* Let the assert fail. */
4443
static int cache_empty(KEY_CACHE *keycache)
4447
if (keycache->disk_blocks <= 0)
4449
for (idx= 0; idx < keycache->disk_blocks; idx++)
4451
BLOCK_LINK *block= keycache->block_root + idx;
4452
if (block->status || block->requests || block->hash_link)
4454
fprintf(stderr, "block index: %u\n", idx);
4459
for (idx= 0; idx < keycache->hash_links; idx++)
4461
HASH_LINK *hash_link= keycache->hash_link_root + idx;
4462
if (hash_link->requests || hash_link->block)
4464
fprintf(stderr, "hash_link index: %u\n", idx);
4465
fail_hlink(hash_link);
4471
fprintf(stderr, "blocks: %d used: %lu\n",
4472
keycache->disk_blocks, keycache->blocks_used);
4473
fprintf(stderr, "hash_links: %d used: %d\n",
4474
keycache->hash_links, keycache->hash_links_used);
4475
fprintf(stderr, "\n");