1212// See the License for the specific language governing permissions and
1313// limitations under the License.
1414
15+ #include < Storages/KVStore/Decode/RegionTable.h>
1516#include < Storages/KVStore/Read/LearnerRead.h>
1617#include < Storages/KVStore/tests/region_kvstore_test.h>
1718
@@ -22,6 +23,7 @@ namespace FailPoints
2223extern const char force_raise_prehandle_exception[];
2324extern const char pause_before_prehandle_subtask[];
2425extern const char force_set_sst_to_dtfile_block_size[];
26+ extern const char force_release_snap_meet_null_storage[];
2527} // namespace FailPoints
2628
2729namespace tests
@@ -528,6 +530,120 @@ try
528530}
529531CATCH
530532
533+ // Test when a region is cancel during releasing pre-handled snapshot.
534+ // And the pre-handled snapshot contains no external files.
535+ TEST_F (RegionKVStoreV2Test, KVStoreSingleSnapReleaseNoExternalFiles)
536+ try
537+ {
538+ auto & ctx = TiFlashTestEnv::getGlobalContext ();
539+ proxy_instance->cluster_ver = RaftstoreVer::V2;
540+ ASSERT_NE (proxy_helper->sst_reader_interfaces .fn_key , nullptr );
541+ ASSERT_NE (proxy_helper->fn_get_config_json , nullptr );
542+ FailPointHelper::enableFailPoint (FailPoints::force_release_snap_meet_null_storage, static_cast <size_t >(0 ));
543+ SCOPE_EXIT ({ FailPointHelper::disableFailPoint (FailPoints::force_release_snap_meet_null_storage); });
544+ UInt64 region_id = 2 ;
545+ initStorages ();
546+ KVStore & kvs = getKVS ();
547+ TableID table_id = proxy_instance->bootstrapTable (ctx, kvs, ctx.getTMTContext ());
548+ auto start = RecordKVFormat::genKey (table_id, 0 );
549+ auto end = RecordKVFormat::genKey (table_id, 40 );
550+ proxy_instance->bootstrapWithRegion ( //
551+ kvs,
552+ ctx.getTMTContext (),
553+ region_id,
554+ std::make_pair (start.toString (), end.toString ()));
555+ auto r1 = proxy_instance->getRegion (region_id);
556+
557+ auto [value_write, value_default] = proxy_instance->generateTiKVKeyValue (111 , 999 );
558+ auto kkk = RecordKVFormat::decodeWriteCfValue (TiKVValue::copyFrom (value_write));
559+ {
560+ // mock an empty region
561+ MockSSTReader::getMockSSTData ().clear ();
562+ MockSSTGenerator default_cf{region_id, table_id, ColumnFamilyType::Default};
563+ default_cf.finish_file (SSTFormatKind::KIND_TABLET);
564+ default_cf.freeze ();
565+ MockSSTGenerator write_cf{region_id, table_id, ColumnFamilyType::Write};
566+ write_cf.finish_file (SSTFormatKind::KIND_TABLET);
567+ write_cf.freeze ();
568+ auto [prehandle_region, res] = proxy_instance->snapshot ( //
569+ kvs,
570+ ctx.getTMTContext (),
571+ region_id,
572+ {default_cf, write_cf},
573+ 0 ,
574+ 0 ,
575+ std::nullopt );
576+ kvs.abortPreHandleSnapshot (region_id, ctx.getTMTContext ());
577+ RegionPtrWithSnapshotFiles region_with_snap (prehandle_region, {});
578+ kvs.releasePreHandledSnapshot (region_with_snap, ctx.getTMTContext ());
579+ }
580+ }
581+ CATCH
582+
583+ // Test when a region is cancel during releasing pre-handled snapshot.
584+ // And the pre-handled snapshot's storage is null.
585+ TEST_F (RegionKVStoreV2Test, KVStoreSingleSnapReleaseNullStorage)
586+ try
587+ {
588+ auto & ctx = TiFlashTestEnv::getGlobalContext ();
589+ proxy_instance->cluster_ver = RaftstoreVer::V2;
590+ ASSERT_NE (proxy_helper->sst_reader_interfaces .fn_key , nullptr );
591+ ASSERT_NE (proxy_helper->fn_get_config_json , nullptr );
592+ FailPointHelper::enableFailPoint (FailPoints::force_release_snap_meet_null_storage, static_cast <size_t >(0 ));
593+ SCOPE_EXIT ({ FailPointHelper::disableFailPoint (FailPoints::force_release_snap_meet_null_storage); });
594+ UInt64 region_id = 2 ;
595+ initStorages ();
596+ KVStore & kvs = getKVS ();
597+ TableID table_id = proxy_instance->bootstrapTable (ctx, kvs, ctx.getTMTContext ());
598+ auto start = RecordKVFormat::genKey (table_id, 0 );
599+ auto end = RecordKVFormat::genKey (table_id, 40 );
600+ HandleID sst_limit = 40 ;
601+ proxy_instance->bootstrapWithRegion ( //
602+ kvs,
603+ ctx.getTMTContext (),
604+ region_id,
605+ std::make_pair (start.toString (), end.toString ()));
606+ auto r1 = proxy_instance->getRegion (region_id);
607+
608+ auto [value_write, value_default] = proxy_instance->generateTiKVKeyValue (111 , 999 );
609+ auto kkk = RecordKVFormat::decodeWriteCfValue (TiKVValue::copyFrom (value_write));
610+ {
611+ MockSSTReader::getMockSSTData ().clear ();
612+ MockSSTGenerator default_cf{region_id, table_id, ColumnFamilyType::Default};
613+ for (HandleID h = 1 ; h < sst_limit; h++)
614+ {
615+ auto k = RecordKVFormat::genKey (table_id, h, 111 );
616+ default_cf.insert_raw (k, value_default);
617+ }
618+ default_cf.finish_file (SSTFormatKind::KIND_TABLET);
619+ default_cf.freeze ();
620+ MockSSTGenerator write_cf{region_id, table_id, ColumnFamilyType::Write};
621+ for (HandleID h = 1 ; h < sst_limit; h++)
622+ {
623+ auto k = RecordKVFormat::genKey (table_id, h, 111 );
624+ write_cf.insert_raw (k, value_write);
625+ }
626+ write_cf.finish_file (SSTFormatKind::KIND_TABLET);
627+ write_cf.freeze ();
628+
629+ auto [prehandle_region, res] = proxy_instance->snapshot ( //
630+ kvs,
631+ ctx.getTMTContext (),
632+ region_id,
633+ {default_cf, write_cf},
634+ 0 ,
635+ 0 ,
636+ std::nullopt ,
637+ [] {
638+ // set the function so that will call releasePreHandledSnapshot
639+ // and verify the null storage handling logic
640+ return nullptr ;
641+ });
642+ UNUSED (prehandle_region, res);
643+ }
644+ }
645+ CATCH
646+
531647// Test several uncommitted keys with only one version.
532648TEST_F (RegionKVStoreV2Test, KVStoreSingleSnap1)
533649try
0 commit comments