Coverage Report

Created: 2026-08-21 21:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/io/cache/inflight_write_buffer_index.h
Line
Count
Source
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
18
#pragma once
19
20
#include <bvar/bvar.h>
21
22
#include <atomic>
23
#include <cstddef>
24
#include <cstdint>
25
#include <functional>
26
#include <memory>
27
#include <mutex>
28
#include <string>
29
#include <unordered_map>
30
#include <vector>
31
32
#include "io/cache/async_cache_write_manager.h"
33
#include "io/cache/file_cache_common.h"
34
35
namespace doris::io {
36
37
/// Metadata for one block whose remote payload is waiting for asynchronous persistence.
38
/// `buffer` is non-null. `buffer_offset` and `buffer_size` describe its valid file interval, while
39
/// `buffer->size()` is the allocation capacity accounted by the index's memory gauge.
40
struct InflightWriteBufferEntry {
41
    AsyncCacheWriteBufferPtr buffer;
42
    size_t buffer_offset {0};
43
    size_t buffer_size {0};
44
    int64_t submit_ts_us {0};
45
46
    InflightWriteBufferEntry(AsyncCacheWriteBufferPtr buffer_, size_t offset_, size_t size_,
47
                             int64_t submit_ts_us_)
48
66
            : buffer(std::move(buffer_)),
49
66
              buffer_offset(offset_),
50
66
              buffer_size(size_),
51
66
              submit_ts_us(submit_ts_us_) {}
52
};
53
54
/// Sharded index from (cache key, aligned block offset) to an accepted async-write payload.
55
/// Readers use it before probing disk cache so concurrent misses can reuse remote bytes in memory.
56
class InflightWriteBufferIndex {
57
public:
58
    /// A batch-lookup result retains the requested offset even when `entry` is null.
59
    struct LookupResult {
60
        size_t block_offset {0};
61
        std::shared_ptr<InflightWriteBufferEntry> entry;
62
    };
63
64
    /// @param shard_count Positive number of independently locked hash shards.
65
    /// @param metric_prefix Prefix that makes per-cache-disk bvar names unique.
66
    explicit InflightWriteBufferIndex(size_t shard_count, std::string metric_prefix = {});
67
68
    /// Claim `(cache_hash, block_offset)` for `entry` if no entry already exists. File contents are
69
    /// immutable for a cache hash, so every entry at the same offset contains interchangeable data
70
    /// even when its persistence task belongs to an invalidated write epoch.
71
    /// @return null when insertion succeeds; otherwise the existing owner.
72
    std::shared_ptr<InflightWriteBufferEntry> insert_if_absent(
73
            const UInt128Wrapper& cache_hash, size_t block_offset,
74
            std::shared_ptr<InflightWriteBufferEntry> entry);
75
76
    /// Find the immutable payload for `(cache_hash, block_offset)` regardless of the persistence
77
    /// task's write epoch.
78
    std::shared_ptr<InflightWriteBufferEntry> lookup(const UInt128Wrapper& cache_hash,
79
                                                     size_t block_offset);
80
81
    /// Look up aligned `block_offsets` in input order.
82
    std::vector<LookupResult> lookup_all(const UInt128Wrapper& cache_hash,
83
                                         const std::vector<size_t>& block_offsets);
84
85
    /// Remove the key only if it still points to `expected`, preventing an old task callback from
86
    /// deleting a replacement entry.
87
    /// @return true if this exact owner was removed.
88
    bool remove_if(const UInt128Wrapper& cache_hash, size_t block_offset,
89
                   const std::shared_ptr<InflightWriteBufferEntry>& expected);
90
91
    /// Return the number of indexed block payloads.
92
34
    size_t count() const { return _count.load(std::memory_order_relaxed); }
93
94
    /// Return the buffer-capacity bytes retained by all current index entries.
95
625
    size_t buffer_bytes() const { return _buffer_bytes.load(std::memory_order_relaxed); }
96
97
    /// Record removal of an inserted entry because queue submission hit backpressure.
98
1
    void record_backpressure_rollback() { *_rollback_on_backpressure_metric << 1; }
99
100
private:
101
    struct Key {
102
        UInt128Wrapper cache_hash;
103
        size_t block_offset {0};
104
105
79
        bool operator==(const Key& other) const {
106
79
            return cache_hash == other.cache_hash && block_offset == other.block_offset;
107
79
        }
108
    };
109
110
    struct KeyHash {
111
325
        size_t operator()(const Key& key) const {
112
325
            return doris::io::KeyHash()(key.cache_hash) ^ std::hash<size_t>()(key.block_offset);
113
325
        }
114
    };
115
116
    struct Shard {
117
        mutable std::mutex mutex;
118
        std::unordered_map<Key, std::shared_ptr<InflightWriteBufferEntry>, KeyHash> entries;
119
    };
120
121
147
    size_t _shard_index(const Key& key) const { return KeyHash()(key) % _shards.size(); }
122
123
    std::vector<std::unique_ptr<Shard>> _shards;
124
    std::atomic<size_t> _count {0};
125
    std::atomic<size_t> _buffer_bytes {0};
126
127
    std::shared_ptr<bvar::PassiveStatus<size_t>> _buffer_bytes_metric;
128
    std::shared_ptr<bvar::Adder<uint64_t>> _lookup_metric;
129
    std::shared_ptr<bvar::Adder<uint64_t>> _hit_metric;
130
    std::shared_ptr<bvar::Adder<uint64_t>> _miss_metric;
131
    std::shared_ptr<bvar::Adder<uint64_t>> _insert_metric;
132
    std::shared_ptr<bvar::Adder<uint64_t>> _insert_existing_metric;
133
    std::shared_ptr<bvar::Adder<uint64_t>> _remove_success_metric;
134
    std::shared_ptr<bvar::Adder<uint64_t>> _remove_failed_metric;
135
    std::shared_ptr<bvar::Adder<uint64_t>> _rollback_on_backpressure_metric;
136
    std::shared_ptr<bvar::LatencyRecorder> _lock_wait_latency_metric;
137
    std::shared_ptr<bvar::LatencyRecorder> _lock_hold_latency_metric;
138
};
139
140
} // namespace doris::io