diff options
author | unknown <ingo@mysql.com> | 2004-05-03 15:55:21 +0200 |
---|---|---|
committer | unknown <ingo@mysql.com> | 2004-05-03 15:55:21 +0200 |
commit | 14bdccb29f837583070e0746d1e35f22f8286cb2 (patch) | |
tree | f82a460f807cff5eea040e4950e8f7b334c28f33 | |
parent | ef19df9610607920a1ac06311780be87c377bc5c (diff) | |
download | mariadb-git-14bdccb29f837583070e0746d1e35f22f8286cb2.tar.gz |
WL#1700 - Properly count key_blocks_used and key_blocks_current.
Introduced a new free blocks list. Free blocks are now re-used before
new blocks are allocated from the pool. There is a new status variable
which can be queried by "show status like key_blocks_unused".
include/keycache.h:
WL#1700 - Properly count key_blocks_used and key_blocks_current.
free_block_list is the new free blocks list. It is implemented like a stack (LIFO).
blocks_unused holds the number of never used blocks plus the number of blocks in the free list.
Removed the variable global_blocks_used, as it was always the same as blocks_used.
mysql-test/r/key_cache.result:
WL#1700 - Properly count key_blocks_used and key_blocks_current.
Inserted some commands which show how key_blocks_used and key_blocks_unused work.
mysql-test/t/key_cache.test:
WL#1700 - Properly count key_blocks_used and key_blocks_current.
Inserted some commands which show how key_blocks_used and key_blocks_unused work.
mysys/mf_keycache.c:
WL#1700 - Properly count key_blocks_used and key_blocks_current.
Introduced a new free blocks list. The introductory comment says it all (I hope).
Removed the variable global_blocks_used, as it was always the same as blocks_used.
sql/mysqld.cc:
WL#1700 - Properly count key_blocks_used and key_blocks_current.
The blocks_unused count can be queried by "show status like key_blocks_unused".
Removed the variable global_blocks_used, as it was always the same as blocks_used.
Introduced SHOW_KEY_CACHE_CONST_LONG for status variables that
must not be modified (i.e. flushed to zero).
sql/sql_show.cc:
WL#1700 - Properly count key_blocks_used and key_blocks_current.
Introduced SHOW_KEY_CACHE_CONST_LONG for status variables that
must not be modified (i.e. flushed to zero).
sql/sql_test.cc:
WL#1700 - Properly count key_blocks_used and key_blocks_current.
Removed the variable global_blocks_used, as it was always the same as blocks_used.
sql/structs.h:
WL#1700 - Properly count key_blocks_used and key_blocks_current.
Introduced SHOW_KEY_CACHE_CONST_LONG for status variables that
must not be modified (i.e. flushed to zero).
-rw-r--r-- | include/keycache.h | 5 | ||||
-rw-r--r-- | mysql-test/r/key_cache.result | 24 | ||||
-rw-r--r-- | mysql-test/t/key_cache.test | 12 | ||||
-rw-r--r-- | mysys/mf_keycache.c | 84 | ||||
-rw-r--r-- | sql/mysqld.cc | 6 | ||||
-rw-r--r-- | sql/sql_show.cc | 1 | ||||
-rw-r--r-- | sql/sql_test.cc | 2 | ||||
-rw-r--r-- | sql/structs.h | 3 |
8 files changed, 115 insertions, 22 deletions
diff --git a/include/keycache.h b/include/keycache.h index b882f3127f5..26ee0ccadb1 100644 --- a/include/keycache.h +++ b/include/keycache.h @@ -57,7 +57,8 @@ typedef struct st_key_cache int hash_links; /* max number of hash links */ int hash_links_used; /* number of hash links currently used */ int disk_blocks; /* max number of blocks in the cache */ - ulong blocks_used; /* number of currently used blocks */ + ulong blocks_used; /* maximum number of concurrently used blocks */ + ulong blocks_unused; /* number of currently unused blocks */ ulong blocks_changed; /* number of currently dirty blocks */ ulong warm_blocks; /* number of blocks in warm sub-chain */ ulong cnt_for_resize_op; /* counter to block resize operation */ @@ -65,6 +66,7 @@ typedef struct st_key_cache HASH_LINK **hash_root; /* arr. of entries into hash table buckets */ HASH_LINK *hash_link_root; /* memory for hash table links */ HASH_LINK *free_hash_list; /* list of free hash links */ + BLOCK_LINK *free_block_list; /* list of free blocks */ BLOCK_LINK *block_root; /* memory for block links */ byte HUGE_PTR *block_mem; /* memory for block buffers */ BLOCK_LINK *used_last; /* ptr to the last block of the LRU chain */ @@ -87,7 +89,6 @@ typedef struct st_key_cache ulong param_age_threshold; /* determines when hot block is downgraded */ /* Statistics variables */ - ulong global_blocks_used; /* number of currently used blocks */ ulong global_blocks_changed; /* number of currently dirty blocks */ ulong global_cache_w_requests;/* number of write requests (write hits) */ ulong global_cache_write; /* number of writes from the cache to files */ diff --git a/mysql-test/r/key_cache.result b/mysql-test/r/key_cache.result index b83a226776d..eeb838dc72c 100644 --- a/mysql-test/r/key_cache.result +++ b/mysql-test/r/key_cache.result @@ -85,6 +85,14 @@ select @@key_cache_block_size; set global keycache1.key_buffer_size=1024*1024; create table t1 (p int primary key, a char(10)) delay_key_write=1; create table t2 (p int primary key, i int, a char(10), key k1(i), key k2(a)); +show status like 'key_blocks_used'; +Variable_name Value +Key_blocks_used 0 +show status like 'The below may fail on 64-bit systems (ingo)'; +Variable_name Value +show status like 'key_blocks_unused'; +Variable_name Value +Key_blocks_unused 1812 insert into t1 values (1, 'qqqq'), (11, 'yyyy'); insert into t2 values (1, 1, 'qqqq'), (2, 1, 'pppp'), (3, 1, 'yyyy'), (4, 3, 'zzzz'); @@ -100,6 +108,14 @@ p i a 4 3 zzzz update t1 set p=2 where p=1; update t2 set i=2 where i=1; +show status like 'key_blocks_used'; +Variable_name Value +Key_blocks_used 4 +show status like 'The below may fail on 64-bit systems (ingo)'; +Variable_name Value +show status like 'key_blocks_unused'; +Variable_name Value +Key_blocks_unused 1808 cache index t1 key (`primary`) in keycache1; Table Op Msg_type Msg_text test.t1 assign_to_keycache status OK @@ -256,6 +272,14 @@ Table Op Msg_type Msg_text test.t1 assign_to_keycache status OK test.t2 assign_to_keycache status OK drop table t1,t2,t3; +show status like 'key_blocks_used'; +Variable_name Value +Key_blocks_used 4 +show status like 'The below may fail on 64-bit systems (ingo)'; +Variable_name Value +show status like 'key_blocks_unused'; +Variable_name Value +Key_blocks_unused 1812 set global keycache2.key_buffer_size=0; set global keycache3.key_buffer_size=100; set global keycache3.key_buffer_size=0; diff --git a/mysql-test/t/key_cache.test b/mysql-test/t/key_cache.test index 2bf5cdbcf6f..ca846a31def 100644 --- a/mysql-test/t/key_cache.test +++ b/mysql-test/t/key_cache.test @@ -66,6 +66,10 @@ set global keycache1.key_buffer_size=1024*1024; create table t1 (p int primary key, a char(10)) delay_key_write=1; create table t2 (p int primary key, i int, a char(10), key k1(i), key k2(a)); +show status like 'key_blocks_used'; +show status like 'The below may fail on 64-bit systems (ingo)'; +show status like 'key_blocks_unused'; # This may fail on 64-bit systems (ingo) + insert into t1 values (1, 'qqqq'), (11, 'yyyy'); insert into t2 values (1, 1, 'qqqq'), (2, 1, 'pppp'), (3, 1, 'yyyy'), (4, 3, 'zzzz'); @@ -75,6 +79,10 @@ select * from t2; update t1 set p=2 where p=1; update t2 set i=2 where i=1; +show status like 'key_blocks_used'; +show status like 'The below may fail on 64-bit systems (ingo)'; +show status like 'key_blocks_unused'; # This may fail on 64-bit systems (ingo) + cache index t1 key (`primary`) in keycache1; explain select p from t1; @@ -133,6 +141,10 @@ cache index t3 in keycache2; cache index t1,t2 in default; drop table t1,t2,t3; +show status like 'key_blocks_used'; +show status like 'The below may fail on 64-bit systems (ingo)'; +show status like 'key_blocks_unused'; # This may fail on 64-bit systems (ingo) + # Cleanup # We don't reset keycache2 as we want to ensure that mysqld will reset it set global keycache2.key_buffer_size=0; diff --git a/mysys/mf_keycache.c b/mysys/mf_keycache.c index 689391537f8..168483f276b 100644 --- a/mysys/mf_keycache.c +++ b/mysys/mf_keycache.c @@ -20,6 +20,23 @@ One cache can handle many files. It must contain buffers of the same blocksize. init_key_cache() should be used to init cache handler. + + The free list (free_block_list) is a stack like structure. + When a block is freed by free_block(), it is pushed onto the stack. + When a new block is required it is first tried to pop one from the stack. + If the stack is empty, it is tried to get a never-used block from the pool. + If this is empty too, then a block is taken from the LRU ring, flushing it + to disk, if neccessary. This is handled in find_key_block(). + With the new free list, the blocks can have three temperatures: + hot, warm and cold (which is free). This is remembered in the block header + by the enum BLOCK_TEMPERATURE temperature variable. Remembering the + temperature is neccessary to correctly count the number of warm blocks, + which is required to decide when blocks are allowed to become hot. Whenever + a block is inserted to another (sub-)chain, we take the old and new + temperature into account to decide if we got one more or less warm block. + blocks_unused is the sum of never used blocks in the pool and of currently + free blocks. blocks_used is the number of blocks fetched from the pool and + as such gives the maximum number of in-use blocks at any time. */ #include "mysys_priv.h" @@ -116,6 +133,9 @@ struct st_hash_link #define PAGE_TO_BE_READ 1 #define PAGE_WAIT_TO_BE_READ 2 +/* block temperature determines in which (sub-)chain the block currently is */ +enum BLOCK_TEMPERATURE { BLOCK_COLD /*free*/ , BLOCK_WARM , BLOCK_HOT }; + /* key cache block */ struct st_block_link { @@ -130,6 +150,7 @@ struct st_block_link uint offset; /* beginning of modified data in the buffer */ uint length; /* end of data in the buffer */ uint status; /* state of the block */ + enum BLOCK_TEMPERATURE temperature; /* block temperature: cold, warm, hot */ uint hits_left; /* number of hits left until promotion */ ulonglong last_hit_time; /* timestamp of the last hit */ KEYCACHE_CONDVAR *condvar; /* condition variable for 'no readers' event */ @@ -340,6 +361,7 @@ int init_key_cache(KEY_CACHE *keycache, uint key_cache_block_size, } blocks= blocks / 4*3; } + keycache->blocks_unused= (ulong) blocks; keycache->disk_blocks= (int) blocks; keycache->hash_links= hash_links; keycache->hash_root= (HASH_LINK**) ((char*) keycache->block_root + @@ -357,12 +379,13 @@ int init_key_cache(KEY_CACHE *keycache, uint key_cache_block_size, keycache->free_hash_list= NULL; keycache->blocks_used= keycache->blocks_changed= 0; - keycache->global_blocks_used= keycache->global_blocks_changed= 0; + keycache->global_blocks_changed= 0; keycache->blocks_available=0; /* For debugging */ /* The LRU chain is empty after initialization */ keycache->used_last= NULL; keycache->used_ins= NULL; + keycache->free_block_list= NULL; keycache->keycache_time= 0; keycache->warm_blocks= 0; keycache->min_warm_blocks= (division_limit ? @@ -596,7 +619,7 @@ void end_key_cache(KEY_CACHE *keycache, my_bool cleanup) DBUG_PRINT("status", ("used: %d changed: %d w_requests: %ld \ writes: %ld r_requests: %ld reads: %ld", - keycache->global_blocks_used, keycache->global_blocks_changed, + keycache->blocks_used, keycache->global_blocks_changed, keycache->global_cache_w_requests, keycache->global_cache_write, keycache->global_cache_r_requests, keycache->global_cache_read)); @@ -1014,7 +1037,9 @@ static inline void unreg_request(KEY_CACHE *keycache, keycache->warm_blocks > keycache->min_warm_blocks; if (hot) { - keycache->warm_blocks--; + if (block->temperature == BLOCK_WARM) + keycache->warm_blocks--; + block->temperature= BLOCK_HOT; KEYCACHE_DBUG_PRINT("unreg_request", ("#warm_blocks=%u", keycache->warm_blocks)); } @@ -1026,7 +1051,11 @@ static inline void unreg_request(KEY_CACHE *keycache, block= keycache->used_ins; unlink_block(keycache, block); link_block(keycache, block, 0, 0); - keycache->warm_blocks++; + if (block->temperature != BLOCK_WARM) + { + keycache->warm_blocks++; + block->temperature= BLOCK_WARM; + } KEYCACHE_DBUG_PRINT("unreg_request", ("#warm_blocks=%u", keycache->warm_blocks)); } @@ -1363,28 +1392,40 @@ restart: if (! block) { /* No block is assigned for the page yet */ - if (keycache->blocks_used < (uint) keycache->disk_blocks) + if (keycache->blocks_unused) { - /* There are some never used blocks, take first of them */ - hash_link->block= block= &keycache->block_root[keycache->blocks_used]; - block->buffer= ADD_TO_PTR(keycache->block_mem, - ((ulong) keycache->blocks_used* - keycache->key_cache_block_size), - byte*); + if (keycache->free_block_list) + { + /* There is a block in the free list. */ + block= keycache->free_block_list; + keycache->free_block_list= block->next_used; + block->next_used= NULL; + } + else + { + /* There are some never used blocks, take first of them */ + block= &keycache->block_root[keycache->blocks_used]; + block->buffer= ADD_TO_PTR(keycache->block_mem, + ((ulong) keycache->blocks_used* + keycache->key_cache_block_size), + byte*); + keycache->blocks_used++; + } + keycache->blocks_unused--; block->status= 0; block->length= 0; block->offset= keycache->key_cache_block_size; block->requests= 1; - keycache->blocks_used++; - keycache->global_blocks_used++; - keycache->warm_blocks++; + block->temperature= BLOCK_COLD; block->hits_left= init_hits_left; block->last_hit_time= 0; link_to_file_list(keycache, block, file, 0); block->hash_link= hash_link; + hash_link->block= block; page_status= PAGE_TO_BE_READ; KEYCACHE_DBUG_PRINT("find_key_block", - ("got never used block %u", BLOCK_NUMBER(block))); + ("got free or never used block %u", + BLOCK_NUMBER(block))); } else { @@ -2021,7 +2062,7 @@ end: /* Free block: remove reference to it from hash table, remove it from the chain file of dirty/clean blocks - and add it at the beginning of the LRU chain + and add it to the free list. */ static void free_block(KEY_CACHE *keycache, BLOCK_LINK *block) @@ -2045,6 +2086,17 @@ static void free_block(KEY_CACHE *keycache, BLOCK_LINK *block) ("block is freed")); unreg_request(keycache, block, 0); block->hash_link= NULL; + + /* Remove the free block from the LRU ring. */ + unlink_block(keycache, block); + if (block->temperature == BLOCK_WARM) + keycache->warm_blocks--; + block->temperature= BLOCK_COLD; + /* Insert the free block in the free list. */ + block->next_used= keycache->free_block_list; + keycache->free_block_list= block; + /* Keep track of the number of currently unused blocks. */ + keycache->blocks_unused++; } diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 3ae5914b439..85f6e4853bb 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -4839,8 +4839,10 @@ struct show_var_st status_vars[]= { {"Handler_discover", (char*) &ha_discover_count, SHOW_LONG}, {"Key_blocks_not_flushed", (char*) &dflt_key_cache_var.global_blocks_changed, SHOW_KEY_CACHE_LONG}, - {"Key_blocks_used", (char*) &dflt_key_cache_var.global_blocks_used, - SHOW_KEY_CACHE_LONG}, + {"Key_blocks_used", (char*) &dflt_key_cache_var.blocks_used, + SHOW_KEY_CACHE_CONST_LONG}, + {"Key_blocks_unused", (char*) &dflt_key_cache_var.blocks_unused, + SHOW_KEY_CACHE_CONST_LONG}, {"Key_read_requests", (char*) &dflt_key_cache_var.global_cache_r_requests, SHOW_KEY_CACHE_LONG}, {"Key_reads", (char*) &dflt_key_cache_var.global_cache_read, diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 448dc825a26..51b44af63ec 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -2021,6 +2021,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables, #endif /* HAVE_OPENSSL */ case SHOW_KEY_CACHE_LONG: + case SHOW_KEY_CACHE_CONST_LONG: value= (value-(char*) &dflt_key_cache_var)+ (char*) sql_key_cache; end= int10_to_str(*(long*) value, buff, 10); break; diff --git a/sql/sql_test.cc b/sql/sql_test.cc index cc3d30e5983..d992c93f8fc 100644 --- a/sql/sql_test.cc +++ b/sql/sql_test.cc @@ -329,7 +329,7 @@ reads: %10lu\n\n", name, (ulong) key_cache->param_buff_size, key_cache->param_block_size, key_cache->param_division_limit, key_cache->param_age_threshold, - key_cache->global_blocks_used,key_cache->global_blocks_changed, + key_cache->blocks_used,key_cache->global_blocks_changed, key_cache->global_cache_w_requests,key_cache->global_cache_write, key_cache->global_cache_r_requests,key_cache->global_cache_read); } diff --git a/sql/structs.h b/sql/structs.h index 86d754f00d6..d9607b220f7 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -183,7 +183,8 @@ enum SHOW_TYPE SHOW_SSL_CTX_SESS_TIMEOUTS, SHOW_SSL_CTX_SESS_CACHE_FULL, SHOW_SSL_GET_CIPHER_LIST, #endif /* HAVE_OPENSSL */ - SHOW_RPL_STATUS, SHOW_SLAVE_RUNNING, SHOW_KEY_CACHE_LONG + SHOW_RPL_STATUS, SHOW_SLAVE_RUNNING, + SHOW_KEY_CACHE_LONG, SHOW_KEY_CACHE_CONST_LONG }; enum SHOW_COMP_OPTION { SHOW_OPTION_YES, SHOW_OPTION_NO, SHOW_OPTION_DISABLED}; |