Commit a65020d2 authored by marko's avatar marko

branches/zip: When logging updates or deletes in the undo log, store long

enough prefixes of externally stored columns, so that purge will not have
to dereference any BLOB pointers, which may be invalid.  This will not be
necessary for logging inserts, because inserts are no-ops in purge, and
the record will remain locked during transaction rollback.

TODO: in dict_build_table_def_step() or dict_build_index_def_step(),
prevent the creation of tables with too many columns for which a
prefix index is defined.  This is because there is a size limit of undo
log records, and for each prefix-indexed column, the log must store
REC_MAX_INDEX_COL_LEN + BTR_EXTERN_FIELD_REF_SIZE bytes.

trx_undo_page_report_insert(): Assert that the index is clustered.

trx_undo_page_fetch_ext(): New function, for fetching the BLOB prefix
in trx_undo_page_report_modify().

trx_undo_page_report_modify(): Write long enough prefixes of the externally
stored columns to the undo log.

trx_undo_rec_get_partial_row(): Remove the parameter "ext".  Assert that
the undo log contains long enough prefixes of the externally stored columns.

purge_node_t: Remove the field "ext".
parent 3044ef35
...@@ -65,8 +65,6 @@ struct purge_node_struct{ ...@@ -65,8 +65,6 @@ struct purge_node_struct{
dtuple_t* row; /* NULL, or a copy (also fields copied to dtuple_t* row; /* NULL, or a copy (also fields copied to
heap) of the indexed fields of the row to heap) of the indexed fields of the row to
handle */ handle */
row_ext_t* ext; /* NULL, or prefixes of the externally
stored columns of the row */
dict_index_t* index; /* NULL, or the next index whose record should dict_index_t* index; /* NULL, or the next index whose record should
be handled */ be handled */
mem_heap_t* heap; /* memory heap used as auxiliary storage for mem_heap_t* heap; /* memory heap used as auxiliary storage for
......
...@@ -178,8 +178,6 @@ trx_undo_rec_get_partial_row( ...@@ -178,8 +178,6 @@ trx_undo_rec_get_partial_row(
record! */ record! */
dict_index_t* index, /* in: clustered index */ dict_index_t* index, /* in: clustered index */
dtuple_t** row, /* out, own: partial row */ dtuple_t** row, /* out, own: partial row */
row_ext_t** ext, /* out, own: prefix cache for
externally stored columns */
mem_heap_t* heap); /* in: memory heap from which the memory mem_heap_t* heap); /* in: memory heap from which the memory
needed is allocated */ needed is allocated */
/*************************************************************************** /***************************************************************************
......
...@@ -337,9 +337,7 @@ row_purge_del_mark( ...@@ -337,9 +337,7 @@ row_purge_del_mark(
index = node->index; index = node->index;
/* Build the index entry */ /* Build the index entry */
entry = row_build_index_entry(node->row, entry = row_build_index_entry(node->row, NULL, index, heap);
node->ext,
index, heap);
ut_a(entry); ut_a(entry);
row_purge_remove_sec_if_poss(node, index, entry); row_purge_remove_sec_if_poss(node, index, entry);
...@@ -385,7 +383,7 @@ row_purge_upd_exist_or_extern( ...@@ -385,7 +383,7 @@ row_purge_upd_exist_or_extern(
if (row_upd_changes_ord_field_binary(NULL, node->index, if (row_upd_changes_ord_field_binary(NULL, node->index,
node->update)) { node->update)) {
/* Build the older version of the index entry */ /* Build the older version of the index entry */
entry = row_build_index_entry(node->row, node->ext, entry = row_build_index_entry(node->row, NULL,
index, heap); index, heap);
ut_a(entry); ut_a(entry);
row_purge_remove_sec_if_poss(node, index, entry); row_purge_remove_sec_if_poss(node, index, entry);
...@@ -562,9 +560,7 @@ row_purge_parse_undo_rec( ...@@ -562,9 +560,7 @@ row_purge_parse_undo_rec(
if (!(cmpl_info & UPD_NODE_NO_ORD_CHANGE)) { if (!(cmpl_info & UPD_NODE_NO_ORD_CHANGE)) {
ptr = trx_undo_rec_get_partial_row(ptr, clust_index, ptr = trx_undo_rec_get_partial_row(ptr, clust_index,
&node->row, &node->row, node->heap);
&node->ext,
node->heap);
} }
return(TRUE); return(TRUE);
......
...@@ -202,6 +202,7 @@ trx_undo_page_report_insert( ...@@ -202,6 +202,7 @@ trx_undo_page_report_insert(
byte* ptr; byte* ptr;
ulint i; ulint i;
ut_ad(dict_index_is_clust(index));
ut_ad(mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR ut_ad(mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR
+ TRX_UNDO_PAGE_TYPE) == TRX_UNDO_INSERT); + TRX_UNDO_PAGE_TYPE) == TRX_UNDO_INSERT);
...@@ -402,6 +403,35 @@ trx_undo_rec_skip_row_ref( ...@@ -402,6 +403,35 @@ trx_undo_rec_skip_row_ref(
return(ptr); return(ptr);
} }
/**************************************************************************
Fetch a prefix of an externally stored column, for writing to the undo log
of an update or delete marking of a clustered index record. */
static
byte*
trx_undo_page_fetch_ext(
/*====================*/
/* out: ext_buf */
byte* ext_buf, /* in: a buffer of
REC_MAX_INDEX_COL_LEN
+ BTR_EXTERN_FIELD_REF_SIZE */
ulint zip_size, /* compressed page size in bytes,
or 0 for uncompressed BLOB */
const byte* field, /* in: an externally stored column */
ulint* len) /* in: length of field;
out: used length of ext_buf */
{
/* Fetch the BLOB. */
ulint ext_len = btr_copy_externally_stored_field_prefix(
ext_buf, REC_MAX_INDEX_COL_LEN, zip_size, field, *len);
ut_a(ext_len);
/* Append the BLOB pointer to the prefix. */
memcpy(ext_buf + ext_len,
field + *len - BTR_EXTERN_FIELD_REF_SIZE,
BTR_EXTERN_FIELD_REF_SIZE);
*len = ext_len + BTR_EXTERN_FIELD_REF_SIZE;
return(ext_buf);
}
/************************************************************************** /**************************************************************************
Reports in the undo log of an update or delete marking of a clustered index Reports in the undo log of an update or delete marking of a clustered index
record. */ record. */
...@@ -435,6 +465,8 @@ trx_undo_page_report_modify( ...@@ -435,6 +465,8 @@ trx_undo_page_report_modify(
ulint type_cmpl; ulint type_cmpl;
byte* type_cmpl_ptr; byte* type_cmpl_ptr;
ulint i; ulint i;
byte ext_buf[REC_MAX_INDEX_COL_LEN
+ BTR_EXTERN_FIELD_REF_SIZE];
ut_a(dict_index_is_clust(index)); ut_a(dict_index_is_clust(index));
ut_ad(rec_offs_validate(rec, index, offsets)); ut_ad(rec_offs_validate(rec, index, offsets));
...@@ -505,7 +537,11 @@ trx_undo_page_report_modify( ...@@ -505,7 +537,11 @@ trx_undo_page_report_modify(
field = rec_get_nth_field(rec, offsets, i, &flen); field = rec_get_nth_field(rec, offsets, i, &flen);
if (trx_undo_left(undo_page, ptr) < 4) { /* The ordering columns must not be stored externally. */
ut_ad(!rec_offs_nth_extern(offsets, i));
ut_ad(dict_index_get_nth_col(index, i)->ord_part);
if (trx_undo_left(undo_page, ptr) < 5) {
return(0); return(0);
} }
...@@ -555,6 +591,18 @@ trx_undo_page_report_modify( ...@@ -555,6 +591,18 @@ trx_undo_page_report_modify(
} }
if (rec_offs_nth_extern(offsets, pos)) { if (rec_offs_nth_extern(offsets, pos)) {
/* If an ordering field has external
storage, we will store a longer
prefix of the field. */
if (dict_index_get_nth_col(index,
pos)->ord_part) {
field = trx_undo_page_fetch_ext(
ext_buf,
dict_table_zip_size(table),
field, &flen);
}
/* If a field has external storage, we add /* If a field has external storage, we add
to flen the flag */ to flen the flag */
...@@ -637,6 +685,15 @@ trx_undo_page_report_modify( ...@@ -637,6 +685,15 @@ trx_undo_page_report_modify(
&flen); &flen);
if (rec_offs_nth_extern(offsets, pos)) { if (rec_offs_nth_extern(offsets, pos)) {
/* If an ordering field has external
storage, we will store a longer
prefix of the field. */
field = trx_undo_page_fetch_ext(
ext_buf,
dict_table_zip_size(table),
field, &flen);
/* If a field has external /* If a field has external
storage, we add to flen the flag */ storage, we add to flen the flag */
...@@ -884,15 +941,11 @@ trx_undo_rec_get_partial_row( ...@@ -884,15 +941,11 @@ trx_undo_rec_get_partial_row(
record! */ record! */
dict_index_t* index, /* in: clustered index */ dict_index_t* index, /* in: clustered index */
dtuple_t** row, /* out, own: partial row */ dtuple_t** row, /* out, own: partial row */
row_ext_t** ext, /* out, own: prefix cache for
externally stored columns */
mem_heap_t* heap) /* in: memory heap from which the memory mem_heap_t* heap) /* in: memory heap from which the memory
needed is allocated */ needed is allocated */
{ {
const byte* end_ptr; const byte* end_ptr;
ulint row_len; ulint row_len;
ulint n_ext_cols;
ulint* ext_cols;
ut_ad(index); ut_ad(index);
ut_ad(ptr); ut_ad(ptr);
...@@ -901,8 +954,6 @@ trx_undo_rec_get_partial_row( ...@@ -901,8 +954,6 @@ trx_undo_rec_get_partial_row(
ut_ad(dict_index_is_clust(index)); ut_ad(dict_index_is_clust(index));
row_len = dict_table_get_n_cols(index->table); row_len = dict_table_get_n_cols(index->table);
n_ext_cols = 0;
ext_cols = mem_heap_alloc(heap, row_len * sizeof *ext_cols);
*row = dtuple_create(heap, row_len); *row = dtuple_create(heap, row_len);
...@@ -935,23 +986,16 @@ trx_undo_rec_get_partial_row( ...@@ -935,23 +986,16 @@ trx_undo_rec_get_partial_row(
dfield_set_len(dfield, dfield_set_len(dfield,
len - UNIV_EXTERN_STORAGE_FIELD); len - UNIV_EXTERN_STORAGE_FIELD);
dfield_set_ext(dfield); dfield_set_ext(dfield);
if (col->ord_part) { /* If the prefix of this column is indexed,
/* We will have to fetch prefixes of ensure that enough prefix is stored in the
externally stored columns that are undo log record. */
referenced by column prefixes. */ ut_a(!col->ord_part
ext_cols[n_ext_cols++] = col_no; || dfield_get_len(dfield)
} >= REC_MAX_INDEX_COL_LEN
+ BTR_EXTERN_FIELD_REF_SIZE);
} }
} }
if (n_ext_cols) {
*ext = row_ext_create(n_ext_cols, ext_cols, *row,
dict_table_zip_size(index->table),
heap);
} else {
*ext = NULL;
}
return(ptr); return(ptr);
} }
......
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