Coverage Report

Created: 2026-08-01 21:36

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/exec/common/hash_table/hash.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
// This file is copied from
18
// https://github.com/ClickHouse/ClickHouse/blob/master/src/Common/HashTable/Hash.h
19
// and modified by Doris
20
21
#pragma once
22
23
#include <type_traits>
24
25
#include "core/extended_types.h"
26
#include "core/string_ref.h"
27
#include "core/types.h"
28
#include "core/uint128.h"
29
#include "parallel_hashmap/phmap_utils.h"
30
31
// Here is an empirical value.
32
static constexpr size_t HASH_MAP_PREFETCH_DIST = 16;
33
34
/** Hash functions that are better than the trivial function std::hash.
35
  *
36
  * Example: when we do aggregation by the visitor ID, the performance increase is more than 5 times.
37
  * This is because of following reasons:
38
  * - in Yandex, visitor identifier is an integer that has timestamp with seconds resolution in lower bits;
39
  * - in typical implementation of standard library, hash function for integers is trivial and just use lower bits;
40
  * - traffic is non-uniformly distributed across a day;
41
  * - we are using open-addressing linear probing hash tables that are most critical to hash function quality,
42
  *   and trivial hash function gives disastrous results.
43
  */
44
45
/** Taken from MurmurHash. This is Murmur finalizer.
46
  * Faster than int_hash32 when inserting into the hash table UInt64 -> UInt64, where the key is the visitor ID.
47
  */
48
60
inline doris::UInt64 int_hash64(doris::UInt64 x) {
49
60
    x ^= x >> 33;
50
60
    x *= 0xff51afd7ed558ccdULL;
51
60
    x ^= x >> 33;
52
60
    x *= 0xc4ceb9fe1a85ec53ULL;
53
60
    x ^= x >> 33;
54
55
60
    return x;
56
60
}
57
58
/** CRC32C is not very high-quality as a hash function,
59
  *  according to avalanche and bit independence tests (see SMHasher software), as well as a small number of bits,
60
  *  but can behave well when used in hash tables,
61
  *  due to high speed (latency 3 + 1 clock cycle, throughput 1 clock cycle).
62
  * Works only with SSE 4.2 support.
63
  */
64
#include "util/sse_util.hpp"
65
66
4.93M
inline doris::UInt64 int_hash_crc32(doris::UInt64 x) {
67
4.93M
#if defined(__SSE4_2__) || (defined(__aarch64__) && defined(__ARM_FEATURE_CRC32))
68
4.93M
    return _mm_crc32_u64(-1ULL, x);
69
#else
70
    /// On other platforms we do not have CRC32. NOTE This can be confusing.
71
    return int_hash64(x);
72
#endif
73
4.93M
}
74
75
template <typename T>
76
60
inline size_t default_hash64(T key) {
77
60
    union {
78
60
        T in;
79
60
        doris::UInt64 out;
80
60
    } u;
81
60
    u.out = 0;
82
60
    u.in = key;
83
60
    return int_hash64(u.out);
84
60
}
Unexecuted instantiation: _Z14default_hash64IhEmT_
Unexecuted instantiation: _Z14default_hash64IaEmT_
Unexecuted instantiation: _Z14default_hash64IsEmT_
_Z14default_hash64IiEmT_
Line
Count
Source
76
16
inline size_t default_hash64(T key) {
77
16
    union {
78
16
        T in;
79
16
        doris::UInt64 out;
80
16
    } u;
81
16
    u.out = 0;
82
16
    u.in = key;
83
16
    return int_hash64(u.out);
84
16
}
Unexecuted instantiation: _Z14default_hash64IlEmT_
_Z14default_hash64InEmT_
Line
Count
Source
76
41
inline size_t default_hash64(T key) {
77
41
    union {
78
41
        T in;
79
41
        doris::UInt64 out;
80
41
    } u;
81
41
    u.out = 0;
82
41
    u.in = key;
83
41
    return int_hash64(u.out);
84
41
}
Unexecuted instantiation: _Z14default_hash64IfEmT_
_Z14default_hash64IdEmT_
Line
Count
Source
76
3
inline size_t default_hash64(T key) {
77
3
    union {
78
3
        T in;
79
3
        doris::UInt64 out;
80
3
    } u;
81
3
    u.out = 0;
82
3
    u.in = key;
83
3
    return int_hash64(u.out);
84
3
}
Unexecuted instantiation: _Z14default_hash64IjEmT_
Unexecuted instantiation: _Z14default_hash64IoEmT_
85
86
template <typename T, typename Enable = void>
87
struct DefaultHash;
88
89
template <typename T>
90
    requires std::is_arithmetic_v<T>
91
struct DefaultHash<T> {
92
60
    size_t operator()(T key) const { return default_hash64<T>(key); }
Unexecuted instantiation: _ZNK11DefaultHashIhvEclEh
Unexecuted instantiation: _ZNK11DefaultHashIavEclEa
Unexecuted instantiation: _ZNK11DefaultHashIsvEclEs
_ZNK11DefaultHashIivEclEi
Line
Count
Source
92
16
    size_t operator()(T key) const { return default_hash64<T>(key); }
Unexecuted instantiation: _ZNK11DefaultHashIlvEclEl
_ZNK11DefaultHashInvEclEn
Line
Count
Source
92
41
    size_t operator()(T key) const { return default_hash64<T>(key); }
Unexecuted instantiation: _ZNK11DefaultHashIfvEclEf
_ZNK11DefaultHashIdvEclEd
Line
Count
Source
92
3
    size_t operator()(T key) const { return default_hash64<T>(key); }
Unexecuted instantiation: _ZNK11DefaultHashIjvEclEj
Unexecuted instantiation: _ZNK11DefaultHashIovEclEo
93
};
94
95
template <>
96
struct DefaultHash<doris::VecDateTimeValue> {
97
0
    size_t operator()(doris::VecDateTimeValue key) const { return int_hash64(*(int64_t*)&key); }
98
};
99
100
template <>
101
struct DefaultHash<doris::DateV2Value<doris::DateTimeV2ValueType>> {
102
0
    size_t operator()(doris::DateV2Value<doris::DateTimeV2ValueType> key) const {
103
0
        return int_hash64(key.to_date_int_val());
104
0
    }
105
};
106
107
template <>
108
struct DefaultHash<doris::DateV2Value<doris::DateV2ValueType>> {
109
0
    size_t operator()(doris::DateV2Value<doris::DateV2ValueType> key) const {
110
0
        return int_hash64(key.to_date_int_val());
111
0
    }
112
};
113
114
template <>
115
struct DefaultHash<doris::DateTimeV2NanoValue> {
116
0
    size_t operator()(doris::DateTimeV2NanoValue key) const {
117
0
        return int_hash64(key.epoch_nanos());
118
0
    }
119
};
120
121
template <>
122
struct DefaultHash<doris::TimestampTzValue> {
123
0
    size_t operator()(doris::TimestampTzValue key) const {
124
0
        return int_hash64(key.to_date_int_val());
125
0
    }
126
};
127
128
template <>
129
struct DefaultHash<doris::StringRef> : public doris::StringRefHash {};
130
131
template <>
132
struct DefaultHash<wide::Int256> : public std::hash<wide::Int256> {};
133
134
template <typename T>
135
struct HashCRC32;
136
137
template <typename T>
138
4.93M
inline size_t hash_crc32(T key) {
139
4.93M
    union {
140
4.93M
        T in;
141
4.93M
        doris::UInt64 out;
142
4.93M
    } u;
143
4.93M
    u.out = 0;
144
4.93M
    u.in = key;
145
4.93M
    return int_hash_crc32(u.out);
146
4.93M
}
_Z10hash_crc32IhEmT_
Line
Count
Source
138
44.8k
inline size_t hash_crc32(T key) {
139
44.8k
    union {
140
44.8k
        T in;
141
44.8k
        doris::UInt64 out;
142
44.8k
    } u;
143
44.8k
    u.out = 0;
144
44.8k
    u.in = key;
145
44.8k
    return int_hash_crc32(u.out);
146
44.8k
}
_Z10hash_crc32IaEmT_
Line
Count
Source
138
8.50k
inline size_t hash_crc32(T key) {
139
8.50k
    union {
140
8.50k
        T in;
141
8.50k
        doris::UInt64 out;
142
8.50k
    } u;
143
8.50k
    u.out = 0;
144
8.50k
    u.in = key;
145
8.50k
    return int_hash_crc32(u.out);
146
8.50k
}
_Z10hash_crc32IsEmT_
Line
Count
Source
138
8.50k
inline size_t hash_crc32(T key) {
139
8.50k
    union {
140
8.50k
        T in;
141
8.50k
        doris::UInt64 out;
142
8.50k
    } u;
143
8.50k
    u.out = 0;
144
8.50k
    u.in = key;
145
8.50k
    return int_hash_crc32(u.out);
146
8.50k
}
_Z10hash_crc32IiEmT_
Line
Count
Source
138
7.16k
inline size_t hash_crc32(T key) {
139
7.16k
    union {
140
7.16k
        T in;
141
7.16k
        doris::UInt64 out;
142
7.16k
    } u;
143
7.16k
    u.out = 0;
144
7.16k
    u.in = key;
145
7.16k
    return int_hash_crc32(u.out);
146
7.16k
}
_Z10hash_crc32IlEmT_
Line
Count
Source
138
29.4k
inline size_t hash_crc32(T key) {
139
29.4k
    union {
140
29.4k
        T in;
141
29.4k
        doris::UInt64 out;
142
29.4k
    } u;
143
29.4k
    u.out = 0;
144
29.4k
    u.in = key;
145
29.4k
    return int_hash_crc32(u.out);
146
29.4k
}
_Z10hash_crc32ImEmT_
Line
Count
Source
138
381k
inline size_t hash_crc32(T key) {
139
381k
    union {
140
381k
        T in;
141
381k
        doris::UInt64 out;
142
381k
    } u;
143
381k
    u.out = 0;
144
381k
    u.in = key;
145
381k
    return int_hash_crc32(u.out);
146
381k
}
Unexecuted instantiation: _Z10hash_crc32IfEmT_
_Z10hash_crc32IdEmT_
Line
Count
Source
138
3
inline size_t hash_crc32(T key) {
139
3
    union {
140
3
        T in;
141
3
        doris::UInt64 out;
142
3
    } u;
143
3
    u.out = 0;
144
3
    u.in = key;
145
3
    return int_hash_crc32(u.out);
146
3
}
_Z10hash_crc32IjEmT_
Line
Count
Source
138
4.42M
inline size_t hash_crc32(T key) {
139
4.42M
    union {
140
4.42M
        T in;
141
4.42M
        doris::UInt64 out;
142
4.42M
    } u;
143
4.42M
    u.out = 0;
144
4.42M
    u.in = key;
145
4.42M
    return int_hash_crc32(u.out);
146
4.42M
}
_Z10hash_crc32ItEmT_
Line
Count
Source
138
26.7k
inline size_t hash_crc32(T key) {
139
26.7k
    union {
140
26.7k
        T in;
141
26.7k
        doris::UInt64 out;
142
26.7k
    } u;
143
26.7k
    u.out = 0;
144
26.7k
    u.in = key;
145
26.7k
    return int_hash_crc32(u.out);
146
26.7k
}
147
148
template <>
149
55.1k
inline size_t hash_crc32(doris::UInt128 u) {
150
55.1k
    return doris::UInt128HashCRC32()(u);
151
55.1k
}
152
153
template <>
154
3
inline size_t hash_crc32(unsigned __int128 u) {
155
3
    return doris::UInt128HashCRC32()(u);
156
3
}
157
158
template <>
159
6
inline size_t hash_crc32(doris::Int128 u) {
160
6
    return doris::UInt128HashCRC32()({(u >> 64) & int64_t(-1), u & int64_t(-1)});
161
6
}
162
163
template <>
164
0
inline size_t hash_crc32(doris::VecDateTimeValue u) {
165
0
    return hash_crc32(*(int64_t*)&u);
166
0
}
167
168
template <>
169
0
inline size_t hash_crc32(doris::DateV2Value<doris::DateTimeV2ValueType> u) {
170
0
    return hash_crc32(u.to_date_int_val());
171
0
}
172
173
template <>
174
0
inline size_t hash_crc32(doris::DateV2Value<doris::DateV2ValueType> u) {
175
0
    return hash_crc32(u.to_date_int_val());
176
0
}
177
178
template <>
179
0
inline size_t hash_crc32(doris::DateTimeV2NanoValue u) {
180
0
    return hash_crc32(u.epoch_nanos());
181
0
}
182
183
template <>
184
0
inline size_t hash_crc32(doris::TimestampTzValue u) {
185
0
    return hash_crc32(u.to_date_int_val());
186
0
}
187
188
#define DEFINE_HASH(T)                   \
189
    template <>                          \
190
    struct HashCRC32<T> {                \
191
4.98M
        size_t operator()(T key) const { \
192
4.98M
            return hash_crc32<T>(key);   \
193
4.98M
        }                                \
_ZNK9HashCRC32IhEclEh
Line
Count
Source
191
44.8k
        size_t operator()(T key) const { \
192
44.8k
            return hash_crc32<T>(key);   \
193
44.8k
        }                                \
_ZNK9HashCRC32IaEclEa
Line
Count
Source
191
8.50k
        size_t operator()(T key) const { \
192
8.50k
            return hash_crc32<T>(key);   \
193
8.50k
        }                                \
_ZNK9HashCRC32IsEclEs
Line
Count
Source
191
8.50k
        size_t operator()(T key) const { \
192
8.50k
            return hash_crc32<T>(key);   \
193
8.50k
        }                                \
_ZNK9HashCRC32IiEclEi
Line
Count
Source
191
7.16k
        size_t operator()(T key) const { \
192
7.16k
            return hash_crc32<T>(key);   \
193
7.16k
        }                                \
_ZNK9HashCRC32IlEclEl
Line
Count
Source
191
29.4k
        size_t operator()(T key) const { \
192
29.4k
            return hash_crc32<T>(key);   \
193
29.4k
        }                                \
_ZNK9HashCRC32InEclEn
Line
Count
Source
191
6
        size_t operator()(T key) const { \
192
6
            return hash_crc32<T>(key);   \
193
6
        }                                \
_ZNK9HashCRC32IN4wide7integerILm128EjEEEclES2_
Line
Count
Source
191
55.1k
        size_t operator()(T key) const { \
192
55.1k
            return hash_crc32<T>(key);   \
193
55.1k
        }                                \
_ZNK9HashCRC32ImEclEm
Line
Count
Source
191
381k
        size_t operator()(T key) const { \
192
381k
            return hash_crc32<T>(key);   \
193
381k
        }                                \
Unexecuted instantiation: _ZNK9HashCRC32IfEclEf
_ZNK9HashCRC32IdEclEd
Line
Count
Source
191
3
        size_t operator()(T key) const { \
192
3
            return hash_crc32<T>(key);   \
193
3
        }                                \
Unexecuted instantiation: _ZNK9HashCRC32IN5doris11DateV2ValueINS0_15DateV2ValueTypeEEEEclES3_
Unexecuted instantiation: _ZNK9HashCRC32IN5doris11DateV2ValueINS0_19DateTimeV2ValueTypeEEEEclES3_
Unexecuted instantiation: _ZNK9HashCRC32IN5doris16TimestampTzValueEEclES1_
_ZNK9HashCRC32ItEclEt
Line
Count
Source
191
26.7k
        size_t operator()(T key) const { \
192
26.7k
            return hash_crc32<T>(key);   \
193
26.7k
        }                                \
_ZNK9HashCRC32IjEclEj
Line
Count
Source
191
4.42M
        size_t operator()(T key) const { \
192
4.42M
            return hash_crc32<T>(key);   \
193
4.42M
        }                                \
Unexecuted instantiation: _ZNK9HashCRC32IN5doris16VecDateTimeValueEEclES1_
Unexecuted instantiation: _ZNK9HashCRC32IN5doris19DateTimeV2NanoValueEEclES1_
_ZNK9HashCRC32IoEclEo
Line
Count
Source
191
3
        size_t operator()(T key) const { \
192
3
            return hash_crc32<T>(key);   \
193
3
        }                                \
194
    };
195
196
DEFINE_HASH(doris::UInt8)
197
DEFINE_HASH(doris::UInt16)
198
DEFINE_HASH(doris::UInt32)
199
DEFINE_HASH(doris::UInt64)
200
DEFINE_HASH(doris::UInt128)
201
DEFINE_HASH(doris::Int8)
202
DEFINE_HASH(doris::Int16)
203
DEFINE_HASH(doris::Int32)
204
DEFINE_HASH(doris::Int64)
205
DEFINE_HASH(doris::Int128)
206
DEFINE_HASH(doris::Float32)
207
DEFINE_HASH(doris::Float64)
208
DEFINE_HASH(doris::VecDateTimeValue)
209
DEFINE_HASH(doris::DateV2Value<doris::DateTimeV2ValueType>)
210
DEFINE_HASH(doris::DateV2Value<doris::DateV2ValueType>)
211
DEFINE_HASH(doris::DateTimeV2NanoValue)
212
DEFINE_HASH(doris::TimestampTzValue)
213
DEFINE_HASH(unsigned __int128)
214
215
#undef DEFINE_HASH
216
217
template <typename Key, typename Hash = HashCRC32<Key>>
218
struct HashMixWrapper {
219
4.67M
    size_t operator()(Key key) const { return phmap::phmap_mix<sizeof(size_t)>()(Hash()(key)); }
_ZNK14HashMixWrapperIm9HashCRC32ImEEclEm
Line
Count
Source
219
348k
    size_t operator()(Key key) const { return phmap::phmap_mix<sizeof(size_t)>()(Hash()(key)); }
_ZNK14HashMixWrapperIj9HashCRC32IjEEclEj
Line
Count
Source
219
4.32M
    size_t operator()(Key key) const { return phmap::phmap_mix<sizeof(size_t)>()(Hash()(key)); }
220
};
221
222
template <>
223
struct HashCRC32<doris::UInt256> {
224
24
    size_t operator()(const doris::UInt256& x) const {
225
24
#if defined(__SSE4_2__) || defined(__aarch64__)
226
24
        doris::UInt64 crc = -1ULL;
227
24
        crc = _mm_crc32_u64(crc, x.items[0]);
228
24
        crc = _mm_crc32_u64(crc, x.items[1]);
229
24
        crc = _mm_crc32_u64(crc, x.items[2]);
230
24
        crc = _mm_crc32_u64(crc, x.items[3]);
231
24
        return crc;
232
#else
233
        return Hash128to64({Hash128to64({x.a, x.b}), Hash128to64({x.c, x.d})});
234
#endif
235
24
    }
236
};
237
238
template <>
239
struct HashCRC32<wide::Int256> {
240
8.19k
    size_t operator()(const wide::Int256& x) const {
241
8.19k
#if defined(__SSE4_2__) || defined(__aarch64__)
242
8.19k
        doris::UInt64 crc = -1ULL;
243
8.19k
        crc = _mm_crc32_u64(crc, x.items[0]);
244
8.19k
        crc = _mm_crc32_u64(crc, x.items[1]);
245
8.19k
        crc = _mm_crc32_u64(crc, x.items[2]);
246
8.19k
        crc = _mm_crc32_u64(crc, x.items[3]);
247
8.19k
        return crc;
248
#else
249
        return Hash128to64(
250
                {Hash128to64({x.items[0], x.items[1]}), Hash128to64({x.items[2], x.items[3]})});
251
#endif
252
8.19k
    }
253
};
254
255
template <>
256
struct HashCRC32<doris::Decimal256> {
257
0
    size_t operator()(const doris::Decimal256& value) const {
258
0
        return HashCRC32<wide::Int256>()(value.value);
259
0
    }
260
};
261
262
template <>
263
struct HashCRC32<doris::Decimal32> {
264
0
    size_t operator()(const doris::Decimal32& value) const {
265
0
        return HashCRC32<int32_t>()(value.value);
266
0
    }
267
};
268
269
template <>
270
struct HashCRC32<doris::Decimal64> {
271
0
    size_t operator()(const doris::Decimal64& value) const {
272
0
        return HashCRC32<int64_t>()(value.value);
273
0
    }
274
};
275
276
template <>
277
struct HashCRC32<doris::Decimal128V3> {
278
0
    size_t operator()(const doris::Decimal128V3& value) const {
279
0
        return HashCRC32<__int128>()(value.value);
280
0
    }
281
};
282
283
template <>
284
struct HashCRC32<doris::Decimal128V2> {
285
0
    size_t operator()(const doris::Decimal128V2& value) const {
286
0
        return HashCRC32<__int128>()(value.value);
287
0
    }
288
};
289
290
template <>
291
struct HashCRC32<doris::DecimalV2Value> {
292
0
    size_t operator()(const doris::DecimalV2Value& value) const {
293
0
        return HashCRC32<__int128>()(value.value());
294
0
    }
295
};
296
297
#include "common/compile_check_avoid_begin.h"
298
299
template <>
300
struct HashCRC32<doris::UInt72> {
301
66
    size_t operator()(const doris::UInt72& x) const {
302
66
        doris::UInt64 crc = -1ULL;
303
66
        crc = _mm_crc32_u8(crc, x.a);
304
66
        crc = _mm_crc32_u64(crc, x.b);
305
66
        return crc;
306
66
    }
307
};
308
309
template <>
310
struct HashCRC32<doris::UInt96> {
311
21
    size_t operator()(const doris::UInt96& x) const {
312
21
        doris::UInt64 crc = -1ULL;
313
21
        crc = _mm_crc32_u32(crc, x.a);
314
21
        crc = _mm_crc32_u64(crc, x.b);
315
21
        return crc;
316
21
    }
317
};
318
319
template <>
320
struct HashCRC32<doris::UInt104> {
321
54
    size_t operator()(const doris::UInt104& x) const {
322
54
        doris::UInt64 crc = -1ULL;
323
54
        crc = _mm_crc32_u8(crc, x.a);
324
54
        crc = _mm_crc32_u32(crc, x.b);
325
54
        crc = _mm_crc32_u64(crc, x.c);
326
54
        return crc;
327
54
    }
328
};
329
330
template <>
331
struct HashCRC32<doris::UInt136> {
332
2
    size_t operator()(const doris::UInt136& x) const {
333
2
        doris::UInt64 crc = -1ULL;
334
2
        crc = _mm_crc32_u8(crc, x.a);
335
2
        crc = _mm_crc32_u64(crc, x.b);
336
2
        crc = _mm_crc32_u64(crc, x.c);
337
2
        return crc;
338
2
    }
339
};
340
341
#include "common/compile_check_avoid_end.h"