/* * 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 static org.junit.Assert.assertEquals; import static org.mockito.Matchers.anyLong; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import alluxio.Configuration; import alluxio.ConfigurationTestUtils; import alluxio.Constants; import alluxio.PropertyKey; import alluxio.Sessions; import alluxio.exception.BlockAlreadyExistsException; import alluxio.thrift.LockBlockTOptions; import alluxio.underfs.UfsManager; import alluxio.underfs.UnderFileSystem; import alluxio.util.io.PathUtils; import alluxio.worker.block.meta.BlockMeta; import alluxio.worker.block.meta.StorageDir; import alluxio.worker.block.meta.TempBlockMeta; import alluxio.worker.block.options.OpenUfsBlockOptions; import alluxio.worker.file.FileSystemMasterClient; import org.junit.After; import org.junit.Assert; 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.io.IOException; import java.util.HashMap; import java.util.HashSet; import java.util.Random; import java.util.Set; /** * Unit tests for {@link DefaultBlockWorker}. */ @RunWith(PowerMockRunner.class) @PrepareForTest( {BlockMasterClient.class, FileSystemMasterClient.class, BlockHeartbeatReporter.class, BlockMetricsReporter.class, BlockMeta.class, BlockStoreLocation.class, BlockStoreMeta.class, StorageDir.class, Configuration.class, UnderFileSystem.class, BlockWorker.class, Sessions.class}) public class BlockWorkerTest { /** Rule to create a new temporary folder during each test. */ @Rule public TemporaryFolder mFolder = new TemporaryFolder(); private BlockMasterClient mBlockMasterClient; private BlockStore mBlockStore; private FileSystemMasterClient mFileSystemMasterClient; private Random mRandom; private Sessions mSessions; private BlockWorker mBlockWorker; private UfsManager mUfsManager; /** * Sets up all dependencies before a test runs. */ @Before public void before() throws IOException { mRandom = new Random(); mBlockMasterClient = PowerMockito.mock(BlockMasterClient.class); mBlockStore = PowerMockito.mock(BlockStore.class); mFileSystemMasterClient = PowerMockito.mock(FileSystemMasterClient.class); mSessions = PowerMockito.mock(Sessions.class); mUfsManager = Mockito.mock(UfsManager.class); Configuration.set(PropertyKey.WORKER_TIERED_STORE_LEVELS, "2"); Configuration.set(PropertyKey.Template.WORKER_TIERED_STORE_LEVEL_DIRS_QUOTA.format(1), String.valueOf(Constants.GB)); Configuration.set(PropertyKey.WORKER_TIERED_STORE_LEVEL0_DIRS_PATH, mFolder.newFolder().getAbsolutePath()); Configuration.set(PropertyKey.WORKER_DATA_PORT, Integer.toString(0)); Configuration.set(PropertyKey.WORKER_TIERED_STORE_LEVEL1_ALIAS, "HDD"); Configuration.set(PropertyKey.WORKER_TIERED_STORE_LEVEL1_DIRS_PATH, mFolder.newFolder().getAbsolutePath()); mBlockWorker = new DefaultBlockWorker(mBlockMasterClient, mFileSystemMasterClient, mSessions, mBlockStore, mUfsManager); } /** * Resets the worker context. */ @After public void after() throws IOException { ConfigurationTestUtils.resetConfiguration(); } @Test public void openUnderFileSystemBlock() throws Exception { long blockId = mRandom.nextLong(); LockBlockTOptions lockBlockTOptions = new LockBlockTOptions(); lockBlockTOptions.setMaxUfsReadConcurrency(10); lockBlockTOptions.setUfsPath("/a"); OpenUfsBlockOptions openUfsBlockOptions = new OpenUfsBlockOptions(lockBlockTOptions); long sessionId = 1; for (; sessionId < 11; sessionId++) { Assert.assertTrue(mBlockWorker.openUfsBlock(sessionId, blockId, openUfsBlockOptions)); } Assert.assertFalse(mBlockWorker.openUfsBlock(sessionId, blockId, openUfsBlockOptions)); } @Test public void closeUnderFileSystemBlock() throws Exception { long blockId = mRandom.nextLong(); LockBlockTOptions lockBlockTOptions = new LockBlockTOptions(); lockBlockTOptions.setMaxUfsReadConcurrency(10); lockBlockTOptions.setUfsPath("/a"); OpenUfsBlockOptions openUfsBlockOptions = new OpenUfsBlockOptions(lockBlockTOptions); long sessionId = 1; for (; sessionId < 11; sessionId++) { Assert.assertTrue(mBlockWorker.openUfsBlock(sessionId, blockId, openUfsBlockOptions)); mBlockWorker.closeUfsBlock(sessionId, blockId); } Assert.assertTrue(mBlockWorker.openUfsBlock(sessionId, blockId, openUfsBlockOptions)); } /** * Tests the {@link BlockWorker#abortBlock(long, long)} method. */ @Test public void abortBlock() throws Exception { long blockId = mRandom.nextLong(); long sessionId = mRandom.nextLong(); mBlockWorker.abortBlock(sessionId, blockId); verify(mBlockStore).abortBlock(sessionId, blockId); } /** * Tests the {@link BlockWorker#accessBlock(long, long)} method. */ @Test public void accessBlock() throws Exception { long blockId = mRandom.nextLong(); long sessionId = mRandom.nextLong(); mBlockWorker.accessBlock(sessionId, blockId); verify(mBlockStore).accessBlock(sessionId, blockId); } /** * Tests the {@link BlockWorker#commitBlock(long, long)} method. */ @Test public void commitBlock() throws Exception { long blockId = mRandom.nextLong(); long length = mRandom.nextLong(); long lockId = mRandom.nextLong(); long sessionId = mRandom.nextLong(); long usedBytes = mRandom.nextLong(); String tierAlias = "MEM"; HashMap<String, Long> usedBytesOnTiers = new HashMap<>(); usedBytesOnTiers.put(tierAlias, usedBytes); BlockMeta blockMeta = PowerMockito.mock(BlockMeta.class); BlockStoreLocation blockStoreLocation = PowerMockito.mock(BlockStoreLocation.class); BlockStoreMeta blockStoreMeta = PowerMockito.mock(BlockStoreMeta.class); when(mBlockStore.lockBlock(sessionId, blockId)).thenReturn(lockId); when(mBlockStore.getBlockMeta(sessionId, blockId, lockId)).thenReturn( blockMeta); when(mBlockStore.getBlockStoreMeta()).thenReturn(blockStoreMeta); when(mBlockStore.getBlockStoreMetaFull()).thenReturn(blockStoreMeta); when(blockMeta.getBlockLocation()).thenReturn(blockStoreLocation); when(blockStoreLocation.tierAlias()).thenReturn(tierAlias); when(blockMeta.getBlockSize()).thenReturn(length); when(blockStoreMeta.getUsedBytesOnTiers()).thenReturn(usedBytesOnTiers); mBlockWorker.commitBlock(sessionId, blockId); verify(mBlockMasterClient).commitBlock(anyLong(), eq(usedBytes), eq(tierAlias), eq(blockId), eq(length)); verify(mBlockStore).unlockBlock(lockId); } /** * Tests that commitBlock doesn't throw an exception when {@link BlockAlreadyExistsException} gets * thrown by the block store. */ @Test public void commitBlockOnRetry() throws Exception { long blockId = mRandom.nextLong(); long length = mRandom.nextLong(); long lockId = mRandom.nextLong(); long sessionId = mRandom.nextLong(); long usedBytes = mRandom.nextLong(); String tierAlias = "MEM"; HashMap<String, Long> usedBytesOnTiers = new HashMap<>(); usedBytesOnTiers.put(tierAlias, usedBytes); BlockMeta blockMeta = PowerMockito.mock(BlockMeta.class); BlockStoreLocation blockStoreLocation = PowerMockito.mock(BlockStoreLocation.class); BlockStoreMeta blockStoreMeta = PowerMockito.mock(BlockStoreMeta.class); when(mBlockStore.lockBlock(sessionId, blockId)).thenReturn(lockId); when(mBlockStore.getBlockMeta(sessionId, blockId, lockId)).thenReturn(blockMeta); when(mBlockStore.getBlockStoreMeta()).thenReturn(blockStoreMeta); when(blockMeta.getBlockLocation()).thenReturn(blockStoreLocation); when(blockStoreLocation.tierAlias()).thenReturn(tierAlias); when(blockMeta.getBlockSize()).thenReturn(length); when(blockStoreMeta.getUsedBytesOnTiers()).thenReturn(usedBytesOnTiers); doThrow(new BlockAlreadyExistsException("")).when(mBlockStore).commitBlock(sessionId, blockId); mBlockWorker.commitBlock(sessionId, blockId); } /** * Tests the {@link BlockWorker#createBlock(long, long, String, long)} method. */ @Test public void createBlock() throws Exception { long blockId = mRandom.nextLong(); long initialBytes = mRandom.nextLong(); long sessionId = mRandom.nextLong(); String tierAlias = "MEM"; BlockStoreLocation location = BlockStoreLocation.anyDirInTier(tierAlias); StorageDir storageDir = Mockito.mock(StorageDir.class); TempBlockMeta meta = new TempBlockMeta(sessionId, blockId, initialBytes, storageDir); when(mBlockStore.createBlock(sessionId, blockId, location, initialBytes)) .thenReturn(meta); when(storageDir.getDirPath()).thenReturn("/tmp"); assertEquals( PathUtils.concatPath("/tmp", ".tmp_blocks", sessionId % 1024, String.format("%x-%x", sessionId, blockId)), mBlockWorker.createBlock(sessionId, blockId, tierAlias, initialBytes)); } /** * Tests the {@link BlockWorker#createBlock(long, long, String, long)} method with a tier * other than MEM. */ @Test public void createBlockLowerTier() throws Exception { long blockId = mRandom.nextLong(); long initialBytes = mRandom.nextLong(); long sessionId = mRandom.nextLong(); String tierAlias = "HDD"; BlockStoreLocation location = BlockStoreLocation.anyDirInTier(tierAlias); StorageDir storageDir = Mockito.mock(StorageDir.class); TempBlockMeta meta = new TempBlockMeta(sessionId, blockId, initialBytes, storageDir); when(mBlockStore.createBlock(sessionId, blockId, location, initialBytes)) .thenReturn(meta); when(storageDir.getDirPath()).thenReturn("/tmp"); assertEquals( PathUtils.concatPath("/tmp", ".tmp_blocks", sessionId % 1024, String.format("%x-%x", sessionId, blockId)), mBlockWorker.createBlock(sessionId, blockId, tierAlias, initialBytes)); } /** * Tests the {@link BlockWorker#createBlockRemote(long, long, String, long)} method. */ @Test public void createBlockRemote() throws Exception { long blockId = mRandom.nextLong(); long initialBytes = mRandom.nextLong(); long sessionId = mRandom.nextLong(); String tierAlias = "MEM"; BlockStoreLocation location = BlockStoreLocation.anyDirInTier(tierAlias); StorageDir storageDir = Mockito.mock(StorageDir.class); TempBlockMeta meta = new TempBlockMeta(sessionId, blockId, initialBytes, storageDir); when(mBlockStore.createBlock(sessionId, blockId, location, initialBytes)) .thenReturn(meta); when(storageDir.getDirPath()).thenReturn("/tmp"); assertEquals(PathUtils.concatPath("/tmp", ".tmp_blocks", sessionId % 1024, String.format("%x-%x", sessionId, blockId)), mBlockWorker.createBlock(sessionId, blockId, tierAlias, initialBytes)); } /** * Tests the {@link BlockWorker#freeSpace(long, long, String)} method. */ @Test public void freeSpace() throws Exception { long sessionId = mRandom.nextLong(); long availableBytes = mRandom.nextLong(); String tierAlias = "MEM"; BlockStoreLocation location = BlockStoreLocation.anyDirInTier(tierAlias); mBlockWorker.freeSpace(sessionId, availableBytes, tierAlias); verify(mBlockStore).freeSpace(sessionId, availableBytes, location); } /** * Tests the {@link BlockWorker#getTempBlockWriterRemote(long, long)} method. */ @Test public void getTempBlockWriterRemote() throws Exception { long blockId = mRandom.nextLong(); long sessionId = mRandom.nextLong(); mBlockWorker.getTempBlockWriterRemote(sessionId, blockId); verify(mBlockStore).getBlockWriter(sessionId, blockId); } /** * Tests the {@link BlockWorker#getReport()} method. */ @Test public void getReport() { BlockHeartbeatReport report = mBlockWorker.getReport(); assertEquals(0, report.getAddedBlocks().size()); assertEquals(0, report.getRemovedBlocks().size()); } /** * Tests the {@link BlockWorker#getStoreMeta()} method. * */ @Test public void getStoreMeta() { mBlockWorker.getStoreMeta(); mBlockWorker.getStoreMetaFull(); verify(mBlockStore).getBlockStoreMeta(); verify(mBlockStore).getBlockStoreMetaFull(); } /** * Tests the {@link BlockWorker#getVolatileBlockMeta(long)} method. */ @Test public void getVolatileBlockMeta() throws Exception { long blockId = mRandom.nextLong(); mBlockWorker.getVolatileBlockMeta(blockId); verify(mBlockStore).getVolatileBlockMeta(blockId); } /** * Tests the {@link BlockWorker#getBlockMeta(long, long, long)} method. */ @Test public void getBlockMeta() throws Exception { long sessionId = mRandom.nextLong(); long blockId = mRandom.nextLong(); long lockId = mRandom.nextLong(); mBlockWorker.getBlockMeta(sessionId, blockId, lockId); verify(mBlockStore).getBlockMeta(sessionId, blockId, lockId); } /** * Tests the {@link BlockWorker#hasBlockMeta(long)} method. */ @Test public void hasBlockMeta() { long blockId = mRandom.nextLong(); mBlockWorker.hasBlockMeta(blockId); verify(mBlockStore).hasBlockMeta(blockId); } /** * Tests the {@link BlockWorker#lockBlock(long, long)} method. */ @Test public void lockBlock() throws Exception { long blockId = mRandom.nextLong(); long sessionId = mRandom.nextLong(); mBlockWorker.lockBlock(sessionId, blockId); verify(mBlockStore).lockBlock(sessionId, blockId); } /** * Tests the {@link BlockWorker#moveBlock(long, long, String)} method. */ @Test public void moveBlock() throws Exception { long blockId = mRandom.nextLong(); long sessionId = mRandom.nextLong(); String tierAlias = "MEM"; BlockStoreLocation location = BlockStoreLocation.anyDirInTier(tierAlias); BlockStoreLocation existingLocation = Mockito.mock(BlockStoreLocation.class); when(existingLocation.belongsTo(location)).thenReturn(false); BlockMeta meta = Mockito.mock(BlockMeta.class); when(meta.getBlockLocation()).thenReturn(existingLocation); when(mBlockStore.getBlockMeta(Mockito.eq(sessionId), Mockito.eq(blockId), Mockito.anyLong())) .thenReturn(meta); mBlockWorker.moveBlock(sessionId, blockId, tierAlias); verify(mBlockStore).moveBlock(sessionId, blockId, location); } /** * Tests the {@link BlockWorker#moveBlock(long, long, String)} method no-ops if the block is * already at the destination location. */ @Test public void moveBlockNoop() throws Exception { long blockId = mRandom.nextLong(); long sessionId = mRandom.nextLong(); String tierAlias = "MEM"; BlockStoreLocation location = BlockStoreLocation.anyDirInTier(tierAlias); BlockStoreLocation existingLocation = Mockito.mock(BlockStoreLocation.class); when(existingLocation.belongsTo(location)).thenReturn(true); BlockMeta meta = Mockito.mock(BlockMeta.class); when(meta.getBlockLocation()).thenReturn(existingLocation); when(mBlockStore.getBlockMeta(Mockito.eq(sessionId), Mockito.eq(blockId), Mockito.anyLong())) .thenReturn(meta); mBlockWorker.moveBlock(sessionId, blockId, tierAlias); verify(mBlockStore, Mockito.times(0)).moveBlock(sessionId, blockId, location); } /** * Tests the {@link BlockWorker#readBlock(long, long, long)} method. */ @Test public void readBlock() throws Exception { long blockId = mRandom.nextLong(); long sessionId = mRandom.nextLong(); long lockId = mRandom.nextLong(); long blockSize = mRandom.nextLong(); StorageDir storageDir = Mockito.mock(StorageDir.class); when(storageDir.getDirPath()).thenReturn("/tmp"); BlockMeta meta = new BlockMeta(blockId, blockSize, storageDir); when(mBlockStore.getBlockMeta(sessionId, blockId, lockId)).thenReturn(meta); mBlockWorker.readBlock(sessionId, blockId, lockId); verify(mBlockStore).getBlockMeta(sessionId, blockId, lockId); assertEquals(PathUtils.concatPath("/tmp", blockId), mBlockWorker.readBlock(sessionId, blockId, lockId)); } /** * Tests the {@link BlockWorker#readBlockRemote(long, long, long)} method. */ @Test public void readBlockRemote() throws Exception { long blockId = mRandom.nextLong(); long sessionId = mRandom.nextLong(); long lockId = mRandom.nextLong(); mBlockWorker.readBlockRemote(sessionId, blockId, lockId); verify(mBlockStore).getBlockReader(sessionId, blockId, lockId); } /** * Tests the {@link BlockWorker#removeBlock(long, long)} method. */ @Test public void removeBlock() throws Exception { long blockId = mRandom.nextLong(); long sessionId = mRandom.nextLong(); mBlockWorker.removeBlock(sessionId, blockId); verify(mBlockStore).removeBlock(sessionId, blockId); } /** * Tests the {@link BlockWorker#requestSpace(long, long, long)} method. */ @Test public void requestSpace() throws Exception { long blockId = mRandom.nextLong(); long sessionId = mRandom.nextLong(); long additionalBytes = mRandom.nextLong(); mBlockWorker.requestSpace(sessionId, blockId, additionalBytes); verify(mBlockStore).requestSpace(sessionId, blockId, additionalBytes); } /** * Tests the {@link BlockWorker#unlockBlock(long)} and * {@link BlockWorker#unlockBlock(long, long)} method. */ @Test public void unlockBlock() throws Exception { long lockId = mRandom.nextLong(); long sessionId = mRandom.nextLong(); long blockId = mRandom.nextLong(); mBlockWorker.unlockBlock(lockId); verify(mBlockStore).unlockBlock(lockId); mBlockWorker.unlockBlock(sessionId, blockId); verify(mBlockStore).unlockBlock(sessionId, blockId); } /** * Tests the {@link BlockWorker#sessionHeartbeat(long)} method. */ @Test public void sessionHeartbeat() { long sessionId = mRandom.nextLong(); mBlockWorker.sessionHeartbeat(sessionId); verify(mSessions).sessionHeartbeat(sessionId); } /** * Tests the {@link BlockWorker#updatePinList(Set)} method. */ @Test public void updatePinList() { Set<Long> pinnedInodes = new HashSet<>(); pinnedInodes.add(mRandom.nextLong()); mBlockWorker.updatePinList(pinnedInodes); verify(mBlockStore).updatePinnedInodes(pinnedInodes); } /** * Tests the {@link BlockWorker#getFileInfo(long)} method. */ @Test public void getFileInfo() throws Exception { long fileId = mRandom.nextLong(); mBlockWorker.getFileInfo(fileId); verify(mFileSystemMasterClient).getFileInfo(fileId); } }