@@ -405,9 +405,22 @@ CacheAllocator<CacheTrait>::allocateInternalTier(TierId tid,
405
405
// TODO: per-tier
406
406
(*stats_.allocAttempts )[pid][cid].inc ();
407
407
408
- void * memory = allocator_[tid]->allocate (pid, requiredSize);
408
+ void *memory = nullptr ;
409
+
410
+ if (tid == 0 && config_.acTopTierEvictionWatermark > 0.0
411
+ && getAllocationClassStats (tid, pid, cid)
412
+ .approxFreePercent < config_.acTopTierEvictionWatermark ) {
413
+ memory = findEviction (tid, pid, cid);
414
+ }
415
+
416
+ if (memory == nullptr ) {
417
+ // TODO: should we try allocate item even if this will result in violating
418
+ // acTopTierEvictionWatermark?
419
+ memory = allocator_[tid]->allocate (pid, requiredSize);
420
+ }
421
+
409
422
// TODO: Today disableEviction means do not evict from memory (DRAM).
410
- // Should we support eviction between memory tiers (e.g. from DRAM to PMEM )?
423
+ // Should we support eviction between memory tiers (e.g. from DRAM to next tier )?
411
424
if (memory == nullptr && !config_.isEvictionDisabled ()) {
412
425
memory = findEviction (tid, pid, cid);
413
426
}
@@ -448,19 +461,71 @@ CacheAllocator<CacheTrait>::allocateInternalTier(TierId tid,
448
461
return handle;
449
462
}
450
463
464
+ template <typename CacheTrait>
465
+ TierId
466
+ CacheAllocator<CacheTrait>::getTargetTierForItem(PoolId pid,
467
+ typename Item::Key key,
468
+ uint32_t size,
469
+ uint32_t creationTime,
470
+ uint32_t expiryTime) {
471
+ if (getNumTiers () == 1 )
472
+ return 0 ;
473
+
474
+ if (config_.forceAllocationTier != UINT64_MAX) {
475
+ return config_.forceAllocationTier ;
476
+ }
477
+
478
+ const TierId defaultTargetTier = 0 ;
479
+
480
+ const auto requiredSize = Item::getRequiredSize (key, size);
481
+ const auto cid = allocator_[defaultTargetTier]->getAllocationClassId (pid, requiredSize);
482
+
483
+ auto freePercentage = getAllocationClassStats (defaultTargetTier, pid, cid).approxFreePercent ;
484
+
485
+ // TODO: COULD we implement BG worker which would move slabs around
486
+ // so that there is similar amount of free space in each pool/ac.
487
+ // Should this be responsibility of BG evictor?
488
+
489
+ if (freePercentage >= config_.maxAcAllocationWatermark )
490
+ return defaultTargetTier;
491
+
492
+ if (freePercentage <= config_.minAcAllocationWatermark )
493
+ return defaultTargetTier + 1 ;
494
+
495
+ // TODO: we can even think about creating different allocation classes for different tiers
496
+ // and we could look at possible fragmentation when deciding where to put the item
497
+ if (config_.sizeThresholdPolicy )
498
+ return requiredSize < config_.sizeThresholdPolicy ? defaultTargetTier : defaultTargetTier + 1 ;
499
+
500
+ // TODO: (e.g. always put chained items to PMEM)
501
+ // if (chainedItemsPolicy)
502
+ // return item.isChainedItem() ? defaultTargetTier + 1 : defaultTargetTier;
503
+
504
+ // TODO:
505
+ // if (expiryTimePolicy)
506
+ // return (expiryTime - creationTime) < expiryTimePolicy ? defaultTargetTier : defaultTargetTier + 1;
507
+
508
+ // TODO:
509
+ // if (keyPolicy) // this can be based on key length or some other properties
510
+ // return getTargetTierForKey(key);
511
+
512
+ // TODO:
513
+ // if (compressabilityPolicy) // if compresses well store in PMEM? latency will be higher anyway
514
+ // return TODO;
515
+
516
+ // TODO: only works for 2 tiers
517
+ return (folly::Random::rand32 () % 100 ) < config_.defaultTierChancePercentage ? defaultTargetTier : defaultTargetTier + 1 ;
518
+ }
519
+
451
520
template <typename CacheTrait>
452
521
typename CacheAllocator<CacheTrait>::WriteHandle
453
522
CacheAllocator<CacheTrait>::allocateInternal(PoolId pid,
454
523
typename Item::Key key,
455
524
uint32_t size,
456
525
uint32_t creationTime,
457
526
uint32_t expiryTime) {
458
- auto tid = 0 ; /* TODO: consult admission policy */
459
- for (TierId tid = 0 ; tid < getNumTiers (); ++tid) {
460
- auto handle = allocateInternalTier (tid, pid, key, size, creationTime, expiryTime);
461
- if (handle) return handle;
462
- }
463
- return {};
527
+ auto tid = getTargetTierForItem (pid, key, size, creationTime, expiryTime);
528
+ return allocateInternalTier (tid, pid, key, size, creationTime, expiryTime);
464
529
}
465
530
466
531
template <typename CacheTrait>
@@ -1636,6 +1701,13 @@ bool CacheAllocator<CacheTrait>::shouldWriteToNvmCacheExclusive(
1636
1701
return true ;
1637
1702
}
1638
1703
1704
+ template <typename CacheTrait>
1705
+ bool CacheAllocator<CacheTrait>::shouldEvictToNextMemoryTier(
1706
+ TierId sourceTierId, TierId targetTierId, PoolId pid, Item& item)
1707
+ {
1708
+ return !(config_.disableEvictionToMemory );
1709
+ }
1710
+
1639
1711
template <typename CacheTrait>
1640
1712
typename CacheAllocator<CacheTrait>::WriteHandle
1641
1713
CacheAllocator<CacheTrait>::tryEvictToNextMemoryTier(
@@ -1649,8 +1721,10 @@ CacheAllocator<CacheTrait>::tryEvictToNextMemoryTier(
1649
1721
if (handle) { return handle; }
1650
1722
}
1651
1723
1652
- TierId nextTier = tid; // TODO - calculate this based on some admission policy
1724
+ TierId nextTier = tid;
1653
1725
while (++nextTier < getNumTiers ()) { // try to evict down to the next memory tiers
1726
+ if (!shouldEvictToNextMemoryTier (tid, nextTier, pid, item))
1727
+ continue ;
1654
1728
// allocateInternal might trigger another eviction
1655
1729
auto newItemHdl = allocateInternalTier (nextTier, pid,
1656
1730
item.getKey (),
@@ -2431,6 +2505,10 @@ void CacheAllocator<CacheTrait>::createMMContainers(const PoolId pid,
2431
2505
.getAllocsPerSlab ()
2432
2506
: 0 );
2433
2507
for (TierId tid = 0 ; tid < getNumTiers (); tid++) {
2508
+ if constexpr (std::is_same_v<MMConfig, MMLru::Config> || std::is_same_v<MMConfig, MM2Q::Config>) {
2509
+ config.lruInsertionPointSpec = config_.memoryTierConfigs [tid].lruInsertionPointSpec ;
2510
+ config.markUsefulChance = config_.memoryTierConfigs [tid].markUsefulChance ;
2511
+ }
2434
2512
mmContainers_[tid][pid][cid].reset (new MMContainer (config, compressor_));
2435
2513
}
2436
2514
}
@@ -2485,7 +2563,7 @@ std::set<PoolId> CacheAllocator<CacheTrait>::getRegularPoolIds() const {
2485
2563
folly::SharedMutex::ReadHolder r (poolsResizeAndRebalanceLock_);
2486
2564
// TODO - get rid of the duplication - right now, each tier
2487
2565
// holds pool objects with mostly the same info
2488
- return filterCompactCachePools (allocator_[0 ]->getPoolIds ());
2566
+ return filterCompactCachePools (allocator_[currentTier () ]->getPoolIds ());
2489
2567
}
2490
2568
2491
2569
template <typename CacheTrait>
0 commit comments