Coverage Report

Created: 2026-10-29 14:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/exprs/datasketches_hll_util.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 <cstddef>
21
#include <cstdint>
22
#include <hll.hpp>
23
#include <memory>
24
#include <string_view>
25
26
#include "core/custom_allocator.h"
27
#include "core/string_ref.h"
28
29
namespace doris::datasketches_hll {
30
31
struct AllocationHeader;
32
void* allocate(size_t bytes);
33
void deallocate(void* ptr) noexcept;
34
35
namespace detail {
36
class AllocationOwner {
37
public:
38
7.77k
    AllocationOwner() = default;
39
    ~AllocationOwner();
40
    AllocationOwner(const AllocationOwner&) = delete;
41
    AllocationOwner& operator=(const AllocationOwner&) = delete;
42
    void clear() noexcept;
43
    void release() noexcept;
44
45
private:
46
    friend void* datasketches_hll::allocate(size_t bytes);
47
    friend void datasketches_hll::deallocate(void* ptr) noexcept;
48
    AllocationHeader* _head = nullptr;
49
};
50
} // namespace detail
51
52
// DataSketches uses allocator.allocate() + placement new in its factories. When a constructor
53
// or a later merge throws, some allocations never reach an owning sketch. Declare this scope
54
// before local sketches, and destroy/reset any existing union before an exception leaves it.
55
// Normal destructors run first; the scope then frees only the allocations they did not release.
56
class AllocationScope {
57
public:
58
    AllocationScope();
59
    ~AllocationScope();
60
61
    AllocationScope(const AllocationScope&) = delete;
62
    AllocationScope& operator=(const AllocationScope&) = delete;
63
64
private:
65
    detail::AllocationOwner _owner;
66
    detail::AllocationOwner* _previous;
67
    int _exceptions;
68
};
69
70
// Stateless across copies and rebinds. The current call's scope records the allocation, so a
71
// union can copy registers from a sketch created in an earlier scope or on another thread.
72
template <typename T>
73
class SketchAllocator {
74
public:
75
    using value_type = T;
76
    SketchAllocator() = default;
77
    template <typename U>
78
27.5k
    SketchAllocator(const SketchAllocator<U>&) noexcept {}
_ZN5doris16datasketches_hll15SketchAllocatorIN12datasketches9Hll8ArrayINS1_IhEEEEEC2IhEERKNS1_IT_EE
Line
Count
Source
78
2.92k
    SketchAllocator(const SketchAllocator<U>&) noexcept {}
_ZN5doris16datasketches_hll15SketchAllocatorIN12datasketches10AuxHashMapINS1_IhEEEEEC2IhEERKNS1_IT_EE
Line
Count
Source
78
301
    SketchAllocator(const SketchAllocator<U>&) noexcept {}
_ZN5doris16datasketches_hll15SketchAllocatorIjEC2IhEERKNS1_IT_EE
Line
Count
Source
78
4.31k
    SketchAllocator(const SketchAllocator<U>&) noexcept {}
_ZN5doris16datasketches_hll15SketchAllocatorIN12datasketches10AuxHashMapINS1_IhEEEEEC2IjEERKNS1_IT_EE
Line
Count
Source
78
286
    SketchAllocator(const SketchAllocator<U>&) noexcept {}
_ZN5doris16datasketches_hll15SketchAllocatorIN12datasketches9Hll6ArrayINS1_IhEEEEEC2IhEERKNS1_IT_EE
Line
Count
Source
78
1.27k
    SketchAllocator(const SketchAllocator<U>&) noexcept {}
_ZN5doris16datasketches_hll15SketchAllocatorIN12datasketches9Hll4ArrayINS1_IhEEEEEC2IhEERKNS1_IT_EE
Line
Count
Source
78
1.71k
    SketchAllocator(const SketchAllocator<U>&) noexcept {}
_ZN5doris16datasketches_hll15SketchAllocatorIN12datasketches10CouponListINS1_IhEEEEEC2IhEERKNS1_IT_EE
Line
Count
Source
78
7.40k
    SketchAllocator(const SketchAllocator<U>&) noexcept {}
_ZN5doris16datasketches_hll15SketchAllocatorIN12datasketches10CouponListINS1_IhEEEEEC2IjEERKNS1_IT_EE
Line
Count
Source
78
844
    SketchAllocator(const SketchAllocator<U>&) noexcept {}
_ZN5doris16datasketches_hll15SketchAllocatorIN12datasketches13CouponHashSetINS1_IhEEEEEC2IhEERKNS1_IT_EE
Line
Count
Source
78
1.78k
    SketchAllocator(const SketchAllocator<U>&) noexcept {}
_ZN5doris16datasketches_hll15SketchAllocatorIN12datasketches13CouponHashSetINS1_IhEEEEEC2IjEERKNS1_IT_EE
Line
Count
Source
78
323
    SketchAllocator(const SketchAllocator<U>&) noexcept {}
_ZN5doris16datasketches_hll15SketchAllocatorIhEC2IjEERKNS1_IT_EE
Line
Count
Source
78
6.40k
    SketchAllocator(const SketchAllocator<U>&) noexcept {}
79
80
19.3k
    T* allocate(size_t count) {
81
19.3k
        static_assert(alignof(T) <= alignof(std::max_align_t));
82
19.3k
        return static_cast<T*>(datasketches_hll::allocate(count * sizeof(T)));
83
19.3k
    }
_ZN5doris16datasketches_hll15SketchAllocatorIN12datasketches9Hll8ArrayINS1_IhEEEEE8allocateEm
Line
Count
Source
80
1.47k
    T* allocate(size_t count) {
81
1.47k
        static_assert(alignof(T) <= alignof(std::max_align_t));
82
1.47k
        return static_cast<T*>(datasketches_hll::allocate(count * sizeof(T)));
83
1.47k
    }
_ZN5doris16datasketches_hll15SketchAllocatorIhE8allocateEm
Line
Count
Source
80
4.52k
    T* allocate(size_t count) {
81
4.52k
        static_assert(alignof(T) <= alignof(std::max_align_t));
82
4.52k
        return static_cast<T*>(datasketches_hll::allocate(count * sizeof(T)));
83
4.52k
    }
_ZN5doris16datasketches_hll15SketchAllocatorIN12datasketches10AuxHashMapINS1_IhEEEEE8allocateEm
Line
Count
Source
80
301
    T* allocate(size_t count) {
81
301
        static_assert(alignof(T) <= alignof(std::max_align_t));
82
301
        return static_cast<T*>(datasketches_hll::allocate(count * sizeof(T)));
83
301
    }
_ZN5doris16datasketches_hll15SketchAllocatorIjE8allocateEm
Line
Count
Source
80
6.33k
    T* allocate(size_t count) {
81
6.33k
        static_assert(alignof(T) <= alignof(std::max_align_t));
82
6.33k
        return static_cast<T*>(datasketches_hll::allocate(count * sizeof(T)));
83
6.33k
    }
_ZN5doris16datasketches_hll15SketchAllocatorIN12datasketches9Hll6ArrayINS1_IhEEEEE8allocateEm
Line
Count
Source
80
640
    T* allocate(size_t count) {
81
640
        static_assert(alignof(T) <= alignof(std::max_align_t));
82
640
        return static_cast<T*>(datasketches_hll::allocate(count * sizeof(T)));
83
640
    }
_ZN5doris16datasketches_hll15SketchAllocatorIN12datasketches9Hll4ArrayINS1_IhEEEEE8allocateEm
Line
Count
Source
80
865
    T* allocate(size_t count) {
81
865
        static_assert(alignof(T) <= alignof(std::max_align_t));
82
865
        return static_cast<T*>(datasketches_hll::allocate(count * sizeof(T)));
83
865
    }
_ZN5doris16datasketches_hll15SketchAllocatorIN12datasketches10CouponListINS1_IhEEEEE8allocateEm
Line
Count
Source
80
4.13k
    T* allocate(size_t count) {
81
4.13k
        static_assert(alignof(T) <= alignof(std::max_align_t));
82
4.13k
        return static_cast<T*>(datasketches_hll::allocate(count * sizeof(T)));
83
4.13k
    }
_ZN5doris16datasketches_hll15SketchAllocatorIN12datasketches13CouponHashSetINS1_IhEEEEE8allocateEm
Line
Count
Source
80
1.06k
    T* allocate(size_t count) {
81
1.06k
        static_assert(alignof(T) <= alignof(std::max_align_t));
82
1.06k
        return static_cast<T*>(datasketches_hll::allocate(count * sizeof(T)));
83
1.06k
    }
84
19.1k
    void deallocate(T* ptr, size_t) noexcept { datasketches_hll::deallocate(ptr); }
_ZN5doris16datasketches_hll15SketchAllocatorIhE10deallocateEPhm
Line
Count
Source
84
4.47k
    void deallocate(T* ptr, size_t) noexcept { datasketches_hll::deallocate(ptr); }
_ZN5doris16datasketches_hll15SketchAllocatorIjE10deallocateEPjm
Line
Count
Source
84
6.26k
    void deallocate(T* ptr, size_t) noexcept { datasketches_hll::deallocate(ptr); }
_ZN5doris16datasketches_hll15SketchAllocatorIN12datasketches10AuxHashMapINS1_IhEEEEE10deallocateEPS5_m
Line
Count
Source
84
287
    void deallocate(T* ptr, size_t) noexcept { datasketches_hll::deallocate(ptr); }
_ZN5doris16datasketches_hll15SketchAllocatorIN12datasketches9Hll4ArrayINS1_IhEEEEE10deallocateEPS5_m
Line
Count
Source
84
846
    void deallocate(T* ptr, size_t) noexcept { datasketches_hll::deallocate(ptr); }
_ZN5doris16datasketches_hll15SketchAllocatorIN12datasketches9Hll6ArrayINS1_IhEEEEE10deallocateEPS5_m
Line
Count
Source
84
636
    void deallocate(T* ptr, size_t) noexcept { datasketches_hll::deallocate(ptr); }
_ZN5doris16datasketches_hll15SketchAllocatorIN12datasketches9Hll8ArrayINS1_IhEEEEE10deallocateEPS5_m
Line
Count
Source
84
1.44k
    void deallocate(T* ptr, size_t) noexcept { datasketches_hll::deallocate(ptr); }
_ZN5doris16datasketches_hll15SketchAllocatorIN12datasketches10CouponListINS1_IhEEEEE10deallocateEPS5_m
Line
Count
Source
84
4.10k
    void deallocate(T* ptr, size_t) noexcept { datasketches_hll::deallocate(ptr); }
_ZN5doris16datasketches_hll15SketchAllocatorIN12datasketches13CouponHashSetINS1_IhEEEEE10deallocateEPS5_m
Line
Count
Source
84
1.03k
    void deallocate(T* ptr, size_t) noexcept { datasketches_hll::deallocate(ptr); }
85
86
    template <typename U>
87
    bool operator==(const SketchAllocator<U>&) const noexcept {
88
        return true;
89
    }
90
    template <typename U>
91
    bool operator!=(const SketchAllocator<U>&) const noexcept {
92
        return false;
93
    }
94
};
95
96
// Shared by the DataSketches HLL aggregate and scalar functions so that both track memory through
97
// Doris allocators and report broken input the same way.
98
using Alloc = SketchAllocator<uint8_t>;
99
using Sketch = datasketches::hll_sketch_alloc<Alloc>;
100
101
// The library can free its old gadget during LIST/SET promotion before installing the new
102
// pointer. If a subsequent allocation fails, that union is not safe to destroy. Keep its
103
// allocations under Doris ownership and discard the failed state without invoking that
104
// invalid library destructor. The public sketch format and estimates remain unchanged.
105
class Union {
106
public:
107
    explicit Union(uint8_t lg_k, const Alloc& allocator = Alloc());
108
    ~Union();
109
    Union(Union&&) noexcept;
110
    Union& operator=(Union&&) noexcept;
111
    Union(const Union&);
112
    Union& operator=(const Union&);
113
114
    void update(const Sketch& sketch);
115
    Sketch get_result(datasketches::target_hll_type type = datasketches::HLL_4) const;
116
    double get_estimate() const;
117
    double get_lower_bound(uint8_t std_devs) const;
118
    double get_upper_bound(uint8_t std_devs) const;
119
    uint8_t get_lg_config_k() const;
120
    static double get_rel_err(bool upper, bool unioned, uint8_t lg_k, uint8_t std_devs);
121
122
private:
123
    struct Impl;
124
    struct Deleter {
125
        void operator()(Impl* ptr) const noexcept;
126
    };
127
    std::unique_ptr<Impl, Deleter> _impl;
128
};
129
130
// Deserializes a serialized DataSketches HLL sketch. `action` names the caller in the error
131
// message, e.g. "add" or "read".
132
//
133
// Empty bytes are rejected before the library reads them. A doris::Exception keeps its code, so
134
// MEM_ALLOC_FAILED raised by the allocator is not reported as corrupted data; any other failure of
135
// the library means the bytes are not a valid sketch and becomes CORRUPTION.
136
Sketch deserialize(const StringRef& value, std::string_view action);
137
138
} // namespace doris::datasketches_hll