/* * 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.meta; import alluxio.AlluxioURI; import alluxio.LocalAlluxioClusterResource; import alluxio.PropertyKey; import alluxio.BaseIntegrationTest; import alluxio.client.ReadType; import alluxio.client.WriteType; import alluxio.client.file.FileInStream; import alluxio.client.file.FileSystem; import alluxio.client.file.FileSystemTestUtils; import alluxio.client.file.URIStatus; import alluxio.client.file.options.OpenFileOptions; import alluxio.client.file.options.SetAttributeOptions; import alluxio.heartbeat.HeartbeatContext; import alluxio.heartbeat.HeartbeatScheduler; import alluxio.heartbeat.ManuallyScheduleHeartbeat; import alluxio.util.io.BufferUtils; import org.junit.Assert; import org.junit.Before; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import java.util.concurrent.TimeUnit; /** * Integration tests for {@link alluxio.worker.block.meta.StorageTier}. */ public class TieredStoreIntegrationTest extends BaseIntegrationTest { private static final int MEM_CAPACITY_BYTES = 1000; private FileSystem mFileSystem; private SetAttributeOptions mSetPinned; private SetAttributeOptions mSetUnpinned; @ClassRule public static ManuallyScheduleHeartbeat sManuallySchedule = new ManuallyScheduleHeartbeat( HeartbeatContext.MASTER_TTL_CHECK, HeartbeatContext.WORKER_BLOCK_SYNC, HeartbeatContext.WORKER_PIN_LIST_SYNC); @Rule public ExpectedException mThrown = ExpectedException.none(); @Rule public LocalAlluxioClusterResource mLocalAlluxioClusterResource = new LocalAlluxioClusterResource.Builder() .setProperty(PropertyKey.WORKER_MEMORY_SIZE, MEM_CAPACITY_BYTES) .setProperty(PropertyKey.USER_BLOCK_SIZE_BYTES_DEFAULT, 1000) .setProperty(PropertyKey.USER_FILE_BUFFER_BYTES, String.valueOf(100)) .setProperty(PropertyKey.WORKER_FILE_BUFFER_SIZE, String.valueOf(100)) .build(); @Before public final void before() throws Exception { mFileSystem = mLocalAlluxioClusterResource.get().getClient(); mSetPinned = SetAttributeOptions.defaults().setPinned(true); mSetUnpinned = SetAttributeOptions.defaults().setPinned(false); } /** * Tests that deletes go through despite failing initially due to concurrent read. */ @Test public void deleteWhileRead() throws Exception { HeartbeatScheduler.await(HeartbeatContext.WORKER_BLOCK_SYNC, 10, TimeUnit.SECONDS); AlluxioURI file = new AlluxioURI("/test1"); FileSystemTestUtils.createByteFile(mFileSystem, file, WriteType.MUST_CACHE, MEM_CAPACITY_BYTES); HeartbeatScheduler.execute(HeartbeatContext.WORKER_BLOCK_SYNC); Assert.assertEquals(100, mFileSystem.getStatus(file).getInMemoryPercentage()); // Open the file OpenFileOptions options = OpenFileOptions.defaults().setReadType(ReadType.CACHE); FileInStream in = mFileSystem.openFile(file, options); Assert.assertEquals(0, in.read()); // Delete the file mFileSystem.delete(file); HeartbeatScheduler.execute(HeartbeatContext.WORKER_BLOCK_SYNC); // After the delete, the master should no longer serve the file Assert.assertFalse(mFileSystem.exists(file)); // However, the previous read should still be able to read it as the data still exists byte[] res = new byte[MEM_CAPACITY_BYTES]; Assert.assertEquals(MEM_CAPACITY_BYTES - 1, in.read(res, 1, MEM_CAPACITY_BYTES - 1)); res[0] = 0; Assert.assertTrue(BufferUtils.equalIncreasingByteArray(MEM_CAPACITY_BYTES, res)); in.close(); HeartbeatScheduler.execute(HeartbeatContext.WORKER_BLOCK_SYNC); // After the file is closed, the master's delete should go through and new files can be created AlluxioURI newFile = new AlluxioURI("/test2"); FileSystemTestUtils.createByteFile(mFileSystem, newFile, WriteType.MUST_CACHE, MEM_CAPACITY_BYTES); HeartbeatScheduler.execute(HeartbeatContext.WORKER_BLOCK_SYNC); Assert.assertEquals(100, mFileSystem.getStatus(newFile).getInMemoryPercentage()); } /** * Tests that pinning a file prevents it from being evicted. */ @Test public void pinFile() throws Exception { // Create a file that fills the entire Alluxio store AlluxioURI file = new AlluxioURI("/test1"); FileSystemTestUtils.createByteFile(mFileSystem, file, WriteType.MUST_CACHE, MEM_CAPACITY_BYTES); HeartbeatScheduler.execute(HeartbeatContext.WORKER_BLOCK_SYNC); // Pin the file mFileSystem.setAttribute(file, mSetPinned); HeartbeatScheduler.execute(HeartbeatContext.WORKER_PIN_LIST_SYNC); // Confirm the pin with master Assert.assertTrue(mFileSystem.getStatus(file).isPinned()); // Try to create a file that cannot be stored unless the previous file is evicted, expect an // exception since worker cannot serve the request mThrown.expect(Exception.class); FileSystemTestUtils.createByteFile(mFileSystem, "/test2", WriteType.MUST_CACHE, MEM_CAPACITY_BYTES); } /** * Tests that pinning a file and then unpinning. */ @Test public void unpinFile() throws Exception { // Create a file that fills the entire Alluxio store AlluxioURI file1 = new AlluxioURI("/test1"); FileSystemTestUtils .createByteFile(mFileSystem, file1, WriteType.MUST_CACHE, MEM_CAPACITY_BYTES); HeartbeatScheduler.execute(HeartbeatContext.WORKER_BLOCK_SYNC); // Pin the file mFileSystem.setAttribute(file1, mSetPinned); HeartbeatScheduler.execute(HeartbeatContext.WORKER_PIN_LIST_SYNC); // Confirm the pin with master Assert.assertTrue(mFileSystem.getStatus(file1).isPinned()); // Unpin the file mFileSystem.setAttribute(file1, mSetUnpinned); HeartbeatScheduler.execute(HeartbeatContext.WORKER_PIN_LIST_SYNC); // Confirm the unpin Assert.assertFalse(mFileSystem.getStatus(file1).isPinned()); // Try to create a file that cannot be stored unless the previous file is evicted, this // should succeed AlluxioURI file2 = new AlluxioURI("/test2"); FileSystemTestUtils .createByteFile(mFileSystem, file2, WriteType.MUST_CACHE, MEM_CAPACITY_BYTES); HeartbeatScheduler.execute(HeartbeatContext.WORKER_BLOCK_SYNC); // File 2 should be in memory and File 1 should be evicted Assert.assertEquals(0, mFileSystem.getStatus(file1).getInMemoryPercentage()); Assert.assertEquals(100, mFileSystem.getStatus(file2).getInMemoryPercentage()); } /** * Tests the promotion of a file. */ @Test public void promoteBlock() throws Exception { AlluxioURI uri1 = new AlluxioURI("/file1"); AlluxioURI uri2 = new AlluxioURI("/file2"); AlluxioURI uri3 = new AlluxioURI("/file3"); FileSystemTestUtils.createByteFile(mFileSystem, uri1, WriteType.CACHE_THROUGH, MEM_CAPACITY_BYTES / 6); FileSystemTestUtils.createByteFile(mFileSystem, uri2, WriteType.CACHE_THROUGH, MEM_CAPACITY_BYTES / 2); FileSystemTestUtils.createByteFile(mFileSystem, uri3, WriteType.CACHE_THROUGH, MEM_CAPACITY_BYTES / 2); HeartbeatScheduler.execute(HeartbeatContext.WORKER_BLOCK_SYNC); AlluxioURI toPromote; int toPromoteLen; URIStatus file1Info = mFileSystem.getStatus(uri1); URIStatus file2Info = mFileSystem.getStatus(uri2); URIStatus file3Info = mFileSystem.getStatus(uri3); // We know some file will not be in memory, but not which one since we do not want to make // any assumptions on the eviction policy if (file1Info.getInMemoryPercentage() < 100) { toPromote = uri1; toPromoteLen = (int) file1Info.getLength(); Assert.assertEquals(100, file2Info.getInMemoryPercentage()); Assert.assertEquals(100, file3Info.getInMemoryPercentage()); } else if (file2Info.getInMemoryPercentage() < 100) { toPromote = uri2; toPromoteLen = (int) file2Info.getLength(); Assert.assertEquals(100, file1Info.getInMemoryPercentage()); Assert.assertEquals(100, file3Info.getInMemoryPercentage()); } else { toPromote = uri3; toPromoteLen = (int) file3Info.getLength(); Assert.assertEquals(100, file1Info.getInMemoryPercentage()); Assert.assertEquals(100, file2Info.getInMemoryPercentage()); } FileInStream is = mFileSystem.openFile(toPromote, OpenFileOptions.defaults().setReadType(ReadType.CACHE_PROMOTE)); byte[] buf = new byte[toPromoteLen]; int len = is.read(buf); is.close(); HeartbeatScheduler.schedule(HeartbeatContext.WORKER_BLOCK_SYNC); HeartbeatScheduler.await(HeartbeatContext.WORKER_BLOCK_SYNC, 10, TimeUnit.SECONDS); Assert.assertEquals(toPromoteLen, len); Assert.assertEquals(100, mFileSystem.getStatus(toPromote).getInMemoryPercentage()); } }