Skip to content

Commit 11cbda4

Browse files
HADOOP-19595. ABFS: AbfsConfiguration should store account type information (HNS or FNS) (#7765)
Contributed by Manish Bhatt
1 parent 6b75775 commit 11cbda4

File tree

11 files changed

+217
-70
lines changed

11 files changed

+217
-70
lines changed

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

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ public class AbfsConfiguration{
9595
private final AbfsServiceType fsConfiguredServiceType;
9696
private final boolean isSecure;
9797
private static final Logger LOG = LoggerFactory.getLogger(AbfsConfiguration.class);
98+
private Trilean isNamespaceEnabled = null;
9899

99100
@StringConfigurationValidatorAnnotation(ConfigurationKey = FS_AZURE_ACCOUNT_IS_HNS_ENABLED,
100101
DefaultValue = DEFAULT_FS_AZURE_ACCOUNT_IS_HNS_ENABLED)
@@ -525,8 +526,11 @@ public AbfsConfiguration(final Configuration rawConfig, String accountName)
525526
* @return TRUE/FALSE value if configured, UNKNOWN if not configured.
526527
*/
527528
public Trilean getIsNamespaceEnabledAccount() {
528-
return Trilean.getTrilean(
529-
getString(FS_AZURE_ACCOUNT_IS_HNS_ENABLED, isNamespaceEnabledAccount));
529+
if (isNamespaceEnabled == null) {
530+
isNamespaceEnabled = Trilean.getTrilean(
531+
getString(FS_AZURE_ACCOUNT_IS_HNS_ENABLED, isNamespaceEnabledAccount));
532+
}
533+
return isNamespaceEnabled;
530534
}
531535

532536
/**
@@ -1524,9 +1528,24 @@ void setMaxBackoffIntervalMilliseconds(int maxBackoffInterval) {
15241528
this.maxBackoffInterval = maxBackoffInterval;
15251529
}
15261530

1531+
/**
1532+
* Sets the namespace enabled account flag.
1533+
*
1534+
* @param isNamespaceEnabledAccount boolean value indicating if the account is namespace enabled.
1535+
*/
1536+
void setIsNamespaceEnabledAccount(boolean isNamespaceEnabledAccount) {
1537+
this.isNamespaceEnabled = Trilean.getTrilean(isNamespaceEnabledAccount);
1538+
}
1539+
1540+
/**
1541+
* Sets the namespace enabled account flag for testing purposes.
1542+
* Use this method only for testing scenarios.
1543+
*
1544+
* @param isNamespaceEnabledAccount Trilean value indicating if the account is namespace enabled.
1545+
*/
15271546
@VisibleForTesting
1528-
void setIsNamespaceEnabledAccount(String isNamespaceEnabledAccount) {
1529-
this.isNamespaceEnabledAccount = isNamespaceEnabledAccount;
1547+
void setIsNamespaceEnabledAccountForTesting(Trilean isNamespaceEnabledAccount) {
1548+
this.isNamespaceEnabled = isNamespaceEnabledAccount;
15301549
}
15311550

15321551
/**

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,8 @@ public void initialize(URI uri, Configuration configuration)
229229
* HNS Account Cannot have Blob Endpoint URI.
230230
*/
231231
try {
232+
// This will update namespaceEnable based on getAcl in case config is not set.
233+
// This Information will be stored in abfsConfiguration class.
232234
abfsConfiguration.validateConfiguredServiceType(
233235
tryGetIsNamespaceEnabled(initFSTracingContext));
234236
} catch (InvalidConfigurationValueException ex) {
@@ -296,7 +298,6 @@ public void initialize(URI uri, Configuration configuration)
296298
}
297299
}
298300
}
299-
getAbfsStore().updateClientWithNamespaceInfo(new TracingContext(initFSTracingContext));
300301

301302
LOG.trace("Initiate check for delegation token manager");
302303
if (UserGroupInformation.isSecurityEnabled()) {

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

Lines changed: 21 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,6 @@ public class AzureBlobFileSystemStore implements Closeable, ListingSupport {
186186

187187
private final AbfsConfiguration abfsConfiguration;
188188
private Set<String> azureInfiniteLeaseDirSet;
189-
private volatile Trilean isNamespaceEnabled;
190189
private final AuthType authType;
191190
private final UserGroupInformation userGroupInformation;
192191
private final IdentityTransformerInterface identityTransformer;
@@ -234,8 +233,6 @@ public AzureBlobFileSystemStore(
234233

235234
LOG.trace("AbfsConfiguration init complete");
236235

237-
this.isNamespaceEnabled = abfsConfiguration.getIsNamespaceEnabledAccount();
238-
239236
this.userGroupInformation = UserGroupInformation.getCurrentUser();
240237
this.userName = userGroupInformation.getShortUserName();
241238
LOG.trace("UGI init complete");
@@ -287,18 +284,6 @@ public AzureBlobFileSystemStore(
287284
"abfs-bounded");
288285
}
289286

290-
/**
291-
* Updates the client with the namespace information.
292-
*
293-
* @param tracingContext the tracing context to be used for the operation
294-
* @throws AzureBlobFileSystemException if an error occurs while updating the client
295-
*/
296-
public void updateClientWithNamespaceInfo(TracingContext tracingContext)
297-
throws AzureBlobFileSystemException {
298-
boolean isNamespaceEnabled = getIsNamespaceEnabled(tracingContext);
299-
AbfsClient.setIsNamespaceEnabled(isNamespaceEnabled);
300-
}
301-
302287
/**
303288
* Checks if the given key in Azure Storage should be stored as a page
304289
* blob instead of block blob.
@@ -384,12 +369,12 @@ private String[] authorityParts(URI uri) throws InvalidUriAuthorityException, In
384369
}
385370

386371
/**
387-
* Resolves namespace information of the filesystem from the state of {@link #isNamespaceEnabled}.
372+
* Resolves namespace information of the filesystem from the state of {@link #isNamespaceEnabled()}.
388373
* if the state is UNKNOWN, it will be determined by making a GET_ACL request
389374
* to the root of the filesystem. GET_ACL call is synchronized to ensure a single
390375
* call is made to determine the namespace information in case multiple threads are
391376
* calling this method at the same time. The resolution of namespace information
392-
* would be stored back as state of {@link #isNamespaceEnabled}.
377+
* would be stored back as {@link #setNamespaceEnabled(boolean)}.
393378
*
394379
* @param tracingContext tracing context
395380
* @return true if namespace is enabled, false otherwise.
@@ -407,34 +392,44 @@ public boolean getIsNamespaceEnabled(TracingContext tracingContext)
407392
return getNamespaceEnabledInformationFromServer(tracingContext);
408393
}
409394

395+
/**
396+
* In case the namespace configuration is not set or invalid, this method will
397+
* make a call to the server to determine if namespace is enabled or not.
398+
* This method is synchronized to ensure that only one thread
399+
* is making the call to the server to determine the namespace
400+
*
401+
* @param tracingContext tracing context
402+
* @return true if namespace is enabled, false otherwise.
403+
* @throws AzureBlobFileSystemException server errors.
404+
*/
410405
private synchronized boolean getNamespaceEnabledInformationFromServer(
411406
final TracingContext tracingContext) throws AzureBlobFileSystemException {
412-
if (isNamespaceEnabled != Trilean.UNKNOWN) {
413-
return isNamespaceEnabled.toBoolean();
407+
if (getAbfsConfiguration().getIsNamespaceEnabledAccount() != Trilean.UNKNOWN) {
408+
return isNamespaceEnabled();
414409
}
415410
try {
416411
LOG.debug("Get root ACL status");
417412
getClient(AbfsServiceType.DFS).getAclStatus(AbfsHttpConstants.ROOT_PATH, tracingContext);
418413
// If getAcl succeeds, namespace is enabled.
419-
isNamespaceEnabled = Trilean.getTrilean(true);
414+
setNamespaceEnabled(true);
420415
} catch (AbfsRestOperationException ex) {
421416
// Get ACL status is a HEAD request, its response doesn't contain errorCode
422417
// So can only rely on its status code to determine account type.
423418
if (HttpURLConnection.HTTP_BAD_REQUEST != ex.getStatusCode()) {
424419
// If getAcl fails with anything other than 400, namespace is enabled.
425-
isNamespaceEnabled = Trilean.getTrilean(true);
420+
setNamespaceEnabled(true);
426421
// Continue to throw exception as earlier.
427422
LOG.debug("Failed to get ACL status with non 400. Inferring namespace enabled", ex);
428423
throw ex;
429424
}
430425
// If getAcl fails with 400, namespace is disabled.
431426
LOG.debug("Failed to get ACL status with 400. "
432427
+ "Inferring namespace disabled and ignoring error", ex);
433-
isNamespaceEnabled = Trilean.getTrilean(false);
428+
setNamespaceEnabled(false);
434429
} catch (AzureBlobFileSystemException ex) {
435430
throw ex;
436431
}
437-
return isNamespaceEnabled.toBoolean();
432+
return isNamespaceEnabled();
438433
}
439434

440435
/**
@@ -443,7 +438,7 @@ private synchronized boolean getNamespaceEnabledInformationFromServer(
443438
*/
444439
@VisibleForTesting
445440
boolean isNamespaceEnabled() throws TrileanConversionException {
446-
return this.isNamespaceEnabled.toBoolean();
441+
return getAbfsConfiguration().getIsNamespaceEnabledAccount().toBoolean();
447442
}
448443

449444
@VisibleForTesting
@@ -2026,9 +2021,8 @@ DataBlocks.BlockFactory getBlockFactory() {
20262021
return blockFactory;
20272022
}
20282023

2029-
@VisibleForTesting
2030-
void setNamespaceEnabled(Trilean isNamespaceEnabled){
2031-
this.isNamespaceEnabled = isNamespaceEnabled;
2024+
void setNamespaceEnabled(boolean isNamespaceEnabled){
2025+
getAbfsConfiguration().setIsNamespaceEnabledAccount(isNamespaceEnabled);
20322026
}
20332027

20342028
@VisibleForTesting

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

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,11 @@
6666
import org.apache.hadoop.fs.azurebfs.contracts.exceptions.AbfsRestOperationException;
6767
import org.apache.hadoop.fs.azurebfs.contracts.exceptions.AzureBlobFileSystemException;
6868
import org.apache.hadoop.fs.azurebfs.contracts.exceptions.InvalidAbfsRestOperationException;
69+
import org.apache.hadoop.fs.azurebfs.contracts.exceptions.InvalidConfigurationValueException;
6970
import org.apache.hadoop.fs.azurebfs.contracts.exceptions.InvalidFileSystemPropertyException;
7071
import org.apache.hadoop.fs.azurebfs.contracts.exceptions.InvalidUriException;
7172
import org.apache.hadoop.fs.azurebfs.contracts.exceptions.SASTokenProviderException;
73+
import org.apache.hadoop.fs.azurebfs.contracts.exceptions.TrileanConversionException;
7274
import org.apache.hadoop.fs.azurebfs.contracts.services.AppendRequestParameters;
7375
import org.apache.hadoop.fs.azurebfs.contracts.services.AzureServiceErrorCode;
7476
import org.apache.hadoop.fs.azurebfs.contracts.services.ListResultEntrySchema;
@@ -196,7 +198,6 @@ public abstract class AbfsClient implements Closeable {
196198
private KeepAliveCache keepAliveCache;
197199

198200
private AbfsApacheHttpClient abfsApacheHttpClient;
199-
private static boolean isNamespaceEnabled = false;
200201

201202
/**
202203
* logging the rename failure if metadata is in an incomplete state.
@@ -442,7 +443,7 @@ protected List<AbfsHttpHeader> createCommonHeaders(ApiVersion xMsVersion) {
442443
requestHeaders.add(new AbfsHttpHeader(X_MS_VERSION, xMsVersion.toString()));
443444
requestHeaders.add(new AbfsHttpHeader(ACCEPT_CHARSET, UTF_8));
444445
requestHeaders.add(new AbfsHttpHeader(CONTENT_TYPE, EMPTY_STRING));
445-
requestHeaders.add(new AbfsHttpHeader(USER_AGENT, userAgent));
446+
requestHeaders.add(new AbfsHttpHeader(USER_AGENT, getUserAgent()));
446447
return requestHeaders;
447448
}
448449

@@ -1322,8 +1323,9 @@ String initializeUserAgent(final AbfsConfiguration abfsConfiguration,
13221323
sb.append(abfsConfiguration.getClusterType());
13231324

13241325
// Add a unique identifier in FNS-Blob user agent string
1325-
if (!getIsNamespaceEnabled()
1326-
&& abfsConfiguration.getFsConfiguredServiceType() == BLOB) {
1326+
// Current filesystem init restricts HNS-Blob combination
1327+
// so namespace check not required.
1328+
if (abfsConfiguration.getFsConfiguredServiceType() == BLOB) {
13271329
sb.append(SEMICOLON)
13281330
.append(SINGLE_WHITE_SPACE)
13291331
.append(FNS_BLOB_USER_AGENT_IDENTIFIER);
@@ -1724,20 +1726,20 @@ protected String getUserAgent() {
17241726

17251727
/**
17261728
* Checks if the namespace is enabled.
1729+
* Filesystem init will fail if namespace is not correctly configured,
1730+
* so instead of swallowing the exception, we should throw the exception
1731+
* in case namespace is not configured correctly.
17271732
*
17281733
* @return True if the namespace is enabled, false otherwise.
1734+
* @throws AzureBlobFileSystemException if the conversion fails.
17291735
*/
1730-
public static boolean getIsNamespaceEnabled() {
1731-
return isNamespaceEnabled;
1732-
}
1733-
1734-
/**
1735-
* Sets the namespace enabled status.
1736-
*
1737-
* @param namespaceEnabled True to enable the namespace, false to disable it.
1738-
*/
1739-
public static void setIsNamespaceEnabled(final boolean namespaceEnabled) {
1740-
isNamespaceEnabled = namespaceEnabled;
1736+
public boolean getIsNamespaceEnabled() throws AzureBlobFileSystemException {
1737+
try {
1738+
return getAbfsConfiguration().getIsNamespaceEnabledAccount().toBoolean();
1739+
} catch (TrileanConversionException ex) {
1740+
LOG.error("Failed to convert namespace enabled account property to boolean", ex);
1741+
throw new InvalidConfigurationValueException("Failed to determine account type", ex);
1742+
}
17411743
}
17421744

17431745
protected boolean isRenameResilience() {

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1563,9 +1563,11 @@ private Hashtable<String, String> parseCommaSeparatedXmsProperties(String xMsPro
15631563
* @param requestHeaders list of headers to be sent with the request
15641564
*
15651565
* @return client transaction id
1566+
* @throws AzureBlobFileSystemException if an error occurs while generating the client transaction id
15661567
*/
15671568
@VisibleForTesting
1568-
public String addClientTransactionIdToHeader(List<AbfsHttpHeader> requestHeaders) {
1569+
public String addClientTransactionIdToHeader(List<AbfsHttpHeader> requestHeaders)
1570+
throws AzureBlobFileSystemException {
15691571
String clientTransactionId = null;
15701572
// Set client transaction ID if the namespace and client transaction ID config are enabled.
15711573
if (getIsNamespaceEnabled() && getAbfsConfiguration().getIsClientTransactionIdEnabled()) {

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,8 @@ private void setTestUserFs() throws Exception {
102102
conf.setBoolean(FS_AZURE_ACCOUNT_IS_HNS_ENABLED, isHNSEnabled);
103103
this.testUserFs = FileSystem.newInstance(conf);
104104
// Resetting the namespace enabled flag to unknown after file system init.
105-
((AzureBlobFileSystem) testUserFs).getAbfsStore().setNamespaceEnabled(
106-
Trilean.UNKNOWN);
105+
((AzureBlobFileSystem) testUserFs).getAbfsStore()
106+
.getAbfsConfiguration().setIsNamespaceEnabledAccountForTesting(Trilean.UNKNOWN);
107107
}
108108

109109
private void setTestFsConf(final String fsConfKey,

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

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
import org.apache.hadoop.fs.azurebfs.contracts.exceptions.AbfsRestOperationException;
3434
import org.apache.hadoop.fs.azurebfs.contracts.exceptions.AzureBlobFileSystemException;
3535
import org.apache.hadoop.fs.azurebfs.contracts.exceptions.InvalidConfigurationValueException;
36-
import org.apache.hadoop.fs.azurebfs.contracts.exceptions.TrileanConversionException;
3736
import org.apache.hadoop.fs.azurebfs.enums.Trilean;
3837
import org.apache.hadoop.fs.azurebfs.services.AbfsClient;
3938
import org.apache.hadoop.fs.azurebfs.services.AbfsRestOperation;
@@ -83,11 +82,7 @@ public void testGetAclCallOnHnsConfigAbsence() throws Exception {
8382
AzureBlobFileSystemStore store = Mockito.spy(fs.getAbfsStore());
8483
AbfsClient client = Mockito.spy(fs.getAbfsStore().getClient(AbfsServiceType.DFS));
8584
Mockito.doReturn(client).when(store).getClient(AbfsServiceType.DFS);
86-
87-
Mockito.doThrow(TrileanConversionException.class)
88-
.when(store)
89-
.isNamespaceEnabled();
90-
store.setNamespaceEnabled(Trilean.UNKNOWN);
85+
store.getAbfsConfiguration().setIsNamespaceEnabledAccountForTesting(Trilean.UNKNOWN);
9186

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

0 commit comments

Comments
 (0)