Commit 1103abda authored by Daniel Black's avatar Daniel Black Committed by Sergey Vojtovich

keycache: restructure functions that are controlled by arguements

finish_resize_simple_key_cache removed argument acquire for acquiring
locks.

resize_simple_key_cache enforces assertion that the cache is inited.

read_block was really two functions, primary and secondary so separated
as such. Make the callers of read_block explictly use the required function.
Signed-off-by: default avatarDaniel Black <daniel@linux.vnet.ibm.com>
parent 0750b5f8
...@@ -749,7 +749,6 @@ int prepare_resize_simple_key_cache(SIMPLE_KEY_CACHE_CB *keycache, ...@@ -749,7 +749,6 @@ int prepare_resize_simple_key_cache(SIMPLE_KEY_CACHE_CB *keycache,
SYNOPSIS SYNOPSIS
finish_resize_simple_key_cache() finish_resize_simple_key_cache()
keycache pointer to the control block of a simple key cache keycache pointer to the control block of a simple key cache
acquire_lock <=> acquire the key cache lock at start
DESCRIPTION DESCRIPTION
This function performs finalizing actions for the operation of This function performs finalizing actions for the operation of
...@@ -757,8 +756,6 @@ int prepare_resize_simple_key_cache(SIMPLE_KEY_CACHE_CB *keycache, ...@@ -757,8 +756,6 @@ int prepare_resize_simple_key_cache(SIMPLE_KEY_CACHE_CB *keycache,
keycache as a pointer to the control block structure of the type keycache as a pointer to the control block structure of the type
SIMPLE_KEY_CACHE_CB for this key cache. The function sets the flag SIMPLE_KEY_CACHE_CB for this key cache. The function sets the flag
in_resize in this structure to FALSE. in_resize in this structure to FALSE.
The parameter acquire_lock says whether the key cache lock must be
acquired at the start of the function.
RETURN VALUE RETURN VALUE
none none
...@@ -770,14 +767,10 @@ int prepare_resize_simple_key_cache(SIMPLE_KEY_CACHE_CB *keycache, ...@@ -770,14 +767,10 @@ int prepare_resize_simple_key_cache(SIMPLE_KEY_CACHE_CB *keycache,
*/ */
static static
void finish_resize_simple_key_cache(SIMPLE_KEY_CACHE_CB *keycache, void finish_resize_simple_key_cache(SIMPLE_KEY_CACHE_CB *keycache)
my_bool acquire_lock)
{ {
DBUG_ENTER("finish_resize_simple_key_cache"); DBUG_ENTER("finish_resize_simple_key_cache");
if (acquire_lock)
keycache_pthread_mutex_lock(&keycache->cache_lock);
mysql_mutex_assert_owner(&keycache->cache_lock); mysql_mutex_assert_owner(&keycache->cache_lock);
/* /*
...@@ -849,8 +842,7 @@ int resize_simple_key_cache(SIMPLE_KEY_CACHE_CB *keycache, ...@@ -849,8 +842,7 @@ int resize_simple_key_cache(SIMPLE_KEY_CACHE_CB *keycache,
int blocks= 0; int blocks= 0;
DBUG_ENTER("resize_simple_key_cache"); DBUG_ENTER("resize_simple_key_cache");
if (!keycache->key_cache_inited) DBUG_ASSERT(keycache->key_cache_inited);
DBUG_RETURN(blocks);
/* /*
Note that the cache_lock mutex and the resize_queue are left untouched. Note that the cache_lock mutex and the resize_queue are left untouched.
...@@ -866,7 +858,7 @@ int resize_simple_key_cache(SIMPLE_KEY_CACHE_CB *keycache, ...@@ -866,7 +858,7 @@ int resize_simple_key_cache(SIMPLE_KEY_CACHE_CB *keycache,
changed_blocks_hash_size); changed_blocks_hash_size);
finish: finish:
finish_resize_simple_key_cache(keycache, 0); finish_resize_simple_key_cache(keycache);
DBUG_RETURN(blocks); DBUG_RETURN(blocks);
} }
...@@ -2611,12 +2603,11 @@ static BLOCK_LINK *find_key_block(SIMPLE_KEY_CACHE_CB *keycache, ...@@ -2611,12 +2603,11 @@ static BLOCK_LINK *find_key_block(SIMPLE_KEY_CACHE_CB *keycache,
SYNOPSIS SYNOPSIS
read_block() read_block_{primary|secondary}()
keycache pointer to a key cache data structure keycache pointer to a key cache data structure
block block to which buffer the data is to be read block block to which buffer the data is to be read
read_length size of data to be read read_length size of data to be read
min_length at least so much data must be read min_length at least so much data must be read
primary <-> the current thread will read the data
RETURN VALUE RETURN VALUE
None None
...@@ -2630,90 +2621,100 @@ static BLOCK_LINK *find_key_block(SIMPLE_KEY_CACHE_CB *keycache, ...@@ -2630,90 +2621,100 @@ static BLOCK_LINK *find_key_block(SIMPLE_KEY_CACHE_CB *keycache,
portion is less than read_length, but not less than min_length. portion is less than read_length, but not less than min_length.
*/ */
static void read_block(SIMPLE_KEY_CACHE_CB *keycache, static void read_block_primary(SIMPLE_KEY_CACHE_CB *keycache,
BLOCK_LINK *block, uint read_length, BLOCK_LINK *block, uint read_length,
uint min_length, my_bool primary) uint min_length)
{ {
size_t got_length; size_t got_length;
/* On entry cache_lock is locked */ /* On entry cache_lock is locked */
KEYCACHE_THREAD_TRACE("read_block"); KEYCACHE_THREAD_TRACE("read_block_primary");
if (primary)
{ /*
/* This code is executed only by threads that submitted primary
This code is executed only by threads that submitted primary requests. Until block->status contains BLOCK_READ, all other
requests. Until block->status contains BLOCK_READ, all other request for the block become secondary requests. For a primary
request for the block become secondary requests. For a primary request the block must be properly initialized.
request the block must be properly initialized. */
*/ DBUG_ASSERT(((block->status & ~BLOCK_FOR_UPDATE) == BLOCK_IN_USE) ||
DBUG_ASSERT(((block->status & ~BLOCK_FOR_UPDATE) == BLOCK_IN_USE) || fail_block(block));
fail_block(block)); DBUG_ASSERT((block->length == 0) || fail_block(block));
DBUG_ASSERT((block->length == 0) || fail_block(block)); DBUG_ASSERT((block->offset == keycache->key_cache_block_size) ||
DBUG_ASSERT((block->offset == keycache->key_cache_block_size) || fail_block(block));
fail_block(block)); DBUG_ASSERT((block->requests > 0) || fail_block(block));
DBUG_ASSERT((block->requests > 0) || fail_block(block));
KEYCACHE_DBUG_PRINT("read_block_primary",
KEYCACHE_DBUG_PRINT("read_block", ("page to be read by primary request"));
("page to be read by primary request"));
keycache->global_cache_read++;
keycache->global_cache_read++; /* Page is not in buffer yet, is to be read from disk */
/* Page is not in buffer yet, is to be read from disk */ keycache_pthread_mutex_unlock(&keycache->cache_lock);
keycache_pthread_mutex_unlock(&keycache->cache_lock); /*
/* Here other threads may step in and register as secondary readers.
Here other threads may step in and register as secondary readers. They will register in block->wqueue[COND_FOR_REQUESTED].
They will register in block->wqueue[COND_FOR_REQUESTED]. */
*/ got_length= my_pread(block->hash_link->file, block->buffer,
got_length= my_pread(block->hash_link->file, block->buffer, read_length, block->hash_link->diskpos, MYF(0));
read_length, block->hash_link->diskpos, MYF(0)); keycache_pthread_mutex_lock(&keycache->cache_lock);
keycache_pthread_mutex_lock(&keycache->cache_lock); /*
/* The block can now have been marked for free (in case of
The block can now have been marked for free (in case of FLUSH_RELEASE). Otherwise the state must be unchanged.
FLUSH_RELEASE). Otherwise the state must be unchanged. */
*/ DBUG_ASSERT(((block->status & ~(BLOCK_REASSIGNED |
DBUG_ASSERT(((block->status & ~(BLOCK_REASSIGNED | BLOCK_FOR_UPDATE)) == BLOCK_IN_USE) ||
BLOCK_FOR_UPDATE)) == BLOCK_IN_USE) || fail_block(block));
fail_block(block)); DBUG_ASSERT((block->length == 0) || fail_block(block));
DBUG_ASSERT((block->length == 0) || fail_block(block)); DBUG_ASSERT((block->offset == keycache->key_cache_block_size) ||
DBUG_ASSERT((block->offset == keycache->key_cache_block_size) || fail_block(block));
fail_block(block)); DBUG_ASSERT((block->requests > 0) || fail_block(block));
DBUG_ASSERT((block->requests > 0) || fail_block(block));
if (got_length < min_length)
if (got_length < min_length) block->status|= BLOCK_ERROR;
block->status|= BLOCK_ERROR;
else
{
block->status|= BLOCK_READ;
block->length= got_length;
/*
Do not set block->offset here. If this block is marked
BLOCK_CHANGED later, we want to flush only the modified part. So
only a writer may set block->offset down from
keycache->key_cache_block_size.
*/
}
KEYCACHE_DBUG_PRINT("read_block",
("primary request: new page in cache"));
/* Signal that all pending requests for this page now can be processed */
release_whole_queue(&block->wqueue[COND_FOR_REQUESTED]);
}
else else
{ {
block->status|= BLOCK_READ;
block->length= got_length;
/* /*
This code is executed only by threads that submitted secondary Do not set block->offset here. If this block is marked
requests. At this point it could happen that the cache block is BLOCK_CHANGED later, we want to flush only the modified part. So
not yet assigned to the hash_link for the requested file block. only a writer may set block->offset down from
But at awake from the wait this should be the case. Unfortunately keycache->key_cache_block_size.
we cannot assert this here because we do not know the hash_link
for the requested file block nor the file and position. So we have
to assert this in the caller.
*/ */
KEYCACHE_DBUG_PRINT("read_block",
("secondary request waiting for new page to be read"));
wait_on_queue(&block->wqueue[COND_FOR_REQUESTED], &keycache->cache_lock);
KEYCACHE_DBUG_PRINT("read_block",
("secondary request: new page in cache"));
} }
KEYCACHE_DBUG_PRINT("read_block_primary",
("primary request: new page in cache"));
/* Signal that all pending requests for this page now can be processed */
release_whole_queue(&block->wqueue[COND_FOR_REQUESTED]);
DBUG_ASSERT(keycache->can_be_used);
}
static void read_block_secondary(SIMPLE_KEY_CACHE_CB *keycache,
BLOCK_LINK *block)
{
KEYCACHE_THREAD_TRACE("read_block_secondary");
/*
This code is executed only by threads that submitted secondary
requests. At this point it could happen that the cache block is
not yet assigned to the hash_link for the requested file block.
But at awake from the wait this should be the case. Unfortunately
we cannot assert this here because we do not know the hash_link
for the requested file block nor the file and position. So we have
to assert this in the caller.
*/
KEYCACHE_DBUG_PRINT("read_block_secondary",
("secondary request waiting for new page to be read"));
wait_on_queue(&block->wqueue[COND_FOR_REQUESTED], &keycache->cache_lock);
KEYCACHE_DBUG_PRINT("read_block_secondary",
("secondary request: new page in cache"));
DBUG_ASSERT(keycache->can_be_used);
DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
} }
...@@ -2858,22 +2859,24 @@ uchar *simple_key_cache_read(SIMPLE_KEY_CACHE_CB *keycache, ...@@ -2858,22 +2859,24 @@ uchar *simple_key_cache_read(SIMPLE_KEY_CACHE_CB *keycache,
} }
if (!(block->status & BLOCK_ERROR)) if (!(block->status & BLOCK_ERROR))
{ {
if (page_st != PAGE_READ) if (page_st == PAGE_TO_BE_READ)
{
MYSQL_KEYCACHE_READ_MISS();
read_block_primary(keycache, block,
keycache->key_cache_block_size, read_length+offset);
}
else if (page_st == PAGE_WAIT_TO_BE_READ)
{ {
MYSQL_KEYCACHE_READ_MISS(); MYSQL_KEYCACHE_READ_MISS();
/* The requested page is to be read into the block buffer */ /* The requested page is to be read into the block buffer */
read_block(keycache, block, read_block_secondary(keycache, block);
keycache->key_cache_block_size, read_length+offset,
(my_bool)(page_st == PAGE_TO_BE_READ));
/* /*
A secondary request must now have the block assigned to the A secondary request must now have the block assigned to the
requested file block. It does not hurt to check it for requested file block.
primary requests too.
*/ */
DBUG_ASSERT(keycache->can_be_used);
DBUG_ASSERT(block->hash_link->file == file); DBUG_ASSERT(block->hash_link->file == file);
DBUG_ASSERT(block->hash_link->diskpos == filepos); DBUG_ASSERT(block->hash_link->diskpos == filepos);
DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
} }
else if (block->length < read_length + offset) else if (block->length < read_length + offset)
{ {
...@@ -3077,23 +3080,30 @@ int simple_key_cache_insert(SIMPLE_KEY_CACHE_CB *keycache, ...@@ -3077,23 +3080,30 @@ int simple_key_cache_insert(SIMPLE_KEY_CACHE_CB *keycache,
} }
if (!(block->status & BLOCK_ERROR)) if (!(block->status & BLOCK_ERROR))
{ {
if ((page_st == PAGE_WAIT_TO_BE_READ) || if (page_st == PAGE_WAIT_TO_BE_READ)
((page_st == PAGE_TO_BE_READ) &&
(offset || (read_length < keycache->key_cache_block_size))))
{ {
/* /*
Either
this is a secondary request for a block to be read into the this is a secondary request for a block to be read into the
cache. The block is in eviction. It is not yet assigned to cache. The block is in eviction. It is not yet assigned to
the requested file block (It does not point to the right the requested file block (It does not point to the right
hash_link). So we cannot call remove_reader() on the block. hash_link). So we cannot call remove_reader() on the block.
And we cannot access the hash_link directly here. We need to And we cannot access the hash_link directly here. We need to
wait until the assignment is complete. read_block() executes wait until the assignment is complete. read_block_secondary()
the correct wait when called with primary == FALSE. executes the correct wait.
*/
Or read_block_secondary(keycache, block);
/*
A secondary request must now have the block assigned to the
requested file block.
*/
DBUG_ASSERT(block->hash_link->file == file);
DBUG_ASSERT(block->hash_link->diskpos == filepos);
}
else if (page_st == PAGE_TO_BE_READ &&
(offset || (read_length < keycache->key_cache_block_size)))
{
/*
this is a primary request for a block to be read into the this is a primary request for a block to be read into the
cache and the supplied data does not fill the whole block. cache and the supplied data does not fill the whole block.
...@@ -3108,17 +3118,8 @@ int simple_key_cache_insert(SIMPLE_KEY_CACHE_CB *keycache, ...@@ -3108,17 +3118,8 @@ int simple_key_cache_insert(SIMPLE_KEY_CACHE_CB *keycache,
Though reading again what the caller did read already is an Though reading again what the caller did read already is an
expensive operation, we need to do this for correctness. expensive operation, we need to do this for correctness.
*/ */
read_block(keycache, block, keycache->key_cache_block_size, read_block_primary(keycache, block, keycache->key_cache_block_size,
read_length + offset, (page_st == PAGE_TO_BE_READ)); read_length + offset);
/*
A secondary request must now have the block assigned to the
requested file block. It does not hurt to check it for
primary requests too.
*/
DBUG_ASSERT(keycache->can_be_used);
DBUG_ASSERT(block->hash_link->file == file);
DBUG_ASSERT(block->hash_link->diskpos == filepos);
DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE));
} }
else if (page_st == PAGE_TO_BE_READ) else if (page_st == PAGE_TO_BE_READ)
{ {
...@@ -3413,25 +3414,29 @@ int simple_key_cache_write(SIMPLE_KEY_CACHE_CB *keycache, ...@@ -3413,25 +3414,29 @@ int simple_key_cache_write(SIMPLE_KEY_CACHE_CB *keycache,
reading the file block. If the read completes after us, it reading the file block. If the read completes after us, it
overwrites our new contents with the old contents. So we have to overwrites our new contents with the old contents. So we have to
wait for the other thread to complete the read of this block. wait for the other thread to complete the read of this block.
read_block() takes care for the wait. read_block_primary|secondary() takes care for the wait.
*/ */
if (!(block->status & BLOCK_ERROR) && if (!(block->status & BLOCK_ERROR))
((page_st == PAGE_TO_BE_READ &&
(offset || read_length < keycache->key_cache_block_size)) ||
(page_st == PAGE_WAIT_TO_BE_READ)))
{ {
read_block(keycache, block, if (page_st == PAGE_TO_BE_READ &&
offset + read_length >= keycache->key_cache_block_size? (offset || read_length < keycache->key_cache_block_size))
offset : keycache->key_cache_block_size, {
offset, (page_st == PAGE_TO_BE_READ)); read_block_primary(keycache, block,
DBUG_ASSERT(keycache->can_be_used); offset + read_length >= keycache->key_cache_block_size?
DBUG_ASSERT(block->status & (BLOCK_READ | BLOCK_IN_USE)); offset : keycache->key_cache_block_size,
/* offset);
Prevent block from flushing and from being selected for to be /*
freed. This must be set when we release the cache_lock. Prevent block from flushing and from being selected for to be
Here we set it in case we could not set it above. freed. This must be set when we release the cache_lock.
*/ Here we set it in case we could not set it above.
block->status|= BLOCK_FOR_UPDATE; */
block->status|= BLOCK_FOR_UPDATE;
}
else if (page_st == PAGE_WAIT_TO_BE_READ)
{
read_block_secondary(keycache, block);
block->status|= BLOCK_FOR_UPDATE;
}
} }
/* /*
The block should always be assigned to the requested file block The block should always be assigned to the requested file block
...@@ -5279,7 +5284,8 @@ int resize_partitioned_key_cache(PARTITIONED_KEY_CACHE_CB *keycache, ...@@ -5279,7 +5284,8 @@ int resize_partitioned_key_cache(PARTITIONED_KEY_CACHE_CB *keycache,
{ {
for (i= 0; i < partitions; i++) for (i= 0; i < partitions; i++)
{ {
finish_resize_simple_key_cache(keycache->partition_array[i], 1); keycache_pthread_mutex_lock(&keycache->partition_array[i]->cache_lock);
finish_resize_simple_key_cache(keycache->partition_array[i]);
} }
} }
DBUG_RETURN(blocks); DBUG_RETURN(blocks);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment