Coverage Report

Created: 2026-08-20 23:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/io/cache/file_block.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 <fmt/format.h>
21
#include <stddef.h>
22
23
#include <atomic>
24
#include <condition_variable>
25
#include <list>
26
#include <memory>
27
#include <mutex>
28
#include <string>
29
#include <utility>
30
31
#include "common/status.h"
32
#include "io/cache/file_cache_common.h"
33
#include "util/slice.h"
34
35
namespace butil {
36
class IOBuf;
37
}
38
39
namespace doris {
40
namespace io {
41
42
struct FileBlocksHolder;
43
struct FileBlocksProbeResult;
44
class BlockFileCache;
45
struct FileBlockCell;
46
47
class FileBlock {
48
    friend struct FileBlocksHolder;
49
    friend struct FileBlocksProbeResult;
50
    friend class BlockFileCache;
51
    friend class CachedRemoteFileReader;
52
    friend struct FileBlockCell;
53
    friend class FileBlockTestAccessor;
54
55
public:
56
    enum class State {
57
        DOWNLOADED,
58
        /**
59
         * When file block is first created and returned to user, it has state EMPTY.
60
         * EMPTY state can become DOWNLOADING when getOrSetDownaloder is called successfully
61
         * by any owner of EMPTY state file block.
62
         */
63
        EMPTY,
64
        /**
65
         * A newly created file block never has DOWNLOADING state until call to getOrSetDownloader
66
         * because each cache user might acquire multiple file blocks and reads them one by one,
67
         * so only user which actually needs to read this block earlier than others - becomes a downloader.
68
         */
69
        DOWNLOADING,
70
        SKIP_CACHE,
71
    };
72
73
    FileBlock(const FileCacheKey& key, size_t size, BlockFileCache* mgr, State download_state);
74
75
114k
    ~FileBlock() = default;
76
77
    State state() const;
78
    State state_unsafe() const;
79
80
    static std::string state_to_string(FileBlock::State state);
81
82
    /// Represents an interval [left, right] including both boundaries.
83
    struct Range {
84
        size_t left;
85
        size_t right;
86
87
853k
        Range(size_t left, size_t right) : left(left), right(right) {}
88
89
1.84M
        [[nodiscard]] size_t size() const { return right - left + 1; }
90
91
24
        [[nodiscard]] std::string to_string() const {
92
24
            return fmt::format("[{}, {}]", std::to_string(left), std::to_string(right));
93
24
        }
94
    };
95
96
5.12M
    const Range& range() const { return _block_range; }
97
98
335k
    const UInt128Wrapper& get_hash_value() const { return _key.hash; }
99
100
442k
    size_t offset() const { return range().left; }
101
102
    State wait();
103
104
    // append data to cache file
105
    [[nodiscard]] Status append(Slice data);
106
    [[nodiscard]] Status appendv(const Slice* data, size_t data_cnt);
107
    [[nodiscard]] Status append_iobuf(const butil::IOBuf& data);
108
109
    // read data from cache file
110
    [[nodiscard]] Status read(Slice buffer, size_t read_offset);
111
    [[nodiscard]] Status read_to_iobuf(butil::IOBuf* out, size_t read_offset, size_t bytes_req,
112
                                       size_t* bytes_read);
113
114
    // finish write, release the file writer
115
    [[nodiscard]] Status finalize();
116
117
    // set downloader if state == EMPTY
118
    uint64_t get_or_set_downloader();
119
120
    uint64_t get_downloader() const;
121
122
    void reset_downloader(std::lock_guard<std::mutex>& block_lock);
123
124
    bool is_downloader() const;
125
126
3.02M
    FileCacheType cache_type() const { return _key.meta.type; }
127
128
108k
    int64_t tablet_id() const { return _key.meta.tablet_id; }
129
130
7
    void set_tablet_id(int64_t id) { _key.meta.tablet_id = id; }
131
132
    static uint64_t get_caller_id();
133
134
    std::string get_info_for_log() const;
135
136
    [[nodiscard]] Status change_cache_type(FileCacheType new_type);
137
138
    [[nodiscard]] Status change_cache_type_lock(FileCacheType new_type,
139
                                                std::lock_guard<std::mutex>&);
140
141
108k
    uint64_t expiration_time() const { return _key.meta.expiration_time; }
142
143
    std::string get_cache_file() const;
144
145
    State state_unlock(std::lock_guard<std::mutex>&) const;
146
147
    FileBlock& operator=(const FileBlock&) = delete;
148
    FileBlock(const FileBlock&) = delete;
149
150
    // block is being using by other thread when deleting, so tag it is_deleting and delete later on¬
151
212
    void set_deleting() { _is_deleting = true; }
152
536k
    bool is_deleting() const { return _is_deleting; };
153
154
public:
155
    std::atomic<bool> _owned_by_cached_reader {
156
            false}; // pocessed by CachedRemoteFileReader::_cache_file_readers
157
158
private:
159
    enum class CacheReferenceRole {
160
        HOLDER,
161
        PROBE,
162
    };
163
164
    std::string get_info_for_log_impl(std::lock_guard<std::mutex>& block_lock) const;
165
166
    [[nodiscard]] Status set_downloaded(std::lock_guard<std::mutex>& block_lock);
167
    bool is_downloader_impl(std::lock_guard<std::mutex>& block_lock) const;
168
169
    void complete_unlocked(std::lock_guard<std::mutex>& block_lock);
170
171
    void reset_downloader_impl(std::lock_guard<std::mutex>& block_lock);
172
173
    /// Release one holder/probe reference and complete deferred EMPTY/deleting block cleanup when
174
    /// it is the last reference outside the cache map.
175
    /// @param[in,out] file_block Reference to release.
176
    /// @param[in] role A holder completes downloader ownership acquired through get_or_set; a
177
    /// read-only probe never changes downloader state.
178
    static void release_cache_reference(std::shared_ptr<FileBlock>& file_block,
179
                                        CacheReferenceRole role);
180
181
    Range _block_range;
182
183
    State _download_state;
184
185
    uint64_t _downloader_id {0};
186
187
    BlockFileCache* _mgr;
188
189
    /// global locking order rule:
190
    /// 1. cache lock
191
    /// 2. block lock
192
    mutable std::mutex _mutex;
193
    std::condition_variable _cv;
194
    FileCacheKey _key;
195
    size_t _downloaded_size {0};
196
    bool _is_deleting {false};
197
198
    FileBlockCell* cell {nullptr};
199
};
200
201
extern std::ostream& operator<<(std::ostream& os, const FileBlock::State& value);
202
203
using FileBlockSPtr = std::shared_ptr<FileBlock>;
204
using FileBlocks = std::list<FileBlockSPtr>;
205
206
struct FileBlocksHolder {
207
725k
    explicit FileBlocksHolder(FileBlocks file_blocks) : file_blocks(std::move(file_blocks)) {}
208
    FileBlocksHolder(FileBlocksHolder&& other) noexcept
209
55
            : file_blocks(std::move(other.file_blocks)) {}
210
211
    FileBlocksHolder& operator=(const FileBlocksHolder&) = delete;
212
    FileBlocksHolder(const FileBlocksHolder&) = delete;
213
    ~FileBlocksHolder();
214
215
    FileBlocks file_blocks;
216
};
217
218
using FileBlocksHolderPtr = std::unique_ptr<FileBlocksHolder>;
219
220
} // namespace io
221
} // namespace doris