Skip to content

Commit bdde429

Browse files
committed
Phase 3: Add fast int64 hash path and batch insert methods to OpenAddressHashAgg
- Add hash_int64() - fast FNV-1a hash for int64 keys without buffer construction - Add insert_batch_int64() and insert_batch_bytes() for batch insertion - Fix find_or_insert_int64() to use key_hash in collision check (was missing) - These support Phase 1 batch encoding optimization
1 parent 9fd4097 commit bdde429

1 file changed

Lines changed: 53 additions & 1 deletion

File tree

include/executor/vectorized_operator.hpp

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,20 @@ class OpenAddressHashAgg {
422422
return hash;
423423
}
424424

425+
// Fast path for int64 keys: hash of [0x02][8-byte-int64] without buffer construction
426+
static uint64_t hash_int64(int64_t key) {
427+
uint64_t h = 14695981039346656037ull;
428+
h ^= 0x02; // type tag for INT64
429+
h *= 1099511628211ull;
430+
// XOR each byte of key in big-endian order
431+
uint64_t v = static_cast<uint64_t>(key);
432+
for (int i = 7; i >= 0; --i) {
433+
h ^= (v >> (i * 8)) & 0xFF;
434+
h *= 1099511628211ull;
435+
}
436+
return h;
437+
}
438+
425439
void init(size_t capacity_hint, size_t max_aggregates) {
426440
max_aggregates_ = max_aggregates;
427441
num_occupied_ = 0;
@@ -487,7 +501,7 @@ class OpenAddressHashAgg {
487501
valid_indices_.push_back(idx);
488502
return bucket;
489503
}
490-
if (bucket.key_type == 0x02 && bucket.key_int64 == key) {
504+
if (bucket.key_hash == hash && bucket.key_type == 0x02 && bucket.key_int64 == key) {
491505
bucket.is_new = false;
492506
return bucket;
493507
}
@@ -520,6 +534,44 @@ class OpenAddressHashAgg {
520534
const std::vector<size_t>& valid_slots() const { return valid_indices_; }
521535
HashBucket& slot(size_t idx) { return buckets_[idx]; }
522536
const HashBucket& slot(size_t idx) const { return buckets_[idx]; }
537+
538+
/**
539+
* @brief Insert a batch of int64 keys with precomputed hashes.
540+
* @param keys Array of int64 keys (n keys)
541+
* @param hashes Array of precomputed FNV-1a hashes (must be precomputed!)
542+
* @param n Number of keys
543+
* @return Number of new groups inserted (keys not found before)
544+
*/
545+
size_t insert_batch_int64(const int64_t* keys, const uint64_t* hashes, size_t n) {
546+
size_t new_groups = 0;
547+
for (size_t i = 0; i < n; ++i) {
548+
auto& bucket = find_or_insert_int64(keys[i], hashes[i]);
549+
if (bucket.is_new) {
550+
new_groups++;
551+
}
552+
}
553+
return new_groups;
554+
}
555+
556+
/**
557+
* @brief Insert a batch of string keys with precomputed hashes.
558+
* @param keys Array of key byte arrays
559+
* @param key_lens Array of key lengths
560+
* @param hashes Array of precomputed hashes
561+
* @param n Number of keys
562+
* @return Number of new groups inserted
563+
*/
564+
size_t insert_batch_bytes(const uint8_t** keys, const size_t* key_lens,
565+
const uint64_t* hashes, size_t n) {
566+
size_t new_groups = 0;
567+
for (size_t i = 0; i < n; ++i) {
568+
auto& bucket = find_or_insert(keys[i], key_lens[i], hashes[i]);
569+
if (bucket.is_new) {
570+
new_groups++;
571+
}
572+
}
573+
return new_groups;
574+
}
523575
};
524576

525577
/**

0 commit comments

Comments
 (0)