Skip to content

Commit 04f598b

Browse files
HADOOP-19595. ABFS: AbfsConfiguration should store account type information (HNS or FNS) (#7765) (#7791)
Contributed by Manish Bhatt
1 parent ca4858e commit 04f598b

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)
@@ -518,8 +519,11 @@ public AbfsConfiguration(final Configuration rawConfig, String accountName)
518519
}
519520

520521
public Trilean getIsNamespaceEnabledAccount() {
521-
return Trilean.getTrilean(
522-
getString(FS_AZURE_ACCOUNT_IS_HNS_ENABLED, isNamespaceEnabledAccount));
522+
if (isNamespaceEnabled == null) {
523+
isNamespaceEnabled = Trilean.getTrilean(
524+
getString(FS_AZURE_ACCOUNT_IS_HNS_ENABLED, isNamespaceEnabledAccount));
525+
}
526+
return isNamespaceEnabled;
523527
}
524528

525529
/**
@@ -1517,9 +1521,24 @@ void setMaxBackoffIntervalMilliseconds(int maxBackoffInterval) {
15171521
this.maxBackoffInterval = maxBackoffInterval;
15181522
}
15191523

1524+
/**
1525+
* Sets the namespace enabled account flag.
1526+
*
1527+
* @param isNamespaceEnabledAccount boolean value indicating if the account is namespace enabled.
1528+
*/
1529+
void setIsNamespaceEnabledAccount(boolean isNamespaceEnabledAccount) {
1530+
this.isNamespaceEnabled = Trilean.getTrilean(isNamespaceEnabledAccount);
1531+
}
1532+
1533+
/**
1534+
* Sets the namespace enabled account flag for testing purposes.
1535+
* Use this method only for testing scenarios.
1536+
*
1537+
* @param isNamespaceEnabledAccount Trilean value indicating if the account is namespace enabled.
1538+
*/
15201539
@VisibleForTesting
1521-
void setIsNamespaceEnabledAccount(String isNamespaceEnabledAccount) {
1522-
this.isNamespaceEnabledAccount = isNamespaceEnabledAccount;
1540+
void setIsNamespaceEnabledAccountForTesting(Trilean isNamespaceEnabledAccount) {
1541+
this.isNamespaceEnabled = isNamespaceEnabledAccount;
15231542
}
15241543

15251544
/**

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.
@@ -446,7 +447,7 @@ protected List<AbfsHttpHeader> createCommonHeaders(ApiVersion xMsVersion) {
446447
requestHeaders.add(new AbfsHttpHeader(X_MS_VERSION, xMsVersion.toString()));
447448
requestHeaders.add(new AbfsHttpHeader(ACCEPT_CHARSET, UTF_8));
448449
requestHeaders.add(new AbfsHttpHeader(CONTENT_TYPE, EMPTY_STRING));
449-
requestHeaders.add(new AbfsHttpHeader(USER_AGENT, userAgent));
450+
requestHeaders.add(new AbfsHttpHeader(USER_AGENT, getUserAgent()));
450451
return requestHeaders;
451452
}
452453

@@ -1326,8 +1327,9 @@ String initializeUserAgent(final AbfsConfiguration abfsConfiguration,
13261327
sb.append(abfsConfiguration.getClusterType());
13271328

13281329
// Add a unique identifier in FNS-Blob user agent string
1329-
if (!getIsNamespaceEnabled()
1330-
&& abfsConfiguration.getFsConfiguredServiceType() == BLOB) {
1330+
// Current filesystem init restricts HNS-Blob combination
1331+
// so namespace check not required.
1332+
if (abfsConfiguration.getFsConfiguredServiceType() == BLOB) {
13311333
sb.append(SEMICOLON)
13321334
.append(SINGLE_WHITE_SPACE)
13331335
.append(FNS_BLOB_USER_AGENT_IDENTIFIER);
@@ -1728,20 +1730,20 @@ protected String getUserAgent() {
17281730

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

17471749
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)