github-actions[bot] commented on code in PR #64186:
URL: https://github.com/apache/doris/pull/64186#discussion_r3409266115
##########
be/src/io/cache/fs_file_cache_storage.cpp:
##########
@@ -672,13 +881,70 @@ bool FSFileCacheStorage::handle_already_loaded_block(
return false;
}
auto block = cell_it->second.file_block;
+ if (is_tmp) {
+ return true;
+ }
+ bool accepted_storage_path = true;
+ if (!storage_file_exists(block->storage_key())) {
+ block->update_storage_expiration_time(context.storage_expiration());
+ block->update_storage_cache_type(context.cache_type);
+ } else if (block->storage_expiration_time() !=
context.storage_expiration()) {
+ remove_file_and_empty_dir(offset_path, key_path);
+ accepted_storage_path = false;
+ } else if (block->storage_cache_type() != context.cache_type) {
+ block->update_storage_cache_type(context.cache_type);
+ }
size_t old_size = block->range().size();
- if (old_size != new_size) {
+ if (accepted_storage_path && old_size != new_size) {
mgr->reset_range(hash, offset, old_size, new_size, cache_lock);
}
+ if (accepted_storage_path && (block->cache_type() != context.cache_type ||
+ block->expiration_time() !=
context.expiration_time)) {
+ mgr->update_hash_logical_meta(hash, context.cache_type,
context.expiration_time,
+ cache_lock);
+ }
return true;
}
+void FSFileCacheStorage::load_blocks_from_dir_unlocked(
+ BlockFileCache* mgr, const UInt128Wrapper& hash, const KeyDir& key_dir,
+ const FileCacheKey* logical_key, std::lock_guard<std::mutex>&
cache_lock) const {
+ CacheContext context_original;
+ context_original.query_id = TUniqueId();
+ context_original.expiration_time =
+ logical_key == nullptr ? key_dir.expiration_time :
logical_key->meta.expiration_time;
+ context_original.storage_expiration_time = key_dir.expiration_time;
Review Comment:
This startup path still derives the logical expiration from the storage
directory when `logical_key == nullptr`, which makes the new logical/storage
split non-durable across BE restarts. For example,
`modify_expiration_time(hash, new_expiration)` now intentionally leaves files
under the old `hash_<old>` directory, and `modify_expiration_time(hash, 0)`
does the same when TTL is cleared. After restart,
`load_cache_info_into_memory()` reaches this branch with no logical key,
`parse_filename_suffix_to_cache_type()` forces `TTL` for the positive directory
expiration, and `add_cell()` repopulates `_key_to_time` from the old storage
expiration. The logical update is lost, and a hash whose TTL was cleared is
resurrected as TTL until another metadata sync happens. Please persist/replay
the logical expiration separately, or avoid treating a storage-only directory
suffix as authoritative logical TTL during startup load. This is distinct from
the existing absent-hash `_key_to_time` thread bec
ause it affects hashes whose logical metadata was validly changed before
restart.
##########
be/src/io/cache/block_file_cache.cpp:
##########
@@ -1378,23 +1553,34 @@ void BlockFileCache::remove_if_cached(const
UInt128Wrapper& file_key) {
// if in use, cache meta will be deleted after use and the block file is then
deleted asynchronously
void BlockFileCache::remove_if_cached_async(const UInt128Wrapper& file_key) {
std::string reason = "remove_if_cached_async";
- SCOPED_CACHE_LOCK(_mutex, this);
- bool is_ttl_file = remove_if_ttl_file_blocks(file_key, true, cache_lock,
/*sync*/ false);
- if (!is_ttl_file) {
- auto iter = _files.find(file_key);
- std::vector<FileBlockCell*> to_remove;
- if (iter != _files.end()) {
- for (auto& [_, cell] : iter->second) {
- *_gc_evict_bytes_metrics << cell.size();
- *_gc_evict_count_metrics << 1;
- if (cell.releasable()) {
- to_remove.push_back(&cell);
- } else {
- cell.file_block->set_deleting();
+ bool has_unreleasable = false;
+ {
+ SCOPED_CACHE_LOCK(_mutex, this);
+ bool is_ttl_file = remove_if_ttl_file_blocks(file_key, true,
cache_lock, /*sync*/ false,
+ &has_unreleasable);
+ if (!is_ttl_file) {
+ auto iter = _files.find(file_key);
+ std::vector<FileBlockCell*> to_remove;
+ if (iter != _files.end()) {
+ for (auto& [_, cell] : iter->second) {
+ *_gc_evict_bytes_metrics << cell.size();
+ *_gc_evict_count_metrics << 1;
+ if (cell.releasable()) {
+ to_remove.push_back(&cell);
+ } else {
+ has_unreleasable = true;
+ cell.file_block->set_deleting();
+ }
}
}
+ remove_file_blocks(to_remove, cache_lock, false, reason);
}
- remove_file_blocks(to_remove, cache_lock, false, reason);
+ if (has_unreleasable) {
+ _hashes_pending_cleanup.insert(file_key);
+ }
+ }
+ if (!has_unreleasable) {
+ enqueue_hash_for_cleanup(file_key);
}
Review Comment:
Queuing a hash-wide cleanup after releasing `_mutex` can delete cache files
created after this invalidation. `remove_if_cached_async()` removes the current
in-memory cells while holding the cache lock, then a later `get_or_set()` for
the same hash can add a new live cell and write a new file before the GC thread
drains `_recycle_hashes`; when `remove_all_by_hash()` eventually runs it
removes every `hash_*` directory, including that new file, leaving the live
cell pointing at missing storage. The synchronous `remove_if_cached()` has the
same post-lock window around its direct `remove_all_by_hash()` call. Please
scope cleanup to the directories observed during invalidation, or otherwise
coordinate hash-wide deletion with new cell creation for the same hash.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]