Uploaded image for project: 'MariaDB Server'
  1. MariaDB Server
  2. MDEV-27924

page_zip_copy_recs() corrupts ROW_FORMAT=COMPRESSED block descriptor

    XMLWordPrintable

    Details

      Description

      A number of innodb_zip tests crash if the preprocessor symbol UNIV_ZIP_COPY is defined. (There currently is no cmake option for enabling that.)
      Here is a simple example:

      10.6 92f79a22e63a3fef71106c64dfd8559ee9bdda4a

      innodb_zip.wl6344_compress_level '16k,innodb' [ pass ]    573
      ***Warnings generated in error logs during shutdown after running tests: innodb_zip.wl6344_compress_level
       
      mariadbd: /mariadb/10.6/storage/innobase/buf/buf0flu.cc:1212: void buf_flush_discard_page(buf_page_t*): Assertion `state == buf_page_t::FREED || state == buf_page_t::UNFIXED || state == buf_page_t::IBUF_EXIST || state == buf_page_t::REINIT' failed.
      

      The cause is that page_zip_copy_recs() is invoking the default copy constructor of page_zip_des_t, which will also overwrite the fix data member, which we only stored in the page_zip_des_t object to avoid alignment loss.

      The following fixes this block descriptor corruption that affects ROW_FORMAT=COMPRESSED pages in the event of a rather rare compression overflow:

      diff --git a/storage/innobase/include/page0types.h b/storage/innobase/include/page0types.h
      index 885d2290f7c..192e572543d 100644
      --- a/storage/innobase/include/page0types.h
      +++ b/storage/innobase/include/page0types.h
      @@ -119,6 +119,16 @@ struct page_zip_des_t
       		       - reinterpret_cast<char*>(this));
       	}
       
      +	page_zip_des_t() = default;
      +	page_zip_des_t(const page_zip_des_t&) = default;
      +
      +	/* Initialize everything except the member "fix". */
      +	page_zip_des_t(const page_zip_des_t& old, bool) {
      +		memcpy((void*) this, (void*) &old,
      +		       reinterpret_cast<char*>(&fix)
      +		       - reinterpret_cast<char*>(this));
      +	}
      +
       private:
       	friend buf_pool_t;
       	friend buf_page_t;
      diff --git a/storage/innobase/page/page0zip.cc b/storage/innobase/page/page0zip.cc
      index ec90d73e765..73124b902f2 100644
      --- a/storage/innobase/page/page0zip.cc
      +++ b/storage/innobase/page/page0zip.cc
      @@ -4562,7 +4562,7 @@ page_zip_copy_recs(
       	to the compressed data page. */
       	{
       		page_zip_t*	data = page_zip->data;
      -		new (page_zip) page_zip_des_t(*src_zip);
      +		new (page_zip) page_zip_des_t(*src_zip, false);
       		page_zip->data = data;
       	}
       	ut_ad(page_zip_get_trailer_len(page_zip, dict_index_is_clust(index))
      

      With this patch (and UNIV_ZIP_COPY), only 2 tests fail with an expected result difference (MDEV-20752):

      Failing test(s): innodb_zip.cmp_per_index innodb_zip.wl6347_comp_indx_stat
      

        Attachments

          Issue Links

            Activity

              People

              Assignee:
              marko Marko Mäkelä
              Reporter:
              marko Marko Mäkelä
              Votes:
              0 Vote for this issue
              Watchers:
              1 Start watching this issue

                Dates

                Created:
                Updated:
                Resolved:

                  Git Integration

                  Error rendering 'com.xiplink.jira.git.jira_git_plugin:git-issue-webpanel'. Please contact your Jira administrators.