From 5d513aec8229a19d71ec1c2070b9ad680ddfc33b Mon Sep 17 00:00:00 2001 From: Xin Liao Date: Mon, 21 Sep 2026 12:18:57 +0800 Subject: [PATCH 1/2] [fix](be) Preserve tablet ID in synchronous file cache writes ### What problem does this PR solve? Issue Number: None Related PR: None Problem Summary: Synchronous cache population could create file cache blocks with tablet ID 0 even when the remote reader had a valid tablet ID. This made per-tablet cache metadata and TTL management unable to find successfully downloaded blocks. Propagate the reader tablet ID into the cache context before creating blocks and add a unit test for the warm-up synchronous write path. ### Release note Fix file cache blocks created by synchronous reads to retain their tablet ID. ### Check List (For Author) - Test - [x] Unit Test - Added AsyncCachedRemoteFileReaderTest.sync_write_path_preserves_tablet_id. - The modified IO library and test object compile successfully. - Full local execution is blocked by stale local third-party Thrift/AWS SDK headers unrelated to this change. - Behavior changed: - [x] Yes. Synchronously populated cache blocks now retain their tablet ownership metadata. - Does this need documentation? - [x] No. --- be/src/io/cache/cached_remote_file_reader.cpp | 1 + .../cache/cached_remote_file_reader_test.cpp | 20 +++++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/be/src/io/cache/cached_remote_file_reader.cpp b/be/src/io/cache/cached_remote_file_reader.cpp index da4d5c42a24920..ab576dbc7f2d3b 100644 --- a/be/src/io/cache/cached_remote_file_reader.cpp +++ b/be/src/io/cache/cached_remote_file_reader.cpp @@ -1078,6 +1078,7 @@ Status CachedRemoteFileReader::_read_from_indirect_cache(size_t offset, Slice re s_align_size(offset + already_read, bytes_req - already_read, size()); CacheContext cache_context(io_ctx); cache_context.stats = &stats; + cache_context.tablet_id = _tablet_id; MonotonicStopWatch sw; sw.start(); ConcurrencyStatsManager::instance().cached_remote_reader_get_or_set->increment(); diff --git a/be/test/io/cache/cached_remote_file_reader_test.cpp b/be/test/io/cache/cached_remote_file_reader_test.cpp index a64fe685bfb8e6..d4dcf04070a0ed 100644 --- a/be/test/io/cache/cached_remote_file_reader_test.cpp +++ b/be/test/io/cache/cached_remote_file_reader_test.cpp @@ -178,6 +178,26 @@ class AsyncCachedRemoteFileReaderTest : public BlockFileCacheTest { } // namespace +TEST_F(AsyncCachedRemoteFileReaderTest, sync_write_path_preserves_tablet_id) { + create_cache("cached_remote_reader_sync_write_tablet_id"); + auto reader = create_reader(open_remote_file()); + + std::string result(64_kb, '\0'); + FileCacheStatistics stats; + IOContext context; + context.file_cache_stats = &stats; + context.is_warmup = true; + size_t bytes_read = 0; + ASSERT_TRUE( + reader->read_at(0, Slice(result.data(), result.size()), &bytes_read, &context).ok()); + EXPECT_EQ(bytes_read, result.size()); + EXPECT_EQ(result, std::string(result.size(), '0')); + + const auto blocks = cache()->get_blocks_by_key(reader->_cache_hash); + ASSERT_EQ(blocks.size(), 1); + EXPECT_EQ(blocks.begin()->second->tablet_id(), 10086); +} + TEST_F(AsyncCachedRemoteFileReaderTest, preallocated_cache_block_can_cover_the_short_file_tail) { create_cache("cached_remote_reader_async_preallocated_file_tail"); auto counting_reader = std::make_shared(open_remote_file()); From a9b77a53979ac8610a84053dbebfd1666481aae3 Mon Sep 17 00:00:00 2001 From: Xin Liao Date: Mon, 21 Sep 2026 15:23:52 +0800 Subject: [PATCH 2/2] [fix](be) Normalize external file cache tablet IDs ### What problem does this PR solve? Issue Number: None Related PR: None Problem Summary: External cached readers keep the unset FileReaderOptions tablet ID of -1. Propagating that value into CacheContext would persist an invalid metadata namespace and enqueue an invalid tablet for TTL maintenance. Normalize external readers to the cache no-tablet sentinel 0, accept only positive IDs in TTL registration, and cover both synchronous and asynchronous external cache writes. ### Release note Normalize external file cache metadata to use tablet ID 0. ### Check List (For Author) - Test - [x] Unit Test - Added external reader coverage for synchronous and asynchronous cache writes. - The modified IO library and test object compile successfully. - Behavior changed: - [x] No user-visible behavior change. - Does this need documentation? - [x] No. --- be/src/io/cache/block_file_cache.cpp | 2 +- be/src/io/cache/cached_remote_file_reader.cpp | 2 +- .../cache/cached_remote_file_reader_test.cpp | 30 +++++++++++++++++++ 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/be/src/io/cache/block_file_cache.cpp b/be/src/io/cache/block_file_cache.cpp index a4c769ad9bb820..33bb9cd1055bf5 100644 --- a/be/src/io/cache/block_file_cache.cpp +++ b/be/src/io/cache/block_file_cache.cpp @@ -1104,7 +1104,7 @@ FileBlocks BlockFileCache::split_range_into_cells(const UInt128Wrapper& hash, cell->update_atime(); } } - if (_ttl_mgr && context.tablet_id != 0) { + if (_ttl_mgr && context.tablet_id > 0) { _ttl_mgr->register_tablet_id(context.tablet_id); } } diff --git a/be/src/io/cache/cached_remote_file_reader.cpp b/be/src/io/cache/cached_remote_file_reader.cpp index ab576dbc7f2d3b..ef0c395b4c137f 100644 --- a/be/src/io/cache/cached_remote_file_reader.cpp +++ b/be/src/io/cache/cached_remote_file_reader.cpp @@ -121,7 +121,7 @@ CachedRemoteFileReader::CachedRemoteFileReader(FileReaderSPtr remote_file_reader : _is_doris_table(opts.is_doris_table), _cache_align_mode(opts.align_mode), _cache_write_mode(opts.cache_write_mode), - _tablet_id(opts.tablet_id), + _tablet_id(opts.is_doris_table ? opts.tablet_id : 0), _storage_resource_id(opts.storage_resource_id), _remote_file_reader(std::move(remote_file_reader)) { DCHECK(!_is_doris_table || _tablet_id > 0); diff --git a/be/test/io/cache/cached_remote_file_reader_test.cpp b/be/test/io/cache/cached_remote_file_reader_test.cpp index d4dcf04070a0ed..6fe9bac5d60384 100644 --- a/be/test/io/cache/cached_remote_file_reader_test.cpp +++ b/be/test/io/cache/cached_remote_file_reader_test.cpp @@ -198,6 +198,36 @@ TEST_F(AsyncCachedRemoteFileReaderTest, sync_write_path_preserves_tablet_id) { EXPECT_EQ(blocks.begin()->second->tablet_id(), 10086); } +TEST_F(AsyncCachedRemoteFileReaderTest, external_reader_normalizes_tablet_id_for_cache_writes) { + create_cache("cached_external_reader_tablet_id"); + FileReaderOptions options; + options.cache_type = FileCachePolicy::FILE_BLOCK_CACHE; + auto reader = std::make_shared(open_remote_file(), options); + + std::string result(64_kb, '\0'); + FileCacheStatistics stats; + IOContext context; + context.file_cache_stats = &stats; + context.is_warmup = true; + size_t bytes_read = 0; + ASSERT_TRUE( + reader->read_at(0, Slice(result.data(), result.size()), &bytes_read, &context).ok()); + EXPECT_EQ(bytes_read, result.size()); + + context.is_warmup = false; + bytes_read = 0; + ASSERT_TRUE( + reader->read_at(1_mb, Slice(result.data(), result.size()), &bytes_read, &context).ok()); + EXPECT_EQ(bytes_read, result.size()); + wait_for_async_writes(); + + const auto blocks = cache()->get_blocks_by_key(reader->_cache_hash); + ASSERT_EQ(blocks.size(), 2); + for (const auto& [offset, block] : blocks) { + EXPECT_EQ(block->tablet_id(), 0) << "offset=" << offset; + } +} + TEST_F(AsyncCachedRemoteFileReaderTest, preallocated_cache_block_can_cover_the_short_file_tail) { create_cache("cached_remote_reader_async_preallocated_file_tail"); auto counting_reader = std::make_shared(open_remote_file());