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.
143
134
Example of the settings:
144
135
#define SERIALIZED_READ_FROM_CACHE
145
136
#define MAX_THREADS 100
146
137
#define KEYCACHE_TIMEOUT 1
147
#define KEYCACHE_DEBUG
148
#define KEYCACHE_DEBUG_LOG "my_key_cache_debug.log"
151
140
#define STRUCT_PTR(TYPE, MEMBER, a) \
225
214
pthread_mutex_t *mutex);
226
215
static void release_whole_queue(KEYCACHE_WQUEUE *wqueue);
227
216
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);
233
218
#define KEYCACHE_HASH(f, pos) \
234
219
(((ulong) ((pos) / keycache->key_cache_block_size) + \
235
220
(ulong) (f)) & (keycache->hash_entries-1))
236
221
#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) */
296
223
#define BLOCK_NUMBER(b) \
297
224
((uint) (((char*)(b)-(char *) keycache->block_root)/sizeof(BLOCK_LINK)))
298
225
#define HASH_LINK_NUMBER(h) \
299
226
((uint) (((char*)(h)-(char *) keycache->hash_link_root)/sizeof(HASH_LINK)))
301
#if (defined(KEYCACHE_TIMEOUT)) || defined(KEYCACHE_DEBUG)
228
#ifdef KEYCACHE_TIMEOUT
302
229
static int keycache_pthread_cond_wait(pthread_cond_t *cond,
303
230
pthread_mutex_t *mutex);
305
232
#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);
313
235
#define keycache_pthread_mutex_lock pthread_mutex_lock
314
236
#define keycache_pthread_mutex_unlock pthread_mutex_unlock
315
237
#define keycache_pthread_cond_signal pthread_cond_signal
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
239
static inline uint next_power(uint value)
1208
1056
static void unlink_block(KEY_CACHE *keycache, BLOCK_LINK *block)
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 &&
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 &&
1215
1063
(block->next_used->prev_used == &block->next_used) &&
1216
1064
(*block->prev_used == block));
1217
1065
if (block->next_used == block)
1372
1200
static void remove_reader(BLOCK_LINK *block)
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);
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);
1380
1208
if (! --block->hash_link->requests && block->condvar)
1381
1209
keycache_pthread_cond_signal(block->condvar);
1391
1219
BLOCK_LINK *block)
1393
1221
struct st_my_thread_var *thread= my_thread_var;
1394
DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
1395
DBUG_ASSERT(!(block->status & (BLOCK_ERROR | BLOCK_IN_FLUSH |
1222
assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
1223
assert(!(block->status & (BLOCK_ERROR | BLOCK_IN_FLUSH |
1396
1224
BLOCK_CHANGED)));
1397
DBUG_ASSERT(block->hash_link);
1398
DBUG_ASSERT(block->hash_link->block == block);
1225
assert(block->hash_link);
1226
assert(block->hash_link->block == block);
1399
1227
/* Linked in file_blocks or changed_blocks hash. */
1400
DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
1228
assert(block->prev_changed && *block->prev_changed == block);
1401
1229
/* Not linked in LRU ring. */
1402
DBUG_ASSERT(!block->next_used);
1403
DBUG_ASSERT(!block->prev_used);
1230
assert(!block->next_used);
1231
assert(!block->prev_used);
1404
1232
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)));
1409
1234
/* There must be no other waiter. We have no queue here. */
1410
DBUG_ASSERT(!block->condvar);
1235
assert(!block->condvar);
1411
1236
block->condvar= &thread->suspend;
1412
1237
keycache_pthread_cond_wait(&thread->suspend, &keycache->cache_lock);
1413
1238
block->condvar= NULL;
1503
1319
hash_link points to the first member of the list
1505
1321
hash_link= *(start= &keycache->hash_root[KEYCACHE_HASH(file, filepos)]);
1506
#if defined(KEYCACHE_DEBUG)
1509
1322
/* Look for an element for the pair (file, filepos) in the bucket chain */
1510
1323
while (hash_link &&
1511
1324
(hash_link->diskpos != filepos || hash_link->file != file))
1513
1326
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);
1529
1328
if (! hash_link)
1613
1409
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););
1629
1413
If the flush phase of a resize operation fails, the cache is left
1630
1414
unusable. This will be detected only after "goto restart".
1632
1416
if (!keycache->can_be_used)
1636
1420
Find the hash_link for the requested file block (file, filepos). We
2009
1781
keycache->key_cache_block_size),
2011
1783
keycache->blocks_used++;
2012
DBUG_ASSERT(!block->next_used);
1784
assert(!block->next_used);
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);
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);
2020
1792
keycache->blocks_unused--;
2021
1793
block->status= BLOCK_IN_USE;
2022
1794
block->length= 0;
2059
1828
link_into_queue(&keycache->waiting_for_block, thread);
2062
KEYCACHE_DBUG_PRINT("find_key_block: wait",
2063
("suspend thread %ld", thread->id));
2064
1831
keycache_pthread_cond_wait(&thread->suspend,
2065
1832
&keycache->cache_lock);
2067
1834
while (thread->next);
2068
1835
thread->opt_info= NULL;
2069
1836
/* Assert that block has a request registered. */
2070
DBUG_ASSERT(hash_link->block->requests);
1837
assert(hash_link->block->requests);
2071
1838
/* Assert that block is not in LRU ring. */
2072
DBUG_ASSERT(!hash_link->block->next_used);
2073
DBUG_ASSERT(!hash_link->block->prev_used);
1839
assert(!hash_link->block->next_used);
1840
assert(!hash_link->block->prev_used);
2076
1843
If we waited above, hash_link->block has been assigned by
2284
2043
Register a request on the block. This is another protection
2285
2044
against eviction.
2287
DBUG_ASSERT(((block->hash_link != hash_link) &&
2046
assert(((block->hash_link != hash_link) &&
2288
2047
(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH))) ||
2289
2048
((block->hash_link == hash_link) &&
2290
2049
!(block->status & BLOCK_READ)) ||
2291
2050
((block->status & BLOCK_READ) &&
2292
2051
!(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH))));
2293
2052
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 ));
2298
2053
page_status= (((block->hash_link == hash_link) &&
2299
2054
(block->status & BLOCK_READ)) ?
2300
2055
PAGE_READ : PAGE_WAIT_TO_BE_READ);
2304
KEYCACHE_DBUG_ASSERT(page_status != -1);
2059
assert(page_status != -1);
2305
2060
/* Same assert basically, but be very sure. */
2306
KEYCACHE_DBUG_ASSERT(block);
2307
2062
/* Assert that block has a request and is not in LRU ring. */
2308
DBUG_ASSERT(block->requests);
2309
DBUG_ASSERT(!block->next_used);
2310
DBUG_ASSERT(!block->prev_used);
2063
assert(block->requests);
2064
assert(!block->next_used);
2065
assert(!block->prev_used);
2311
2066
/* Assert that we return the correct block. */
2312
DBUG_ASSERT((page_status == PAGE_WAIT_TO_BE_READ) ||
2067
assert((page_status == PAGE_WAIT_TO_BE_READ) ||
2313
2068
((block->hash_link->file == file) &&
2314
2069
(block->hash_link->diskpos == filepos)));
2315
2070
*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");
2368
2113
request for the block become secondary requests. For a primary
2369
2114
request the block must be properly initialized.
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"));
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));
2381
2121
keycache->global_cache_read++;
2382
2122
/* Page is not in buffer yet, is to be read from disk */
3229
2934
is registered in the hash_link and free_block() will wait for it
3232
DBUG_ASSERT((block->status & BLOCK_IN_USE) &&
2937
assert((block->status & BLOCK_IN_USE) &&
3233
2938
!(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH |
3234
2939
BLOCK_REASSIGNED | BLOCK_IN_FLUSH |
3235
2940
BLOCK_CHANGED | BLOCK_FOR_UPDATE)));
3236
2941
/* Assert that the block is in a file_blocks chain. */
3237
DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
2942
assert(block->prev_changed && *block->prev_changed == block);
3238
2943
/* Assert that the block is not in the LRU ring. */
3239
DBUG_ASSERT(!block->next_used && !block->prev_used);
2944
assert(!block->next_used && !block->prev_used);
3241
2946
IMHO the below condition (if()) makes no sense. I can't see how it
3242
2947
could be possible that free_block() is entered with a NULL hash_link
3243
2948
pointer. The only place where it can become NULL is in free_block()
3244
2949
(or before its first use ever, but for those blocks free_block() is
3245
2950
not called). I don't remove the conditional as it cannot harm, but
3246
place an DBUG_ASSERT to confirm my hypothesis. Eventually the
2951
place an assert to confirm my hypothesis. Eventually the
3247
2952
condition (if()) can be removed.
3249
DBUG_ASSERT(block->hash_link && block->hash_link->block == block);
2954
assert(block->hash_link && block->hash_link->block == block);
3250
2955
if (block->hash_link)
4106
3767
int reset_key_cache_counters(const char *name __attribute__((unused)),
4107
3768
KEY_CACHE *key_cache)
4109
DBUG_ENTER("reset_key_cache_counters");
4110
3770
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));
4117
3774
key_cache->global_blocks_changed= 0; /* Key_blocks_not_flushed */
4118
3775
key_cache->global_cache_r_requests= 0; /* Key_read_requests */
4119
3776
key_cache->global_cache_read= 0; /* Key_reads */
4120
3777
key_cache->global_cache_w_requests= 0; /* Key_write_requests */
4121
3778
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)))
4138
3782
#if defined(KEYCACHE_TIMEOUT)
4257
3893
1 nanosecond = 1000 micro seconds
4259
3895
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);
4267
3896
rc= pthread_cond_timedwait(cond, mutex, &timeout);
4268
KEYCACHE_THREAD_TRACE_BEGIN("finished waiting");
4269
3897
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);
4276
3899
keycache_dump();
4279
#if defined(KEYCACHE_DEBUG)
4280
KEYCACHE_DBUG_ASSERT(rc != ETIMEDOUT);
4282
3902
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");
4298
3905
#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");