diff --git a/tx_service/include/cc/object_cc_map.h b/tx_service/include/cc/object_cc_map.h index b5926e4a..b07c7408 100644 --- a/tx_service/include/cc/object_cc_map.h +++ b/tx_service/include/cc/object_cc_map.h @@ -1970,7 +1970,7 @@ class ObjectCcMap : public TemplateCcMap cce->payload_.cur_payload_ == nullptr ? RecordStatus::Deleted : RecordStatus::Normal; - bool was_dirty = (cce->CommitTs() > 1 && !cce->IsPersistent()); + bool was_dirty = cce->IsDirty(); cce->SetCommitTsPayloadStatus(commit_ts, payload_status); this->OnCommittedUpdate(cce, was_dirty); if (s_obj_exist && payload_status != RecordStatus::Normal) @@ -2006,7 +2006,7 @@ class ObjectCcMap : public TemplateCcMap // Emplace txn_cmd and try to commit all pending commands. int64_t buffered_cmd_cnt_old = buffered_cmd_list.Size(); - bool was_dirty = (cce->CommitTs() > 1 && !cce->IsPersistent()); + bool was_dirty = cce->IsDirty(); cce->EmplaceAndCommitBufferedTxnCommand( txn_cmd, shard_->NowInMilliseconds()); this->OnCommittedUpdate(cce, was_dirty); diff --git a/tx_service/include/cc/template_cc_map.h b/tx_service/include/cc/template_cc_map.h index ba458bf2..4e4da192 100644 --- a/tx_service/include/cc/template_cc_map.h +++ b/tx_service/include/cc/template_cc_map.h @@ -10148,13 +10148,17 @@ class TemplateCcMap : public CcMap location_infos.emplace_back(key_idx_in_page, false); // Don't need to empalce key. But we need to update entry's // payload - target_page->Entry(key_idx_in_page) - ->UpdateCcEntry(slice_items[item_idx], - shard_->EnableMvcc(), - normal_rec_change, - target_page, - shard_, - shard_->NowInMilliseconds()); + auto *target_cce = target_page->Entry(key_idx_in_page); + bool was_dirty = target_cce->IsDirty(); + target_cce->UpdateCcEntry(slice_items[item_idx], + shard_->EnableMvcc(), + normal_rec_change, + target_page, + shard_, + shard_->NowInMilliseconds()); + // Keep shard-level dirty-key stats in sync for overwrite path. + OnFlushed(target_cce, was_dirty); + OnCommittedUpdate(target_cce, was_dirty); item_idx++; key_idx_in_page++; } diff --git a/tx_service/src/cc/cc_req_misc.cpp b/tx_service/src/cc/cc_req_misc.cpp index ead420ac..95d64614 100644 --- a/tx_service/src/cc/cc_req_misc.cpp +++ b/tx_service/src/cc/cc_req_misc.cpp @@ -1212,22 +1212,24 @@ bool UpdateCceCkptTsCc::Execute(CcShard &ccs) static_cast *>(ref.cce_); assert(v_entry->CommitTs() > 1 && !v_entry->IsPersistent()); + bool was_dirty = v_entry->IsDirty(); v_entry->entry_info_.SetDataStoreSize(ref.post_flush_size_); v_entry->SetCkptTs(ref.commit_ts_); v_entry->ClearBeingCkpt(); - ccm->OnEntryFlushed(true, v_entry->IsPersistent()); + ccm->OnEntryFlushed(was_dirty, v_entry->IsPersistent()); } else { VersionedLruEntry *v_entry = static_cast *>(ref.cce_); assert(v_entry->CommitTs() > 1 && !v_entry->IsPersistent()); + bool was_dirty = v_entry->IsDirty(); v_entry->entry_info_.SetDataStoreSize(ref.post_flush_size_); v_entry->SetCkptTs(ref.commit_ts_); v_entry->ClearBeingCkpt(); - ccm->OnEntryFlushed(true, v_entry->IsPersistent()); + ccm->OnEntryFlushed(was_dirty, v_entry->IsPersistent()); } } else @@ -1238,9 +1240,10 @@ bool UpdateCceCkptTsCc::Execute(CcShard &ccs) static_cast *>(ref.cce_); assert(v_entry->CommitTs() > 1 && !v_entry->IsPersistent()); + bool was_dirty = v_entry->IsDirty(); v_entry->SetCkptTs(ref.commit_ts_); v_entry->ClearBeingCkpt(); - ccm->OnEntryFlushed(true, v_entry->IsPersistent()); + ccm->OnEntryFlushed(was_dirty, v_entry->IsPersistent()); } else { @@ -1248,9 +1251,10 @@ bool UpdateCceCkptTsCc::Execute(CcShard &ccs) static_cast *>(ref.cce_); assert(v_entry->CommitTs() > 1 && !v_entry->IsPersistent()); + bool was_dirty = v_entry->IsDirty(); v_entry->SetCkptTs(ref.commit_ts_); v_entry->ClearBeingCkpt(); - ccm->OnEntryFlushed(true, v_entry->IsPersistent()); + ccm->OnEntryFlushed(was_dirty, v_entry->IsPersistent()); } } } diff --git a/tx_service/src/cc/cc_shard.cpp b/tx_service/src/cc/cc_shard.cpp index c61cc0dc..04b7ef18 100644 --- a/tx_service/src/cc/cc_shard.cpp +++ b/tx_service/src/cc/cc_shard.cpp @@ -390,16 +390,35 @@ void CcShard::AdjustDataKeyStats(const TableName &table_name, { assert(size_delta >= 0 || data_key_count_ >= static_cast(-size_delta)); - data_key_count_ = static_cast( - static_cast(data_key_count_) + size_delta); + int64_t new_size = static_cast(data_key_count_) + size_delta; + if (new_size < 0) + { + data_key_count_ = 0; + } + else + { + data_key_count_ = static_cast(new_size); + } } if (dirty_delta != 0) { + // Sanity check in debug mode. assert(dirty_delta >= 0 || dirty_data_key_count_ >= static_cast(-dirty_delta)); - dirty_data_key_count_ = static_cast( - static_cast(dirty_data_key_count_) + dirty_delta); + // Clamp to avoid underflow when an entry is flushed but was never + // counted dirty (e.g. became dirty via a path that doesn't call + // OnCommittedUpdate). + int64_t new_dirty = + static_cast(dirty_data_key_count_) + dirty_delta; + if (new_dirty < 0) + { + dirty_data_key_count_ = 0; + } + else + { + dirty_data_key_count_ = static_cast(new_dirty); + } } }