Coverage Report

Created: 2026-10-28 22:39

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
236
    void set_deleting() { _is_deleting = true; }
152
644k
    bool is_deleting() const { return _is_deleting; };
153
154
private:
155
    enum class CacheReferenceRole {
156
        HOLDER,
157
        PROBE,
158
    };
159
160
    std::string get_info_for_log_impl(std::lock_guard<std::mutex>& block_lock) const;
161
162
    [[nodiscard]] Status set_downloaded(std::lock_guard<std::mutex>& block_lock);
163
    bool is_downloader_impl(std::lock_guard<std::mutex>& block_lock) const;
164
165
    void complete_unlocked(std::lock_guard<std::mutex>& block_lock);
166
167
    void reset_downloader_impl(std::lock_guard<std::mutex>& block_lock);
168
169
    /// Release one holder/probe reference and complete deferred EMPTY/deleting block cleanup when
170
    /// it is the last reference outside the cache map.
171
    /// @param[in,out] file_block Reference to release.
172
    /// @param[in] role A holder completes downloader ownership acquired through get_or_set; a
173
    /// read-only probe never changes downloader state.
174
    static void release_cache_reference(std::shared_ptr<FileBlock>& file_block,
175
                                        CacheReferenceRole role);
176
177
    Range _block_range;
178
179
    State _download_state;
180
181
    uint64_t _downloader_id {0};
182
183
    BlockFileCache* _mgr;
184
185
    /// global locking order rule:
186
    /// 1. cache lock
187
    /// 2. block lock
188
    mutable std::mutex _mutex;
189
    std::condition_variable _cv;
190
    FileCacheKey _key;
191
    size_t _downloaded_size {0};
192
    bool _is_deleting {false};
193
194
    FileBlockCell* cell {nullptr};
195
};
196
197
extern std::ostream& operator<<(std::ostream& os, const FileBlock::State& value);
198
199
using FileBlockSPtr = std::shared_ptr<FileBlock>;
200
using FileBlocks = std::list<FileBlockSPtr>;
201
202
struct FileBlocksHolder {
203
725k
    explicit FileBlocksHolder(FileBlocks file_blocks) : file_blocks(std::move(file_blocks)) {}
204
    FileBlocksHolder(FileBlocksHolder&& other) noexcept
205
56
            : file_blocks(std::move(other.file_blocks)) {}
206
207
    FileBlocksHolder& operator=(const FileBlocksHolder&) = delete;
208
    FileBlocksHolder(const FileBlocksHolder&) = delete;
209
    ~FileBlocksHolder();
210
211
    FileBlocks file_blocks;
212
};
213
214
using FileBlocksHolderPtr = std::unique_ptr<FileBlocksHolder>;
215
216
} // namespace io
217
} // namespace doris