fix: properly handle larger final IPC chunk in mmap store (#645)

This commit is contained in:
egolearner 2026-08-04 16:58:10 +08:00 committed by GitHub
parent 3e66f8b268
commit 6eed986ac5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 50 additions and 4 deletions

View File

@ -118,11 +118,13 @@ arrow::Status MmapForwardStore::OpenIPC(
chunk_index_map_.emplace_back(num_rows_, num_rows_ + chunk->length() - 1);
num_rows_ += chunk->length();
// Check if all chunks have the same size except possibly the last one
// All non-last chunks must have the same size. The last chunk may be
// smaller, but a larger last chunk also requires the general lookup path.
if (fixed_batch_size_ == -1) {
fixed_batch_size_ = chunk->length();
} else if (fixed_batch_size_ != chunk->length()) {
if (i != chunked_array->num_chunks() - 1) {
if (i != chunked_array->num_chunks() - 1 ||
chunk->length() > fixed_batch_size_) {
is_fixed_batch_size_ = false;
}
}
@ -568,4 +570,4 @@ RecordBatchReaderPtr MmapForwardStore::scan(
}
}
} // namespace zvec
} // namespace zvec

View File

@ -22,6 +22,7 @@
#include <arrow/table.h>
#include <gtest/gtest.h>
#include "db/common/constants.h"
#include "db/index/storage/chunked_file_writer.h"
#define private public
#define protected public
#include "db/index/storage/mmap_forward_store.h"
@ -31,6 +32,31 @@
using namespace zvec;
namespace {
arrow::Status WriteUnevenBatchIPC(const std::string &path) {
auto schema = arrow::schema({arrow::field("id", arrow::int32())});
auto writer = ChunkedFileWriter::Open(path, schema, FileFormat::IPC);
if (!writer) {
return arrow::Status::IOError("failed to open IPC writer");
}
int32_t next_id = 0;
for (int64_t batch_size : {3, 4}) {
arrow::Int32Builder builder;
for (int64_t i = 0; i < batch_size; ++i) {
ARROW_RETURN_NOT_OK(builder.Append(next_id++));
}
std::shared_ptr<arrow::Array> ids;
ARROW_RETURN_NOT_OK(builder.Finish(&ids));
auto batch = arrow::RecordBatch::Make(schema, batch_size, {ids});
ARROW_RETURN_NOT_OK(writer->Write(*batch));
}
return writer->Close();
}
} // namespace
class MmapStoreTest : public testing::Test {
protected:
void SetUp() override {
@ -53,10 +79,14 @@ class MmapStoreTest : public testing::Test {
if (std::filesystem::exists(parquet_path)) {
std::filesystem::remove(parquet_path);
}
if (std::filesystem::exists(uneven_ipc_path)) {
std::filesystem::remove(uneven_ipc_path);
}
}
std::string ipc_path = "test.ipc";
std::string parquet_path = "test.parquet";
std::string uneven_ipc_path = "uneven.ipc";
};
@ -516,6 +546,20 @@ TEST_F(MmapStoreTest, IPCFetchSingleRow) {
}
}
TEST_F(MmapStoreTest, IPCFetchFromLargerLastChunk) {
ASSERT_TRUE(WriteUnevenBatchIPC(uneven_ipc_path).ok());
auto ipc_store = std::make_shared<MmapForwardStore>(uneven_ipc_path);
ASSERT_TRUE(ipc_store->Open().ok());
auto result = ipc_store->fetch({"id"}, std::vector<int>{6});
ASSERT_NE(result, nullptr);
ASSERT_EQ(result->num_rows(), 1);
auto ids =
std::dynamic_pointer_cast<arrow::Int32Array>(result->column(0)->chunk(0));
ASSERT_NE(ids, nullptr);
EXPECT_EQ(ids->Value(0), 6);
}
TEST_F(MmapStoreTest, ParquetFetchSingleRow) {
auto parquet_store = std::make_shared<MmapForwardStore>(parquet_path);
ASSERT_TRUE(parquet_store->Open().ok());
@ -673,4 +717,4 @@ TEST_F(MmapStoreTest, ConstructorAndPhysicSchema) {
TEST_F(MmapStoreTest, DeleteDestructs) {
MmapForwardStore *store = new MmapForwardStore(ipc_path);
delete store;
}
}