@@ -288,13 +288,18 @@ class FixedSizeIndex : public Index {
288
288
void initialize ();
289
289
290
290
// Random prime numbers for the distance for next bucket slot to use.
291
- static constexpr uint8_t kNextBucketOffset [4 ] = {0 , 23 , 61 , 97 };
291
+ static constexpr std::array<uint8_t , 4 > kNextBucketOffset {0 , 23 , 61 , 97 };
292
+ // This offset will be used to indicate there's no valid bucket slot matching
293
+ // the given key
294
+ static constexpr uint8_t kInvalidBucketSlotOffset = 0xff ;
295
+ // This bucket id will be used to indicate there's no valid bucket for the key
296
+ static constexpr uint64_t kInvalidBucketId = 0xffffffffffffffff ;
292
297
293
298
uint8_t decideBucketOffset (uint64_t bid, uint64_t key) const {
294
299
auto mid = mutexId (bid);
295
300
296
301
// Check if there's already one matching
297
- for (auto i = 0 ; i < 4 ; i++) {
302
+ for (size_t i = 0 ; i < kNextBucketOffset . size () ; i++) {
298
303
auto curBid = calcBucketId (bid, i);
299
304
// Make sure we don't go across the mutex boundary
300
305
XDCHECK (mutexId (curBid) == mid) << bid << " " << i << " " << curBid;
@@ -307,7 +312,7 @@ class FixedSizeIndex : public Index {
307
312
}
308
313
309
314
// No match. Find the empty one
310
- for (auto i = 0 ; i < 4 ; i++) {
315
+ for (size_t i = 0 ; i < kNextBucketOffset . size () ; i++) {
311
316
auto curBid = calcBucketId (bid, i);
312
317
// Make sure we don't go across the mutex boundary
313
318
XDCHECK (mutexId (curBid) == mid) << bid << " " << i << " " << curBid;
@@ -324,7 +329,7 @@ class FixedSizeIndex : public Index {
324
329
uint8_t checkBucketOffset (uint64_t bid, uint64_t key) const {
325
330
auto mid = mutexId (bid);
326
331
327
- for (auto i = 1 ; i < 4 ; i++) {
332
+ for (size_t i = 0 ; i < kNextBucketOffset . size () ; i++) {
328
333
auto curBid = calcBucketId (bid, i);
329
334
// Make sure we don't go across the mutex boundary
330
335
XDCHECK (mutexId (curBid) == mid) << bid << " " << i << " " << curBid;
@@ -335,7 +340,20 @@ class FixedSizeIndex : public Index {
335
340
return i;
336
341
}
337
342
}
338
- return 0 ;
343
+ return kInvalidBucketSlotOffset ;
344
+ }
345
+
346
+ // This helper will get the proper bucket id and record entry
347
+ // Return value : The pair of <Bucket id, pointer to the record>
348
+ std::pair<uint64_t , PackedItemRecord*> getBucket (uint64_t orgBid,
349
+ uint8_t offset) const {
350
+ if (offset != kInvalidBucketSlotOffset ) {
351
+ auto bid = calcBucketId (orgBid, offset);
352
+ return std::make_pair (bid, &ht_[bid]);
353
+ } else {
354
+ // There's no bucket for the given key
355
+ return std::make_pair (kInvalidBucketId , nullptr );
356
+ }
339
357
}
340
358
341
359
// Updates hits information of a key.
@@ -366,6 +384,7 @@ class FixedSizeIndex : public Index {
366
384
// We don't want to go across the mutex boundary, so if it goes beyond that,
367
385
// it will wrap around and go back to the beginning of current mutex
368
386
// boundary
387
+ XDCHECK (offset < kNextBucketOffset .size ()) << offset;
369
388
return (bid / numBucketsPerMutex_) * numBucketsPerMutex_ +
370
389
((bid + kNextBucketOffset [offset]) % numBucketsPerMutex_);
371
390
}
@@ -388,8 +407,8 @@ class FixedSizeIndex : public Index {
388
407
389
408
// A helper class for exclusive locked access to a bucket.
390
409
// It will lock the proper mutex with the given key when it's created.
391
- // recordRef () and validBucketCntRef() will return the record and
392
- // valid bucket count with exclusively locked bucket reference . Locked
410
+ // recordPtr () and validBucketCntRef() will return the record and
411
+ // valid bucket count with exclusively locked bucket. Locked
393
412
// mutex will be released when it's destroyed.
394
413
class ExclusiveLockedBucket {
395
414
public:
@@ -399,59 +418,60 @@ class FixedSizeIndex : public Index {
399
418
: bid_(index.bucketId(key)),
400
419
mid_{index.mutexId (bid_)},
401
420
lg_{index.mutex_ [mid_]},
402
- record_{&index.ht_ [bid_]},
403
421
validBuckets_{index.validBucketsPerMutex_ [mid_]} {
404
422
auto offset = alloc ? index.decideBucketOffset (bid_, key)
405
423
: index.checkBucketOffset (bid_, key);
406
- if (offset != 0 ) {
407
- bid_ = index.calcBucketId (bid_, offset);
408
- record_ = &index.ht_ [bid_];
409
- bucketOffset_ = offset;
410
- }
424
+ std::tie (bid_, record_) = index.getBucket (bid_, offset);
425
+ bucketOffset_ = offset;
411
426
}
412
427
413
- PackedItemRecord& recordRef () { return * record_; }
428
+ PackedItemRecord* recordPtr () { return record_; }
414
429
size_t & validBucketCntRef () { return validBuckets_; }
415
430
void updateDistInfo (uint64_t key, FixedSizeIndex& index) {
416
- index.bucketDistInfo_ .updateBucketFillInfo (
417
- bid_, bucketOffset_, index.partialKeyBits (key));
431
+ if (bucketOffset_ != kInvalidBucketSlotOffset ) {
432
+ index.bucketDistInfo_ .updateBucketFillInfo (
433
+ bid_, bucketOffset_, index.partialKeyBits (key));
434
+ }
435
+ }
436
+ bool isValidRecord () const {
437
+ return (record_ != nullptr && record_->isValid ());
418
438
}
439
+ bool bucketExist () const { return record_ != nullptr ; }
419
440
420
441
private:
421
442
uint64_t bid_;
422
443
uint64_t mid_;
423
444
std::lock_guard<SharedMutex> lg_;
424
- PackedItemRecord* record_;
425
445
size_t & validBuckets_;
426
- uint8_t bucketOffset_{0 };
446
+ PackedItemRecord* record_{};
447
+ uint8_t bucketOffset_{kInvalidBucketSlotOffset };
427
448
};
428
449
429
450
// A helper class for shared locked access to a bucket.
430
451
// It will lock the proper mutex with the given key when it's created.
431
- // recordRef () will return the record with shared locked bucket reference .
452
+ // recordPtr () will return the record with shared locked bucket.
432
453
// Locked mutex will be released when it's destroyed.
433
454
class SharedLockedBucket {
434
455
public:
435
456
explicit SharedLockedBucket (uint64_t key, const FixedSizeIndex& index)
436
457
: bid_(index.bucketId(key)),
437
458
mid_{index.mutexId (bid_)},
438
- lg_{index.mutex_ [mid_]},
439
- record_{&index.ht_ [bid_]} {
459
+ lg_{index.mutex_ [mid_]} {
440
460
// check next bucket if it should be used
441
- auto offset = (index.checkBucketOffset (bid_, key));
442
- if (offset != 0 ) {
443
- bid_ = index.calcBucketId (bid_, offset);
444
- record_ = &index.ht_ [bid_];
445
- }
461
+ std::tie (bid_, record_) =
462
+ index.getBucket (bid_, index.checkBucketOffset (bid_, key));
446
463
}
447
464
448
- const PackedItemRecord& recordRef () const { return *record_; }
465
+ const PackedItemRecord* recordPtr () const { return record_; }
466
+ bool isValidRecord () const {
467
+ return (record_ != nullptr && record_->isValid ());
468
+ }
449
469
450
470
private:
451
471
uint64_t bid_;
452
472
uint64_t mid_;
453
473
std::shared_lock<SharedMutex> lg_;
454
- const PackedItemRecord* record_;
474
+ const PackedItemRecord* record_{} ;
455
475
};
456
476
457
477
// For unit tests private member access
0 commit comments