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) \
285
274
ulong blocks, hash_links;
288
DBUG_ASSERT(key_cache_block_size >= 512);
277
assert(key_cache_block_size >= 512);
290
279
if (keycache->key_cache_inited && keycache->disk_blocks > 0)
703
692
static void unlink_from_queue(KEYCACHE_WQUEUE *wqueue,
704
693
struct st_my_thread_var *thread)
706
DBUG_ASSERT(thread->next && thread->prev);
695
assert(thread->next && thread->prev);
707
696
if (thread->next == thread)
708
697
/* The queue contains only one member */
709
698
wqueue->last_thread= NULL;
756
739
struct st_my_thread_var *thread= my_thread_var;
758
741
/* Add to queue. */
759
DBUG_ASSERT(!thread->next);
760
DBUG_ASSERT(!thread->prev); /* Not required, but must be true anyway. */
742
assert(!thread->next);
743
assert(!thread->prev); /* Not required, but must be true anyway. */
761
744
if (! (last= wqueue->last_thread))
762
745
thread->next= thread;
826
809
Unlink a block from the chain of dirty/clean blocks
829
811
static inline void unlink_changed(BLOCK_LINK *block)
831
DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
813
assert(block->prev_changed && *block->prev_changed == block);
832
814
if (block->next_changed)
833
815
block->next_changed->prev_changed= block->prev_changed;
834
816
*block->prev_changed= block->next_changed;
836
#if !defined(DBUG_OFF)
838
This makes it easier to see it's not in a chain during debugging.
839
And some DBUG_ASSERT() rely on it.
841
817
block->next_changed= NULL;
842
818
block->prev_changed= NULL;
851
826
static inline void link_changed(BLOCK_LINK *block, BLOCK_LINK **phead)
853
DBUG_ASSERT(!block->next_changed);
854
DBUG_ASSERT(!block->prev_changed);
828
assert(!block->next_changed);
829
assert(!block->prev_changed);
855
830
block->prev_changed= phead;
856
831
if ((block->next_changed= *phead))
857
832
(*phead)->prev_changed= &block->next_changed;
888
863
BLOCK_LINK *block, int file,
889
864
my_bool unlink_block)
891
DBUG_ASSERT(block->status & BLOCK_IN_USE);
892
DBUG_ASSERT(block->hash_link && block->hash_link->block == block);
893
DBUG_ASSERT(block->hash_link->file == file);
866
assert(block->status & BLOCK_IN_USE);
867
assert(block->hash_link && block->hash_link->block == block);
868
assert(block->hash_link->file == file);
894
869
if (unlink_block)
895
870
unlink_changed(block);
896
871
link_changed(block, &keycache->file_blocks[FILE_HASH(file)]);
928
903
static void link_to_changed_list(KEY_CACHE *keycache,
929
904
BLOCK_LINK *block)
931
DBUG_ASSERT(block->status & BLOCK_IN_USE);
932
DBUG_ASSERT(!(block->status & BLOCK_CHANGED));
933
DBUG_ASSERT(block->hash_link && block->hash_link->block == block);
906
assert(block->status & BLOCK_IN_USE);
907
assert(!(block->status & BLOCK_CHANGED));
908
assert(block->hash_link && block->hash_link->block == block);
935
910
unlink_changed(block);
936
911
link_changed(block,
987
962
BLOCK_LINK **pins;
989
DBUG_ASSERT((block->status & ~BLOCK_CHANGED) == (BLOCK_READ | BLOCK_IN_USE));
990
DBUG_ASSERT(block->hash_link); /*backptr to block NULL from free_block()*/
991
DBUG_ASSERT(!block->requests);
992
DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
993
DBUG_ASSERT(!block->next_used);
994
DBUG_ASSERT(!block->prev_used);
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);
995
970
if (!hot && keycache->waiting_for_block.last_thread)
997
972
/* Signal that in the LRU warm sub-chain an available block has appeared */
1060
1035
keycache->used_last= keycache->used_ins= block->next_used= block;
1061
1036
block->prev_used= &block->next_used;
1063
#if defined(KEYCACHE_DEBUG)
1064
keycache->blocks_available++;
1065
assert((ulong) keycache->blocks_available <=
1066
keycache->blocks_used);
1086
1056
static void unlink_block(KEY_CACHE *keycache, BLOCK_LINK *block)
1088
DBUG_ASSERT((block->status & ~BLOCK_CHANGED) == (BLOCK_READ | BLOCK_IN_USE));
1089
DBUG_ASSERT(block->hash_link); /*backptr to block NULL from free_block()*/
1090
DBUG_ASSERT(!block->requests);
1091
DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
1092
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 &&
1093
1063
(block->next_used->prev_used == &block->next_used) &&
1094
1064
(*block->prev_used == block));
1095
1065
if (block->next_used == block)
1105
1075
keycache->used_ins=STRUCT_PTR(BLOCK_LINK, next_used, block->prev_used);
1107
1077
block->next_used= NULL;
1108
#if !defined(DBUG_OFF)
1110
This makes it easier to see it's not in a chain during debugging.
1111
And some DBUG_ASSERT() rely on it.
1113
1078
block->prev_used= NULL;
1116
#if defined(KEYCACHE_DEBUG)
1117
assert(keycache->blocks_available != 0);
1118
keycache->blocks_available--;
1139
1098
static void reg_requests(KEY_CACHE *keycache, BLOCK_LINK *block, int count)
1141
DBUG_ASSERT(block->status & BLOCK_IN_USE);
1142
DBUG_ASSERT(block->hash_link);
1100
assert(block->status & BLOCK_IN_USE);
1101
assert(block->hash_link);
1144
1103
if (!block->requests)
1145
1104
unlink_block(keycache, block);
1164
1123
Every linking to the LRU ring decrements by one a special block
1165
counter (if it's positive). If the at_end parameter is TRUE the block is
1124
counter (if it's positive). If the at_end parameter is true the block is
1166
1125
added either at the end of warm sub-chain or at the end of hot sub-chain.
1167
1126
It is added to the hot subchain if its counter is zero and number of
1168
1127
blocks in warm sub-chain is not less than some low limit (determined by
1169
1128
the division_limit parameter). Otherwise the block is added to the warm
1170
sub-chain. If the at_end parameter is FALSE the block is always added
1129
sub-chain. If the at_end parameter is false the block is always added
1171
1130
at beginning of the warm sub-chain.
1172
1131
Thus a warm block can be promoted to the hot sub-chain when its counter
1173
1132
becomes zero for the first time.
1182
1141
static void unreg_request(KEY_CACHE *keycache,
1183
1142
BLOCK_LINK *block, int at_end)
1185
DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
1186
DBUG_ASSERT(block->hash_link); /*backptr to block NULL from free_block()*/
1187
DBUG_ASSERT(block->requests);
1188
DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
1189
DBUG_ASSERT(!block->next_used);
1190
DBUG_ASSERT(!block->prev_used);
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);
1191
1150
if (! --block->requests)
1241
1200
static void remove_reader(BLOCK_LINK *block)
1243
DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
1244
DBUG_ASSERT(block->hash_link && block->hash_link->block == block);
1245
DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
1246
DBUG_ASSERT(!block->next_used);
1247
DBUG_ASSERT(!block->prev_used);
1248
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);
1249
1208
if (! --block->hash_link->requests && block->condvar)
1250
1209
keycache_pthread_cond_signal(block->condvar);
1260
1219
BLOCK_LINK *block)
1262
1221
struct st_my_thread_var *thread= my_thread_var;
1263
DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
1264
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 |
1265
1224
BLOCK_CHANGED)));
1266
DBUG_ASSERT(block->hash_link);
1267
DBUG_ASSERT(block->hash_link->block == block);
1225
assert(block->hash_link);
1226
assert(block->hash_link->block == block);
1268
1227
/* Linked in file_blocks or changed_blocks hash. */
1269
DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
1228
assert(block->prev_changed && *block->prev_changed == block);
1270
1229
/* Not linked in LRU ring. */
1271
DBUG_ASSERT(!block->next_used);
1272
DBUG_ASSERT(!block->prev_used);
1230
assert(!block->next_used);
1231
assert(!block->prev_used);
1273
1232
while (block->hash_link->requests)
1275
1234
/* There must be no other waiter. We have no queue here. */
1276
DBUG_ASSERT(!block->condvar);
1235
assert(!block->condvar);
1277
1236
block->condvar= &thread->suspend;
1278
1237
keycache_pthread_cond_wait(&thread->suspend, &keycache->cache_lock);
1279
1238
block->condvar= NULL;
1363
1319
hash_link points to the first member of the list
1365
1321
hash_link= *(start= &keycache->hash_root[KEYCACHE_HASH(file, filepos)]);
1366
#if defined(KEYCACHE_DEBUG)
1369
1322
/* Look for an element for the pair (file, filepos) in the bucket chain */
1370
1323
while (hash_link &&
1371
1324
(hash_link->diskpos != filepos || hash_link->file != file))
1373
1326
hash_link= hash_link->next;
1374
#if defined(KEYCACHE_DEBUG)
1376
if (! (cnt <= keycache->hash_links_used))
1379
for (i=0, hash_link= *start ;
1380
i < cnt ; i++, hash_link= hash_link->next) {/* Do Nothing */ }
1382
assert(cnt <= keycache->hash_links_used);
1385
1328
if (! hash_link)
1497
1440
- not changed (clean).
1499
1442
hash_link= get_hash_link(keycache, file, filepos);
1500
DBUG_ASSERT((hash_link->file == file) && (hash_link->diskpos == filepos));
1443
assert((hash_link->file == file) && (hash_link->diskpos == filepos));
1502
1445
page_status= -1;
1503
1446
if ((block= hash_link->block) &&
1601
1544
only. Waiting here on COND_FOR_REQUESTED works in all
1604
DBUG_ASSERT(((block->hash_link != hash_link) &&
1547
assert(((block->hash_link != hash_link) &&
1605
1548
(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH))) ||
1606
1549
((block->hash_link == hash_link) &&
1607
1550
!(block->status & BLOCK_READ)));
1616
1559
again in eviction because we registered an request on it before
1617
1560
starting to wait.
1619
DBUG_ASSERT(block->hash_link == hash_link);
1620
DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
1621
DBUG_ASSERT(!(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH)));
1562
assert(block->hash_link == hash_link);
1563
assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
1564
assert(!(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH)));
1624
1567
The block is in the cache. Assigned to the hash_link. Valid data.
1631
1574
/* A reader can just read the block. */
1632
1575
*page_st= PAGE_READ;
1633
DBUG_ASSERT((hash_link->file == file) &&
1576
assert((hash_link->file == file) &&
1634
1577
(hash_link->diskpos == filepos) &&
1635
1578
(block->hash_link == hash_link));
1640
1583
This is a writer. No two writers for the same block can exist.
1641
1584
This must be assured by locks outside of the key cache.
1643
DBUG_ASSERT(!(block->status & BLOCK_FOR_UPDATE));
1586
assert(!(block->status & BLOCK_FOR_UPDATE));
1645
1588
while (block->status & BLOCK_IN_FLUSH)
1664
1607
unreg_request(keycache, block, 1);
1667
DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
1668
DBUG_ASSERT(!(block->status & BLOCK_FOR_UPDATE));
1669
DBUG_ASSERT(block->hash_link == hash_link);
1610
assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
1611
assert(!(block->status & BLOCK_FOR_UPDATE));
1612
assert(block->hash_link == hash_link);
1672
1615
if (block->status & BLOCK_CHANGED)
1679
1622
not yet been selected for flush, we can still add our changes.
1681
1624
*page_st= PAGE_READ;
1682
DBUG_ASSERT((hash_link->file == file) &&
1625
assert((hash_link->file == file) &&
1683
1626
(hash_link->diskpos == filepos) &&
1684
1627
(block->hash_link == hash_link));
1793
1736
as soon as possible. Again we must wait so that we don't find
1794
1737
the same hash_link + block again and again.
1796
DBUG_ASSERT(hash_link->requests);
1739
assert(hash_link->requests);
1797
1740
hash_link->requests--;
1798
1741
wait_on_queue(&block->wqueue[COND_FOR_SAVED], &keycache->cache_lock);
1832
1775
/* There are some never used blocks, take first of them */
1833
DBUG_ASSERT(keycache->blocks_used <
1776
assert(keycache->blocks_used <
1834
1777
(ulong) keycache->disk_blocks);
1835
1778
block= &keycache->block_root[keycache->blocks_used];
1836
1779
block->buffer= ADD_TO_PTR(keycache->block_mem,
1838
1781
keycache->key_cache_block_size),
1840
1783
keycache->blocks_used++;
1841
DBUG_ASSERT(!block->next_used);
1784
assert(!block->next_used);
1843
DBUG_ASSERT(!block->prev_used);
1844
DBUG_ASSERT(!block->next_changed);
1845
DBUG_ASSERT(!block->prev_changed);
1846
DBUG_ASSERT(!block->hash_link);
1847
DBUG_ASSERT(!block->status);
1848
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);
1849
1792
keycache->blocks_unused--;
1850
1793
block->status= BLOCK_IN_USE;
1851
1794
block->length= 0;
1891
1834
while (thread->next);
1892
1835
thread->opt_info= NULL;
1893
1836
/* Assert that block has a request registered. */
1894
DBUG_ASSERT(hash_link->block->requests);
1837
assert(hash_link->block->requests);
1895
1838
/* Assert that block is not in LRU ring. */
1896
DBUG_ASSERT(!hash_link->block->next_used);
1897
DBUG_ASSERT(!hash_link->block->prev_used);
1839
assert(!hash_link->block->next_used);
1840
assert(!hash_link->block->prev_used);
1900
1843
If we waited above, hash_link->block has been assigned by
1913
1856
Register a request on the block. This unlinks it from the
1914
1857
LRU ring and protects it against eviction.
1916
DBUG_ASSERT(!block->requests);
1859
assert(!block->requests);
1917
1860
reg_requests(keycache, block,1);
1919
1862
We do not need to set block->status|= BLOCK_IN_EVICTION here
1956
1899
The block is marked BLOCK_IN_SWITCH. It should be left
1957
1900
alone except for reading. No free, no write.
1959
DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
1960
DBUG_ASSERT(!(block->status & (BLOCK_REASSIGNED |
1902
assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
1903
assert(!(block->status & (BLOCK_REASSIGNED |
1961
1904
BLOCK_CHANGED |
1962
1905
BLOCK_FOR_UPDATE)));
1968
1911
BLOCK_IN_EVICTION may be true or not. Other flags must
1969
1912
have a fixed value.
1971
DBUG_ASSERT((block->status & ~BLOCK_IN_EVICTION) ==
1914
assert((block->status & ~BLOCK_IN_EVICTION) ==
1972
1915
(BLOCK_READ | BLOCK_IN_SWITCH |
1973
1916
BLOCK_IN_FLUSH | BLOCK_IN_FLUSHWRITE |
1974
1917
BLOCK_CHANGED | BLOCK_IN_USE));
1975
DBUG_ASSERT(block->hash_link);
1918
assert(block->hash_link);
1977
1920
keycache_pthread_mutex_unlock(&keycache->cache_lock);
1986
1929
keycache_pthread_mutex_lock(&keycache->cache_lock);
1988
1931
/* Block status must not have changed. */
1989
DBUG_ASSERT((block->status & ~BLOCK_IN_EVICTION) ==
1932
assert((block->status & ~BLOCK_IN_EVICTION) ==
1990
1933
(BLOCK_READ | BLOCK_IN_SWITCH |
1991
1934
BLOCK_IN_FLUSH | BLOCK_IN_FLUSHWRITE |
1992
1935
BLOCK_CHANGED | BLOCK_IN_USE));
2026
1969
a page in the cache in a sweep, without yielding control)
2028
1971
wait_for_readers(keycache, block);
2029
DBUG_ASSERT(block->hash_link && block->hash_link->block == block &&
1972
assert(block->hash_link && block->hash_link->block == block &&
2030
1973
block->prev_changed);
2031
1974
/* The reader must not have been a writer. */
2032
DBUG_ASSERT(!(block->status & BLOCK_CHANGED));
1975
assert(!(block->status & BLOCK_CHANGED));
2034
1977
/* Wake flushers that might have found the block in between. */
2035
1978
release_whole_queue(&block->wqueue[COND_FOR_SAVED]);
2042
1985
and hash_link refer to each other. Hence we need to assign
2043
1986
the hash_link first, but then we would not know if it was
2044
1987
linked before. Hence we would not know if to unlink it. So
2045
unlink it here and call link_to_file_list(..., FALSE).
1988
unlink it here and call link_to_file_list(..., false).
2047
1990
unlink_changed(block);
2100
2043
Register a request on the block. This is another protection
2101
2044
against eviction.
2103
DBUG_ASSERT(((block->hash_link != hash_link) &&
2046
assert(((block->hash_link != hash_link) &&
2104
2047
(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH))) ||
2105
2048
((block->hash_link == hash_link) &&
2106
2049
!(block->status & BLOCK_READ)) ||
2117
2060
/* Same assert basically, but be very sure. */
2119
2062
/* Assert that block has a request and is not in LRU ring. */
2120
DBUG_ASSERT(block->requests);
2121
DBUG_ASSERT(!block->next_used);
2122
DBUG_ASSERT(!block->prev_used);
2063
assert(block->requests);
2064
assert(!block->next_used);
2065
assert(!block->prev_used);
2123
2066
/* Assert that we return the correct block. */
2124
DBUG_ASSERT((page_status == PAGE_WAIT_TO_BE_READ) ||
2067
assert((page_status == PAGE_WAIT_TO_BE_READ) ||
2125
2068
((block->hash_link->file == file) &&
2126
2069
(block->hash_link->diskpos == filepos)));
2127
2070
*page_st=page_status;
2170
2113
request for the block become secondary requests. For a primary
2171
2114
request the block must be properly initialized.
2173
DBUG_ASSERT(((block->status & ~BLOCK_FOR_UPDATE) == BLOCK_IN_USE));
2174
DBUG_ASSERT((block->length == 0));
2175
DBUG_ASSERT((block->offset == keycache->key_cache_block_size));
2176
DBUG_ASSERT((block->requests > 0));
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));
2178
2121
keycache->global_cache_read++;
2179
2122
/* Page is not in buffer yet, is to be read from disk */
2188
2131
The block can now have been marked for free (in case of
2189
2132
FLUSH_RELEASE). Otherwise the state must be unchanged.
2191
DBUG_ASSERT(((block->status & ~(BLOCK_REASSIGNED |
2134
assert(((block->status & ~(BLOCK_REASSIGNED |
2192
2135
BLOCK_FOR_UPDATE)) == BLOCK_IN_USE));
2193
DBUG_ASSERT((block->length == 0));
2194
DBUG_ASSERT((block->offset == keycache->key_cache_block_size));
2195
DBUG_ASSERT((block->requests > 0));
2136
assert((block->length == 0));
2137
assert((block->offset == keycache->key_cache_block_size));
2138
assert((block->requests > 0));
2197
2140
if (got_length < min_length)
2198
2141
block->status|= BLOCK_ERROR;
2248
2191
The function ensures that a block of data of size length from file
2249
2192
positioned at filepos is in the buffers for some key cache blocks.
2250
2193
Then the function either copies the data into the buffer buff, or,
2251
if return_buffer is TRUE, it just returns the pointer to the key cache
2194
if return_buffer is true, it just returns the pointer to the key cache
2252
2195
buffer with the data.
2253
2196
Filepos must be a multiple of 'block_length', but it doesn't
2254
2197
have to be a multiple of key_cache_block_size;
2260
2203
uint block_length __attribute__((unused)),
2261
2204
int return_buffer __attribute__((unused)))
2263
my_bool locked_and_incremented= FALSE;
2206
my_bool locked_and_incremented= false;
2265
2208
uchar *start= buff;
2298
2241
wait_on_queue(&keycache->resize_queue, &keycache->cache_lock);
2299
2242
/* Register the I/O for the next resize. */
2300
2243
inc_counter_for_resize_op(keycache);
2301
locked_and_incremented= TRUE;
2244
locked_and_incremented= true;
2302
2245
/* Requested data may not always be aligned to cache blocks. */
2303
2246
offset= (uint) (filepos % keycache->key_cache_block_size);
2304
2247
/* Read data in key_cache_block_size increments */
2344
2287
requested file block. It does not hurt to check it for
2345
2288
primary requests too.
2347
DBUG_ASSERT(keycache->can_be_used);
2348
DBUG_ASSERT(block->hash_link->file == file);
2349
DBUG_ASSERT(block->hash_link->diskpos == filepos);
2350
DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
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));
2352
2295
else if (block->length < read_length + offset)
2365
2308
if (!((status= block->status) & BLOCK_ERROR))
2368
DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
2311
assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
2369
2312
#if !defined(SERIALIZED_READ_FROM_CACHE)
2370
2313
keycache_pthread_mutex_unlock(&keycache->cache_lock);
2379
2322
#if !defined(SERIALIZED_READ_FROM_CACHE)
2380
2323
keycache_pthread_mutex_lock(&keycache->cache_lock);
2381
DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
2324
assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
2479
2422
goto no_key_cache;
2480
2423
/* Register the pseudo I/O for the next resize. */
2481
2424
inc_counter_for_resize_op(keycache);
2482
locked_and_incremented= TRUE;
2425
locked_and_incremented= true;
2483
2426
/* Loaded data may not always be aligned to cache blocks. */
2484
2427
offset= (uint) (filepos % keycache->key_cache_block_size);
2485
2428
/* Load data in key_cache_block_size increments. */
2524
2467
hash_link). So we cannot call remove_reader() on the block.
2525
2468
And we cannot access the hash_link directly here. We need to
2526
2469
wait until the assignment is complete. read_block() executes
2527
the correct wait when called with primary == FALSE.
2470
the correct wait when called with primary == false.
2549
2492
requested file block. It does not hurt to check it for
2550
2493
primary requests too.
2552
DBUG_ASSERT(keycache->can_be_used);
2553
DBUG_ASSERT(block->hash_link->file == file);
2554
DBUG_ASSERT(block->hash_link->diskpos == filepos);
2555
DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
2495
assert(keycache->can_be_used);
2496
assert(block->hash_link->file == file);
2497
assert(block->hash_link->diskpos == filepos);
2498
assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
2557
2500
else if (page_st == PAGE_TO_BE_READ)
2560
2503
This is a new block in the cache. If we come here, we have
2561
2504
data for the whole block.
2563
DBUG_ASSERT(block->hash_link->requests);
2564
DBUG_ASSERT(block->status & BLOCK_IN_USE);
2565
DBUG_ASSERT((page_st == PAGE_TO_BE_READ) ||
2506
assert(block->hash_link->requests);
2507
assert(block->status & BLOCK_IN_USE);
2508
assert((page_st == PAGE_TO_BE_READ) ||
2566
2509
(block->status & BLOCK_READ));
2568
2511
#if !defined(SERIALIZED_READ_FROM_CACHE)
2582
2525
#if !defined(SERIALIZED_READ_FROM_CACHE)
2583
2526
keycache_pthread_mutex_lock(&keycache->cache_lock);
2584
DBUG_ASSERT(block->status & BLOCK_IN_USE);
2585
DBUG_ASSERT((page_st == PAGE_TO_BE_READ) ||
2527
assert(block->status & BLOCK_IN_USE);
2528
assert((page_st == PAGE_TO_BE_READ) ||
2586
2529
(block->status & BLOCK_READ));
2614
2557
with the new data. If the condition is met, we can simply
2615
2558
ignore the block.
2617
DBUG_ASSERT((page_st == PAGE_READ) &&
2560
assert((page_st == PAGE_READ) &&
2618
2561
(read_length + offset <= block->length));
2623
2566
requested file block. It does not hurt to check it for primary
2626
DBUG_ASSERT(block->hash_link->file == file);
2627
DBUG_ASSERT(block->hash_link->diskpos == filepos);
2628
DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
2569
assert(block->hash_link->file == file);
2570
assert(block->hash_link->diskpos == filepos);
2571
assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
2629
2572
} /* end of if (!(block->status & BLOCK_ERROR)) */
2679
2622
The function copies the data of size length from buff into buffers
2680
2623
for key cache blocks that are assigned to contain the portion of
2681
2624
the file starting with position filepos.
2682
It ensures that this data is flushed to the file if dont_write is FALSE.
2625
It ensures that this data is flushed to the file if dont_write is false.
2683
2626
Filepos must be a multiple of 'block_length', but it doesn't
2684
2627
have to be a multiple of key_cache_block_size;
2686
dont_write is always TRUE in the server (info->lock_type is never F_UNLCK).
2629
dont_write is always true in the server (info->lock_type is never F_UNLCK).
2689
2632
int key_cache_write(KEY_CACHE *keycache,
2741
2684
wait_on_queue(&keycache->resize_queue, &keycache->cache_lock);
2742
2685
/* Register the I/O for the next resize. */
2743
2686
inc_counter_for_resize_op(keycache);
2744
locked_and_incremented= TRUE;
2687
locked_and_incremented= true;
2745
2688
/* Requested data may not always be aligned to cache blocks. */
2746
2689
offset= (uint) (filepos % keycache->key_cache_block_size);
2747
2690
/* Write data in key_cache_block_size increments. */
2807
2750
offset + read_length >= keycache->key_cache_block_size?
2808
2751
offset : keycache->key_cache_block_size,
2809
2752
offset, (page_st == PAGE_TO_BE_READ));
2810
DBUG_ASSERT(keycache->can_be_used);
2811
DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
2753
assert(keycache->can_be_used);
2754
assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
2813
2756
Prevent block from flushing and from being selected for to be
2814
2757
freed. This must be set when we release the cache_lock.
2820
2763
The block should always be assigned to the requested file block
2821
2764
here. It need not be BLOCK_READ when overwriting the whole block.
2823
DBUG_ASSERT(block->hash_link->file == file);
2824
DBUG_ASSERT(block->hash_link->diskpos == filepos);
2825
DBUG_ASSERT(block->status & BLOCK_IN_USE);
2826
DBUG_ASSERT((page_st == PAGE_TO_BE_READ) || (block->status & BLOCK_READ));
2766
assert(block->hash_link->file == file);
2767
assert(block->hash_link->diskpos == filepos);
2768
assert(block->status & BLOCK_IN_USE);
2769
assert((page_st == PAGE_TO_BE_READ) || (block->status & BLOCK_READ));
2828
2771
The block to be written must not be marked BLOCK_REASSIGNED.
2829
2772
Otherwise it could be freed in dirty state or reused without
2846
2789
another hash_link until we release our request on it.
2848
2791
wait_on_queue(&block->wqueue[COND_FOR_SAVED], &keycache->cache_lock);
2849
DBUG_ASSERT(keycache->can_be_used);
2850
DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
2792
assert(keycache->can_be_used);
2793
assert(block->status & (BLOCK_READ | BLOCK_IN_USE));
2851
2794
/* Still must not be marked for free. */
2852
DBUG_ASSERT(!(block->status & BLOCK_REASSIGNED));
2853
DBUG_ASSERT(block->hash_link && (block->hash_link->block == block));
2795
assert(!(block->status & BLOCK_REASSIGNED));
2796
assert(block->hash_link && (block->hash_link->block == block));
2991
2934
is registered in the hash_link and free_block() will wait for it
2994
DBUG_ASSERT((block->status & BLOCK_IN_USE) &&
2937
assert((block->status & BLOCK_IN_USE) &&
2995
2938
!(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH |
2996
2939
BLOCK_REASSIGNED | BLOCK_IN_FLUSH |
2997
2940
BLOCK_CHANGED | BLOCK_FOR_UPDATE)));
2998
2941
/* Assert that the block is in a file_blocks chain. */
2999
DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
2942
assert(block->prev_changed && *block->prev_changed == block);
3000
2943
/* Assert that the block is not in the LRU ring. */
3001
DBUG_ASSERT(!block->next_used && !block->prev_used);
2944
assert(!block->next_used && !block->prev_used);
3003
2946
IMHO the below condition (if()) makes no sense. I can't see how it
3004
2947
could be possible that free_block() is entered with a NULL hash_link
3005
2948
pointer. The only place where it can become NULL is in free_block()
3006
2949
(or before its first use ever, but for those blocks free_block() is
3007
2950
not called). I don't remove the conditional as it cannot harm, but
3008
place an DBUG_ASSERT to confirm my hypothesis. Eventually the
2951
place an assert to confirm my hypothesis. Eventually the
3009
2952
condition (if()) can be removed.
3011
DBUG_ASSERT(block->hash_link && block->hash_link->block == block);
2954
assert(block->hash_link && block->hash_link->block == block);
3012
2955
if (block->hash_link)
3024
2967
checks. An additional requirement is that it must be read now
3027
DBUG_ASSERT(block->hash_link && block->hash_link->block == block);
3028
DBUG_ASSERT((block->status & (BLOCK_READ | BLOCK_IN_USE |
2970
assert(block->hash_link && block->hash_link->block == block);
2971
assert((block->status & (BLOCK_READ | BLOCK_IN_USE |
3029
2972
BLOCK_REASSIGNED)) &&
3030
2973
!(block->status & (BLOCK_IN_EVICTION | BLOCK_IN_SWITCH |
3031
2974
BLOCK_IN_FLUSH | BLOCK_CHANGED |
3032
2975
BLOCK_FOR_UPDATE)));
3033
DBUG_ASSERT(block->prev_changed && *block->prev_changed == block);
3034
DBUG_ASSERT(!block->prev_used);
2976
assert(block->prev_changed && *block->prev_changed == block);
2977
assert(!block->prev_used);
3036
2979
Unset BLOCK_REASSIGNED again. If we hand the block to an evicting
3037
2980
thread (through unreg_request() below), other threads must not see
3054
2997
operation in this case. Assert that there are no other requests
3057
DBUG_ASSERT(block->requests == 1);
3000
assert(block->requests == 1);
3058
3001
unreg_request(keycache, block, 0);
3060
3003
Note that even without releasing the cache lock it is possible that
3068
3011
/* Here the block must be in the LRU ring. Unlink it again. */
3069
DBUG_ASSERT(block->next_used && block->prev_used &&
3012
assert(block->next_used && block->prev_used &&
3070
3013
*block->prev_used == block);
3071
3014
unlink_block(keycache, block);
3072
3015
if (block->temperature == BLOCK_WARM)
3085
3028
block->offset= keycache->key_cache_block_size;
3087
3030
/* Enforced by unlink_changed(), but just to be sure. */
3088
DBUG_ASSERT(!block->next_changed && !block->prev_changed);
3031
assert(!block->next_changed && !block->prev_changed);
3089
3032
/* Enforced by unlink_block(): not in LRU ring nor in free_block_list. */
3090
DBUG_ASSERT(!block->next_used && !block->prev_used);
3033
assert(!block->next_used && !block->prev_used);
3091
3034
/* Insert the free block in the free list. */
3092
3035
block->next_used= keycache->free_block_list;
3093
3036
keycache->free_block_list= block;
3145
3088
if (!(block->status & BLOCK_FOR_UPDATE))
3147
3090
/* Blocks coming here must have a certain status. */
3148
DBUG_ASSERT(block->hash_link);
3149
DBUG_ASSERT(block->hash_link->block == block);
3150
DBUG_ASSERT(block->hash_link->file == file);
3151
DBUG_ASSERT((block->status & ~BLOCK_IN_EVICTION) ==
3091
assert(block->hash_link);
3092
assert(block->hash_link->block == block);
3093
assert(block->hash_link->file == file);
3094
assert((block->status & ~BLOCK_IN_EVICTION) ==
3152
3095
(BLOCK_READ | BLOCK_IN_FLUSH | BLOCK_CHANGED | BLOCK_IN_USE));
3153
3096
block->status|= BLOCK_IN_FLUSHWRITE;
3154
3097
keycache_pthread_mutex_unlock(&keycache->cache_lock);
3167
3110
block->status&= ~BLOCK_IN_FLUSHWRITE;
3168
3111
/* Block must not have changed status except BLOCK_FOR_UPDATE. */
3169
DBUG_ASSERT(block->hash_link);
3170
DBUG_ASSERT(block->hash_link->block == block);
3171
DBUG_ASSERT(block->hash_link->file == file);
3172
DBUG_ASSERT((block->status & ~(BLOCK_FOR_UPDATE | BLOCK_IN_EVICTION)) ==
3112
assert(block->hash_link);
3113
assert(block->hash_link->block == block);
3114
assert(block->hash_link->file == file);
3115
assert((block->status & ~(BLOCK_FOR_UPDATE | BLOCK_IN_EVICTION)) ==
3173
3116
(BLOCK_READ | BLOCK_IN_FLUSH | BLOCK_CHANGED | BLOCK_IN_USE));
3175
3118
Set correct status and link in right queue for free or later use.
3256
3199
BLOCK_LINK *last_in_flush;
3257
3200
BLOCK_LINK *last_for_update;
3258
3201
BLOCK_LINK *block, *next;
3259
#if defined(KEYCACHE_DEBUG)
3263
3203
if (type != FLUSH_IGNORE_CHANGED)
3493
3429
while (first_in_switch)
3495
#if defined(KEYCACHE_DEBUG)
3498
3431
wait_on_queue(&first_in_switch->wqueue[COND_FOR_SAVED],
3499
3432
&keycache->cache_lock);
3500
#if defined(KEYCACHE_DEBUG)
3502
assert(cnt <= keycache->blocks_used);
3505
3434
Do not restart here. We have flushed all blocks that were
3506
3435
changed when entering this function and were not marked for
3531
3460
next= block->next_changed;
3533
3462
/* Changed blocks cannot appear in the file_blocks hash. */
3534
DBUG_ASSERT(!(block->status & BLOCK_CHANGED));
3463
assert(!(block->status & BLOCK_CHANGED));
3535
3464
if (block->hash_link->file == file)
3537
3466
/* We must skip blocks that will be changed. */
3579
3508
next_hash_link= next->hash_link;
3580
3509
next_diskpos= next_hash_link->diskpos;
3581
3510
next_file= next_hash_link->file;
3582
DBUG_ASSERT(next == next_hash_link->block);
3511
assert(next == next_hash_link->block);
3585
3514
free_block(keycache, block);
3626
3555
if (last_for_update)
3628
3557
/* We did not wait. Block must not have changed status. */
3629
DBUG_ASSERT(last_for_update->status & BLOCK_FOR_UPDATE);
3558
assert(last_for_update->status & BLOCK_FOR_UPDATE);
3630
3559
wait_on_queue(&last_for_update->wqueue[COND_FOR_REQUESTED],
3631
3560
&keycache->cache_lock);
3639
3568
if (last_in_switch)
3641
3570
/* We did not wait. Block must not have changed status. */
3642
DBUG_ASSERT(last_in_switch->status & (BLOCK_IN_EVICTION |
3571
assert(last_in_switch->status & (BLOCK_IN_EVICTION |
3643
3572
BLOCK_IN_SWITCH |
3644
3573
BLOCK_REASSIGNED));
3645
3574
wait_on_queue(&last_in_switch->wqueue[COND_FOR_SAVED],
3815
3744
before the resize started (BLOCK_FOR_UPDATE). Re-check the hashes.
3817
3746
} while (total_found);
3820
/* Now there should not exist any block any more. */
3821
for (idx= 0; idx < CHANGED_BLOCKS_HASH; idx++)
3823
DBUG_ASSERT(!keycache->changed_blocks[idx]);
3824
DBUG_ASSERT(!keycache->file_blocks[idx]);
3956
3875
fclose(keycache_dump_file);
3959
#endif /* defined(KEYCACHE_TIMEOUT) */
3961
#if defined(KEYCACHE_TIMEOUT)
3964
3878
static int keycache_pthread_cond_wait(pthread_cond_t *cond,
3965
3879
pthread_mutex_t *mutex)
3982
3893
1 nanosecond = 1000 micro seconds
3984
3895
timeout.tv_nsec= now.tv_usec * 1000;
3985
#if defined(KEYCACHE_DEBUG)
3988
fprintf(keycache_debug_log, "waiting...\n");
3989
fflush(keycache_debug_log);
3991
3896
rc= pthread_cond_timedwait(cond, mutex, &timeout);
3992
3897
if (rc == ETIMEDOUT || rc == ETIME)
3994
#if defined(KEYCACHE_DEBUG)
3995
fprintf(keycache_debug_log,"aborted by keycache timeout\n");
3996
fclose(keycache_debug_log);
3999
3899
keycache_dump();
4002
3902
assert(rc != ETIMEDOUT);
4006
#if defined(KEYCACHE_DEBUG)
4007
static int keycache_pthread_cond_wait(pthread_cond_t *cond,
4008
pthread_mutex_t *mutex)
4011
rc= pthread_cond_wait(cond, mutex);
4015
3905
#endif /* defined(KEYCACHE_TIMEOUT) */
4017
#if defined(KEYCACHE_DEBUG)
4020
static int keycache_pthread_mutex_lock(pthread_mutex_t *mutex)
4023
rc= pthread_mutex_lock(mutex);
4028
static void keycache_pthread_mutex_unlock(pthread_mutex_t *mutex)
4030
pthread_mutex_unlock(mutex);
4034
static int keycache_pthread_cond_signal(pthread_cond_t *cond)
4037
rc= pthread_cond_signal(cond);
4042
#if defined(KEYCACHE_DEBUG_LOG)
4045
static void keycache_debug_print(const char * fmt,...)
4049
if (keycache_debug_log)
4051
VOID(vfprintf(keycache_debug_log, fmt, args));
4052
VOID(fputc('\n',keycache_debug_log));
4056
#endif /* defined(KEYCACHE_DEBUG_LOG) */
4058
#if defined(KEYCACHE_DEBUG_LOG)
4061
void keycache_debug_log_close(void)
4063
if (keycache_debug_log)
4064
fclose(keycache_debug_log);
4066
#endif /* defined(KEYCACHE_DEBUG_LOG) */
4068
#endif /* defined(KEYCACHE_DEBUG) */