-
Notifications
You must be signed in to change notification settings - Fork 9.1k
HADOOP-18399. S3A Prefetch - SingleFilePerBlockCache to use LocalDirAllocator #5054
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
e24a37f
98c89bf
f9a7774
a61f573
75ae49f
38050c7
fd9fe64
641d773
5e3ecfe
2ae91d2
4b5c6ac
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -27,10 +27,9 @@ | |
| import java.nio.file.Files; | ||
| import java.nio.file.OpenOption; | ||
| import java.nio.file.Path; | ||
| import java.nio.file.Paths; | ||
| import java.nio.file.StandardOpenOption; | ||
| import java.nio.file.attribute.FileAttribute; | ||
| import java.nio.file.attribute.PosixFilePermission; | ||
| import java.nio.file.attribute.PosixFilePermissions; | ||
| import java.util.ArrayList; | ||
| import java.util.Collections; | ||
| import java.util.EnumSet; | ||
|
|
@@ -39,9 +38,13 @@ | |
| import java.util.Set; | ||
| import java.util.concurrent.ConcurrentHashMap; | ||
|
|
||
| import org.apache.hadoop.thirdparty.com.google.common.collect.ImmutableSet; | ||
| import org.slf4j.Logger; | ||
| import org.slf4j.LoggerFactory; | ||
|
|
||
| import org.apache.hadoop.conf.Configuration; | ||
| import org.apache.hadoop.fs.LocalDirAllocator; | ||
|
|
||
| import static java.util.Objects.requireNonNull; | ||
| import static org.apache.hadoop.fs.impl.prefetch.Validate.checkNotNull; | ||
|
|
||
|
|
@@ -67,6 +70,12 @@ public class SingleFilePerBlockCache implements BlockCache { | |
|
|
||
| private final PrefetchingStatistics prefetchingStatistics; | ||
|
|
||
| /** | ||
| * File attributes attached to any intermediate temporary file created during index creation. | ||
| */ | ||
| private static final Set<PosixFilePermission> TEMP_FILE_ATTRS = | ||
| ImmutableSet.of(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE); | ||
|
|
||
| /** | ||
| * Cache entry. | ||
| * Each block is stored as a separate file. | ||
|
|
@@ -172,11 +181,17 @@ private Entry getEntry(int blockNumber) { | |
| /** | ||
| * Puts the given block in this cache. | ||
| * | ||
| * @throws IllegalArgumentException if buffer is null. | ||
| * @throws IllegalArgumentException if buffer.limit() is zero or negative. | ||
| * @param blockNumber the block number, used as a key for blocks map. | ||
| * @param buffer buffer contents of the given block to be added to this cache. | ||
| * @param conf the configuration. | ||
| * @param localDirAllocator the local dir allocator instance. | ||
| * @throws IOException if either local dir allocator fails to allocate file or if IO error | ||
| * occurs while writing the buffer content to the file. | ||
| * @throws IllegalArgumentException if buffer is null, or if buffer.limit() is zero or negative. | ||
| */ | ||
| @Override | ||
| public void put(int blockNumber, ByteBuffer buffer) throws IOException { | ||
| public void put(int blockNumber, ByteBuffer buffer, Configuration conf, | ||
| LocalDirAllocator localDirAllocator) throws IOException { | ||
| if (closed) { | ||
| return; | ||
| } | ||
|
|
@@ -191,7 +206,7 @@ public void put(int blockNumber, ByteBuffer buffer) throws IOException { | |
|
|
||
| Validate.checkPositiveInteger(buffer.limit(), "buffer.limit()"); | ||
|
|
||
| Path blockFilePath = getCacheFilePath(); | ||
| Path blockFilePath = getCacheFilePath(conf, localDirAllocator); | ||
| long size = Files.size(blockFilePath); | ||
| if (size != 0) { | ||
| String message = | ||
|
|
@@ -221,8 +236,19 @@ protected void writeFile(Path path, ByteBuffer buffer) throws IOException { | |
| writeChannel.close(); | ||
| } | ||
|
|
||
| protected Path getCacheFilePath() throws IOException { | ||
| return getTempFilePath(); | ||
| /** | ||
| * Return temporary file created based on the file path retrieved from local dir allocator. | ||
| * | ||
| * @param conf The configuration object. | ||
| * @param localDirAllocator Local dir allocator instance. | ||
| * @return Path of the temporary file created. | ||
| * @throws IOException if IO error occurs while local dir allocator tries to retrieve path | ||
| * from local FS or file creation fails or permission set fails. | ||
| */ | ||
| protected Path getCacheFilePath(final Configuration conf, | ||
steveloughran marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| final LocalDirAllocator localDirAllocator) | ||
| throws IOException { | ||
| return getTempFilePath(conf, localDirAllocator); | ||
| } | ||
|
|
||
| @Override | ||
|
|
@@ -323,9 +349,19 @@ private String getStats() { | |
|
|
||
| private static final String CACHE_FILE_PREFIX = "fs-cache-"; | ||
|
|
||
| public static boolean isCacheSpaceAvailable(long fileSize) { | ||
| /** | ||
| * Determine if the cache space is available on the local FS. | ||
| * | ||
| * @param fileSize The size of the file. | ||
| * @param conf The configuration. | ||
| * @param localDirAllocator Local dir allocator instance. | ||
| * @return True if the given file size is less than the available free space on local FS, | ||
| * False otherwise. | ||
| */ | ||
| public static boolean isCacheSpaceAvailable(long fileSize, Configuration conf, | ||
steveloughran marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| LocalDirAllocator localDirAllocator) { | ||
| try { | ||
| Path cacheFilePath = getTempFilePath(); | ||
| Path cacheFilePath = getTempFilePath(conf, localDirAllocator); | ||
| long freeSpace = new File(cacheFilePath.toString()).getUsableSpace(); | ||
| LOG.info("fileSize = {}, freeSpace = {}", fileSize, freeSpace); | ||
| Files.deleteIfExists(cacheFilePath); | ||
|
|
@@ -339,16 +375,25 @@ public static boolean isCacheSpaceAvailable(long fileSize) { | |
| // The suffix (file extension) of each serialized index file. | ||
| private static final String BINARY_FILE_SUFFIX = ".bin"; | ||
|
|
||
| // File attributes attached to any intermediate temporary file created during index creation. | ||
| private static final FileAttribute<Set<PosixFilePermission>> TEMP_FILE_ATTRS = | ||
| PosixFilePermissions.asFileAttribute(EnumSet.of(PosixFilePermission.OWNER_READ, | ||
| PosixFilePermission.OWNER_WRITE)); | ||
|
|
||
| private static Path getTempFilePath() throws IOException { | ||
| return Files.createTempFile( | ||
| CACHE_FILE_PREFIX, | ||
| BINARY_FILE_SUFFIX, | ||
| TEMP_FILE_ATTRS | ||
| ); | ||
| /** | ||
| * Create temporary file based on the file path retrieved from local dir allocator | ||
| * instance. The file is created with .bin suffix. The created file has been granted | ||
| * posix file permissions available in TEMP_FILE_ATTRS. | ||
| * | ||
| * @param conf the configuration. | ||
| * @param localDirAllocator the local dir allocator instance. | ||
| * @return path of the file created. | ||
| * @throws IOException if IO error occurs while local dir allocator tries to retrieve path | ||
| * from local FS or file creation fails or permission set fails. | ||
| */ | ||
| private static Path getTempFilePath(final Configuration conf, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Javadocs or comments in the method would be helpful. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
| final LocalDirAllocator localDirAllocator) throws IOException { | ||
| org.apache.hadoop.fs.Path path = | ||
| localDirAllocator.getLocalPathForWrite(CACHE_FILE_PREFIX, conf); | ||
| File dir = new File(path.getParent().toUri().getPath()); | ||
| String prefix = path.getName(); | ||
| File tmpFile = File.createTempFile(prefix, BINARY_FILE_SUFFIX, dir); | ||
| Path tmpFilePath = Paths.get(tmpFile.toURI()); | ||
| return Files.setPosixFilePermissions(tmpFilePath, TEMP_FILE_ATTRS); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -23,8 +23,11 @@ | |
|
|
||
| import org.junit.Test; | ||
|
|
||
| import org.apache.hadoop.conf.Configuration; | ||
| import org.apache.hadoop.fs.LocalDirAllocator; | ||
| import org.apache.hadoop.test.AbstractHadoopTestBase; | ||
|
|
||
| import static org.apache.hadoop.fs.CommonConfigurationKeys.HADOOP_TMP_DIR; | ||
| import static org.apache.hadoop.test.LambdaTestUtils.intercept; | ||
| import static org.junit.Assert.assertEquals; | ||
| import static org.junit.Assert.assertFalse; | ||
|
|
@@ -36,6 +39,8 @@ public class TestBlockCache extends AbstractHadoopTestBase { | |
|
|
||
| private static final int BUFFER_SIZE = 16; | ||
|
|
||
| private static final Configuration CONF = new Configuration(); | ||
|
|
||
| @Test | ||
| public void testArgChecks() throws Exception { | ||
| // Should not throw. | ||
|
|
@@ -46,7 +51,7 @@ public void testArgChecks() throws Exception { | |
|
|
||
| // Verify it throws correctly. | ||
| intercept(IllegalArgumentException.class, "'buffer' must not be null", | ||
| () -> cache.put(42, null)); | ||
| () -> cache.put(42, null, null, null)); | ||
|
|
||
|
|
||
| intercept(NullPointerException.class, null, | ||
|
|
@@ -67,7 +72,7 @@ public void testPutAndGet() throws Exception { | |
|
|
||
| assertEquals(0, cache.size()); | ||
| assertFalse(cache.containsBlock(0)); | ||
| cache.put(0, buffer1); | ||
| cache.put(0, buffer1, CONF, new LocalDirAllocator(HADOOP_TMP_DIR)); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For Test* classes, using Hence, using |
||
| assertEquals(1, cache.size()); | ||
| assertTrue(cache.containsBlock(0)); | ||
| ByteBuffer buffer2 = ByteBuffer.allocate(BUFFER_SIZE); | ||
|
|
@@ -77,7 +82,7 @@ public void testPutAndGet() throws Exception { | |
|
|
||
| assertEquals(1, cache.size()); | ||
| assertFalse(cache.containsBlock(1)); | ||
| cache.put(1, buffer1); | ||
| cache.put(1, buffer1, CONF, new LocalDirAllocator(HADOOP_TMP_DIR)); | ||
| assertEquals(2, cache.size()); | ||
| assertTrue(cache.containsBlock(1)); | ||
| ByteBuffer buffer3 = ByteBuffer.allocate(BUFFER_SIZE); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add
@parametervalues in the javadocs.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done