Coverage Report

Created: 2026-07-01 20:24

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
class BlockFileCache;
44
struct FileBlockCell;
45
46
class FileBlock {
47
    friend struct FileBlocksHolder;
48
    friend class BlockFileCache;
49
    friend class CachedRemoteFileReader;
50
    friend struct FileBlockCell;
51
    friend class FileBlockTestAccessor;
52
53
public:
54
    enum class State {
55
        DOWNLOADED,
56
        /**
57
         * When file block is first created and returned to user, it has state EMPTY.
58
         * EMPTY state can become DOWNLOADING when getOrSetDownaloder is called successfully
59
         * by any owner of EMPTY state file block.
60
         */
61
        EMPTY,
62
        /**
63
         * A newly created file block never has DOWNLOADING state until call to getOrSetDownloader
64
         * because each cache user might acquire multiple file blocks and reads them one by one,
65
         * so only user which actually needs to read this block earlier than others - becomes a downloader.
66
         */
67
        DOWNLOADING,
68
        SKIP_CACHE,
69
    };
70
71
    FileBlock(const FileCacheKey& key, size_t size, BlockFileCache* mgr, State download_state);
72
73
220k
    ~FileBlock() = default;
74
75
    State state() const;
76
    State state_unsafe() const;
77
78
    static std::string state_to_string(FileBlock::State state);
79
80
    /// Represents an interval [left, right] including both boundaries.
81
    struct Range {
82
        size_t left;
83
        size_t right;
84
85
1.14M
        Range(size_t left, size_t right) : left(left), right(right) {}
86
87
10.4M
        [[nodiscard]] size_t size() const { return right - left + 1; }
88
89
24
        [[nodiscard]] std::string to_string() const {
90
24
            return fmt::format("[{}, {}]", std::to_string(left), std::to_string(right));
91
24
        }
92
    };
93
94
17.5M
    const Range& range() const { return _block_range; }
95
96
864k
    const UInt128Wrapper& get_hash_value() const { return _key.hash; }
97
98
6.39M
    size_t offset() const { return range().left; }
99
100
    State wait();
101
102
    // append data to cache file
103
    [[nodiscard]] Status append(Slice data);
104
    [[nodiscard]] Status appendv(const Slice* data, size_t data_cnt);
105
    [[nodiscard]] Status append_iobuf(const butil::IOBuf& data);
106
107
    // read data from cache file
108
    [[nodiscard]] Status read(Slice buffer, size_t read_offset);
109
    [[nodiscard]] Status read_to_iobuf(butil::IOBuf* out, size_t read_offset, size_t bytes_req,
110
                                       size_t* bytes_read);
111
112
    // finish write, release the file writer
113
    [[nodiscard]] Status finalize();
114
115
    // set downloader if state == EMPTY
116
    uint64_t get_or_set_downloader();
117
118
    uint64_t get_downloader() const;
119
120
    void reset_downloader(std::lock_guard<std::mutex>& block_lock);
121
122
    bool is_downloader() const;
123
124
4.45M
    FileCacheType cache_type() const { return _key.meta.type; }
125
126
238k
    int64_t tablet_id() const { return _key.meta.tablet_id; }
127
128
7
    void set_tablet_id(int64_t id) { _key.meta.tablet_id = id; }
129
130
    static uint64_t get_caller_id();
131
132
    std::string get_info_for_log() const;
133
134
    [[nodiscard]] Status change_cache_type(FileCacheType new_type);
135
136
    [[nodiscard]] Status change_cache_type_lock(FileCacheType new_type,
137
                                                std::lock_guard<std::mutex>&);
138
139
238k
    uint64_t expiration_time() const { return _key.meta.expiration_time; }
140
141
    std::string get_cache_file() const;
142
143
    State state_unlock(std::lock_guard<std::mutex>&) const;
144
145
    FileBlock& operator=(const FileBlock&) = delete;
146
    FileBlock(const FileBlock&) = delete;
147
148
    // block is being using by other thread when deleting, so tag it is_deleting and delete later on¬
149
9.57k
    void set_deleting() { _is_deleting = true; }
150
687k
    bool is_deleting() const { return _is_deleting; };
151
152
public:
153
    std::atomic<bool> _owned_by_cached_reader {
154
            false}; // pocessed by CachedRemoteFileReader::_cache_file_readers
155
156
private:
157
    std::string get_info_for_log_impl(std::lock_guard<std::mutex>& block_lock) const;
158
159
    [[nodiscard]] Status set_downloaded(std::lock_guard<std::mutex>& block_lock);
160
    bool is_downloader_impl(std::lock_guard<std::mutex>& block_lock) const;
161
162
    void complete_unlocked(std::lock_guard<std::mutex>& block_lock);
163
164
    void reset_downloader_impl(std::lock_guard<std::mutex>& block_lock);
165
166
    Range _block_range;
167
168
    State _download_state;
169
170
    uint64_t _downloader_id {0};
171
172
    BlockFileCache* _mgr;
173
174
    /// global locking order rule:
175
    /// 1. cache lock
176
    /// 2. block lock
177
    mutable std::mutex _mutex;
178
    std::condition_variable _cv;
179
    FileCacheKey _key;
180
    size_t _downloaded_size {0};
181
    bool _is_deleting {false};
182
183
    FileBlockCell* cell {nullptr};
184
};
185
186
extern std::ostream& operator<<(std::ostream& os, const FileBlock::State& value);
187
188
using FileBlockSPtr = std::shared_ptr<FileBlock>;
189
using FileBlocks = std::list<FileBlockSPtr>;
190
191
struct FileBlocksHolder {
192
877k
    explicit FileBlocksHolder(FileBlocks file_blocks) : file_blocks(std::move(file_blocks)) {}
193
    FileBlocksHolder(FileBlocksHolder&& other) noexcept
194
6.10k
            : file_blocks(std::move(other.file_blocks)) {}
195
196
    FileBlocksHolder& operator=(const FileBlocksHolder&) = delete;
197
    FileBlocksHolder(const FileBlocksHolder&) = delete;
198
    ~FileBlocksHolder();
199
200
    FileBlocks file_blocks;
201
};
202
203
using FileBlocksHolderPtr = std::unique_ptr<FileBlocksHolder>;
204
205
} // namespace io
206
} // namespace doris