Coverage Report

Created: 2026-10-29 18:51

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/exec/spill/remote_spill_data_dir.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 <atomic>
21
#include <mutex>
22
#include <string>
23
24
#include "exec/spill/spill_data_dir.h"
25
26
namespace doris {
27
namespace io {
28
class RemoteFileSystem;
29
} // namespace io
30
31
/// Spill store on the object storage of a cloud storage vault (spill_storage_type=s3).
32
///
33
/// Object layout, relative to the vault prefix:
34
///   spill/{ip}_{port}/{query_id}/{spill file}/{part}
35
/// {ip}_{port} is the address this BE advertises (BackendOptions::get_localhost(), normally its
36
/// IP) and its heartbeat_service_port, the pair FE identifies a BE by, so several BEs on one
37
/// host get different directories and a key tells which BE wrote it and which query it belongs
38
/// to. The objects of a spill file are deleted when its SpillFile is destroyed, which happens
39
/// when the query is done with it; a deletion that failed is retried by the GC thread. Nothing
40
/// else deletes spill objects: what a BE that crashed left behind stays until an object
41
/// lifecycle rule of the bucket (expiring keys under <vault prefix>/spill/ and aborting
42
/// incomplete multipart uploads) removes it.
43
///
44
/// The file system is resolved lazily by ensure_ready(): the storage vault may not be known
45
/// yet when BE starts. See select_vault_fs() for which vault is used. Every SpillFile keeps the
46
/// file system it was created on, so its objects are read and deleted on that vault even when
47
/// a later file is created on another one.
48
class RemoteSpillDataDir final : public SpillDataDir {
49
public:
50
    /// @param vault_id  storage vault ID, empty selects one automatically (see select_vault_fs()).
51
    explicit RemoteSpillDataDir(std::string vault_id);
52
53
    /// The file system spill writes new files to:
54
    ///   1. `vault_id` (spill_s3_storage_vault_id) when it is set;
55
    ///   2. otherwise `latest_fs`, which only an instance without storage vaults has;
56
    ///   3. otherwise the S3 storage vault with the largest ID (the newest one), so that
57
    ///      changing the default vault does not move spill.
58
    /// nullptr when no such vault is known.
59
    static std::shared_ptr<io::RemoteFileSystem> select_vault_fs(
60
            const std::string& vault_id, const std::shared_ptr<io::RemoteFileSystem>& latest_fs);
61
62
    Status init() override;
63
64
1.24k
    bool is_remote() const override { return true; }
65
66
111
    bool ready() const override { return _ready.load(std::memory_order_acquire); }
67
68
    /// Resolve the vault for a new file and return an immutable filesystem snapshot. Without
69
    /// spill_s3_storage_vault_id every call selects again; existing files retain their FS.
70
    Status ensure_ready(io::FileSystemSPtr* file_fs);
71
72
    /// Bind a file system directly for tests without a cloud storage engine.
73
    void init_remote_fs(io::FileSystemSPtr fs, std::string endpoint);
74
75
    /// nullptr until ready.
76
    io::FileSystemSPtr fs() const override;
77
78
    /// Object storage has no capacity to probe; only spill_storage_limit_bytes applies.
79
    Status update_capacity() override;
80
81
    void record_persisted_bytes(int64_t bytes) override;
82
    void release_persisted_bytes(int64_t bytes) override;
83
    int64_t get_persisted_bytes() override;
84
85
    /// "{ip}_{port}" in the object keys; empty until ready.
86
1
    const std::string& endpoint() const { return _endpoint; }
87
88
1
    const std::string& vault_id() const { return _vault_id; }
89
90
protected:
91
    bool _reach_limit_unlocked(int64_t incoming_data_size) override;
92
93
private:
94
    void _bind_fs_unlocked(io::FileSystemSPtr fs, std::string endpoint);
95
    std::string _vault_id;
96
    std::string _endpoint;
97
    mutable std::mutex _init_mutex;
98
    std::atomic<bool> _ready {false};
99
    io::FileSystemSPtr _fs;
100
    bool _test_binding = false;
101
    int64_t _persisted_bytes = 0;
102
};
103
104
} // namespace doris