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{
dtuple_t* row; /* NULL, or a copy (also fields copied to
heap) of the indexed fields of the row to
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
be handled */
mem_heap_t* heap; /* memory heap used as auxiliary storage for
......
......@@ -178,8 +178,6 @@ trx_undo_rec_get_partial_row(
record! */
dict_index_t* index, /* in: clustered index */
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
needed is allocated */
/***************************************************************************
......
......@@ -337,9 +337,7 @@ row_purge_del_mark(
index = node->index;
/* Build the index entry */
entry = row_build_index_entry(node->row,
node->ext,
index, heap);
entry = row_build_index_entry(node->row, NULL, index, heap);
ut_a(entry);
row_purge_remove_sec_if_poss(node, index, entry);
......@@ -385,7 +383,7 @@ row_purge_upd_exist_or_extern(
if (row_upd_changes_ord_field_binary(NULL, node->index,
node->update)) {
/* 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);
ut_a(entry);
row_purge_remove_sec_if_poss(node, index, entry);
......@@ -562,9 +560,7 @@ row_purge_parse_undo_rec(
if (!(cmpl_info & UPD_NODE_NO_ORD_CHANGE)) {
ptr = trx_undo_rec_get_partial_row(ptr, clust_index,
&node->row,
&node->ext,
node->heap);
&node->row, node->heap);
}
return(TRUE);
......
......@@ -202,6 +202,7 @@ trx_undo_page_report_insert(
byte* ptr;
ulint i;
ut_ad(dict_index_is_clust(index));
ut_ad(mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR
+ TRX_UNDO_PAGE_TYPE) == TRX_UNDO_INSERT);
......@@ -402,6 +403,35 @@ trx_undo_rec_skip_row_ref(
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
record. */
......@@ -435,6 +465,8 @@ trx_undo_page_report_modify(
ulint type_cmpl;
byte* type_cmpl_ptr;
ulint i;
byte ext_buf[REC_MAX_INDEX_COL_LEN
+ BTR_EXTERN_FIELD_REF_SIZE];
ut_a(dict_index_is_clust(index));
ut_ad(rec_offs_validate(rec, index, offsets));
......@@ -505,7 +537,11 @@ trx_undo_page_report_modify(
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);
}
......@@ -555,6 +591,18 @@ trx_undo_page_report_modify(
}
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
to flen the flag */
......@@ -637,6 +685,15 @@ trx_undo_page_report_modify(
&flen);
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
storage, we add to flen the flag */
......@@ -884,15 +941,11 @@ trx_undo_rec_get_partial_row(
record! */
dict_index_t* index, /* in: clustered index */
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
needed is allocated */
{
const byte* end_ptr;
ulint row_len;
ulint n_ext_cols;
ulint* ext_cols;
ut_ad(index);
ut_ad(ptr);
......@@ -901,8 +954,6 @@ trx_undo_rec_get_partial_row(
ut_ad(dict_index_is_clust(index));
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);
......@@ -935,23 +986,16 @@ trx_undo_rec_get_partial_row(
dfield_set_len(dfield,
len - UNIV_EXTERN_STORAGE_FIELD);
dfield_set_ext(dfield);
if (col->ord_part) {
/* We will have to fetch prefixes of
externally stored columns that are
referenced by column prefixes. */
ext_cols[n_ext_cols++] = col_no;
}
/* If the prefix of this column is indexed,
ensure that enough prefix is stored in the
undo log record. */
ut_a(!col->ord_part
|| 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);
}
......
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