summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2020-03-03 13:23:04 +0200
committerMarko Mäkelä <marko.makela@mariadb.com>2020-03-03 13:25:45 +0200
commitfae259f036e429f4667dd8b4f040e88b41a86a2b (patch)
tree0ee5a66157cfba3ca4b61870fd874747bb2001a7
parent73dfb402bfb58deaae06d4c5062b1de017e2d520 (diff)
downloadmariadb-git-fae259f036e429f4667dd8b4f040e88b41a86a2b.tar.gz
MDEV-12353: Introduce an EXTENDED record subtype TRIM_PAGES
For undo log truncation, commit 055a3334adc004bd3a897990c2f93178e6bb5f90 repurposed the MLOG_FILE_CREATE2 record with a nonzero page size to indicate that an undo tablespace will be shrunk in size. In commit 7ae21b18a6b73bbc3bf1ff448faf60c29ac1d386 the MLOG_FILE_CREATE2 record was replaced by a FILE_CREATE record. Now that the redo log encoding was changed, there is no actual need to write a file name in the log record; it suffices to write the page identifier of the first page that is not part of the file. This TRIM_PAGES record could allow us to shrink any data files in the future. For now, it will be limited to undo tablespaces. mtr_t::log_file_op(): Remove the parameter first_page_no, because it would always be 0 for file operations. mtr_t::trim_pages(): Replaces fil_truncate_log(). mtr_t::log_write(): Avoid same_page encoding if !bpage&&!m_last. fil_op_replay_rename(): Remove the constant parameter first_page_no=0.
-rw-r--r--storage/innobase/fil/fil0fil.cc66
-rw-r--r--storage/innobase/include/fil0fil.h6
-rw-r--r--storage/innobase/include/mtr0log.h15
-rw-r--r--storage/innobase/include/mtr0mtr.h6
-rw-r--r--storage/innobase/include/mtr0types.h4
-rw-r--r--storage/innobase/log/log0recv.cc41
-rw-r--r--storage/innobase/trx/trx0purge.cc2
7 files changed, 55 insertions, 85 deletions
diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc
index d9c35afd001..a7bad31078a 100644
--- a/storage/innobase/fil/fil0fil.cc
+++ b/storage/innobase/fil/fil0fil.cc
@@ -1814,23 +1814,19 @@ fil_create_directory_for_tablename(
/** Write a log record about a file operation.
@param type file operation
-@param space_id tablespace identifier
@param first_page_no first page number in the file
@param path file path
@param new_path new file path for type=FILE_RENAME */
-inline void mtr_t::log_file_op(mfile_type_t type,
- ulint space_id, ulint first_page_no,
+inline void mtr_t::log_file_op(mfile_type_t type, ulint space_id,
const char *path, const char *new_path)
{
- ut_ad(first_page_no == 0 || type == FILE_CREATE);
ut_ad((new_path != nullptr) == (type == FILE_RENAME));
ut_ad(!(byte(type) & 15));
/* fil_name_parse() requires that there be at least one path
separator and that the file path end with ".ibd". */
ut_ad(strchr(path, OS_PATH_SEPARATOR) != NULL);
- ut_ad(first_page_no /* trimming an undo tablespace */ ||
- !strcmp(&path[strlen(path) - strlen(DOT_IBD)], DOT_IBD));
+ ut_ad(!strcmp(&path[strlen(path) - strlen(DOT_IBD)], DOT_IBD));
set_modified();
if (m_log_mode != MTR_LOG_ALL)
@@ -1841,10 +1837,10 @@ inline void mtr_t::log_file_op(mfile_type_t type,
const size_t new_len= type == FILE_RENAME ? 1 + strlen(new_path) : 0;
ut_ad(len > 0);
byte *const log_ptr= m_log.open(1 + 3/*length*/ + 5/*space_id*/ +
- 5/*first_page_no*/);
+ 1/*page_no=0*/);
byte *end= log_ptr + 1;
end= mlog_encode_varint(end, space_id);
- end= mlog_encode_varint(end, first_page_no);
+ *end++= 0;
if (UNIV_LIKELY(end + len + new_len >= &log_ptr[16]))
{
*log_ptr= type;
@@ -1855,7 +1851,7 @@ inline void mtr_t::log_file_op(mfile_type_t type,
total_len++;
end= mlog_encode_varint(log_ptr + 1, total_len);
end= mlog_encode_varint(end, space_id);
- end= mlog_encode_varint(end, first_page_no);
+ *end++= 0;
}
else
{
@@ -1877,7 +1873,6 @@ inline void mtr_t::log_file_op(mfile_type_t type,
/** Write redo log for renaming a file.
@param[in] space_id tablespace id
-@param[in] first_page_no first page number in the file
@param[in] old_name tablespace file name
@param[in] new_name tablespace file name after renaming
@param[in,out] mtr mini-transaction */
@@ -1885,13 +1880,12 @@ static
void
fil_name_write_rename_low(
ulint space_id,
- ulint first_page_no,
const char* old_name,
const char* new_name,
mtr_t* mtr)
{
ut_ad(!is_predefined_tablespace(space_id));
- mtr->log_file_op(FILE_RENAME, space_id, first_page_no, old_name, new_name);
+ mtr->log_file_op(FILE_RENAME, space_id, old_name, new_name);
}
/** Write redo log for renaming a file.
@@ -1906,46 +1900,28 @@ fil_name_write_rename(
{
mtr_t mtr;
mtr.start();
- fil_name_write_rename_low(space_id, 0, old_name, new_name, &mtr);
+ fil_name_write_rename_low(space_id, old_name, new_name, &mtr);
mtr.commit();
log_write_up_to(mtr.commit_lsn(), true);
}
/** Write FILE_MODIFY for a file.
@param[in] space_id tablespace id
-@param[in] first_page_no first page number in the file
@param[in] name tablespace file name
@param[in,out] mtr mini-transaction */
static
void
fil_name_write(
ulint space_id,
- ulint first_page_no,
const char* name,
mtr_t* mtr)
{
ut_ad(!is_predefined_tablespace(space_id));
- mtr->log_file_op(FILE_MODIFY, space_id, first_page_no, name);
-}
-/** Write FILE_MODIFY for a file.
-@param[in] space tablespace
-@param[in] first_page_no first page number in the file
-@param[in] file tablespace file
-@param[in,out] mtr mini-transaction */
-static
-void
-fil_name_write(
- const fil_space_t* space,
- ulint first_page_no,
- const fil_node_t* file,
- mtr_t* mtr)
-{
- fil_name_write(space->id, first_page_no, file->name, mtr);
+ mtr->log_file_op(FILE_MODIFY, space_id, name);
}
/** Replay a file rename operation if possible.
@param[in] space_id tablespace identifier
-@param[in] first_page_no first page number in the file
@param[in] name old file name
@param[in] new_name new file name
@return whether the operation was successfully applied
@@ -1954,12 +1930,9 @@ name was successfully renamed to new_name) */
bool
fil_op_replay_rename(
ulint space_id,
- ulint first_page_no,
const char* name,
const char* new_name)
{
- ut_ad(first_page_no == 0);
-
/* In order to replay the rename, the following must hold:
* The new name is not already used.
* A tablespace exists with the old name.
@@ -2341,7 +2314,7 @@ fil_delete_tablespace(
mtr_t mtr;
mtr.start();
- mtr.log_file_op(FILE_DELETE, id, 0, path);
+ mtr.log_file_op(FILE_DELETE, id, path);
mtr.commit();
/* Even if we got killed shortly after deleting the
tablespace file, the record must have already been
@@ -2420,17 +2393,6 @@ fil_space_t* fil_truncate_prepare(ulint space_id)
return space;
}
-/** Write log about an undo tablespace truncate operation. */
-void fil_truncate_log(fil_space_t* space, ulint size, mtr_t* mtr)
-{
- /* Write a record with the new size, so that recovery and
- backup will ignore any preceding redo log records for writing
- pages that are after the new end of the tablespace. */
- ut_ad(UT_LIST_GET_LEN(space->chain) == 1);
- const fil_node_t *file= UT_LIST_GET_FIRST(space->chain);
- mtr->log_file_op(FILE_CREATE, space->id, size, file->name);
-}
-
/*******************************************************************//**
Allocates and builds a file name from a path, a table or tablespace name
and a suffix. The string must be freed by caller with ut_free().
@@ -2921,7 +2883,7 @@ err_exit:
false, true);
mtr_t mtr;
mtr.start();
- mtr.log_file_op(FILE_CREATE, space_id, 0, node->name);
+ mtr.log_file_op(FILE_CREATE, space_id, node->name);
mtr.commit();
node->find_metadata(file);
@@ -4499,7 +4461,7 @@ fil_mtr_rename_log(
}
fil_name_write_rename_low(
- old_table->space_id, 0, old_path, tmp_path, mtr);
+ old_table->space_id, old_path, tmp_path, mtr);
ut_free(tmp_path);
}
@@ -4522,7 +4484,7 @@ fil_mtr_rename_log(
}
fil_name_write_rename_low(
- new_table->space_id, 0, new_path, old_path, mtr);
+ new_table->space_id, new_path, old_path, mtr);
ut_free(old_path);
}
@@ -4562,7 +4524,7 @@ fil_names_write(
mtr_t* mtr)
{
ut_ad(UT_LIST_GET_LEN(space->chain) == 1);
- fil_name_write(space, 0, UT_LIST_GET_FIRST(space->chain), mtr);
+ fil_name_write(space->id, UT_LIST_GET_FIRST(space->chain)->name, mtr);
}
/** Note that a non-predefined persistent tablespace has been modified
@@ -4602,7 +4564,7 @@ void fil_names_dirty_and_write(fil_space_t* space)
char bogus_name[] = "./test/bogus file.ibd";
os_normalize_path(bogus_name);
fil_name_write(
- SRV_SPACE_ID_UPPER_BOUND, 0,
+ SRV_SPACE_ID_UPPER_BOUND,
bogus_name, &mtr);
});
diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h
index b57ad5cc1f5..59ef0f80c42 100644
--- a/storage/innobase/include/fil0fil.h
+++ b/storage/innobase/include/fil0fil.h
@@ -1162,7 +1162,6 @@ fil_create_directory_for_tablename(
'databasename/tablename' format */
/** Replay a file rename operation if possible.
@param[in] space_id tablespace identifier
-@param[in] first_page_no first page number in the file
@param[in] name old file name
@param[in] new_name new file name
@return whether the operation was successfully applied
@@ -1171,7 +1170,6 @@ name was successfully renamed to new_name) */
bool
fil_op_replay_rename(
ulint space_id,
- ulint first_page_no,
const char* name,
const char* new_name)
MY_ATTRIBUTE((warn_unused_result));
@@ -1204,10 +1202,6 @@ fil_delete_tablespace(
@retval NULL if the tablespace does not exist */
fil_space_t* fil_truncate_prepare(ulint space_id);
-/** Write log about an undo tablespace truncate operation. */
-void fil_truncate_log(fil_space_t* space, ulint size, mtr_t* mtr)
- MY_ATTRIBUTE((nonnull));
-
/*******************************************************************//**
Closes a single-table tablespace. The tablespace must be cached in the
memory cache. Free all pages used by the tablespace.
diff --git a/storage/innobase/include/mtr0log.h b/storage/innobase/include/mtr0log.h
index 05c92df3e03..45398f787e0 100644
--- a/storage/innobase/include/mtr0log.h
+++ b/storage/innobase/include/mtr0log.h
@@ -393,10 +393,10 @@ inline byte *mtr_t::log_write(const page_id_t id, const buf_page_t *bpage,
if (!have_len)
max_len= 1 + 5 + 5;
else if (!have_offset)
- max_len= m_last == bpage
+ max_len= bpage && m_last == bpage
? 1 + 3
: 1 + 3 + 5 + 5;
- else if (m_last == bpage && m_last_offset <= offset)
+ else if (bpage && m_last == bpage && m_last_offset <= offset)
{
/* Encode the offset relative from m_last_offset. */
offset-= m_last_offset;
@@ -631,3 +631,14 @@ inline void mtr_t::undo_append(const buf_block_t &block,
}
m_last_offset= FIL_PAGE_TYPE;
}
+
+/** Trim the end of a tablespace.
+@param id first page identifier that will not be in the file */
+inline void mtr_t::trim_pages(const page_id_t id)
+{
+ if (m_log_mode != MTR_LOG_ALL)
+ return;
+ byte *l= log_write<EXTENDED>(id, nullptr, 1, true);
+ *l++= TRIM_PAGES;
+ m_log.close(l);
+}
diff --git a/storage/innobase/include/mtr0mtr.h b/storage/innobase/include/mtr0mtr.h
index 1a270ebb975..0dae70b4235 100644
--- a/storage/innobase/include/mtr0mtr.h
+++ b/storage/innobase/include/mtr0mtr.h
@@ -556,15 +556,17 @@ struct mtr_t {
@param len length of the undo record, in bytes */
inline void undo_append(const buf_block_t &block,
const void *data, size_t len);
+ /** Trim the end of a tablespace.
+ @param id first page identifier that will not be in the file */
+ inline void trim_pages(const page_id_t id);
/** Write a log record about a file operation.
@param type file operation
@param space_id tablespace identifier
- @param first_page_no first page number in the file
@param path file path
@param new_path new file path for type=FILE_RENAME */
inline void log_file_op(mfile_type_t type, ulint space_id,
- ulint first_page_no, const char *path,
+ const char *path,
const char *new_path= nullptr);
private:
diff --git a/storage/innobase/include/mtr0types.h b/storage/innobase/include/mtr0types.h
index bae6d247d59..f110e45aad8 100644
--- a/storage/innobase/include/mtr0types.h
+++ b/storage/innobase/include/mtr0types.h
@@ -285,7 +285,9 @@ enum mrec_ext_t
and include the total size of the record being deleted.
The current byte offset will be reset to FIL_PAGE_TYPE.
This is similar to the old MLOG_COMP_REC_DELETE record. */
- DELETE_ROW_FORMAT_DYNAMIC= 9
+ DELETE_ROW_FORMAT_DYNAMIC= 9,
+ /** Truncate a data file. */
+ TRIM_PAGES= 10
};
diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc
index 40daf88ef05..faf2ea72324 100644
--- a/storage/innobase/log/log0recv.cc
+++ b/storage/innobase/log/log0recv.cc
@@ -1977,14 +1977,31 @@ same_page:
last_offset= 1; /* the next record must not be same_page */
goto free_or_init_page;
case INIT_PAGE:
- free_or_init_page:
last_offset= FIL_PAGE_TYPE;
+ free_or_init_page:
if (UNIV_UNLIKELY(rlen != 0))
goto record_corrupted;
break;
case EXTENDED:
if (UNIV_UNLIKELY(!rlen))
goto record_corrupted;
+ if (rlen == 1 && *l == TRIM_PAGES)
+ {
+#if 0 /* For now, we can only truncate an undo log tablespace */
+ if (UNIV_UNLIKELY(!space_id || !page_no))
+ goto record_corrupted;
+#else
+ if (!srv_is_undo_tablespace(space_id) ||
+ page_no != SRV_UNDO_TABLESPACE_SIZE_IN_PAGES)
+ goto record_corrupted;
+ static_assert(UT_ARR_SIZE(truncated_undo_spaces) ==
+ TRX_SYS_MAX_UNDO_SPACES, "compatibility");
+ truncated_undo_spaces[space_id - srv_undo_space_id_start]=
+ { recovered_lsn, page_no };
+#endif
+ last_offset= 1; /* the next record must not be same_page */
+ continue;
+ }
last_offset= FIL_PAGE_TYPE;
break;
case RESERVED:
@@ -2145,7 +2162,7 @@ same_page:
}
/* fall through */
case FILE_CREATE:
- if (UNIV_UNLIKELY(space_id == 0))
+ if (UNIV_UNLIKELY(!space_id || page_no))
goto file_rec_error;
/* There is no terminating NUL character. Names must end in .ibd.
For FILE_RENAME, there is a NUL between the two file names. */
@@ -2167,24 +2184,6 @@ same_page:
goto file_rec_error;
}
- if (page_no)
- {
- if (UNIV_UNLIKELY((b & 0xf0) != FILE_CREATE))
- goto file_rec_error;
- /* truncating an undo log tablespace */
- ut_ad(fnend - fn >= 7);
- ut_ad(!memcmp(fnend - 7, "undo", 4));
- ut_d(char n[4]; char *end; memcpy(n, fnend - 3, 3); n[3]= 0);
- ut_ad(strtoul(n, &end, 10) <= 127);
- ut_ad(end == &n[3]);
- ut_ad(page_no == SRV_UNDO_TABLESPACE_SIZE_IN_PAGES);
- ut_ad(srv_is_undo_tablespace(space_id));
- static_assert(UT_ARR_SIZE(truncated_undo_spaces) ==
- TRX_SYS_MAX_UNDO_SPACES, "compatibility");
- truncated_undo_spaces[space_id - srv_undo_space_id_start]=
- { recovered_lsn, page_no };
- continue;
- }
if (is_predefined_tablespace(space_id))
goto file_rec_error;
if (fnend - fn < 4 || memcmp(fnend - 4, DOT_IBD, 4))
@@ -2204,7 +2203,7 @@ same_page:
fn2 ? static_cast<ulint>(fn2end - fn2) : 0);
if (!fn2 || !apply);
- else if (!fil_op_replay_rename(space_id, 0, fn, fn2))
+ else if (!fil_op_replay_rename(space_id, fn, fn2))
found_corrupt_fs= true;
const_cast<char&>(fn[rlen])= saved_end;
if (UNIV_UNLIKELY(found_corrupt_fs))
diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc
index fa3a3fcc951..a4fb2051325 100644
--- a/storage/innobase/trx/trx0purge.cc
+++ b/storage/innobase/trx/trx0purge.cc
@@ -687,7 +687,7 @@ not_free:
const ulint size = SRV_UNDO_TABLESPACE_SIZE_IN_PAGES;
mtr.start();
mtr_x_lock_space(purge_sys.truncate.current, &mtr);
- fil_truncate_log(purge_sys.truncate.current, size, &mtr);
+ mtr.trim_pages(page_id_t(space.id, size));
fsp_header_init(purge_sys.truncate.current, size, &mtr);
mutex_enter(&fil_system.mutex);
purge_sys.truncate.current->size = file->size = size;