Coverage Report

Created: 2026-06-02 18:53

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
be/src/util/hash/murmur_hash3.cpp
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
//-----------------------------------------------------------------------------
19
// MurmurHash3 was written by Austin Appleby, and is placed in the public
20
// domain. The author hereby disclaims copyright to this source code.
21
22
// Note - The x86 and x64 versions do _not_ produce the same results, as the
23
// algorithms are optimized for their respective platforms. You can still
24
// compile and run any of them on any platform, but your performance with the
25
// non-native version will be less than optimal.
26
27
#include "util/hash/murmur_hash3.h"
28
29
#if defined(_MSC_VER)
30
#include <stdlib.h>
31
#endif
32
33
#include <glog/logging.h>
34
35
#include "util/unaligned.h"
36
37
namespace doris {
38
39
#if defined(_MSC_VER)
40
41
#define FORCE_INLINE __forceinline
42
43
#define ROTL32(x, y) _rotl(x, y)
44
#define ROTL64(x, y) _rotl64(x, y)
45
46
#define BIG_CONSTANT(x) (x)
47
48
// Other compilers
49
50
#else // defined(_MSC_VER)
51
52
#define FORCE_INLINE inline __attribute__((always_inline))
53
54
1.52k
FORCE_INLINE uint32_t rotl32(uint32_t x, int8_t r) {
55
1.52k
    return (x << r) | (x >> (32 - r));
56
1.52k
}
57
58
939M
FORCE_INLINE uint64_t rotl64(uint64_t x, int8_t r) {
59
939M
    return (x << r) | (x >> (64 - r));
60
939M
}
61
62
1.52k
#define ROTL32(x, y) rotl32(x, y)
63
940M
#define ROTL64(x, y) rotl64(x, y)
64
65
227M
#define BIG_CONSTANT(x) (x##LLU)
66
67
#endif // !defined(_MSC_VER)
68
69
//-----------------------------------------------------------------------------
70
// Block read - if your platform needs to do endian-swapping or can only
71
// handle aligned reads, do the conversion here
72
73
244
FORCE_INLINE uint32_t getblock32(const uint32_t* p, int i) {
74
244
    return unaligned_load<uint32_t>(&p[i]);
75
244
}
76
77
454M
FORCE_INLINE uint64_t getblock64(const uint64_t* p, size_t i) {
78
454M
    return unaligned_load<uint64_t>(&p[i]);
79
454M
}
80
81
//-----------------------------------------------------------------------------
82
// Finalization mix - force all bits of a hash block to avalanche
83
84
1.09k
FORCE_INLINE uint32_t fmix32(uint32_t h) {
85
1.09k
    h ^= h >> 16;
86
1.09k
    h *= 0x85ebca6b;
87
1.09k
    h ^= h >> 13;
88
1.09k
    h *= 0xc2b2ae35;
89
1.09k
    h ^= h >> 16;
90
91
1.09k
    return h;
92
1.09k
}
93
94
//----------
95
96
56.8M
FORCE_INLINE uint64_t fmix64(uint64_t k) {
97
56.8M
    k ^= k >> 33;
98
56.8M
    k *= BIG_CONSTANT(0xff51afd7ed558ccd);
99
56.8M
    k ^= k >> 33;
100
56.8M
    k *= BIG_CONSTANT(0xc4ceb9fe1a85ec53);
101
56.8M
    k ^= k >> 33;
102
103
56.8M
    return k;
104
56.8M
}
105
106
//-----------------------------------------------------------------------------
107
108
1.09k
void murmur_hash3_x86_32(const void* key, int64_t len, uint32_t seed, void* out) {
109
1.09k
    const uint8_t* data = (const uint8_t*)key;
110
1.09k
    const int nblocks = (int)len / 4;
111
112
1.09k
    uint32_t h1 = seed;
113
114
1.09k
    const uint32_t c1 = 0xcc9e2d51;
115
1.09k
    const uint32_t c2 = 0x1b873593;
116
117
    //----------
118
    // body
119
120
1.09k
    const uint32_t* blocks = (const uint32_t*)(data + nblocks * 4);
121
122
1.33k
    for (int i = -nblocks; i; i++) {
123
244
        uint32_t k1 = getblock32(blocks, i);
124
125
244
        k1 *= c1;
126
244
        k1 = ROTL32(k1, 15);
127
244
        k1 *= c2;
128
129
244
        h1 ^= k1;
130
244
        h1 = ROTL32(h1, 13);
131
244
        h1 = h1 * 5 + 0xe6546b64;
132
244
    }
133
134
    //----------
135
    // tail
136
137
1.09k
    const uint8_t* tail = (const uint8_t*)(data + nblocks * 4);
138
139
1.09k
    uint32_t k1 = 0;
140
141
1.09k
    switch (len & 3) {
142
49
    case 3:
143
49
        k1 ^= tail[2] << 16;
144
49
        [[fallthrough]];
145
271
    case 2:
146
271
        k1 ^= tail[1] << 8;
147
271
        [[fallthrough]];
148
1.03k
    case 1:
149
1.03k
        k1 ^= tail[0];
150
1.03k
        k1 *= c1;
151
1.03k
        k1 = ROTL32(k1, 15);
152
1.03k
        k1 *= c2;
153
1.03k
        h1 ^= k1;
154
1.09k
    };
155
156
    //----------
157
    // finalization
158
159
1.09k
    h1 ^= len;
160
161
1.09k
    h1 = fmix32(h1);
162
163
1.09k
    *(uint32_t*)out = h1;
164
1.09k
}
165
166
//-----------------------------------------------------------------------------
167
168
0
void murmur_hash3_x86_128(const void* key, const int len, uint32_t seed, void* out) {
169
0
    const uint8_t* data = (const uint8_t*)key;
170
0
    const int nblocks = len / 16;
171
172
0
    uint32_t h1 = seed;
173
0
    uint32_t h2 = seed;
174
0
    uint32_t h3 = seed;
175
0
    uint32_t h4 = seed;
176
177
0
    const uint32_t c1 = 0x239b961b;
178
0
    const uint32_t c2 = 0xab0e9789;
179
0
    const uint32_t c3 = 0x38b34ae5;
180
0
    const uint32_t c4 = 0xa1e38b93;
181
182
    //----------
183
    // body
184
185
0
    const uint32_t* blocks = (const uint32_t*)(data + nblocks * 16);
186
187
0
    for (int i = -nblocks; i; i++) {
188
0
        uint32_t k1 = getblock32(blocks, i * 4 + 0);
189
0
        uint32_t k2 = getblock32(blocks, i * 4 + 1);
190
0
        uint32_t k3 = getblock32(blocks, i * 4 + 2);
191
0
        uint32_t k4 = getblock32(blocks, i * 4 + 3);
192
193
0
        k1 *= c1;
194
0
        k1 = ROTL32(k1, 15);
195
0
        k1 *= c2;
196
0
        h1 ^= k1;
197
198
0
        h1 = ROTL32(h1, 19);
199
0
        h1 += h2;
200
0
        h1 = h1 * 5 + 0x561ccd1b;
201
202
0
        k2 *= c2;
203
0
        k2 = ROTL32(k2, 16);
204
0
        k2 *= c3;
205
0
        h2 ^= k2;
206
207
0
        h2 = ROTL32(h2, 17);
208
0
        h2 += h3;
209
0
        h2 = h2 * 5 + 0x0bcaa747;
210
211
0
        k3 *= c3;
212
0
        k3 = ROTL32(k3, 17);
213
0
        k3 *= c4;
214
0
        h3 ^= k3;
215
216
0
        h3 = ROTL32(h3, 15);
217
0
        h3 += h4;
218
0
        h3 = h3 * 5 + 0x96cd1c35;
219
220
0
        k4 *= c4;
221
0
        k4 = ROTL32(k4, 18);
222
0
        k4 *= c1;
223
0
        h4 ^= k4;
224
225
0
        h4 = ROTL32(h4, 13);
226
0
        h4 += h1;
227
0
        h4 = h4 * 5 + 0x32ac3b17;
228
0
    }
229
230
    //----------
231
    // tail
232
233
0
    const uint8_t* tail = (const uint8_t*)(data + nblocks * 16);
234
235
0
    uint32_t k1 = 0;
236
0
    uint32_t k2 = 0;
237
0
    uint32_t k3 = 0;
238
0
    uint32_t k4 = 0;
239
240
0
    switch (len & 15) {
241
0
    case 15:
242
0
        k4 ^= tail[14] << 16;
243
0
        [[fallthrough]];
244
0
    case 14:
245
0
        k4 ^= tail[13] << 8;
246
0
        [[fallthrough]];
247
0
    case 13:
248
0
        k4 ^= tail[12] << 0;
249
0
        k4 *= c4;
250
0
        k4 = ROTL32(k4, 18);
251
0
        k4 *= c1;
252
0
        h4 ^= k4;
253
0
        [[fallthrough]];
254
0
    case 12:
255
0
        k3 ^= tail[11] << 24;
256
0
        [[fallthrough]];
257
0
    case 11:
258
0
        k3 ^= tail[10] << 16;
259
0
        [[fallthrough]];
260
0
    case 10:
261
0
        k3 ^= tail[9] << 8;
262
0
        [[fallthrough]];
263
0
    case 9:
264
0
        k3 ^= tail[8] << 0;
265
0
        k3 *= c3;
266
0
        k3 = ROTL32(k3, 17);
267
0
        k3 *= c4;
268
0
        h3 ^= k3;
269
0
        [[fallthrough]];
270
0
    case 8:
271
0
        k2 ^= tail[7] << 24;
272
0
        [[fallthrough]];
273
0
    case 7:
274
0
        k2 ^= tail[6] << 16;
275
0
        [[fallthrough]];
276
0
    case 6:
277
0
        k2 ^= tail[5] << 8;
278
0
        [[fallthrough]];
279
0
    case 5:
280
0
        k2 ^= tail[4] << 0;
281
0
        k2 *= c2;
282
0
        k2 = ROTL32(k2, 16);
283
0
        k2 *= c3;
284
0
        h2 ^= k2;
285
0
        [[fallthrough]];
286
0
    case 4:
287
0
        k1 ^= tail[3] << 24;
288
0
        [[fallthrough]];
289
0
    case 3:
290
0
        k1 ^= tail[2] << 16;
291
0
        [[fallthrough]];
292
0
    case 2:
293
0
        k1 ^= tail[1] << 8;
294
0
        [[fallthrough]];
295
0
    case 1:
296
0
        k1 ^= tail[0] << 0;
297
0
        k1 *= c1;
298
0
        k1 = ROTL32(k1, 15);
299
0
        k1 *= c2;
300
0
        h1 ^= k1;
301
0
    };
302
303
    //----------
304
    // finalization
305
306
0
    h1 ^= len;
307
0
    h2 ^= len;
308
0
    h3 ^= len;
309
0
    h4 ^= len;
310
311
0
    h1 += h2;
312
0
    h1 += h3;
313
0
    h1 += h4;
314
0
    h2 += h1;
315
0
    h3 += h1;
316
0
    h4 += h1;
317
318
0
    h1 = fmix32(h1);
319
0
    h2 = fmix32(h2);
320
0
    h3 = fmix32(h3);
321
0
    h4 = fmix32(h4);
322
323
0
    h1 += h2;
324
0
    h1 += h3;
325
0
    h1 += h4;
326
0
    h2 += h1;
327
0
    h3 += h1;
328
0
    h4 += h1;
329
330
0
    ((uint32_t*)out)[0] = h1;
331
0
    ((uint32_t*)out)[1] = h2;
332
0
    ((uint32_t*)out)[2] = h3;
333
0
    ((uint32_t*)out)[3] = h4;
334
0
}
335
336
//-----------------------------------------------------------------------------
337
338
// Helper function that implements the core MurmurHash3 128-bit hashing algorithm
339
327
void murmur_hash3_x64_process(const void* key, const size_t len, uint64_t& h1, uint64_t& h2) {
340
327
    const uint8_t* data = (const uint8_t*)key;
341
327
    const size_t nblocks = len / 16;
342
343
327
    const uint64_t c1 = BIG_CONSTANT(0x87c37b91114253d5);
344
327
    const uint64_t c2 = BIG_CONSTANT(0x4cf5ad432745937f);
345
346
    //----------
347
    // body
348
349
327
    const uint64_t* blocks = (const uint64_t*)(data);
350
351
392
    for (size_t i = 0; i < nblocks; i++) {
352
65
        uint64_t k1 = getblock64(blocks, i * 2 + 0);
353
65
        uint64_t k2 = getblock64(blocks, i * 2 + 1);
354
355
65
        k1 *= c1;
356
65
        k1 = ROTL64(k1, 31);
357
65
        k1 *= c2;
358
65
        h1 ^= k1;
359
360
65
        h1 = ROTL64(h1, 27);
361
65
        h1 += h2;
362
65
        h1 = h1 * 5 + 0x52dce729;
363
364
65
        k2 *= c2;
365
65
        k2 = ROTL64(k2, 33);
366
65
        k2 *= c1;
367
65
        h2 ^= k2;
368
369
65
        h2 = ROTL64(h2, 31);
370
65
        h2 += h1;
371
65
        h2 = h2 * 5 + 0x38495ab5;
372
65
    }
373
374
    //----------
375
    // tail
376
377
327
    const uint8_t* tail = (const uint8_t*)(data + nblocks * 16);
378
379
327
    uint64_t k1 = 0;
380
327
    uint64_t k2 = 0;
381
382
327
    switch (len & 15) {
383
0
    case 15:
384
0
        k2 ^= ((uint64_t)tail[14]) << 48;
385
0
        [[fallthrough]];
386
0
    case 14:
387
0
        k2 ^= ((uint64_t)tail[13]) << 40;
388
0
        [[fallthrough]];
389
0
    case 13:
390
0
        k2 ^= ((uint64_t)tail[12]) << 32;
391
0
        [[fallthrough]];
392
19
    case 12:
393
19
        k2 ^= ((uint64_t)tail[11]) << 24;
394
19
        [[fallthrough]];
395
49
    case 11:
396
49
        k2 ^= ((uint64_t)tail[10]) << 16;
397
49
        [[fallthrough]];
398
67
    case 10:
399
67
        k2 ^= ((uint64_t)tail[9]) << 8;
400
67
        [[fallthrough]];
401
67
    case 9:
402
67
        k2 ^= ((uint64_t)tail[8]) << 0;
403
67
        k2 *= c2;
404
67
        k2 = ROTL64(k2, 33);
405
67
        k2 *= c1;
406
67
        h2 ^= k2;
407
67
        [[fallthrough]];
408
67
    case 8:
409
67
        k1 ^= ((uint64_t)tail[7]) << 56;
410
67
        [[fallthrough]];
411
67
    case 7:
412
67
        k1 ^= ((uint64_t)tail[6]) << 48;
413
67
        [[fallthrough]];
414
69
    case 6:
415
69
        k1 ^= ((uint64_t)tail[5]) << 40;
416
69
        [[fallthrough]];
417
252
    case 5:
418
252
        k1 ^= ((uint64_t)tail[4]) << 32;
419
252
        [[fallthrough]];
420
254
    case 4:
421
254
        k1 ^= ((uint64_t)tail[3]) << 24;
422
254
        [[fallthrough]];
423
256
    case 3:
424
256
        k1 ^= ((uint64_t)tail[2]) << 16;
425
256
        [[fallthrough]];
426
256
    case 2:
427
256
        k1 ^= ((uint64_t)tail[1]) << 8;
428
256
        [[fallthrough]];
429
284
    case 1:
430
284
        k1 ^= ((uint64_t)tail[0]) << 0;
431
284
        k1 *= c1;
432
284
        k1 = ROTL64(k1, 31);
433
284
        k1 *= c2;
434
284
        h1 ^= k1;
435
327
    };
436
437
    //----------
438
    // finalization
439
440
327
    h1 ^= len;
441
327
    h2 ^= len;
442
443
327
    h1 += h2;
444
327
    h2 += h1;
445
446
327
    h1 = fmix64(h1);
447
327
    h2 = fmix64(h2);
448
449
327
    h1 += h2;
450
327
    h2 += h1;
451
327
}
452
453
//-----------------------------------------------------------------------------
454
455
// The origin function `murmur_hash3_x64_128` is copied from: https://github.com/aappleby/smhasher/blob/master/src/MurmurHash3.cpp
456
// And Doris modified it into function `murmur_hash3_x64_process`
457
// For this reason, this function is still retained even though it has no calls.
458
141
void murmur_hash3_x64_128(const void* key, const size_t len, const uint32_t seed, void* out) {
459
141
    uint64_t h1 = seed;
460
141
    uint64_t h2 = seed;
461
141
    murmur_hash3_x64_process(key, len, h1, h2);
462
141
    ((uint64_t*)out)[0] = h1;
463
141
    ((uint64_t*)out)[1] = h2;
464
141
}
465
466
//-----------------------------------------------------------------------------
467
468
// MurmurHash3 x64 64-bit variant using shared 128-bit processing function
469
// This implementation reuses the murmur_hash3_x64_process function and only outputs the first hash value
470
// Used for function mmh3_64_v2
471
void murmur_hash3_x64_64_shared(const void* key, const int64_t len, const uint64_t seed,
472
63
                                void* out) {
473
63
    DCHECK_GE(len, 0);
474
63
    uint64_t h1 = seed;
475
63
    uint64_t h2 = seed;
476
63
    murmur_hash3_x64_process(key, static_cast<size_t>(len), h1, h2);
477
63
    ((uint64_t*)out)[0] = h1;
478
63
}
479
480
//-----------------------------------------------------------------------------
481
482
// MurmurHash3 x64 64-bit variant with optimized standalone implementation
483
// This implementation is specifically optimized for 64-bit output
484
// Used for function mmh3_64
485
56.9M
void murmur_hash3_x64_64(const void* key, const int64_t len, const uint64_t seed, void* out) {
486
56.9M
    const uint8_t* data = (const uint8_t*)key;
487
56.9M
    const int nblocks = (int)len / 8;
488
56.9M
    uint64_t h1 = seed;
489
490
56.9M
    const uint64_t c1 = BIG_CONSTANT(0x87c37b91114253d5);
491
56.9M
    const uint64_t c2 = BIG_CONSTANT(0x4cf5ad432745937f);
492
493
    //----------
494
    // body
495
496
56.9M
    const uint64_t* blocks = (const uint64_t*)(data);
497
498
511M
    for (int i = 0; i < nblocks; i++) {
499
454M
        uint64_t k1 = getblock64(blocks, i);
500
501
454M
        k1 *= c1;
502
454M
        k1 = ROTL64(k1, 31);
503
454M
        k1 *= c2;
504
454M
        h1 ^= k1;
505
506
454M
        h1 = ROTL64(h1, 27);
507
454M
        h1 = h1 * 5 + 0x52dce729;
508
454M
    }
509
510
    //----------
511
    // tail
512
513
56.9M
    const uint8_t* tail = (const uint8_t*)(data + nblocks * 8);
514
56.9M
    uint64_t k1 = 0;
515
516
56.9M
    switch (len & 7) {
517
2.71M
    case 7:
518
2.71M
        k1 ^= ((uint64_t)tail[6]) << 48;
519
2.71M
        [[fallthrough]];
520
4.19M
    case 6:
521
4.19M
        k1 ^= ((uint64_t)tail[5]) << 40;
522
4.19M
        [[fallthrough]];
523
6.77M
    case 5:
524
6.77M
        k1 ^= ((uint64_t)tail[4]) << 32;
525
6.77M
        [[fallthrough]];
526
17.1M
    case 4:
527
17.1M
        k1 ^= ((uint64_t)tail[3]) << 24;
528
17.1M
        [[fallthrough]];
529
18.8M
    case 3:
530
18.8M
        k1 ^= ((uint64_t)tail[2]) << 16;
531
18.8M
        [[fallthrough]];
532
21.6M
    case 2:
533
21.6M
        k1 ^= ((uint64_t)tail[1]) << 8;
534
21.6M
        [[fallthrough]];
535
32.5M
    case 1:
536
32.5M
        k1 ^= ((uint64_t)tail[0]) << 0;
537
32.5M
        k1 *= c1;
538
32.5M
        k1 = ROTL64(k1, 31);
539
32.5M
        k1 *= c2;
540
32.5M
        h1 ^= k1;
541
56.9M
    };
542
543
    //----------
544
    // finalization
545
546
56.8M
    h1 ^= len;
547
56.8M
    h1 = fmix64(h1);
548
549
56.8M
    ((uint64_t*)out)[0] = h1;
550
56.8M
}
551
552
} // namespace doris