summaryrefslogtreecommitdiff
path: root/storage/innobase/row/row0vers.cc
diff options
context:
space:
mode:
Diffstat (limited to 'storage/innobase/row/row0vers.cc')
-rw-r--r--storage/innobase/row/row0vers.cc242
1 files changed, 200 insertions, 42 deletions
diff --git a/storage/innobase/row/row0vers.cc b/storage/innobase/row/row0vers.cc
index da342701d4b..fd17683fb48 100644
--- a/storage/innobase/row/row0vers.cc
+++ b/storage/innobase/row/row0vers.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1997, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1997, 2016, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -53,16 +53,20 @@ Created 2/6/1997 Heikki Tuuri
the cluster index
@param[in] index the secondary index
@param[in] row the cluster index row in dtuple form
+@param[in] ext externally stored column prefix or NULL
@param[in] ientry the secondary index entry
+@param[in,out] heap heap used to build virtual dtuple
@param[in,out] n_non_v_col number of non-virtual columns in the index
@return true if all matches, false otherwise */
static
bool
row_vers_non_vc_match(
- dict_index_t* index,
- const dtuple_t* row,
- const dtuple_t* ientry,
- ulint* n_non_v_col);
+ dict_index_t* index,
+ const dtuple_t* row,
+ const row_ext_t* ext,
+ const dtuple_t* ientry,
+ mem_heap_t* heap,
+ ulint* n_non_v_col);
/*****************************************************************//**
Finds out if an active transaction has inserted or modified a secondary
index record.
@@ -90,6 +94,8 @@ row_vers_impl_x_locked_low(
ulint* clust_offsets;
mem_heap_t* heap;
dtuple_t* ientry = NULL;
+ mem_heap_t* v_heap = NULL;
+ const dtuple_t* cur_vrow = NULL;
DBUG_ENTER("row_vers_impl_x_locked_low");
@@ -126,7 +132,14 @@ row_vers_impl_x_locked_low(
if (dict_index_has_virtual(index)) {
ulint n_ext;
- ientry = row_rec_to_index_entry(rec, index, offsets, &n_ext, heap);
+ ulint est_size = DTUPLE_EST_ALLOC(index->n_fields);
+
+ /* Allocate the dtuple for virtual columns extracted from undo
+ log with its own heap, so to avoid it being freed as we
+ iterating in the version loop below. */
+ v_heap = mem_heap_create(est_size);
+ ientry = row_rec_to_index_entry(
+ rec, index, offsets, &n_ext, v_heap);
}
/* We look up if some earlier version, which was modified by
@@ -148,7 +161,6 @@ row_vers_impl_x_locked_low(
trx_id_t prev_trx_id;
mem_heap_t* old_heap = heap;
const dtuple_t* vrow = NULL;
- bool skip_cmp = false;
/* We keep the semaphore in mtr on the clust_rec page, so
that no other transaction can update it and get an
@@ -215,28 +227,34 @@ row_vers_impl_x_locked_low(
NULL, NULL, NULL, &ext, heap);
if (dict_index_has_virtual(index)) {
- if (!vrow) {
- ulint n_non_v_col = 0;
+ if (vrow) {
+ /* Keep the virtual row info for the next
+ version */
+ cur_vrow = dtuple_copy(vrow, v_heap);
+ dtuple_dup_v_fld(cur_vrow, v_heap);
+ }
- if (!row_vers_non_vc_match(
- index, row, ientry, &n_non_v_col)) {
- if (!rec_del) {
- break;
- }
- }
+ if (!cur_vrow) {
+ ulint n_non_v_col = 0;
/* If the indexed virtual columns has changed,
there must be log record to generate vrow.
Otherwise, it is not changed, so no need
to compare */
- skip_cmp = true;
- if (rec_del != vers_del) {
+ if (row_vers_non_vc_match(
+ index, row, ext, ientry, heap,
+ &n_non_v_col) == 0) {
+ if (rec_del != vers_del) {
+ break;
+ }
+ } else if (!rec_del) {
break;
}
+
goto result_check;
} else {
- ut_ad(row->n_v_fields == vrow->n_v_fields);
- dtuple_copy_v_fields(row, vrow);
+ ut_ad(row->n_v_fields == cur_vrow->n_v_fields);
+ dtuple_copy_v_fields(row, cur_vrow);
}
}
@@ -260,7 +278,7 @@ row_vers_impl_x_locked_low(
/* We check if entry and rec are identified in the alphabetical
ordering */
- if (!skip_cmp && 0 == cmp_dtuple_rec(entry, rec, offsets)) {
+ if (0 == cmp_dtuple_rec(entry, rec, offsets)) {
/* The delete marks of rec and prev_version should be
equal for rec to be in the state required by
prev_version */
@@ -303,6 +321,10 @@ result_check:
DBUG_PRINT("info", ("Implicit lock is held by trx:" TRX_ID_FMT, trx_id));
+ if (v_heap != NULL) {
+ mem_heap_free(v_heap);
+ }
+
mem_heap_free(heap);
DBUG_RETURN(trx);
}
@@ -394,16 +416,20 @@ row_vers_must_preserve_del_marked(
the cluster index
@param[in] index the secondary index
@param[in] row the cluster index row in dtuple form
+@param[in] ext externally stored column prefix or NULL
@param[in] ientry the secondary index entry
+@param[in,out] heap heap used to build virtual dtuple
@param[in,out] n_non_v_col number of non-virtual columns in the index
@return true if all matches, false otherwise */
static
bool
row_vers_non_vc_match(
- dict_index_t* index,
- const dtuple_t* row,
- const dtuple_t* ientry,
- ulint* n_non_v_col)
+ dict_index_t* index,
+ const dtuple_t* row,
+ const row_ext_t* ext,
+ const dtuple_t* ientry,
+ mem_heap_t* heap,
+ ulint* n_non_v_col)
{
const dfield_t* field1;
dfield_t* field2;
@@ -412,20 +438,23 @@ row_vers_non_vc_match(
*n_non_v_col = 0;
+ /* Build index entry out of row */
+ dtuple_t* nentry = row_build_index_entry(row, ext, index, heap);
+
for (ulint i = 0; i < n_fields; i++) {
const dict_field_t* ind_field = dict_index_get_nth_field(
index, i);
const dict_col_t* col = ind_field->col;
+ /* Only check non-virtual columns */
if (dict_col_is_virtual(col)) {
continue;
}
if (ret) {
field1 = dtuple_get_nth_field(ientry, i);
- field2 = dtuple_get_nth_field(
- row, dict_col_get_no(col));
+ field2 = dtuple_get_nth_field(nentry, i);
if (cmp_dfield_dfield(field1, field2) != 0) {
ret = false;
@@ -438,9 +467,10 @@ row_vers_non_vc_match(
return(ret);
}
+#ifdef MYSQL_VIRTUAL_COLUMNS
/** build virtual column value from current cluster index record data
@param[in,out] row the cluster index row in dtuple form
-@param[in] clust_index cluster index
+@param[in] clust_index clustered index
@param[in] index the secondary index
@param[in] heap heap used to build virtual dtuple */
static
@@ -463,8 +493,9 @@ row_vers_build_clust_v_col(
ind_field->col);
innobase_get_computed_value(
- row, col, clust_index, NULL, &local_heap,
- heap, NULL, true);
+ row, col, clust_index, &local_heap,
+ heap, NULL, current_thd, NULL, NULL,
+ NULL, NULL);
}
}
@@ -472,6 +503,114 @@ row_vers_build_clust_v_col(
mem_heap_free(local_heap);
}
}
+/** Build latest virtual column data from undo log
+@param[in] in_purge whether this is the purge thread
+@param[in] rec clustered index record
+@param[in] clust_index clustered index
+@param[in,out] clust_offsets offsets on the clustered index record
+@param[in] index the secondary index
+@param[in] roll_ptr the rollback pointer for the purging record
+@param[in] trx_id trx id for the purging record
+@param[in,out] v_heap heap used to build vrow
+@param[out] v_row dtuple holding the virtual rows
+@param[in,out] mtr mtr holding the latch on rec */
+static
+void
+row_vers_build_cur_vrow_low(
+ bool in_purge,
+ const rec_t* rec,
+ dict_index_t* clust_index,
+ ulint* clust_offsets,
+ dict_index_t* index,
+ roll_ptr_t roll_ptr,
+ trx_id_t trx_id,
+ mem_heap_t* v_heap,
+ const dtuple_t**vrow,
+ mtr_t* mtr)
+{
+ const rec_t* version;
+ rec_t* prev_version;
+ mem_heap_t* heap = NULL;
+ ulint num_v = dict_table_get_n_v_cols(index->table);
+ const dfield_t* field;
+ ulint i;
+ bool all_filled = false;
+
+ *vrow = dtuple_create_with_vcol(v_heap, 0, num_v);
+ dtuple_init_v_fld(*vrow);
+
+ for (i = 0; i < num_v; i++) {
+ dfield_get_type(dtuple_get_nth_v_field(*vrow, i))->mtype
+ = DATA_MISSING;
+ }
+
+ version = rec;
+
+ /* If this is called by purge thread, set TRX_UNDO_PREV_IN_PURGE
+ bit to search the undo log until we hit the current undo log with
+ roll_ptr */
+ const ulint status = in_purge
+ ? TRX_UNDO_PREV_IN_PURGE | TRX_UNDO_GET_OLD_V_VALUE
+ : TRX_UNDO_GET_OLD_V_VALUE;
+
+ while (!all_filled) {
+ mem_heap_t* heap2 = heap;
+ heap = mem_heap_create(1024);
+ roll_ptr_t cur_roll_ptr = row_get_rec_roll_ptr(
+ version, clust_index, clust_offsets);
+
+ trx_undo_prev_version_build(
+ rec, mtr, version, clust_index, clust_offsets,
+ heap, &prev_version, NULL, vrow, status);
+
+ if (heap2) {
+ mem_heap_free(heap2);
+ }
+
+ if (!prev_version) {
+ /* Versions end here */
+ break;
+ }
+
+ clust_offsets = rec_get_offsets(prev_version, clust_index,
+ NULL, ULINT_UNDEFINED, &heap);
+
+ ulint entry_len = dict_index_get_n_fields(index);
+
+ all_filled = true;
+
+ for (i = 0; i < entry_len; i++) {
+ const dict_field_t* ind_field
+ = dict_index_get_nth_field(index, i);
+ const dict_col_t* col = ind_field->col;
+
+ if (!dict_col_is_virtual(col)) {
+ continue;
+ }
+
+ const dict_v_col_t* v_col
+ = reinterpret_cast<const dict_v_col_t*>(col);
+ field = dtuple_get_nth_v_field(*vrow, v_col->v_pos);
+
+ if (dfield_get_type(field)->mtype == DATA_MISSING) {
+ all_filled = false;
+ break;
+ }
+
+ }
+
+ trx_id_t rec_trx_id = row_get_rec_trx_id(
+ prev_version, clust_index, clust_offsets);
+
+ if (rec_trx_id < trx_id || roll_ptr == cur_roll_ptr) {
+ break;
+ }
+
+ version = prev_version;
+ }
+
+ mem_heap_free(heap);
+}
/** Check a virtual column value index secondary virtual index matches
that of current cluster index record, which is recreated from information
@@ -479,6 +618,7 @@ stored in undo log
@param[in] in_purge called by purge thread
@param[in] rec record in the clustered index
@param[in] row the cluster index row in dtuple form
+@param[in] ext externally stored column prefix or NULL
@param[in] clust_index cluster index
@param[in] clust_offsets offsets on the cluster record
@param[in] index the secondary index
@@ -495,6 +635,7 @@ row_vers_vc_matches_cluster(
bool in_purge,
const rec_t* rec,
const dtuple_t* row,
+ row_ext_t* ext,
dict_index_t* clust_index,
ulint* clust_offsets,
dict_index_t* index,
@@ -519,15 +660,17 @@ row_vers_vc_matches_cluster(
dfield_t* field2;
ulint i;
+ tuple_heap = mem_heap_create(1024);
+
/* First compare non-virtual columns (primary keys) */
- if (!row_vers_non_vc_match(index, row, ientry, &n_non_v_col)) {
+ if (!row_vers_non_vc_match(index, row, ext, ientry, tuple_heap,
+ &n_non_v_col)) {
+ mem_heap_free(tuple_heap);
return(false);
}
ut_ad(n_fields > n_non_v_col);
- tuple_heap = mem_heap_create(1024);
-
*vrow = dtuple_create_with_vcol(v_heap ? v_heap : tuple_heap, 0, num_v);
dtuple_init_v_fld(*vrow);
@@ -551,6 +694,9 @@ row_vers_vc_matches_cluster(
roll_ptr_t cur_roll_ptr = row_get_rec_roll_ptr(
version, clust_index, clust_offsets);
+ ut_ad(cur_roll_ptr != 0);
+ ut_ad(in_purge == (roll_ptr != 0));
+
trx_undo_prev_version_build(
rec, mtr, version, clust_index, clust_offsets,
heap, &prev_version, NULL, vrow, status);
@@ -663,11 +809,6 @@ row_vers_build_cur_vrow(
mtr_t* mtr)
{
const dtuple_t* cur_vrow = NULL;
- row_ext_t* ext;
-
- dtuple_t* row = row_build(ROW_COPY_POINTERS, clust_index,
- rec, *clust_offsets,
- NULL, NULL, NULL, &ext, heap);
roll_ptr_t t_roll_ptr = row_get_rec_roll_ptr(
rec, clust_index, *clust_offsets);
@@ -675,21 +816,32 @@ row_vers_build_cur_vrow(
/* if the row is newly inserted, then the virtual
columns need to be computed */
if (trx_undo_roll_ptr_is_insert(t_roll_ptr)) {
+
+ ut_ad(!rec_get_deleted_flag(rec, page_rec_is_comp(rec)));
+
+ /* This is a newly inserted record and cannot
+ be deleted, So the externally stored field
+ cannot be freed yet. */
+ dtuple_t* row = row_build(ROW_COPY_POINTERS, clust_index,
+ rec, *clust_offsets,
+ NULL, NULL, NULL, NULL, heap);
+
row_vers_build_clust_v_col(
row, clust_index, index, heap);
cur_vrow = dtuple_copy(row, v_heap);
dtuple_dup_v_fld(cur_vrow, v_heap);
} else {
- row_vers_vc_matches_cluster(
- in_purge, rec, row, clust_index, *clust_offsets,
- index, ientry, roll_ptr,
- trx_id, v_heap, &cur_vrow, mtr);
+ /* Try to fetch virtual column data from undo log */
+ row_vers_build_cur_vrow_low(
+ in_purge, rec, clust_index, *clust_offsets,
+ index, roll_ptr, trx_id, v_heap, &cur_vrow, mtr);
}
*clust_offsets = rec_get_offsets(rec, clust_index, NULL,
ULINT_UNDEFINED, &heap);
return(cur_vrow);
}
+#endif /* MYSQL_VIRTUAL_COLUMNS */
/*****************************************************************//**
Finds out if a version of the record, where the version >= the current
@@ -760,6 +912,9 @@ row_vers_old_has_index_entry(
NULL, NULL, NULL, &ext, heap);
if (dict_index_has_virtual(index)) {
+
+#ifdef MYSQL_VIRTUAL_COLUMNS
+
#ifdef DBUG_OFF
# define dbug_v_purge false
#else /* DBUG_OFF */
@@ -794,7 +949,7 @@ row_vers_old_has_index_entry(
}
} else {
if (row_vers_vc_matches_cluster(
- also_curr, rec, row, clust_index,
+ also_curr, rec, row, ext, clust_index,
clust_offsets, index, ientry, roll_ptr,
trx_id, NULL, &vrow, mtr)) {
mem_heap_free(heap);
@@ -808,6 +963,7 @@ row_vers_old_has_index_entry(
}
clust_offsets = rec_get_offsets(rec, clust_index, NULL,
ULINT_UNDEFINED, &heap);
+#endif /* MYSQL_VIRTUAL_COLUMNS */
} else {
entry = row_build_index_entry(
@@ -845,6 +1001,7 @@ row_vers_old_has_index_entry(
}
}
} else if (dict_index_has_virtual(index)) {
+#ifdef MYSQL_VIRTUAL_COLUMNS
/* The current cluster index record could be
deleted, but the previous version of it might not. We will
need to get the virtual column data from undo record
@@ -852,6 +1009,7 @@ row_vers_old_has_index_entry(
cur_vrow = row_vers_build_cur_vrow(
also_curr, rec, clust_index, &clust_offsets,
index, ientry, roll_ptr, trx_id, heap, v_heap, mtr);
+#endif /* MYSQL_VIRTUAL_COLUMNS */
}
version = rec;