Skip to content

Commit 596fa98

Browse files
anujmodi2021Anuj Modi
authored andcommitted
HADOOP-19208: [ABFS] Fixing logic to determine HNS nature of account to avoid extra getAcl() calls (#6893)
1 parent 69806de commit 596fa98

File tree

3 files changed

+60
-3
lines changed

3 files changed

+60
-3
lines changed

hadoop-tools/hadoop-azure/src/main/java/org/apache/hadoop/fs/azurebfs/AzureBlobFileSystemStore.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -395,14 +395,21 @@ private synchronized boolean getNamespaceEnabledInformationFromServer(
395395
try {
396396
LOG.debug("Get root ACL status");
397397
getClient().getAclStatus(AbfsHttpConstants.ROOT_PATH, tracingContext);
398+
// If getAcl succeeds, namespace is enabled.
398399
isNamespaceEnabled = Trilean.getTrilean(true);
399400
} catch (AbfsRestOperationException ex) {
400-
// Get ACL status is a HEAD request, its response doesn't contain
401-
// errorCode
402-
// So can only rely on its status code to determine its account type.
401+
// Get ACL status is a HEAD request, its response doesn't contain errorCode
402+
// So can only rely on its status code to determine account type.
403403
if (HttpURLConnection.HTTP_BAD_REQUEST != ex.getStatusCode()) {
404+
// If getAcl fails with anything other than 400, namespace is enabled.
405+
isNamespaceEnabled = Trilean.getTrilean(true);
406+
// Continue to throw exception as earlier.
407+
LOG.debug("Failed to get ACL status with non 400. Inferring namespace enabled", ex);
404408
throw ex;
405409
}
410+
// If getAcl fails with 400, namespace is disabled.
411+
LOG.debug("Failed to get ACL status with 400. "
412+
+ "Inferring namespace disabled and ignoring error", ex);
406413
isNamespaceEnabled = Trilean.getTrilean(false);
407414
} catch (AzureBlobFileSystemException ex) {
408415
throw ex;

hadoop-tools/hadoop-azure/src/test/java/org/apache/hadoop/fs/azurebfs/ITestAzureBlobFileSystemInitAndCreate.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
import org.apache.hadoop.fs.azurebfs.constants.ConfigurationKeys;
3030
import org.apache.hadoop.fs.azurebfs.contracts.exceptions.TrileanConversionException;
31+
import org.apache.hadoop.fs.azurebfs.enums.Trilean;
3132
import org.apache.hadoop.fs.azurebfs.services.AbfsClient;
3233
import org.apache.hadoop.fs.azurebfs.services.AbfsRestOperation;
3334
import org.apache.hadoop.fs.azurebfs.utils.TracingContext;
@@ -67,6 +68,7 @@ public void testGetAclCallOnHnsConfigAbsence() throws Exception {
6768
Mockito.doThrow(TrileanConversionException.class)
6869
.when(store)
6970
.isNamespaceEnabled();
71+
store.setNamespaceEnabled(Trilean.UNKNOWN);
7072

7173
TracingContext tracingContext = getSampleTracingContext(fs, true);
7274
Mockito.doReturn(Mockito.mock(AbfsRestOperation.class))

hadoop-tools/hadoop-azure/src/test/java/org/apache/hadoop/fs/azurebfs/ITestGetNameSpaceEnabled.java

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,26 @@
2424
import org.junit.Assume;
2525
import org.junit.Test;
2626
import org.assertj.core.api.Assertions;
27+
import org.mockito.Mockito;
2728

2829
import org.apache.hadoop.fs.CommonConfigurationKeysPublic;
2930
import org.apache.hadoop.fs.FileSystem;
31+
import org.apache.hadoop.fs.azurebfs.contracts.exceptions.AbfsRestOperationException;
3032
import org.apache.hadoop.fs.azurebfs.services.AbfsClient;
3133
import org.apache.hadoop.fs.azurebfs.services.AbfsRestOperation;
3234
import org.apache.hadoop.conf.Configuration;
3335
import org.apache.hadoop.fs.Path;
3436
import org.apache.hadoop.fs.azurebfs.enums.Trilean;
3537
import org.apache.hadoop.fs.azurebfs.utils.TracingContext;
3638

39+
import static java.net.HttpURLConnection.HTTP_BAD_REQUEST;
40+
import static java.net.HttpURLConnection.HTTP_INTERNAL_ERROR;
41+
import static java.net.HttpURLConnection.HTTP_NOT_FOUND;
42+
import static java.net.HttpURLConnection.HTTP_UNAVAILABLE;
3743
import static org.mockito.ArgumentMatchers.any;
3844
import static org.mockito.ArgumentMatchers.anyString;
3945
import static org.mockito.Mockito.doReturn;
46+
import static org.mockito.Mockito.doThrow;
4047
import static org.mockito.Mockito.mock;
4148
import static org.mockito.Mockito.never;
4249
import static org.mockito.Mockito.times;
@@ -217,4 +224,45 @@ private AbfsClient callAbfsGetIsNamespaceEnabledAndReturnMockAbfsClient()
217224
return mockClient;
218225
}
219226

227+
@Test
228+
public void ensureGetAclDetermineHnsStatusAccurately() throws Exception {
229+
ensureGetAclDetermineHnsStatusAccuratelyInternal(HTTP_BAD_REQUEST,
230+
false, false);
231+
ensureGetAclDetermineHnsStatusAccuratelyInternal(HTTP_NOT_FOUND,
232+
true, true);
233+
ensureGetAclDetermineHnsStatusAccuratelyInternal(HTTP_INTERNAL_ERROR,
234+
true, true);
235+
ensureGetAclDetermineHnsStatusAccuratelyInternal(HTTP_UNAVAILABLE,
236+
true, true);
237+
}
238+
239+
private void ensureGetAclDetermineHnsStatusAccuratelyInternal(int statusCode,
240+
boolean expectedValue, boolean isExceptionExpected) throws Exception {
241+
AzureBlobFileSystemStore store = Mockito.spy(getFileSystem().getAbfsStore());
242+
AbfsClient mockClient = mock(AbfsClient.class);
243+
store.setNamespaceEnabled(Trilean.UNKNOWN);
244+
doReturn(mockClient).when(store).getClient();
245+
AbfsRestOperationException ex = new AbfsRestOperationException(
246+
statusCode, null, Integer.toString(statusCode), null);
247+
doThrow(ex).when(mockClient).getAclStatus(anyString(), any(TracingContext.class));
248+
249+
if (isExceptionExpected) {
250+
try {
251+
store.getIsNamespaceEnabled(getTestTracingContext(getFileSystem(), false));
252+
Assertions.fail(
253+
"Exception Should have been thrown with status code: " + statusCode);
254+
} catch (AbfsRestOperationException caughtEx) {
255+
Assertions.assertThat(caughtEx.getStatusCode()).isEqualTo(statusCode);
256+
Assertions.assertThat(caughtEx.getErrorMessage()).isEqualTo(ex.getErrorMessage());
257+
}
258+
}
259+
// This should not trigger extra getAcl() call in case of exceptions.
260+
boolean isHnsEnabled = store.getIsNamespaceEnabled(
261+
getTestTracingContext(getFileSystem(), false));
262+
Assertions.assertThat(isHnsEnabled).isEqualTo(expectedValue);
263+
264+
// GetAcl() should be called only once to determine the HNS status.
265+
Mockito.verify(mockClient, times(1))
266+
.getAclStatus(anyString(), any(TracingContext.class));
267+
}
220268
}

0 commit comments

Comments
 (0)