fix: clean up RocksDB files on drop_index so create_index can be repeated (#485)
This commit is contained in:
parent
a055c7e0a2
commit
0ac294a9fd
|
|
@ -1992,6 +1992,7 @@ Status SegmentImpl::create_scalar_index(const std::vector<std::string> &columns,
|
|||
auto new_segment_meta = std::make_shared<SegmentMeta>(*segment_meta_);
|
||||
if (fields.empty()) {
|
||||
*segment_meta = new_segment_meta;
|
||||
*scalar_indexer = invert_indexers_;
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
|
|
@ -2166,8 +2167,16 @@ Status SegmentImpl::reload_scalar_index(
|
|||
collection_schema_ = std::make_shared<CollectionSchema>(schema);
|
||||
segment_meta_ = segment_meta;
|
||||
|
||||
if (invert_indexers_ == scalar_indexer) {
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
if (!scalar_indexer) {
|
||||
// no need to reload inverted indexer
|
||||
if (invert_indexers_) {
|
||||
auto old_dir = invert_indexers_->working_dir();
|
||||
invert_indexers_ = nullptr;
|
||||
FileHelper::RemoveDirectory(old_dir);
|
||||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
|
|
@ -2176,7 +2185,6 @@ Status SegmentImpl::reload_scalar_index(
|
|||
if (invert_indexers_) {
|
||||
auto old_dir = invert_indexers_->working_dir();
|
||||
invert_indexers_ = scalar_indexer;
|
||||
|
||||
FileHelper::RemoveDirectory(old_dir);
|
||||
} else {
|
||||
invert_indexers_ = scalar_indexer;
|
||||
|
|
|
|||
|
|
@ -6050,3 +6050,113 @@ TEST_F(CollectionTest, Feature_CreateOrDropFtsIndex) {
|
|||
FileHelper::RemoveDirectory(col_path);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(CollectionTest, Feature_DropAndRecreateScalarIndex) {
|
||||
#ifdef __ANDROID__
|
||||
GTEST_SKIP() << "Skipped on Android: emulator filesystem lacks hardlink "
|
||||
"support (needed by RocksDB checkpoint)";
|
||||
#endif
|
||||
int doc_count = 100;
|
||||
|
||||
auto schema = TestHelper::CreateNormalSchema(false, "demo");
|
||||
auto options = CollectionOptions{false, true, 64 * 1024 * 1024};
|
||||
auto collection = TestHelper::CreateCollectionWithDoc(
|
||||
col_path, *schema, options, 0, doc_count, false);
|
||||
|
||||
ASSERT_TRUE(collection->Flush().ok());
|
||||
ASSERT_EQ(collection->Stats().value().doc_count, doc_count);
|
||||
|
||||
auto index_params = std::make_shared<InvertIndexParams>(false);
|
||||
|
||||
// Round 1: create index
|
||||
auto s = collection->CreateIndex("int32", index_params);
|
||||
ASSERT_TRUE(s.ok()) << "Round 1 create failed: " << s.message();
|
||||
|
||||
// Round 1: drop index
|
||||
s = collection->DropIndex("int32");
|
||||
ASSERT_TRUE(s.ok()) << "Round 1 drop failed: " << s.message();
|
||||
|
||||
// Round 2: recreate index on same field — this was the bug
|
||||
s = collection->CreateIndex("int32", index_params);
|
||||
ASSERT_TRUE(s.ok()) << "Round 2 create failed: " << s.message();
|
||||
|
||||
// Round 2: drop again
|
||||
s = collection->DropIndex("int32");
|
||||
ASSERT_TRUE(s.ok()) << "Round 2 drop failed: " << s.message();
|
||||
|
||||
// Round 3: one more cycle
|
||||
s = collection->CreateIndex("int32", index_params);
|
||||
ASSERT_TRUE(s.ok()) << "Round 3 create failed: " << s.message();
|
||||
|
||||
// Verify data integrity after multiple create/drop cycles
|
||||
for (int i = 0; i < doc_count; i++) {
|
||||
auto expect_doc = TestHelper::CreateDoc(i, *schema);
|
||||
auto result = collection->Fetch({expect_doc.pk()});
|
||||
ASSERT_TRUE(result.has_value());
|
||||
ASSERT_EQ(result.value().size(), 1);
|
||||
auto doc = result.value()[expect_doc.pk()];
|
||||
ASSERT_NE(doc, nullptr);
|
||||
ASSERT_EQ(*doc, expect_doc);
|
||||
}
|
||||
|
||||
// Final drop
|
||||
s = collection->DropIndex("int32");
|
||||
ASSERT_TRUE(s.ok()) << "Final drop failed: " << s.message();
|
||||
}
|
||||
|
||||
TEST_F(CollectionTest, Feature_DropAndRecreateScalarIndex_MultipleFields) {
|
||||
#ifdef __ANDROID__
|
||||
GTEST_SKIP() << "Skipped on Android: emulator filesystem lacks hardlink "
|
||||
"support (needed by RocksDB checkpoint)";
|
||||
#endif
|
||||
int doc_count = 100;
|
||||
|
||||
auto schema = TestHelper::CreateNormalSchema(false, "demo");
|
||||
auto options = CollectionOptions{false, true, 64 * 1024 * 1024};
|
||||
auto collection = TestHelper::CreateCollectionWithDoc(
|
||||
col_path, *schema, options, 0, doc_count, false);
|
||||
|
||||
ASSERT_TRUE(collection->Flush().ok());
|
||||
|
||||
auto index_params = std::make_shared<InvertIndexParams>(false);
|
||||
|
||||
// Create index on two fields
|
||||
auto s = collection->CreateIndex("int32", index_params);
|
||||
ASSERT_TRUE(s.ok());
|
||||
s = collection->CreateIndex("string", index_params);
|
||||
ASSERT_TRUE(s.ok());
|
||||
|
||||
// Drop only one field — the other should remain functional
|
||||
s = collection->DropIndex("int32");
|
||||
ASSERT_TRUE(s.ok());
|
||||
|
||||
// Recreate the dropped one
|
||||
s = collection->CreateIndex("int32", index_params);
|
||||
ASSERT_TRUE(s.ok()) << "Recreate int32 after partial drop failed: "
|
||||
<< s.message();
|
||||
|
||||
// Drop both
|
||||
s = collection->DropIndex("int32");
|
||||
ASSERT_TRUE(s.ok());
|
||||
s = collection->DropIndex("string");
|
||||
ASSERT_TRUE(s.ok());
|
||||
|
||||
// Recreate both
|
||||
s = collection->CreateIndex("int32", index_params);
|
||||
ASSERT_TRUE(s.ok()) << "Recreate int32 after full drop failed: "
|
||||
<< s.message();
|
||||
s = collection->CreateIndex("string", index_params);
|
||||
ASSERT_TRUE(s.ok()) << "Recreate string after full drop failed: "
|
||||
<< s.message();
|
||||
|
||||
// Verify data integrity
|
||||
for (int i = 0; i < doc_count; i++) {
|
||||
auto expect_doc = TestHelper::CreateDoc(i, *schema);
|
||||
auto result = collection->Fetch({expect_doc.pk()});
|
||||
ASSERT_TRUE(result.has_value());
|
||||
ASSERT_EQ(result.value().size(), 1);
|
||||
auto doc = result.value()[expect_doc.pk()];
|
||||
ASSERT_NE(doc, nullptr);
|
||||
ASSERT_EQ(*doc, expect_doc);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue