Bug #74152 Make freeing index trees more idempotent
Submitted: 30 Sep 2014 9:29 Modified: 14 Oct 2014 22:22
Reporter: Marko Mäkelä Email Updates:
Status: Closed Impact on me:
None 
Category:MySQL Server: InnoDB storage engine Severity:S3 (Non-critical)
Version:5.7.5 OS:Any
Assigned to: CPU Architecture:Any

[30 Sep 2014 9:29] Marko Mäkelä
Description:
The logic for freeing index trees in InnoDB is a little messy.

The recently introduced function fil_index_tree_is_freed()
is inherently unsafe. The problem with this function is that
we would return a false negative when the index root page has
been reallocated for something else.

The safe way to detect if a root page was freed is to check
the contents and to initialize the root page when dropping it.

Also, there is a redundant parameter is_drop=true passed to
dict_drop_index_tree().

How to repeat:
See Description.

Suggested fix:
Remove fil_index_tree_is_freed().
Remove the redundant parameter is_drop=true.

Write an idempotent function btr_free_if_exists()
that will initialize the index tree root page afterwards,
and do nothing if the page is not an index page containing
the expected PAGE_INDEX_ID.
[9 Oct 2014 19:42] Daniel Price
Posted by developer:
 
 Bug#19710798 MAKE FREEING INDEX TREES MORE IDEMPOTENT
  
  The logic for freeing index trees in InnoDB is a little messy.
  
  The recently introduced function fil_index_tree_is_freed()
  is inherently unsafe. The problem with this function is that
  we would return a false negative when the index root page has
  been reallocated for something else.
  
  The safe way to detect if a root page was freed is to check
  the contents and to initialize the root page when dropping it.
  
  Also, there is a redundant parameter is_drop=true passed to
  dict_drop_index_tree().
  
  fil_index_tree_is_freed(): Remove.
  dict_drop_index_tree(): Remove the parameter is_drop=true.
  
  btr_free_if_exists(): Idempotently free an index tree.
  Does nothing if the page is not an index page containing
  the expected PAGE_INDEX_ID. After deleting, initializes
  the page so that a repeated call would do nothing.
  
  dict_drop_index_tree(): Return whether freeing was attempted.
  
  BTR_FREED_INDEX_ID: The index ID of freed root pages (0).
  This ID is guaranteed to be unassigned, because the
  sequence DICT_HDR_INDEX_ID starts from DICT_HDR_FIRST_ID (10).
  
  btr_free_root_check(): Get an index root page that matches an index ID,
  or NULL if there is no match.
  
  btr_free_root_invalidate(): Make btr_free_root_check() fail by
  setting PAGE_INDEX_ID to BTR_FREED_INDEX_ID.
  
  page_is_root(): New predicate, for checking if a page is
  an index root page.
  
  rb#6865 approved by Vasil Dimov and Kevin Lewis
[14 Oct 2014 22:22] Daniel Price
Fixed as of the upcoming 5.7.6 release, and here's the changelog entry:

The "fil_index_tree_is_freed()" function, which would return a false
negative when the index root page was reallocated, has been replaced by
improved logic for freeing index trees. This patch also removed a
redundant parameter that was passed to "dict_drop_index_tree()".