/* * The Alluxio Open Foundation licenses this work under the Apache License, version 2.0 * (the "License"). You may not use this work except in compliance with the License, which is * available at www.apache.org/licenses/LICENSE-2.0 * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, * either express or implied, as more fully set forth in the License. * * See the NOTICE file distributed with this work for information regarding copyright ownership. */ package alluxio.worker.block.evictor; import alluxio.ConfigurationTestUtils; import alluxio.worker.block.BlockStoreLocation; import alluxio.worker.block.TieredBlockStoreTestUtils; import alluxio.worker.block.meta.StorageDir; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; /** * Unit tests for specific behavior of {@link PartialLRUEvictor} such as evicting/moving least * recently used blocks in {@link StorageDir} with max free space and cascading * {@link PartialLRUEvictor} eviction. */ public class PartialLRUEvictorTest extends EvictorTestBase { /** * Sets up all dependencies before a test runs. */ @Before public final void before() throws Exception { init(PartialLRUEvictor.class.getName()); } /** * Resets the context of the worker after a test ran. */ @After public void after() { ConfigurationTestUtils.resetConfiguration(); } /** * Tests that the eviction in the bottom tier works. */ @Test public void evictInBottomTier() throws Exception { int bottomTierLevel = TieredBlockStoreTestUtils.TIER_ORDINAL[TieredBlockStoreTestUtils.TIER_ORDINAL.length - 1]; // capacity increases with index long[] bottomTierDirCapacity = TieredBlockStoreTestUtils.TIER_CAPACITY_BYTES[bottomTierLevel]; long smallestCapacity = bottomTierDirCapacity[0]; long delta = smallestCapacity / 10; int nDir = bottomTierDirCapacity.length; // free space of StorageDir increases with Dir index for (int i = 0; i < nDir; i++) { cache(SESSION_ID, BLOCK_ID + i, bottomTierDirCapacity[i] - i * delta, bottomTierLevel, i); } BlockStoreLocation anyDirInBottomTier = BlockStoreLocation.anyDirInTier(TieredBlockStoreTestUtils.TIER_ALIAS[bottomTierLevel]); // free the StorageDir with max free space EvictionPlan plan = mEvictor.freeSpaceWithView(smallestCapacity, anyDirInBottomTier, mManagerView); Assert.assertNotNull(plan); Assert.assertTrue(plan.toMove().isEmpty()); Assert.assertEquals(1, plan.toEvict().size()); long toEvictBlockId = plan.toEvict().get(0).getFirst(); Assert.assertEquals(BLOCK_ID + nDir - 1, toEvictBlockId); } /** * Tests the cascading eviction with the first tier filled and the second tier empty resulting in * no eviction. */ @Test public void cascadingEvictionTest1() throws Exception { // Two tiers, each dir in the second tier has more space than any dir in the first tier. Fill in // the first tier, leave the second tier empty. Request space from the first tier, blocks should // be moved from the first to the second tier without eviction. int firstTierOrdinal = TieredBlockStoreTestUtils.TIER_ORDINAL[0]; long[] firstTierDirCapacity = TieredBlockStoreTestUtils.TIER_CAPACITY_BYTES[0]; long smallestCapacity = firstTierDirCapacity[0]; long delta = smallestCapacity / 10; int nDir = firstTierDirCapacity.length; for (int i = 0; i < nDir; i++) { cache(SESSION_ID, BLOCK_ID + i, firstTierDirCapacity[i] - delta * i, firstTierOrdinal, i); } BlockStoreLocation anyDirInFirstTier = BlockStoreLocation.anyDirInTier(TieredBlockStoreTestUtils.TIER_ALIAS[firstTierOrdinal]); EvictionPlan plan = mEvictor.freeSpaceWithView(smallestCapacity, anyDirInFirstTier, mManagerView); Assert.assertTrue(EvictorTestUtils.validCascadingPlan(smallestCapacity, plan, mMetaManager)); Assert.assertEquals(0, plan.toEvict().size()); Assert.assertEquals(1, plan.toMove().size()); long blockId = plan.toMove().get(0).getBlockId(); Assert.assertEquals(BLOCK_ID + nDir - 1, blockId); } /** * Tests the cascading eviction with the first and second tier filled resulting in blocks in the * second tier are evicted. */ @Test public void cascadingEvictionTest2() throws Exception { // Two tiers, the second tier has more dirs than the first tier and each dir in the second tier // has more space than any dir in the first tier. Fill in all dirs and request space from the // first tier, blocks should be moved from the first to the second tier, and some blocks in the // second tier should be evicted to hold blocks moved from the first tier. BlockStoreLocation anyDirInFirstTier = BlockStoreLocation.anyDirInTier(TieredBlockStoreTestUtils.TIER_ALIAS[0]); int nDirInFirstTier = TieredBlockStoreTestUtils.TIER_CAPACITY_BYTES[0].length; int nDirInSecondTier = TieredBlockStoreTestUtils.TIER_CAPACITY_BYTES[1].length; long smallestCapacity = TieredBlockStoreTestUtils.TIER_CAPACITY_BYTES[0][0]; long delta = smallestCapacity / 10; long blockId = BLOCK_ID; for (int tierLevel : TieredBlockStoreTestUtils.TIER_ORDINAL) { long[] tierCapacity = TieredBlockStoreTestUtils.TIER_CAPACITY_BYTES[tierLevel]; for (int dirIdx = 0; dirIdx < tierCapacity.length; dirIdx++) { cache(SESSION_ID, blockId, tierCapacity[dirIdx] - dirIdx * delta, tierLevel, dirIdx); blockId++; } } EvictionPlan plan = mEvictor.freeSpaceWithView(smallestCapacity, anyDirInFirstTier, mManagerView); Assert.assertTrue(EvictorTestUtils.validCascadingPlan(smallestCapacity, plan, mMetaManager)); // block in StorageDir with max free space in the first tier needs to be moved to the second // tier Assert.assertEquals(1, plan.toMove().size()); long blockIdMovedInFirstTier = plan.toMove().get(0).getBlockId(); Assert.assertEquals(BLOCK_ID + nDirInFirstTier - 1, blockIdMovedInFirstTier); // block in StorageDir with max free space in the second tier will be evicted to hold blocks // moved from first tier Assert.assertEquals(1, plan.toEvict().size()); long blockIdEvictedInSecondTier = plan.toEvict().get(0).getFirst(); Assert.assertEquals(BLOCK_ID + nDirInFirstTier + nDirInSecondTier - 1, blockIdEvictedInSecondTier); } }