Coverage Report

Created: 2026-03-12 16:03

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