/*
* 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;
import alluxio.Configuration;
import alluxio.ConfigurationTestUtils;
import alluxio.PropertyKey;
import alluxio.Sessions;
import alluxio.heartbeat.HeartbeatContext;
import alluxio.heartbeat.HeartbeatScheduler;
import alluxio.heartbeat.HeartbeatThread;
import alluxio.heartbeat.ManuallyScheduleHeartbeat;
import alluxio.util.ThreadFactoryUtils;
import com.google.common.collect.ImmutableMap;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Unit tests for {@link SpaceReserver}.
*/
@RunWith(PowerMockRunner.class)
@PrepareForTest({BlockWorker.class, BlockStoreMeta.class})
public class SpaceReserverTest {
private ExecutorService mExecutorService;
/** Rule to create a new temporary folder during each test. */
@Rule
public TemporaryFolder mTempFolder = new TemporaryFolder();
@Rule
public ManuallyScheduleHeartbeat mSchedule =
new ManuallyScheduleHeartbeat(HeartbeatContext.WORKER_SPACE_RESERVER);
@Before
public void before() {
mExecutorService =
Executors.newFixedThreadPool(1, ThreadFactoryUtils.build("space-reserver-test", true));
ConfigurationTestUtils.resetConfiguration();
}
@After
public void after() {
mExecutorService.shutdownNow();
}
@Test
public void reserveCorrectAmountsOfSpace() throws Exception {
BlockWorker blockWorker = PowerMockito.mock(BlockWorker.class);
BlockStoreMeta storeMeta = PowerMockito.mock(BlockStoreMeta.class);
Mockito.when(blockWorker.getStoreMeta()).thenReturn(storeMeta);
Map<String, Long> capacityBytesOnTiers = ImmutableMap.of("MEM", 400L, "HDD", 1000L);
Mockito.when(storeMeta.getCapacityBytesOnTiers()).thenReturn(capacityBytesOnTiers);
// Create two tiers named "MEM" and "HDD" with aliases 0 and 1.
TieredBlockStoreTestUtils.setupConfWithMultiTier("/",
new int[]{0, 1}, new String[] {"MEM", "HDD"},
new String[][]{new String[]{"/a"}, new String[]{"/b"}},
new long[][]{new long[]{0}, new long[]{0}}, "/");
PropertyKey reserveRatioProp =
PropertyKey.Template.WORKER_TIERED_STORE_LEVEL_RESERVED_RATIO.format(0);
Configuration.set(reserveRatioProp, "0.2");
reserveRatioProp =
PropertyKey.Template.WORKER_TIERED_STORE_LEVEL_RESERVED_RATIO.format(1);
Configuration.set(reserveRatioProp, "0.3");
SpaceReserver spaceReserver = new SpaceReserver(blockWorker);
mExecutorService.submit(
new HeartbeatThread(HeartbeatContext.WORKER_SPACE_RESERVER, spaceReserver, 0));
// Run the space reserver once.
HeartbeatScheduler.execute(HeartbeatContext.WORKER_SPACE_RESERVER);
// 400 * 0.2 = 80
Mockito.verify(blockWorker).freeSpace(Sessions.MIGRATE_DATA_SESSION_ID, 80L, "MEM");
// 400 * 0.2 + 1000 * 0.3 = 380
Mockito.verify(blockWorker).freeSpace(Sessions.MIGRATE_DATA_SESSION_ID, 380L, "HDD");
}
@Test
public void testLowWatermark() throws Exception {
BlockWorker blockWorker = PowerMockito.mock(BlockWorker.class);
BlockStoreMeta storeMeta = PowerMockito.mock(BlockStoreMeta.class);
Mockito.when(blockWorker.getStoreMeta()).thenReturn(storeMeta);
Map<String, Long> capacityBytesOnTiers = ImmutableMap.of("MEM", 100L, "SSD", 200L, "HDD",
1000L);
Map<String, Long> usedCapacityBytesOnTiers = ImmutableMap.of("MEM", 100L, "SSD", 200L, "HDD",
1000L);
Mockito.when(storeMeta.getCapacityBytesOnTiers()).thenReturn(capacityBytesOnTiers);
Mockito.when(storeMeta.getUsedBytesOnTiers()).thenReturn(usedCapacityBytesOnTiers);
// Create two tiers named "MEM", "SSD" and "HDD" with aliases 0, 1 and 2.
TieredBlockStoreTestUtils.setupConfWithMultiTier("/",
new int[]{0, 1, 2}, new String[] {"MEM", "SSD", "HDD"},
new String[][]{new String[]{"/a"}, new String[]{"/b"}, new String[]{"/c"}},
new long[][]{new long[]{0}, new long[]{0}, new long[]{0}}, "/");
PropertyKey highWatermarkRatioProp =
PropertyKey.Template.WORKER_TIERED_STORE_LEVEL_HIGH_WATERMARK_RATIO.format(0);
Configuration.set(highWatermarkRatioProp, "0.9");
PropertyKey lowWatermarkRatioProp =
PropertyKey.Template.WORKER_TIERED_STORE_LEVEL_LOW_WATERMARK_RATIO.format(0);
Configuration.set(lowWatermarkRatioProp, "0.8");
highWatermarkRatioProp =
PropertyKey.Template.WORKER_TIERED_STORE_LEVEL_HIGH_WATERMARK_RATIO.format(1);
Configuration.set(highWatermarkRatioProp, "0.9");
lowWatermarkRatioProp =
PropertyKey.Template.WORKER_TIERED_STORE_LEVEL_LOW_WATERMARK_RATIO.format(1);
Configuration.set(lowWatermarkRatioProp, "0.7");
highWatermarkRatioProp =
PropertyKey.Template.WORKER_TIERED_STORE_LEVEL_HIGH_WATERMARK_RATIO.format(2);
Configuration.set(highWatermarkRatioProp, "0.8");
lowWatermarkRatioProp =
PropertyKey.Template.WORKER_TIERED_STORE_LEVEL_LOW_WATERMARK_RATIO.format(2);
Configuration.set(lowWatermarkRatioProp, "0.6");
SpaceReserver spaceReserver = new SpaceReserver(blockWorker);
mExecutorService.submit(
new HeartbeatThread(HeartbeatContext.WORKER_SPACE_RESERVER, spaceReserver, 0));
// Run the space reserver once.
HeartbeatScheduler.execute(HeartbeatContext.WORKER_SPACE_RESERVER);
// 1000 * 0.4 + 200 * 0.3 + 100 * 0.2 = 480
Mockito.verify(blockWorker).freeSpace(Sessions.MIGRATE_DATA_SESSION_ID, 480L, "HDD");
// 200 * 0.3 + 100 * 0.2 = 80
Mockito.verify(blockWorker).freeSpace(Sessions.MIGRATE_DATA_SESSION_ID, 80L, "SSD");
// 100 * 0.2 = 20
Mockito.verify(blockWorker).freeSpace(Sessions.MIGRATE_DATA_SESSION_ID, 20L, "MEM");
}
@Test
public void testHighWatermark() throws Exception {
BlockWorker blockWorker = PowerMockito.mock(BlockWorker.class);
BlockStoreMeta storeMeta = PowerMockito.mock(BlockStoreMeta.class);
Mockito.when(blockWorker.getStoreMeta()).thenReturn(storeMeta);
Map<String, Long> capacityBytesOnTiers = ImmutableMap.of("MEM", 100L, "SSD", 200L, "HDD",
1000L);
Map<String, Long> usedCapacityBytesOnTiers =
ImmutableMap.of("MEM", 100L, "SSD", 100L, "HDD", 0L);
Mockito.when(storeMeta.getCapacityBytesOnTiers()).thenReturn(capacityBytesOnTiers);
Mockito.when(storeMeta.getUsedBytesOnTiers()).thenReturn(usedCapacityBytesOnTiers);
// Create two tiers named "MEM", "SSD" and "HDD" with aliases 0, 1 and 2.
TieredBlockStoreTestUtils.setupConfWithMultiTier("/",
new int[]{0, 1, 2}, new String[] {"MEM", "SSD", "HDD"},
new String[][]{new String[]{"/a"}, new String[]{"/b"}, new String[]{"/c"}},
new long[][]{new long[]{0}, new long[]{0}, new long[]{0}}, "/");
PropertyKey highWatermarkRatioProp =
PropertyKey.Template.WORKER_TIERED_STORE_LEVEL_HIGH_WATERMARK_RATIO.format(0);
Configuration.set(highWatermarkRatioProp, "0.9");
PropertyKey lowWatermarkRatioProp =
PropertyKey.Template.WORKER_TIERED_STORE_LEVEL_LOW_WATERMARK_RATIO.format(0);
Configuration.set(lowWatermarkRatioProp, "0.8");
highWatermarkRatioProp =
PropertyKey.Template.WORKER_TIERED_STORE_LEVEL_HIGH_WATERMARK_RATIO.format(1);
Configuration.set(highWatermarkRatioProp, "0.9");
lowWatermarkRatioProp =
PropertyKey.Template.WORKER_TIERED_STORE_LEVEL_LOW_WATERMARK_RATIO.format(1);
Configuration.set(lowWatermarkRatioProp, "0.7");
highWatermarkRatioProp =
PropertyKey.Template.WORKER_TIERED_STORE_LEVEL_HIGH_WATERMARK_RATIO.format(2);
Configuration.set(highWatermarkRatioProp, "0.8");
lowWatermarkRatioProp =
PropertyKey.Template.WORKER_TIERED_STORE_LEVEL_LOW_WATERMARK_RATIO.format(2);
Configuration.set(lowWatermarkRatioProp, "0.6");
SpaceReserver spaceReserver = new SpaceReserver(blockWorker);
mExecutorService.submit(
new HeartbeatThread(HeartbeatContext.WORKER_SPACE_RESERVER, spaceReserver, 0));
// Run the space reserver once.
HeartbeatScheduler.execute(HeartbeatContext.WORKER_SPACE_RESERVER);
// 1000 * 0.4 + 200 * 0.3 + 100 * 0.2 = 480
Mockito.verify(blockWorker, Mockito.times(0)).freeSpace(Sessions.MIGRATE_DATA_SESSION_ID,
480L, "HDD");
// 200 * 0.3 + 100 * 0.2 = 80
Mockito.verify(blockWorker, Mockito.times(0)).freeSpace(Sessions.MIGRATE_DATA_SESSION_ID,
80L, "SSD");
// 100 * 0.2 = 20
Mockito.verify(blockWorker).freeSpace(Sessions.MIGRATE_DATA_SESSION_ID, 20L, "MEM");
}
}