[FIX] Using start_log_ts in keepalive log to check upper_trans_version calc
This commit is contained in:
@ -176,13 +176,13 @@ void ObTxDataTable::stop()
|
||||
|
||||
void ObTxDataTable::reset()
|
||||
{
|
||||
min_start_log_ts_in_ctx_ = 0;
|
||||
last_update_min_start_log_ts_ = 0;
|
||||
tablet_id_ = 0;
|
||||
ls_ = nullptr;
|
||||
ls_tablet_svr_ = nullptr;
|
||||
memtable_mgr_ = nullptr;
|
||||
tx_ctx_table_ = nullptr;
|
||||
calc_upper_info_.reset();
|
||||
calc_upper_trans_version_cache_.reset();
|
||||
memtables_cache_.reuse();
|
||||
slice_allocator_.purge_extra_cached_block(0);
|
||||
is_started_ = false;
|
||||
@ -205,8 +205,7 @@ int ObTxDataTable::offline()
|
||||
} else if (OB_FAIL(clean_memtables_cache_())) {
|
||||
STORAGE_LOG(WARN, "clean memtables cache failed", KR(ret), KPC(this));
|
||||
} else {
|
||||
min_start_log_ts_in_ctx_ = 0;
|
||||
last_update_min_start_log_ts_ = 0;
|
||||
calc_upper_info_.reset();
|
||||
calc_upper_trans_version_cache_.reset();
|
||||
}
|
||||
return ret;
|
||||
@ -854,6 +853,7 @@ int ObTxDataTable::get_upper_trans_version_before_given_log_ts(const int64_t sst
|
||||
K(upper_trans_version));
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -978,52 +978,108 @@ int ObTxDataTable::DEBUG_calc_with_row_iter_(ObStoreRowIterator *row_iter,
|
||||
return ret;
|
||||
}
|
||||
|
||||
// This function is implemented for two reasons : accuracy and performance of upper_trans_version
|
||||
// calculation.
|
||||
//
|
||||
// 1. Accuracy :
|
||||
// If there are some running transactions with start_log_ts which is less than or equal to
|
||||
// sstable_end_log_ts, we skip this upper_trans_version calculation because it is currently
|
||||
// undetermined.
|
||||
//
|
||||
// 2. Performance :
|
||||
// If there are some commited transactions with start_log_ts which is less than or equal to
|
||||
// sstable_end_log_ts stil in tx data memtable, we skip this upper_trans_version calculation because
|
||||
// calculating upper_trans_version in tx data memtable is very slow.
|
||||
bool ObTxDataTable::skip_this_sstable_end_log_ts_(int64_t sstable_end_log_ts)
|
||||
bool ObTxDataTable::skip_this_sstable_end_log_ts_(const int64_t sstable_end_log_ts)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
bool need_skip = false;
|
||||
int64_t cur_ts = common::ObTimeUtility::fast_current_time();
|
||||
int64_t tmp_update_ts = ATOMIC_LOAD(&last_update_min_start_log_ts_);
|
||||
int64_t min_start_ts_in_tx_data_memtable = INT64_MAX;
|
||||
int64_t max_decided_log_ts = 0;
|
||||
|
||||
// make sure the max decided log ts is greater than sstable_end_log_ts
|
||||
if (OB_FAIL(ls_->get_max_decided_log_ts_ns(max_decided_log_ts))) {
|
||||
STORAGE_LOG(WARN, "get max decided log ts failed", KR(ret), "ls_id", get_ls_id().id());
|
||||
} else if (max_decided_log_ts < sstable_end_log_ts) {
|
||||
need_skip = true;
|
||||
STORAGE_LOG(INFO, "skip calc upper trans version once", K(max_decided_log_ts), K(sstable_end_log_ts));
|
||||
STORAGE_LOG(WARN, "get max decided log ts failed", KR(ret), "ls_id", get_ls_id().id());
|
||||
}
|
||||
|
||||
// If the min_start_log_ts_in_ctx has not been updated for more than 30 seconds,
|
||||
// check if the min_start_log_ts_in_ctx is larger than sstable_end_log_ts
|
||||
if (need_skip) {
|
||||
} else if (cur_ts - tmp_update_ts > 30_s
|
||||
&& tmp_update_ts == ATOMIC_CAS(&last_update_min_start_log_ts_, tmp_update_ts, cur_ts)) {
|
||||
// update last_update_min_start_log_ts
|
||||
if (OB_FAIL(tx_ctx_table_->get_min_start_log_ts(min_start_log_ts_in_ctx_))) {
|
||||
STORAGE_LOG(WARN, "get min start log ts from tx ctx table failed.", KR(ret));
|
||||
} else if (OB_FAIL(check_min_start_in_ctx_(sstable_end_log_ts, max_decided_log_ts, need_skip))) {
|
||||
need_skip = true;
|
||||
STORAGE_LOG(WARN, "check min start in ctx failed", KR(ret), KP(this), K(sstable_end_log_ts));
|
||||
}
|
||||
|
||||
if (need_skip) {
|
||||
} else if (OB_FAIL(check_min_start_in_tx_data_(sstable_end_log_ts, min_start_ts_in_tx_data_memtable, need_skip))) {
|
||||
need_skip = true;
|
||||
STORAGE_LOG(WARN, "check min start in tx data failed", KR(ret), KP(this), K(sstable_end_log_ts));
|
||||
}
|
||||
|
||||
if (!need_skip) {
|
||||
STORAGE_LOG(INFO,
|
||||
"do calculate upper trans version.",
|
||||
K(need_skip),
|
||||
K(sstable_end_log_ts),
|
||||
K(max_decided_log_ts),
|
||||
K(calc_upper_info_),
|
||||
K(min_start_ts_in_tx_data_memtable));
|
||||
}
|
||||
|
||||
return need_skip;
|
||||
}
|
||||
|
||||
int ObTxDataTable::check_min_start_in_ctx_(const int64_t sstable_end_log_ts,
|
||||
const int64_t max_decided_log_ts,
|
||||
bool &need_skip)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
bool need_update_info = false;
|
||||
int64_t cur_ts = common::ObTimeUtility::fast_current_time();
|
||||
|
||||
{
|
||||
SpinRLockGuard lock_guard(calc_upper_info_.lock_);
|
||||
if (calc_upper_info_.min_start_scn_in_ctx_ <= sstable_end_log_ts ||
|
||||
calc_upper_info_.keep_alive_scn_ >= max_decided_log_ts) {
|
||||
need_skip = true;
|
||||
}
|
||||
|
||||
if (cur_ts - calc_upper_info_.update_ts_ > 30_s && max_decided_log_ts > calc_upper_info_.keep_alive_scn_) {
|
||||
need_update_info = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (need_skip) {
|
||||
} else if (OB_FAIL(ret)) {
|
||||
need_skip = true;
|
||||
} else if (min_start_log_ts_in_ctx_ <= sstable_end_log_ts) {
|
||||
// skip this sstable end log ts calculation
|
||||
need_skip = true;
|
||||
} else if (OB_FAIL(update_memtables_cache())) {
|
||||
if (need_update_info) {
|
||||
update_calc_upper_info_(max_decided_log_ts);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ObTxDataTable::update_calc_upper_info_(const int64_t max_decided_log_ts)
|
||||
{
|
||||
int64_t cur_ts = common::ObTimeUtility::fast_current_time();
|
||||
SpinWLockGuard lock_guard(calc_upper_info_.lock_);
|
||||
// recheck update condition and do update calc_upper_info
|
||||
if (cur_ts - calc_upper_info_.update_ts_ > 30_s && max_decided_log_ts > calc_upper_info_.keep_alive_scn_) {
|
||||
int64_t min_start_scn = 0;
|
||||
int64_t keep_alive_scn = 0;
|
||||
MinStartScnStatus status;
|
||||
ls_->get_min_start_scn(min_start_scn, keep_alive_scn, status);
|
||||
switch (status) {
|
||||
case MinStartScnStatus::UNKOWN:
|
||||
// do nothing
|
||||
break;
|
||||
case MinStartScnStatus::NO_CTX:
|
||||
// use the last keep_alive_scn as min_start_scn
|
||||
calc_upper_info_.min_start_scn_in_ctx_ = calc_upper_info_.keep_alive_scn_;
|
||||
calc_upper_info_.keep_alive_scn_ = keep_alive_scn;
|
||||
calc_upper_info_.update_ts_ = cur_ts;
|
||||
break;
|
||||
case MinStartScnStatus::HAS_CTX:
|
||||
calc_upper_info_.min_start_scn_in_ctx_ = min_start_scn;
|
||||
calc_upper_info_.keep_alive_scn_ = keep_alive_scn;
|
||||
calc_upper_info_.update_ts_ = cur_ts;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int ObTxDataTable::check_min_start_in_tx_data_(const int64_t sstable_end_log_ts,
|
||||
int64_t &min_start_ts_in_tx_data_memtable,
|
||||
bool &need_skip)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
if (OB_FAIL(update_memtables_cache())) {
|
||||
STORAGE_LOG(WARN, "update memtables fail.", KR(ret));
|
||||
// something wrong happend, skip calculation
|
||||
need_skip = true;
|
||||
@ -1035,15 +1091,17 @@ bool ObTxDataTable::skip_this_sstable_end_log_ts_(int64_t sstable_end_log_ts)
|
||||
tx_data_memtable = nullptr;
|
||||
if (OB_FAIL(memtable_handles.at(i).get_tx_data_memtable(tx_data_memtable))) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
STORAGE_LOG(ERROR, "get tx data memtable from table handles fail.", KR(ret), KP(this),
|
||||
K(tablet_id_), K(memtable_handles.at(i)));
|
||||
STORAGE_LOG(ERROR,
|
||||
"get tx data memtable from table handles fail.",
|
||||
KR(ret),
|
||||
KP(this),
|
||||
K(tablet_id_),
|
||||
K(memtable_handles.at(i)));
|
||||
} else if (OB_ISNULL(tx_data_memtable)) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
STORAGE_LOG(ERROR, "tx data memtable is nullptr.", KR(ret), KP(this), K(tablet_id_),
|
||||
K(memtable_handles.at(i)));
|
||||
} else if (FALSE_IT(min_start_ts_in_tx_data_memtable
|
||||
= std::min(min_start_ts_in_tx_data_memtable,
|
||||
tx_data_memtable->get_min_start_log_ts()))) {
|
||||
STORAGE_LOG(ERROR, "tx data memtable is nullptr.", KR(ret), KP(this), K(tablet_id_), K(memtable_handles.at(i)));
|
||||
} else if (FALSE_IT(min_start_ts_in_tx_data_memtable =
|
||||
std::min(min_start_ts_in_tx_data_memtable, tx_data_memtable->get_min_start_log_ts()))) {
|
||||
} else if (sstable_end_log_ts >= min_start_ts_in_tx_data_memtable) {
|
||||
// there is a min_start_log_ts in tx_data_memtable less than sstable_end_log_ts, skip this
|
||||
// calculation
|
||||
@ -1051,17 +1109,9 @@ bool ObTxDataTable::skip_this_sstable_end_log_ts_(int64_t sstable_end_log_ts)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!need_skip) {
|
||||
|
||||
STORAGE_LOG(INFO, "check skip upper trans version calculation finish.", K(need_skip),
|
||||
K(sstable_end_log_ts), K(min_start_log_ts_in_ctx_),
|
||||
K(min_start_ts_in_tx_data_memtable));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return need_skip;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ObTxDataTable::update_cache_if_needed_(bool &skip_calc)
|
||||
@ -1072,19 +1122,21 @@ int ObTxDataTable::update_cache_if_needed_(bool &skip_calc)
|
||||
if (OB_FAIL(ls_tablet_svr_->get_tablet(LS_TX_DATA_TABLET, tablet_handle))) {
|
||||
STORAGE_LOG(WARN, "get tablet from ls tablet service failed.", KR(ret));
|
||||
} else {
|
||||
ObITable *table
|
||||
= tablet_handle.get_obj()->get_table_store().get_minor_sstables().get_boundary_table(
|
||||
true /*is_last*/);
|
||||
ObITable *table =
|
||||
tablet_handle.get_obj()->get_table_store().get_minor_sstables().get_boundary_table(true /*is_last*/);
|
||||
|
||||
if (nullptr == table) {
|
||||
skip_calc = true;
|
||||
} else if (!calc_upper_trans_version_cache_.is_inited_
|
||||
|| calc_upper_trans_version_cache_.cache_version_ < table->get_end_log_ts()) {
|
||||
} else if (!calc_upper_trans_version_cache_.is_inited_ ||
|
||||
calc_upper_trans_version_cache_.cache_version_ < table->get_end_log_ts()) {
|
||||
ret = update_calc_upper_trans_version_cache_(table);
|
||||
} else if (calc_upper_trans_version_cache_.cache_version_ > table->get_end_log_ts()) {
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
STORAGE_LOG(ERROR, "the end log ts of the latest sstable is unexpected smaller", KR(ret),
|
||||
KPC(tablet_handle.get_obj()), KPC(table));
|
||||
STORAGE_LOG(ERROR,
|
||||
"the end log ts of the latest sstable is unexpected smaller",
|
||||
KR(ret),
|
||||
KPC(tablet_handle.get_obj()),
|
||||
KPC(table));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1119,8 +1171,7 @@ int ObTxDataTable::update_calc_upper_trans_version_cache_(ObITable *table)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ObTxDataTable::calc_upper_trans_version_(const int64_t sstable_end_log_ts,
|
||||
int64_t &upper_trans_version)
|
||||
int ObTxDataTable::calc_upper_trans_version_(const int64_t sstable_end_log_ts, int64_t &upper_trans_version)
|
||||
{
|
||||
int ret = OB_SUCCESS;
|
||||
|
||||
@ -1210,7 +1261,7 @@ int ObTxDataTable::get_start_tx_scn(int64_t &start_tx_scn)
|
||||
ret = OB_ERR_UNEXPECTED;
|
||||
STORAGE_LOG(ERROR, "tablet is nullptr.", KR(ret), KP(this), K(tablet_id_));
|
||||
} else if (OB_ISNULL(oldest_minor_sstable =
|
||||
(ObSSTable *)tablet->get_table_store().get_minor_sstables().get_boundary_table(false /*is_last*/))) {
|
||||
(ObSSTable *)tablet->get_table_store().get_minor_sstables().get_boundary_table(false /*is_last*/))) {
|
||||
start_tx_scn = INT64_MAX;
|
||||
STORAGE_LOG(INFO, "this logstream do not have tx data sstable", K(start_tx_scn), K(get_ls_id()), KPC(tablet));
|
||||
} else if (FALSE_IT(start_tx_scn = oldest_minor_sstable->get_filled_tx_scn())) {
|
||||
|
||||
Reference in New Issue
Block a user