Commit 4a960979 authored by Marko Mäkelä's avatar Marko Mäkelä

Cleanup: Simplify MVCC checks

row_sel_clust_sees(): Replaces lock_clust_rec_cons_read_sees().

lock_sec_rec_cons_read_sees(): Replaced with lower-level code.
parent ffead38d
......@@ -386,37 +386,6 @@ lock_clust_rec_read_check_and_lock_alt(
que_thr_t* thr) /*!< in: query thread */
MY_ATTRIBUTE((warn_unused_result));
/*********************************************************************//**
Checks that a record is seen in a consistent read.
@return true if sees, or false if an earlier version of the record
should be retrieved */
bool
lock_clust_rec_cons_read_sees(
/*==========================*/
const rec_t* rec, /*!< in: user record which should be read or
passed over by a read cursor */
dict_index_t* index, /*!< in: clustered index */
const rec_offs* offsets,/*!< in: rec_get_offsets(rec, index) */
ReadView* view); /*!< in: consistent read view */
/*********************************************************************//**
Checks that a non-clustered index record is seen in a consistent read.
NOTE that a non-clustered index page contains so little information on
its modifications that also in the case false, the present version of
rec may be the right, but we must check this from the clustered index
record.
@return true if certainly sees, or false if an earlier version of the
clustered index record might be needed */
bool
lock_sec_rec_cons_read_sees(
/*========================*/
const rec_t* rec, /*!< in: user record which
should be read or passed over
by a read cursor */
const dict_index_t* index, /*!< in: index */
const ReadView* view) /*!< in: consistent read view */
MY_ATTRIBUTE((warn_unused_result));
/*********************************************************************//**
Locks the specified database table in the mode given. If the lock cannot
be granted immediately, the query thread is put to wait.
@return DB_SUCCESS, DB_LOCK_WAIT, or DB_DEADLOCK */
......
......@@ -360,83 +360,6 @@ lock_check_trx_id_sanity(
return true;
}
/*********************************************************************//**
Checks that a record is seen in a consistent read.
@return true if sees, or false if an earlier version of the record
should be retrieved */
bool
lock_clust_rec_cons_read_sees(
/*==========================*/
const rec_t* rec, /*!< in: user record which should be read or
passed over by a read cursor */
dict_index_t* index, /*!< in: clustered index */
const rec_offs* offsets,/*!< in: rec_get_offsets(rec, index) */
ReadView* view) /*!< in: consistent read view */
{
ut_ad(dict_index_is_clust(index));
ut_ad(page_rec_is_user_rec(rec));
ut_ad(rec_offs_validate(rec, index, offsets));
ut_ad(!rec_is_metadata(rec, *index));
/* Temp-tables are not shared across connections and multiple
transactions from different connections cannot simultaneously
operate on same temp-table and so read of temp-table is
always consistent read. */
if (index->table->is_temporary()) {
return(true);
}
/* NOTE that we call this function while holding the search
system latch. */
trx_id_t trx_id = row_get_rec_trx_id(rec, index, offsets);
return(view->changes_visible(trx_id, index->table->name));
}
/*********************************************************************//**
Checks that a non-clustered index record is seen in a consistent read.
NOTE that a non-clustered index page contains so little information on
its modifications that also in the case false, the present version of
rec may be the right, but we must check this from the clustered index
record.
@return true if certainly sees, or false if an earlier version of the
clustered index record might be needed */
bool
lock_sec_rec_cons_read_sees(
/*========================*/
const rec_t* rec, /*!< in: user record which
should be read or passed over
by a read cursor */
const dict_index_t* index, /*!< in: index */
const ReadView* view) /*!< in: consistent read view */
{
ut_ad(page_rec_is_user_rec(rec));
ut_ad(!index->is_primary());
ut_ad(!rec_is_metadata(rec, *index));
/* NOTE that we might call this function while holding the search
system latch. */
if (index->table->is_temporary()) {
/* Temp-tables are not shared across connections and multiple
transactions from different connections cannot simultaneously
operate on same temp-table and so read of temp-table is
always consistent read. */
return(true);
}
trx_id_t max_trx_id = page_get_max_trx_id(page_align(rec));
ut_ad(max_trx_id > 0);
return(view->sees(max_trx_id));
}
/**
Creates the lock system at database start.
......
......@@ -875,6 +875,25 @@ row_sel_test_other_conds(
return(TRUE);
}
/** Check that a clustered index record is visible in a consistent read view.
@param rec clustered index record (in leaf page, or in memory)
@param index clustered index
@param offsets rec_get_offsets(rec, index)
@param view consistent read view
@return whether rec is visible in view */
static bool row_sel_clust_sees(const rec_t *rec, const dict_index_t &index,
const rec_offs *offsets, const ReadView &view)
{
ut_ad(index.is_primary());
ut_ad(page_rec_is_user_rec(rec));
ut_ad(rec_offs_validate(rec, &index, offsets));
ut_ad(!rec_is_metadata(rec, index));
ut_ad(!index.table->is_temporary());
return view.changes_visible(row_get_rec_trx_id(rec, &index, offsets),
index.table->name);
}
/*********************************************************************//**
Retrieves the clustered index record corresponding to a record in a
non-clustered index. Does the necessary locking.
......@@ -977,8 +996,8 @@ row_sel_get_clust_rec(
old_vers = NULL;
if (!lock_clust_rec_cons_read_sees(clust_rec, index, offsets,
node->read_view)) {
if (!row_sel_clust_sees(clust_rec, *index, offsets,
*node->read_view)) {
err = row_sel_build_prev_vers(
node->read_view, index, clust_rec,
......@@ -1494,14 +1513,16 @@ row_sel_try_search_shortcut(
ULINT_UNDEFINED, &heap);
if (dict_index_is_clust(index)) {
if (!lock_clust_rec_cons_read_sees(rec, index, offsets,
node->read_view)) {
if (!row_sel_clust_sees(rec, *index, offsets,
*node->read_view)) {
goto retry;
}
} else if (!srv_read_only_mode) {
trx_id_t trx_id = page_get_max_trx_id(page_align(rec));
ut_ad(trx_id);
if (!node->read_view->sees(trx_id)) {
goto retry;
}
} else if (!srv_read_only_mode
&& !lock_sec_rec_cons_read_sees(
rec, index, node->read_view)) {
goto retry;
}
if (rec_get_deleted_flag(rec, dict_table_is_comp(plan->table))) {
......@@ -1851,10 +1872,9 @@ row_sel(
a previous version of the record */
if (dict_index_is_clust(index)) {
if (!lock_clust_rec_cons_read_sees(
rec, index, offsets, node->read_view)) {
if (!node->read_view->changes_visible(
row_get_rec_trx_id(rec, index, offsets),
index->table->name)) {
err = row_sel_build_prev_vers(
node->read_view, index, rec,
&offsets, &heap, &plan->old_vers_heap,
......@@ -1901,11 +1921,12 @@ row_sel(
rec = old_vers;
}
} else if (!srv_read_only_mode
&& !lock_sec_rec_cons_read_sees(
rec, index, node->read_view)) {
cons_read_requires_clust_rec = TRUE;
} else if (!srv_read_only_mode) {
trx_id_t trx_id = page_get_max_trx_id(page_align(rec));
ut_ad(trx_id);
if (!node->read_view->sees(trx_id)) {
cons_read_requires_clust_rec = TRUE;
}
}
}
......@@ -3404,13 +3425,13 @@ Row_sel_get_clust_rec_for_mysql::operator()(
old_vers = NULL;
/* If the isolation level allows reading of uncommitted data,
then we never look for an earlier version */
if (trx->isolation_level > TRX_ISO_READ_UNCOMMITTED
&& !lock_clust_rec_cons_read_sees(
clust_rec, clust_index, *offsets,
&trx->read_view)) {
if (trx->isolation_level == TRX_ISO_READ_UNCOMMITTED
|| clust_index->table->is_temporary()) {
/* If the isolation level allows reading of
uncommitted data, then we never look for an
earlier version */
} else if (!row_sel_clust_sees(clust_rec, *clust_index,
*offsets, trx->read_view)) {
const buf_page_t& bpage = btr_pcur_get_block(
prebuilt->clust_pcur)->page;
......@@ -3889,8 +3910,7 @@ row_sel_try_search_shortcut_for_mysql(
*offsets = rec_get_offsets(rec, index, *offsets, true,
ULINT_UNDEFINED, heap);
if (!lock_clust_rec_cons_read_sees(rec, index, *offsets,
&trx->read_view)) {
if (!row_sel_clust_sees(rec, *index, *offsets, trx->read_view)) {
goto retry;
}
......@@ -5192,6 +5212,7 @@ row_search_mvcc(
a previous version of the record */
if (trx->isolation_level == TRX_ISO_READ_UNCOMMITTED
|| prebuilt->table->is_temporary()
|| prebuilt->table->no_rollback()) {
/* Do nothing: we let a non-locking SELECT read the
......@@ -5204,8 +5225,8 @@ row_search_mvcc(
high force recovery level set, we try to avoid crashes
by skipping this lookup */
if (!lock_clust_rec_cons_read_sees(
rec, index, offsets, &trx->read_view)) {
if (!row_sel_clust_sees(rec, *index, offsets,
trx->read_view)) {
ut_ad(srv_force_recovery
< SRV_FORCE_NO_UNDO_LOG_SCAN);
rec_t* old_vers;
......@@ -5240,9 +5261,13 @@ row_search_mvcc(
ut_ad(!dict_index_is_clust(index));
if (!srv_read_only_mode
&& !lock_sec_rec_cons_read_sees(
rec, index, &trx->read_view)) {
if (!srv_read_only_mode) {
trx_id_t trx_id = page_get_max_trx_id(
page_align(rec));
ut_ad(trx_id);
if (trx->read_view.sees(trx_id)) {
goto locks_ok;
}
/* We should look at the clustered index.
However, as this is a non-locking read,
we can skip the clustered index lookup if
......
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