diff --git a/store_handler/data_store_service_client_closure.cpp b/store_handler/data_store_service_client_closure.cpp index efc27dce..2c3c8fe4 100644 --- a/store_handler/data_store_service_client_closure.cpp +++ b/store_handler/data_store_service_client_closure.cpp @@ -1276,11 +1276,17 @@ void LoadRangeSliceCallback(void *data, std::string key_str, value_str; uint64_t ts, ttl; + uint64_t snapshot_ts = fill_store_slice_req->SnapshotTs(); for (uint32_t i = 0; i < items_size; i++) { scan_next_closure->GetItem(i, key_str, value_str, ts, ttl); txservice::TxKey key = catalog_factory->CreateTxKey(key_str.data(), key_str.size()); + if (i == items_size - 1) + { + fill_store_slice_req->kv_start_key_ = + std::string_view(key.Data(), key.Size()); + } std::unique_ptr record = catalog_factory->CreateTxRecord(); bool is_deleted = false; @@ -1308,18 +1314,25 @@ void LoadRangeSliceCallback(void *data, std::abort(); } + if ((snapshot_ts == 0 && is_deleted) || + (snapshot_ts > 0 && snapshot_ts > ts)) + { + // if it is not a snapshot read, there is no need to return + // deleted keys. + // If it is a snapshot read and the latest version is newer than + // snapshot read ts, we need to backfill deleted key since there + // might be visible archive version of this key for snapshot ts. + // The caller will decide if reading archive table is necessary + // based on the deleted key version. + continue; + } + if (!is_deleted) { record->Deserialize(value_str.data(), offset); } } - if (i == items_size - 1) - { - fill_store_slice_req->kv_start_key_ = - std::string_view(key.Data(), key.Size()); - } - fill_store_slice_req->AddDataItem( std::move(key), std::move(record), ts, is_deleted); } diff --git a/tx_service/include/cc/template_cc_map.h b/tx_service/include/cc/template_cc_map.h index 6af998f4..d69b400c 100644 --- a/tx_service/include/cc/template_cc_map.h +++ b/tx_service/include/cc/template_cc_map.h @@ -5421,7 +5421,11 @@ class TemplateCcMap : public CcMap range_ptr->FindSlice(slice_key); assert(slice->PostCkptSize() != UINT64_MAX); - return slice->PostCkptSize() > StoreSlice::slice_upper_bound; + // Only need to split the slice when the post ckpt size of the slice + // is greater than the current size and greater than the slice upper + // bound. + return (slice->PostCkptSize() > StoreSlice::slice_upper_bound && + slice->PostCkptSize() > slice->Size()); }; const KeyT *const req_start_key = req.start_key_ != nullptr diff --git a/tx_service/src/cc/local_cc_shards.cpp b/tx_service/src/cc/local_cc_shards.cpp index 9e0414fe..94054024 100644 --- a/tx_service/src/cc/local_cc_shards.cpp +++ b/tx_service/src/cc/local_cc_shards.cpp @@ -5462,8 +5462,11 @@ void LocalCcShards::UpdateSlices(const TableName &table_name, : false; uint64_t slice_post_ckpt_size = curr_slice->PostCkptSize(); + // If post ckpt size of the slice is less than or equal to the current + // size, there is no need to split the slice. if (slice_post_ckpt_size == UINT64_MAX || - slice_post_ckpt_size <= StoreSlice::slice_upper_bound) + slice_post_ckpt_size <= StoreSlice::slice_upper_bound || + slice_post_ckpt_size <= curr_slice->Size()) { // Case 1: There is no unpersisted data in the current slice, so no // need to split the slice. Only to migrate this data from the old