Coverage Report

Created: 2026-08-02 12:16

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/util/adbc_driver_registry.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 <arrow-adbc/adbc.h>
21
22
#include <cstddef>
23
#include <map>
24
#include <mutex>
25
#include <string>
26
27
#include "common/status.h"
28
29
namespace doris {
30
31
/// Process-wide ADBC driver load cache.
32
///
33
/// Each resolved path is passed to AdbcLoadDriver (which dlopens it) at most once, and is **never
34
/// dlclosed**: drivers carry global state and background threads -- Go runtimes especially -- so
35
/// unloading one is a use-after-free hazard. Handles stay live until the process exits.
36
///
37
/// Failures are cached too, so a bad path does not retry the dlopen once per scan range.
38
///
39
/// **The registry itself is never destroyed either** -- see instance(). A function-local static
40
/// would be torn down during static destruction, which would both dangle every AdbcDriver* already
41
/// handed out and orphan the driver manager's own per-driver state (it is freed only by the
42
/// driver's release callback, which this registry deliberately never calls).
43
class AdbcDriverRegistry {
44
public:
45
    AdbcDriverRegistry(const AdbcDriverRegistry&) = delete;
46
    AdbcDriverRegistry& operator=(const AdbcDriverRegistry&) = delete;
47
48
    static AdbcDriverRegistry& instance();
49
50
    /// Loads the driver at `driver_path`, or returns the already-loaded one. An empty `entrypoint`
51
    /// lets the driver manager search for one based on the driver name. The returned pointer stays
52
    /// valid for the lifetime of the process.
53
    Status get_or_load(const std::string& driver_path, const std::string& entrypoint,
54
                       const AdbcDriver** out);
55
56
    /// Test only: how many paths have been attempted, successes and failures alike.
57
    size_t loaded_count() const;
58
59
private:
60
1
    AdbcDriverRegistry() = default;
61
    ~AdbcDriverRegistry() = default;
62
63
    struct Entry {
64
        AdbcDriver driver {};
65
        Status load_status;
66
        bool loaded = false;
67
    };
68
69
    mutable std::mutex _mutex;
70
    // Keyed by realpath(driver_path), falling back to the original string when it cannot be
71
    // resolved. std::map keeps the entries pointer-stable, which the returned AdbcDriver* needs.
72
    std::map<std::string, Entry> _drivers;
73
};
74
75
} // namespace doris