@@ -272,4 +272,69 @@ TEST(Allocator, UsePriorities) {
272272 }
273273}
274274
275+ TEST (Allocator, UseDifferentAllocatorsForPriorities) {
276+ std::vector<uint32_t > hits (4 );
277+ auto policy = std::make_unique<MockPolicy>(&hits);
278+
279+ std::vector<uint32_t > allocatorsPerPriority{1 , 2 , 3 };
280+ // One regions per priority and one extra clean region.
281+ uint32_t kNumRegions = std::accumulate (allocatorsPerPriority.begin (),
282+ allocatorsPerPriority.end (), 0U ) +
283+ 1 ;
284+ constexpr uint32_t kRegionSize = 16 * 1024 ;
285+ auto device =
286+ createMemoryDevice (kNumRegions * kRegionSize , nullptr /* encryption */ );
287+ RegionEvictCallback evictCb{[](RegionId, BufferView) { return 0 ; }};
288+ RegionCleanupCallback cleanupCb{[](RegionId, BufferView) {}};
289+ auto rm = std::make_unique<RegionManager>(
290+ kNumRegions , kRegionSize , 0 , *device, 1 /* numCleanRegions */ ,
291+ 1 /* numWorkers */ , 0 , std::move (evictCb), std::move (cleanupCb),
292+ std::move (policy), kNumRegions /* numInMemBuffers */ ,
293+ 3 /* numPriorities */ , kFlushRetryLimit , true /* workeAsyncFlush */ );
294+
295+ Allocator allocator = makeAllocator (*rm, allocatorsPerPriority);
296+
297+ ENABLE_INJECT_PAUSE_IN_SCOPE ();
298+
299+ injectPauseSet (" pause_reclaim_done" );
300+
301+ // Allocate to make sure a reclaim is triggered
302+ auto [desc, slotSize, addr] = allocator.allocate (1024 , 0 , false , kKeyHash );
303+ EXPECT_EQ (OpenStatus::Retry, desc.status ());
304+ EXPECT_TRUE (injectPauseWait (" pause_reclaim_done" ));
305+
306+ uint32_t allocatedRegion = 0 ;
307+ // Allocate one item from each priortiy, we should see each allocation
308+ // results in a new region being allocated for its priority
309+ for (uint16_t pri = 0 ; pri < 3 ; pri++) {
310+ // For each priority, allocate one item per allocator
311+ for (uint32_t index = 0 ; index < allocatorsPerPriority[pri]; index++) {
312+ // Use index as keyhash to allocate via a specific allocator.
313+ std::tie (desc, slotSize, addr) =
314+ allocator.allocate (1024 , pri, false , index);
315+ EXPECT_TRUE (desc.isReady ());
316+ EXPECT_EQ (RegionId{allocatedRegion++}, addr.rid ());
317+ EXPECT_EQ (pri, rm->getRegion (addr.rid ()).getPriority ());
318+ // The allocation should be from a fresh region
319+ EXPECT_EQ (0 , addr.offset ());
320+ // Reclaim should have been triggered
321+ EXPECT_TRUE (injectPauseWait (" pause_reclaim_done" ));
322+ }
323+ // Now that each allocator has their region allocated into, further
324+ // allocating to the region (provide it is not full) should not trigger
325+ // reclaim.
326+ for (uint32_t index = 0 ; index < allocatorsPerPriority[pri]; index++) {
327+ // Use index as keyhash to allocate via a specific allocator.
328+ std::tie (desc, slotSize, addr) =
329+ allocator.allocate (1024 , pri, false , index);
330+ EXPECT_TRUE (desc.isReady ());
331+ EXPECT_EQ (pri, rm->getRegion (addr.rid ()).getPriority ());
332+ // The allocation should be from an existing region as the second item
333+ EXPECT_EQ (1024 , addr.offset ());
334+ // Reclaim should not have been triggered
335+ EXPECT_FALSE (injectPauseWait (" pause_reclaim_done" ));
336+ }
337+ }
338+ }
339+
275340} // namespace facebook::cachelib::navy::tests
0 commit comments