-
Notifications
You must be signed in to change notification settings - Fork 20
feat: Introduce sst file format for btree global index #49
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
| @@ -0,0 +1,42 @@ | |||
| /* | |||
| * Copyright 2024-present Alibaba Inc. | |||
| * | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please update the copyright year from 2024 to 2026 for new files.
| class CacheValue { | ||
| public: | ||
| explicit CacheValue(std::shared_ptr<MemorySegment>& segment) : segment_(segment) {} | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const std::shared_ptr& segment may be better.
| std::function<std::shared_ptr<CacheValue>(const std::shared_ptr<CacheKey>&)> supplier) = 0; | ||
|
|
||
| virtual void Put(const std::shared_ptr<CacheKey>& key, std::shared_ptr<CacheValue>& value) = 0; | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const std::shared_ptr& value may be better.
| size_t seed = 0; | ||
| seed ^= | ||
| std::hash<std::string>{}(file_path_) + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2); | ||
| seed ^= std::hash<int64_t>{}(position_) + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider converting 0x9e3779b97f4a7c15ULL to a static constant
| std::function<Result<MemorySegment>(const std::shared_ptr<CacheKey>&)> reader) { | ||
| auto& cache = key->IsIndex() ? index_cache_ : data_cache_; | ||
| auto supplier = [&reader](const std::shared_ptr<CacheKey>& k) -> std::shared_ptr<CacheValue> { | ||
| auto segment = reader(k).value(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Capturing &reader by reference may risk memory leaks. May consider capturing by value instead. Also ensure Result is .ok() before calling .value() to avoid undefined behavior.
| return BlockAlignedType::UNALIGNED; | ||
| } else { | ||
| throw std::invalid_argument("Invalid block aligned type: " + std::to_string(v)); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, may return Result<BlockAlignedType>
| BlockCache(std::string& file_path, std::shared_ptr<InputStream>& in, | ||
| std::shared_ptr<MemoryPool>& pool, std::unique_ptr<CacheManager>& cache_manager) | ||
| : file_path_(file_path), in_(in), pool_(pool), cache_manager_(std::move(cache_manager)) {} | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
may pass const shared_ptr& or unique_ptr&&
| public: | ||
| BlockEntry(std::shared_ptr<MemorySlice>& key, std::shared_ptr<MemorySlice>& value) | ||
| : key_(key), value_(value) {} | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider making BlockEntry a struct if it only has Get methods.
|
|
||
| public: | ||
| static constexpr int32_t MAX_ENCODED_LENGTH = 9 + 5; | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add a comment explaining the value of MAX_ENCODED_LENGTH?
| auto output = std::make_shared<MemorySliceOutput>(MAX_ENCODED_LENGTH, pool); | ||
| output->WriteVarLenLong(offset_); | ||
| output->WriteVarLenLong(size_); | ||
| return output->ToSlice(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if reading uses an int followed by a long (ReadVarLenLong for offset and ReadVarLenInt for size), while writing uses two longs. Is this correct? Consider adding a test to verify.
| std::unique_ptr<BlockEntry> BlockIterator::Next() { | ||
| if (!HasNext()) { | ||
| throw std::invalid_argument("no such element"); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
May use bad status instead of exceptions.
| } | ||
|
|
||
| return false; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a test for BlockReader and BlockIterator.
| class BlockIterator; | ||
|
|
||
| /** Reader for a block. */ | ||
| class BlockReader : public std::enable_shared_from_this<BlockReader> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider using /// for class or interface comments to maintain a consistent format.
| auto data = block->Slice(0, index_offset); | ||
| auto index = block->Slice(index_offset, index_length); | ||
| return std::make_shared<UnAlignedBlockReader>(data, index, comparator); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can 5 be a static constant rather than a magic number? Or add comments for it.
| std::string BlockTrailer::ToString() const { | ||
| return "BlockTrailer{compression_type=" + std::to_string(compression_type_) + ", crc32c_=0x" + | ||
| std::to_string(crc32c_) + "}"; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
May add a conversion to ensure the return value is a hexadecimal string for crc32c.
| if (aligned_) { | ||
| int currentSize = endPosition - startPosition; | ||
| if (aligned_size_ == 0) { | ||
| aligned_size_ = currentSize; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
current_size & end_position & start_position
| BlockWriter* IndexWriter() const { | ||
| return index_block_writer_.get(); | ||
| } | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Test interface can be private.
| std::shared_ptr<Bytes> last_key_; | ||
|
|
||
| const std::shared_ptr<MemoryPool>& pool_; | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ensure that obtaining a shared_ptr reference does not introduce any risk of memory leaks?
| if (!handle.ok()) { | ||
| return handle.status(); | ||
| } | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
May use PAIMON_ASSIGN_OR_RAISE() (ps: Ensure that the macro PAIMON_ASSIGN_OR_RAISE always includes the return type not auto ).
|
|
||
| private: | ||
| static constexpr int32_t BYTE_SIZE = 8; | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can the existing BloomFilter64 and BitSet classes in paimon/common/utils/ meet your requirements for bloom filter file index?
|
|
||
| bool IsIndex() override; | ||
|
|
||
| int64_t Position(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Get method can be const.
Purpose
#38
This PR only covers basic reading and writing of SST format files, data compression encoding and caching are not considered. Too much code in the PR will make it difficult to review, so I will continue work for this in the future.
DONE:
TODO:
Tests
./build/debug/paimon-common-sst-file-format-test
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from SstFileIOTest
[ RUN ] SstFileIOTest.TestSimple
[ OK ] SstFileIOTest.TestSimple (2 ms)
[----------] 1 test from SstFileIOTest (2 ms total)
[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (2 ms total)
[ PASSED ] 1 test.
./build/debug/paimon-common-test
[----------] 1 test from BitSetTest
[ RUN ] BitSetTest.TestBitSet
[ OK ] BitSetTest.TestBitSet (0 ms)
[----------] 1 test from BitSetTest (0 ms total)
[----------] 5 tests from BloomFilterTest
[ RUN ] BloomFilterTest.TestOneSegmentBuilder
[ OK ] BloomFilterTest.TestOneSegmentBuilder (0 ms)
[ RUN ] BloomFilterTest.TestEstimatedHashFunctions
[ OK ] BloomFilterTest.TestEstimatedHashFunctions (0 ms)
[ RUN ] BloomFilterTest.TestBloomNumBits
[ OK ] BloomFilterTest.TestBloomNumBits (0 ms)
[ RUN ] BloomFilterTest.TestBloomNumHashFunctions
[ OK ] BloomFilterTest.TestBloomNumHashFunctions (0 ms)
[ RUN ] BloomFilterTest.TestBloomFilter
[ OK ] BloomFilterTest.TestBloomFilter (2 ms)
[----------] 5 tests from BloomFilterTest (2 ms total)