@@ -493,7 +493,8 @@ static my_bool info_check_lock(PAGECACHE_BLOCK_LINK *block,
493493
494494#define FLUSH_CACHE 2000 /* sort this many blocks at once */
495495
496- static void free_block (PAGECACHE * pagecache , PAGECACHE_BLOCK_LINK * block );
496+ static my_bool free_block (PAGECACHE * pagecache , PAGECACHE_BLOCK_LINK * block ,
497+ my_bool abort_if_pinned );
497498static void unlink_hash (PAGECACHE * pagecache , PAGECACHE_HASH_LINK * hash_link );
498499#ifndef DBUG_OFF
499500static void test_key_cache (PAGECACHE * pagecache ,
@@ -1939,7 +1940,7 @@ static PAGECACHE_BLOCK_LINK *find_block(PAGECACHE *pagecache,
19391940 removed from the cache as we set the PCBLOCK_REASSIGNED
19401941 flag (see the code below that handles reading requests).
19411942 */
1942- free_block (pagecache , block );
1943+ free_block (pagecache , block , 0 );
19431944 return 0 ;
19441945 }
19451946 /* Wait until the page is flushed on disk */
@@ -1950,7 +1951,7 @@ static PAGECACHE_BLOCK_LINK *find_block(PAGECACHE *pagecache,
19501951 /* Invalidate page in the block if it has not been done yet */
19511952 DBUG_ASSERT (block -> status ); /* Should always be true */
19521953 if (block -> status )
1953- free_block (pagecache , block );
1954+ free_block (pagecache , block , 0 );
19541955 return 0 ;
19551956 }
19561957
@@ -1975,8 +1976,13 @@ static PAGECACHE_BLOCK_LINK *find_block(PAGECACHE *pagecache,
19751976 }
19761977 else
19771978 {
1978- DBUG_ASSERT (hash_link -> requests > 0 );
1979- hash_link -> requests -- ;
1979+ /*
1980+ When we come here either PCBLOCK_REASSIGNED or PCBLOCK_IN_SWITCH are
1981+ active. In both cases wqueue_release_queue() is called when the
1982+ state changes.
1983+ */
1984+ DBUG_ASSERT (block -> hash_link == hash_link );
1985+ remove_reader (block );
19801986 KEYCACHE_DBUG_PRINT ("find_block" ,
19811987 ("request waiting for old page to be saved" ));
19821988 {
@@ -3635,7 +3641,7 @@ static my_bool pagecache_delete_internal(PAGECACHE *pagecache,
36353641 DBUG_ASSERT (block -> hash_link -> requests > 0 );
36363642 page_link -> requests -- ;
36373643 /* See NOTE for pagecache_unlock() about registering requests. */
3638- free_block (pagecache , block );
3644+ free_block (pagecache , block , 0 );
36393645 dec_counter_for_resize_op (pagecache );
36403646 return 0 ;
36413647
@@ -4227,7 +4233,8 @@ my_bool pagecache_write_part(PAGECACHE *pagecache,
42274233 and add it to the free list.
42284234*/
42294235
4230- static void free_block (PAGECACHE * pagecache , PAGECACHE_BLOCK_LINK * block )
4236+ static my_bool free_block (PAGECACHE * pagecache , PAGECACHE_BLOCK_LINK * block ,
4237+ my_bool abort_if_pinned )
42314238{
42324239 uint status = block -> status ;
42334240 KEYCACHE_THREAD_TRACE ("free block" );
@@ -4241,11 +4248,27 @@ static void free_block(PAGECACHE *pagecache, PAGECACHE_BLOCK_LINK *block)
42414248 /*
42424249 While waiting for readers to finish, new readers might request the
42434250 block. But since we set block->status|= PCBLOCK_REASSIGNED, they
4244- will wait on block->wqueue[COND_FOR_SAVED]. They must be signalled
4251+ will wait on block->wqueue[COND_FOR_SAVED]. They must be signaled
42454252 later.
42464253 */
42474254 block -> status |= PCBLOCK_REASSIGNED ;
42484255 wait_for_readers (pagecache , block );
4256+ if (unlikely (abort_if_pinned ) && unlikely (block -> pins ))
4257+ {
4258+ /*
4259+ Block got pinned while waiting for readers.
4260+ This can only happens when called from flush_pagecache_blocks_int()
4261+ when flushing blocks as part of prepare for maria_close() or from
4262+ flush_cached_blocks()
4263+ */
4264+ block -> status &= ~PCBLOCK_REASSIGNED ;
4265+ unreg_request (pagecache , block , 0 );
4266+
4267+ /* All pending requests for this page must be resubmitted. */
4268+ if (block -> wqueue [COND_FOR_SAVED ].last_thread )
4269+ wqueue_release_queue (& block -> wqueue [COND_FOR_SAVED ]);
4270+ return 1 ;
4271+ }
42494272 unlink_hash (pagecache , block -> hash_link );
42504273 }
42514274
@@ -4296,6 +4319,8 @@ static void free_block(PAGECACHE *pagecache, PAGECACHE_BLOCK_LINK *block)
42964319 /* All pending requests for this page must be resubmitted. */
42974320 if (block -> wqueue [COND_FOR_SAVED ].last_thread )
42984321 wqueue_release_queue (& block -> wqueue [COND_FOR_SAVED ]);
4322+
4323+ return 0 ;
42994324}
43004325
43014326
@@ -4431,9 +4456,16 @@ static int flush_cached_blocks(PAGECACHE *pagecache,
44314456 if (! (type == FLUSH_KEEP || type == FLUSH_KEEP_LAZY ||
44324457 type == FLUSH_FORCE_WRITE ))
44334458 {
4434- pagecache -> blocks_changed -- ;
4435- pagecache -> global_blocks_changed -- ;
4436- free_block (pagecache , block );
4459+ if (!free_block (pagecache , block , 1 ))
4460+ {
4461+ pagecache -> blocks_changed -- ;
4462+ pagecache -> global_blocks_changed -- ;
4463+ }
4464+ else
4465+ {
4466+ block -> status &= ~PCBLOCK_IN_FLUSH ;
4467+ link_to_file_list (pagecache , block , file , 1 );
4468+ }
44374469 }
44384470 else
44394471 {
@@ -4671,7 +4703,7 @@ static int flush_pagecache_blocks_int(PAGECACHE *pagecache,
46714703 /* It's a temporary file */
46724704 pagecache -> blocks_changed -- ;
46734705 pagecache -> global_blocks_changed -- ;
4674- free_block (pagecache , block );
4706+ free_block (pagecache , block , 0 );
46754707 }
46764708 }
46774709 else if (type != FLUSH_KEEP_LAZY )
@@ -4741,11 +4773,12 @@ static int flush_pagecache_blocks_int(PAGECACHE *pagecache,
47414773#endif
47424774 next = block -> next_changed ;
47434775 if (block -> hash_link -> file .file == file -> file &&
4776+ !block -> pins &&
47444777 (! (block -> status & PCBLOCK_CHANGED )
47454778 || type == FLUSH_IGNORE_CHANGED ))
47464779 {
47474780 reg_requests (pagecache , block , 1 );
4748- free_block (pagecache , block );
4781+ free_block (pagecache , block , 1 );
47494782 }
47504783 }
47514784 }
0 commit comments