HADOOP-18873. ABFS: AbfsOutputStream doesnt close DataBlocks object. (#6010)
AbfsOutputStream to close the dataBlock object created for the upload. Contributed By: Pranav Saxena
This commit is contained in:
parent
39f36d9071
commit
f24b73e5f3
@ -329,7 +329,7 @@ public String getKeyToBufferDir() {
|
|||||||
*/
|
*/
|
||||||
public static abstract class DataBlock implements Closeable {
|
public static abstract class DataBlock implements Closeable {
|
||||||
|
|
||||||
enum DestState {Writing, Upload, Closed}
|
public enum DestState {Writing, Upload, Closed}
|
||||||
|
|
||||||
private volatile DestState state = Writing;
|
private volatile DestState state = Writing;
|
||||||
private final long index;
|
private final long index;
|
||||||
@ -375,7 +375,7 @@ protected final void verifyState(DestState expected)
|
|||||||
*
|
*
|
||||||
* @return the current state.
|
* @return the current state.
|
||||||
*/
|
*/
|
||||||
final DestState getState() {
|
public final DestState getState() {
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -330,7 +330,7 @@ public FSDataOutputStream create(final Path f,
|
|||||||
try {
|
try {
|
||||||
TracingContext tracingContext = new TracingContext(clientCorrelationId,
|
TracingContext tracingContext = new TracingContext(clientCorrelationId,
|
||||||
fileSystemId, FSOperationType.CREATE, overwrite, tracingHeaderFormat, listener);
|
fileSystemId, FSOperationType.CREATE, overwrite, tracingHeaderFormat, listener);
|
||||||
OutputStream outputStream = abfsStore.createFile(qualifiedPath, statistics, overwrite,
|
OutputStream outputStream = getAbfsStore().createFile(qualifiedPath, statistics, overwrite,
|
||||||
permission == null ? FsPermission.getFileDefault() : permission,
|
permission == null ? FsPermission.getFileDefault() : permission,
|
||||||
FsPermission.getUMask(getConf()), tracingContext);
|
FsPermission.getUMask(getConf()), tracingContext);
|
||||||
statIncrement(FILES_CREATED);
|
statIncrement(FILES_CREATED);
|
||||||
|
@ -707,7 +707,7 @@ private AbfsOutputStreamContext populateAbfsOutputStreamContext(
|
|||||||
.withWriteMaxConcurrentRequestCount(abfsConfiguration.getWriteMaxConcurrentRequestCount())
|
.withWriteMaxConcurrentRequestCount(abfsConfiguration.getWriteMaxConcurrentRequestCount())
|
||||||
.withMaxWriteRequestsToQueue(abfsConfiguration.getMaxWriteRequestsToQueue())
|
.withMaxWriteRequestsToQueue(abfsConfiguration.getMaxWriteRequestsToQueue())
|
||||||
.withLease(lease)
|
.withLease(lease)
|
||||||
.withBlockFactory(blockFactory)
|
.withBlockFactory(getBlockFactory())
|
||||||
.withBlockOutputActiveBlocks(blockOutputActiveBlocks)
|
.withBlockOutputActiveBlocks(blockOutputActiveBlocks)
|
||||||
.withClient(client)
|
.withClient(client)
|
||||||
.withPosition(position)
|
.withPosition(position)
|
||||||
@ -1940,6 +1940,11 @@ void setClient(AbfsClient client) {
|
|||||||
this.client = client;
|
this.client = client;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
DataBlocks.BlockFactory getBlockFactory() {
|
||||||
|
return blockFactory;
|
||||||
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
void setNamespaceEnabled(Trilean isNamespaceEnabled){
|
void setNamespaceEnabled(Trilean isNamespaceEnabled){
|
||||||
this.isNamespaceEnabled = isNamespaceEnabled;
|
this.isNamespaceEnabled = isNamespaceEnabled;
|
||||||
|
@ -344,7 +344,7 @@ private void uploadBlockAsync(DataBlocks.DataBlock blockToUpload,
|
|||||||
outputStreamStatistics.uploadSuccessful(bytesLength);
|
outputStreamStatistics.uploadSuccessful(bytesLength);
|
||||||
return null;
|
return null;
|
||||||
} finally {
|
} finally {
|
||||||
IOUtils.close(blockUploadData);
|
IOUtils.close(blockUploadData, blockToUpload);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
writeOperations.add(new WriteOperation(job, offset, bytesLength));
|
writeOperations.add(new WriteOperation(job, offset, bytesLength));
|
||||||
|
@ -20,15 +20,31 @@
|
|||||||
|
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.assertj.core.api.Assertions;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.mockito.Mockito;
|
||||||
|
|
||||||
|
import org.apache.hadoop.conf.Configuration;
|
||||||
import org.apache.hadoop.fs.FSDataOutputStream;
|
import org.apache.hadoop.fs.FSDataOutputStream;
|
||||||
|
import org.apache.hadoop.fs.FileSystem;
|
||||||
import org.apache.hadoop.fs.Path;
|
import org.apache.hadoop.fs.Path;
|
||||||
import org.apache.hadoop.fs.azurebfs.constants.FSOperationType;
|
import org.apache.hadoop.fs.azurebfs.constants.FSOperationType;
|
||||||
import org.apache.hadoop.fs.azurebfs.utils.TracingHeaderValidator;
|
import org.apache.hadoop.fs.azurebfs.utils.TracingHeaderValidator;
|
||||||
import org.apache.hadoop.fs.contract.ContractTestUtils;
|
import org.apache.hadoop.fs.contract.ContractTestUtils;
|
||||||
|
import org.apache.hadoop.fs.store.BlockUploadStatistics;
|
||||||
|
import org.apache.hadoop.fs.store.DataBlocks;
|
||||||
|
|
||||||
|
import static org.apache.hadoop.fs.azurebfs.constants.ConfigurationKeys.DATA_BLOCKS_BUFFER;
|
||||||
|
import static org.apache.hadoop.fs.store.DataBlocks.DATA_BLOCKS_BUFFER_ARRAY;
|
||||||
|
import static org.apache.hadoop.fs.store.DataBlocks.DATA_BLOCKS_BUFFER_DISK;
|
||||||
|
import static org.apache.hadoop.fs.store.DataBlocks.DATA_BLOCKS_BYTEBUFFER;
|
||||||
|
import static org.apache.hadoop.fs.store.DataBlocks.DataBlock.DestState.Closed;
|
||||||
|
import static org.apache.hadoop.fs.store.DataBlocks.DataBlock.DestState.Writing;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test append operations.
|
* Test append operations.
|
||||||
@ -90,4 +106,47 @@ public void testTracingForAppend() throws IOException {
|
|||||||
fs.getFileSystemId(), FSOperationType.APPEND, false, 0));
|
fs.getFileSystemId(), FSOperationType.APPEND, false, 0));
|
||||||
fs.append(testPath, 10);
|
fs.append(testPath, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCloseOfDataBlockOnAppendComplete() throws Exception {
|
||||||
|
Set<String> blockBufferTypes = new HashSet<>();
|
||||||
|
blockBufferTypes.add(DATA_BLOCKS_BUFFER_DISK);
|
||||||
|
blockBufferTypes.add(DATA_BLOCKS_BYTEBUFFER);
|
||||||
|
blockBufferTypes.add(DATA_BLOCKS_BUFFER_ARRAY);
|
||||||
|
for (String blockBufferType : blockBufferTypes) {
|
||||||
|
Configuration configuration = new Configuration(getRawConfiguration());
|
||||||
|
configuration.set(DATA_BLOCKS_BUFFER, blockBufferType);
|
||||||
|
AzureBlobFileSystem fs = Mockito.spy(
|
||||||
|
(AzureBlobFileSystem) FileSystem.newInstance(configuration));
|
||||||
|
AzureBlobFileSystemStore store = Mockito.spy(fs.getAbfsStore());
|
||||||
|
Mockito.doReturn(store).when(fs).getAbfsStore();
|
||||||
|
DataBlocks.DataBlock[] dataBlock = new DataBlocks.DataBlock[1];
|
||||||
|
Mockito.doAnswer(getBlobFactoryInvocation -> {
|
||||||
|
DataBlocks.BlockFactory factory = Mockito.spy(
|
||||||
|
(DataBlocks.BlockFactory) getBlobFactoryInvocation.callRealMethod());
|
||||||
|
Mockito.doAnswer(factoryCreateInvocation -> {
|
||||||
|
dataBlock[0] = Mockito.spy(
|
||||||
|
(DataBlocks.DataBlock) factoryCreateInvocation.callRealMethod());
|
||||||
|
return dataBlock[0];
|
||||||
|
})
|
||||||
|
.when(factory)
|
||||||
|
.create(Mockito.anyLong(), Mockito.anyInt(), Mockito.any(
|
||||||
|
BlockUploadStatistics.class));
|
||||||
|
return factory;
|
||||||
|
}).when(store).getBlockFactory();
|
||||||
|
try (OutputStream os = fs.create(
|
||||||
|
new Path(getMethodName() + "_" + blockBufferType))) {
|
||||||
|
os.write(new byte[1]);
|
||||||
|
Assertions.assertThat(dataBlock[0].getState())
|
||||||
|
.describedAs(
|
||||||
|
"On write of data in outputStream, state should become Writing")
|
||||||
|
.isEqualTo(Writing);
|
||||||
|
os.close();
|
||||||
|
Mockito.verify(dataBlock[0], Mockito.times(1)).close();
|
||||||
|
Assertions.assertThat(dataBlock[0].getState())
|
||||||
|
.describedAs("On close of outputStream, state should become Closed")
|
||||||
|
.isEqualTo(Closed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user