GH-39297: [C++][FS]: Inform caller of container not-existing when checking for HNS support - #39298

Merged
felipecrv merged 5 commits into
apache:mainfrom
felipecrv:hns_check
Dec 20, 2023
Merged

GH-39297: [C++][FS]: Inform caller of container not-existing when checking for HNS support#39298
felipecrv merged 5 commits into
apache:mainfrom
felipecrv:hns_check

Conversation

@felipecrv

@felipecrvfelipecrv commented Dec 19, 2023

Copy link
Copy Markdown
Contributor

Rationale for this change

An operation checking for Hierarchical Namespace support shouldn't fail completely when the reason for the check failing is the container not existing. We can allow the caller to decide what to do in that situation by returning a result that indicates the check didn't succeed because the container doesn't exist.

What changes are included in this PR?

  • Removal of the azurefs_intern.h/cc files
  • Implementation of the check as a free-function instead of a class
  • Memoization of the result in the AzureFileSystem class

Are these changes tested?

Yes. The tests were improved to cover all cases.

@github-actions

Copy link
Copy Markdown

⚠️ GitHub issue #39297has been automatically assigned in GitHub to PR creator.

if (hns_support == HNSSupport::kContainerNotFound ||
hns_support == HNSSupport::kEnabled) {
// If the hierarchical namespace is enabled, then the storage account will
// have explicit directories. Neither a file nor a directory was found.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These refactorings preserve the existing semantics as the goal of this PR is just rewriting the HNS check, but I'm changing the semantics of directory operations in a follow-up PR.

@github-actionsgithub-actionsBot added awaiting committer review Awaiting committer review and removed awaiting review Awaiting review labels Dec 19, 2023
@felipecrv

Copy link
Copy Markdown
ContributorAuthor

@kou@Tom-Newton

@Tom-Newton

Tom-Newton commented Dec 19, 2023

Copy link
Copy Markdown
Contributor

Is there a specific reason to combine everything back into a single file? Personally, I thought we should probably move more stuff into azurefs_internal.cc given the size of azurefs.cc.

@Tom-NewtonTom-Newton left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There were a some things I liked about the old implementation but as a C++ noob my opinion probably doesn't have much weight here.

std::unique_ptr<DataLake::DataLakeServiceClient> datalake_service_client_;
std::unique_ptr<Blobs::BlobServiceClient> blob_service_client_;
internal::HierarchicalNamespaceDetector hns_detector_;
HNSSupport cached_hns_support_ = HNSSupport::kUnknown;

@Tom-NewtonTom-NewtonDec 19, 2023

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally, I liked having the separate detector class so that the cached value could be kept private from the implementation of the filesystem to prevent inadvertent misuse of the cache.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This split separates the stateful part of HNS checking from the request and error handling logic. To counter the possibility of inadvertent misuse of the value, I renamed it to cached_.... There are valid uses for this value directly and the name describes that it's a cached value that could contain much more than the two states of a boolean.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are valid uses for this value directly

Can you give some examples? I can't think of any

@felipecrvfelipecrvDec 20, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An operation could decide to use the DataLakeFileSystemClient if cached_hns_support in kUnknown/kContainerNotFound/kEnabled and set the value of cached_hns_support_ based on the error/success handling of that operation before falling back to the Blob API. This would save the mandatory extra request in the uncached case.

Another scenario is if we were to add threads to the mix, we would like to avoid having multiple HNS check requests going in parallel by having cached_hns_support_ be some kind of atomic variable or protected by a mutex that also protects other member variables in the AzureFileSystem::Impl class.

@Tom-NewtonTom-NewtonDec 20, 2023

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be honest I'm not really convinced by either of these, but it probably doesn't matter.

Technically you could avoid the call to check for hierarchical NS but I don't think it really makes sense because of the very small performance cost and the high added complexity cost. DataLakeFileSystemClient largely works on flat NS accounts so it would require extra error handling on every call and as we know from the hierarchical namespace detection code Azure often gives strange responses and its difficult to determine if the failure is genuine or if the error is just because hierarchical namespace is detected.

I don't really see why we would need to protect other member variables of AzureFileSystem::Impl behind the same mutex. I would have kept the separate detector class which could have just one mutex. When AzureFileSystem::Impl tries to check whether hierarchical NS is enabled in concurrently it would hit the mutex but otherwise I would want AzureFileSystem::Impl to be free to make other calls to blob storage without any mutexs getting in the way. Additionally, I was under the impression that AzureFileSystem would never be used in multiple threads. I think only RandomAccessFile::ReadAt is used concurrently.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will consider extracting the memoized HierarchicalNamespaceSupport() check to a separate class (added to my TODO list together with splitting the azurefs.cc file), but I maintain that having an underlying function that doesn't do any mutable state manipulation (just the request to the backend) makes it easier to reason about the correctness and cost of the calls.

AzureFileSystem would never be used in multiple threads. I think only RandomAccessFile::ReadAt is used concurrently.

I meant AzureFileSystem itself would be using multiple threads to run the operations.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...its difficult to determine if the failure is genuine or if the error is just because hierarchical namespace is detected.

I noticed this and I'm working on changes that puts us in a position where we never have to make that distinction. Because we can never cover all possible cases and Azurite being very broken when we make Data Lake Storage API calls to it makes it even worse.

Comment threadcpp/src/arrow/filesystem/azurefs.cc Outdated
Comment threadcpp/src/arrow/filesystem/azurefs.cc Outdated
@github-actionsgithub-actionsBot added awaiting changes Awaiting changes and removed awaiting committer review Awaiting committer review labels Dec 19, 2023
@felipecrv

felipecrv commented Dec 19, 2023

Copy link
Copy Markdown
ContributorAuthor

Is there a specific reason to combine everything back into a single file? Personally, I thought we should probably move more stuff into azurefs_internal.cc given the size of azurefs.cc.

@Tom-Newton This split caused 2 ExceptionToStatus functions to exist and would force me to expose IsDfsEmulator and IsContainerNotFound in the azurefs_internal.h header since I need them to implement the HNS check and other filesystem operations that now live in azurefs.cc. I'm not opposed to partitioning azurefs.cc into smaller files, but that split should be one that minimizes the shared interfaces between the partitions that have to be announced in a header -- a more natural split will be more evident when we finish the implementation.

@github-actionsgithub-actionsBot added awaiting change review Awaiting change review and removed awaiting changes Awaiting changes labels Dec 20, 2023
@Tom-Newton

Copy link
Copy Markdown
Contributor

@Tom-Newton This split caused 2 ExceptionToStatus functions to exist and would force me to expose IsDfsEmulator and IsContainerNotFound in the azurefs_internal.h header since I need them to implement the HNS check and other filesystem operations that now live in azurefs.cc. I'm not opposed to partitioning azurefs.cc into smaller files, but that split should be one that minimizes the shared interfaces between the partitions that have to be announced in a header -- a more natural split will be more evident when we finish the implementation.

I think personally I would have moved IsDfsEmulator and IsContainerNotFound in the azurefs_internal.h but I don't feel strongly.


namespace internal {

enum class HNSSupport {

@Tom-NewtonTom-NewtonDec 20, 2023

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again I don't feel strongly, but I would not have abbreviated so much. Yes, the docstring explains in detail but someone who just sees that name and Googles "HNS" will find themselves learning about the Croatian Football Federation 😄

@felipecrvfelipecrvDec 20, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I abbreviated the enum class because it gets repeated a lot, but kept the function names with the full name :-)

HNS is used in Microsoft documentation together with NFS, SFTP... so it's not so bad.

https://learn.microsoft.com/en-us/azure/storage/blobs/storage-feature-support-in-storage-accounts

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather have the full name as well, even if unfortunately long.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can I at least alias it in azurefs.cc?

@github-actionsgithub-actionsBot added awaiting changes Awaiting changes and removed awaiting change review Awaiting change review labels Dec 20, 2023
We don't need to say "Azure error" because ExceptionToStatus will do
that for us at the end of the message.
We don't need to say "unexpected" because if we are reporting the error,
it is unexpected.
@felipecrv
felipecrv requested a review from kouDecember 20, 2023 01:50
@github-actionsgithub-actionsBot added awaiting change review Awaiting change review and removed awaiting changes Awaiting changes labels Dec 20, 2023
@felipecrv

Copy link
Copy Markdown
ContributorAuthor

@kou can you look again? I had forgotten to push the unit test fixing commit before. Note that I added some error message cleanups as well.

kou
kou approved these changes Dec 20, 2023

@koukou left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

I think that we can merge this after @felipecrv and @Tom-Newton reach a consensus (and apply necessary changes if needed).
I don't have strong opinion for on going discussion.

@github-actionsgithub-actionsBot added awaiting merge Awaiting merge and removed awaiting change review Awaiting change review labels Dec 20, 2023
@Tom-Newton

Tom-Newton commented Dec 20, 2023

Copy link
Copy Markdown
Contributor

I would have done this differently but I don't feel strongly. @felipecrv feel free to merge

@felipecrv
felipecrv merged commit 7265689 into apache:mainDec 20, 2023
@felipecrvfelipecrv removed the awaiting merge Awaiting merge label Dec 20, 2023
@felipecrv
felipecrv deleted the hns_check branch December 20, 2023 13:43
@github-actionsgithub-actionsBot added the awaiting committer review Awaiting committer review label Dec 20, 2023
/// account.
/// \return kEnabled/kDisabled/kContainerNotFound (kUnknown is never
/// returned).
Result<HNSSupport> CheckIfHierarchicalNamespaceIsEnabled(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand why this is exposed in azurefs.h? Normally the user wouldn't interact with Azure SDK types directly, only through the FileSystem abstraction.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because this is called from tests. But note that it's in the internal namespace.

I removed azurefs_internal.h and moved everything to azurefs.cc to minimize the export of utilities that mention Azure SDK types and this was the only one left in the internal namespace because it's called directly from unit tests (cc @Tom-Newton).

@felipecrvfelipecrvDec 20, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And the types are only forward-declared here. No header-bloat from the SDK.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I would have rather kept the azurefs_internal.{h,cc} as that's a useful separation, and it makes reading the headers easier.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even if that requires exposing more symbols that are now private to azurefs.cc? I will need to expose:

  • ExceptionToStatus (which is a template on my fork at the moment)
  • IsDfsEmulator
  • IsContainerNotFound

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The solution to avoiding exposing extra symbols is moving the CheckIfHierarchicalNamespaceIsEnabled to azurefs_internal.h, but implementing it in azurefs.cc. I will have that done in the next PR I push.

@felipecrv

Copy link
Copy Markdown
ContributorAuthor

@pitrou@Tom-Newton follow-up PR addressing your feedback and simplifying error messages #39323

@conbench-apache-arrow

Copy link
Copy Markdown

After merging your PR, Conbench analyzed the 6 benchmarking runs that have been run so far on merge-commit 7265689.

There were 6 benchmark results indicating a performance regression:

The full Conbench report has more details. It also includes information about 1 possible false positive for unstable benchmarks that are known to sometimes produce them.

dgreiss pushed a commit to dgreiss/arrow that referenced this pull request Feb 19, 2024
…en checking for HNS support (apache#39298)
### Rationale for this change
An operation checking for Hierarchical Namespace support shouldn't fail completely when the reason for the check failing is the container not existing. We can allow the caller to decide what to do in that situation by returning a result that indicates the check didn't succeed because the container doesn't exist.
### What changes are included in this PR?
- Removal of the `azurefs_intern.h/cc` files
- Implementation of the check as a free-function instead of a class
- Memoization of the result in the `AzureFileSystem` class
### Are these changes tested?
Yes. The tests were improved to cover all cases.
* Closes: apache#39297
Authored-by: Felipe Oliveira Carvalho <felipekde@gmail.com>
Signed-off-by: Felipe Oliveira Carvalho <felipekde@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[C++] Inform caller of Azure Storage container not-existing when checking for HNS support

4 participants

@felipecrv@Tom-Newton@kou@pitrou
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

GH-39297: [C++][FS]: Inform caller of container not-existing when checking for HNS support - #39298

Merged
felipecrv merged 5 commits into
apache:mainfrom
felipecrv:hns_check
Dec 20, 2023
Merged

GH-39297: [C++][FS]: Inform caller of container not-existing when checking for HNS support#39298
felipecrv merged 5 commits into
apache:mainfrom
felipecrv:hns_check

Conversation

@felipecrv

@felipecrvfelipecrv commented Dec 19, 2023

Copy link
Copy Markdown
Contributor

Rationale for this change

An operation checking for Hierarchical Namespace support shouldn't fail completely when the reason for the check failing is the container not existing. We can allow the caller to decide what to do in that situation by returning a result that indicates the check didn't succeed because the container doesn't exist.

What changes are included in this PR?

  • Removal of the azurefs_intern.h/cc files
  • Implementation of the check as a free-function instead of a class
  • Memoization of the result in the AzureFileSystem class

Are these changes tested?

Yes. The tests were improved to cover all cases.

@github-actions

Copy link
Copy Markdown

⚠️ GitHub issue #39297has been automatically assigned in GitHub to PR creator.

if (hns_support == HNSSupport::kContainerNotFound ||
hns_support == HNSSupport::kEnabled) {
// If the hierarchical namespace is enabled, then the storage account will
// have explicit directories. Neither a file nor a directory was found.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These refactorings preserve the existing semantics as the goal of this PR is just rewriting the HNS check, but I'm changing the semantics of directory operations in a follow-up PR.

@github-actionsgithub-actionsBot added awaiting committer review Awaiting committer review and removed awaiting review Awaiting review labels Dec 19, 2023
@felipecrv

Copy link
Copy Markdown
ContributorAuthor

@kou@Tom-Newton

@Tom-Newton

Tom-Newton commented Dec 19, 2023

Copy link
Copy Markdown
Contributor

Is there a specific reason to combine everything back into a single file? Personally, I thought we should probably move more stuff into azurefs_internal.cc given the size of azurefs.cc.

@Tom-NewtonTom-Newton left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There were a some things I liked about the old implementation but as a C++ noob my opinion probably doesn't have much weight here.

std::unique_ptr<DataLake::DataLakeServiceClient> datalake_service_client_;
std::unique_ptr<Blobs::BlobServiceClient> blob_service_client_;
internal::HierarchicalNamespaceDetector hns_detector_;
HNSSupport cached_hns_support_ = HNSSupport::kUnknown;

@Tom-NewtonTom-NewtonDec 19, 2023

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally, I liked having the separate detector class so that the cached value could be kept private from the implementation of the filesystem to prevent inadvertent misuse of the cache.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This split separates the stateful part of HNS checking from the request and error handling logic. To counter the possibility of inadvertent misuse of the value, I renamed it to cached_.... There are valid uses for this value directly and the name describes that it's a cached value that could contain much more than the two states of a boolean.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are valid uses for this value directly

Can you give some examples? I can't think of any

@felipecrvfelipecrvDec 20, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An operation could decide to use the DataLakeFileSystemClient if cached_hns_support in kUnknown/kContainerNotFound/kEnabled and set the value of cached_hns_support_ based on the error/success handling of that operation before falling back to the Blob API. This would save the mandatory extra request in the uncached case.

Another scenario is if we were to add threads to the mix, we would like to avoid having multiple HNS check requests going in parallel by having cached_hns_support_ be some kind of atomic variable or protected by a mutex that also protects other member variables in the AzureFileSystem::Impl class.

@Tom-NewtonTom-NewtonDec 20, 2023

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be honest I'm not really convinced by either of these, but it probably doesn't matter.

Technically you could avoid the call to check for hierarchical NS but I don't think it really makes sense because of the very small performance cost and the high added complexity cost. DataLakeFileSystemClient largely works on flat NS accounts so it would require extra error handling on every call and as we know from the hierarchical namespace detection code Azure often gives strange responses and its difficult to determine if the failure is genuine or if the error is just because hierarchical namespace is detected.

I don't really see why we would need to protect other member variables of AzureFileSystem::Impl behind the same mutex. I would have kept the separate detector class which could have just one mutex. When AzureFileSystem::Impl tries to check whether hierarchical NS is enabled in concurrently it would hit the mutex but otherwise I would want AzureFileSystem::Impl to be free to make other calls to blob storage without any mutexs getting in the way. Additionally, I was under the impression that AzureFileSystem would never be used in multiple threads. I think only RandomAccessFile::ReadAt is used concurrently.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will consider extracting the memoized HierarchicalNamespaceSupport() check to a separate class (added to my TODO list together with splitting the azurefs.cc file), but I maintain that having an underlying function that doesn't do any mutable state manipulation (just the request to the backend) makes it easier to reason about the correctness and cost of the calls.

AzureFileSystem would never be used in multiple threads. I think only RandomAccessFile::ReadAt is used concurrently.

I meant AzureFileSystem itself would be using multiple threads to run the operations.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...its difficult to determine if the failure is genuine or if the error is just because hierarchical namespace is detected.

I noticed this and I'm working on changes that puts us in a position where we never have to make that distinction. Because we can never cover all possible cases and Azurite being very broken when we make Data Lake Storage API calls to it makes it even worse.

Comment threadcpp/src/arrow/filesystem/azurefs.cc Outdated
Comment threadcpp/src/arrow/filesystem/azurefs.cc Outdated
@github-actionsgithub-actionsBot added awaiting changes Awaiting changes and removed awaiting committer review Awaiting committer review labels Dec 19, 2023
@felipecrv

felipecrv commented Dec 19, 2023

Copy link
Copy Markdown
ContributorAuthor

Is there a specific reason to combine everything back into a single file? Personally, I thought we should probably move more stuff into azurefs_internal.cc given the size of azurefs.cc.

@Tom-Newton This split caused 2 ExceptionToStatus functions to exist and would force me to expose IsDfsEmulator and IsContainerNotFound in the azurefs_internal.h header since I need them to implement the HNS check and other filesystem operations that now live in azurefs.cc. I'm not opposed to partitioning azurefs.cc into smaller files, but that split should be one that minimizes the shared interfaces between the partitions that have to be announced in a header -- a more natural split will be more evident when we finish the implementation.

@github-actionsgithub-actionsBot added awaiting change review Awaiting change review and removed awaiting changes Awaiting changes labels Dec 20, 2023
@Tom-Newton

Copy link
Copy Markdown
Contributor

@Tom-Newton This split caused 2 ExceptionToStatus functions to exist and would force me to expose IsDfsEmulator and IsContainerNotFound in the azurefs_internal.h header since I need them to implement the HNS check and other filesystem operations that now live in azurefs.cc. I'm not opposed to partitioning azurefs.cc into smaller files, but that split should be one that minimizes the shared interfaces between the partitions that have to be announced in a header -- a more natural split will be more evident when we finish the implementation.

I think personally I would have moved IsDfsEmulator and IsContainerNotFound in the azurefs_internal.h but I don't feel strongly.


namespace internal {

enum class HNSSupport {

@Tom-NewtonTom-NewtonDec 20, 2023

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again I don't feel strongly, but I would not have abbreviated so much. Yes, the docstring explains in detail but someone who just sees that name and Googles "HNS" will find themselves learning about the Croatian Football Federation 😄

@felipecrvfelipecrvDec 20, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I abbreviated the enum class because it gets repeated a lot, but kept the function names with the full name :-)

HNS is used in Microsoft documentation together with NFS, SFTP... so it's not so bad.

https://learn.microsoft.com/en-us/azure/storage/blobs/storage-feature-support-in-storage-accounts

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather have the full name as well, even if unfortunately long.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can I at least alias it in azurefs.cc?

@github-actionsgithub-actionsBot added awaiting changes Awaiting changes and removed awaiting change review Awaiting change review labels Dec 20, 2023
We don't need to say "Azure error" because ExceptionToStatus will do
that for us at the end of the message.
We don't need to say "unexpected" because if we are reporting the error,
it is unexpected.
@felipecrv
felipecrv requested a review from kouDecember 20, 2023 01:50
@github-actionsgithub-actionsBot added awaiting change review Awaiting change review and removed awaiting changes Awaiting changes labels Dec 20, 2023
@felipecrv

Copy link
Copy Markdown
ContributorAuthor

@kou can you look again? I had forgotten to push the unit test fixing commit before. Note that I added some error message cleanups as well.

kou
kou approved these changes Dec 20, 2023

@koukou left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

I think that we can merge this after @felipecrv and @Tom-Newton reach a consensus (and apply necessary changes if needed).
I don't have strong opinion for on going discussion.

@github-actionsgithub-actionsBot added awaiting merge Awaiting merge and removed awaiting change review Awaiting change review labels Dec 20, 2023
@Tom-Newton

Tom-Newton commented Dec 20, 2023

Copy link
Copy Markdown
Contributor

I would have done this differently but I don't feel strongly. @felipecrv feel free to merge

@felipecrv
felipecrv merged commit 7265689 into apache:mainDec 20, 2023
@felipecrvfelipecrv removed the awaiting merge Awaiting merge label Dec 20, 2023
@felipecrv
felipecrv deleted the hns_check branch December 20, 2023 13:43
@github-actionsgithub-actionsBot added the awaiting committer review Awaiting committer review label Dec 20, 2023
/// account.
/// \return kEnabled/kDisabled/kContainerNotFound (kUnknown is never
/// returned).
Result<HNSSupport> CheckIfHierarchicalNamespaceIsEnabled(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand why this is exposed in azurefs.h? Normally the user wouldn't interact with Azure SDK types directly, only through the FileSystem abstraction.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because this is called from tests. But note that it's in the internal namespace.

I removed azurefs_internal.h and moved everything to azurefs.cc to minimize the export of utilities that mention Azure SDK types and this was the only one left in the internal namespace because it's called directly from unit tests (cc @Tom-Newton).

@felipecrvfelipecrvDec 20, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And the types are only forward-declared here. No header-bloat from the SDK.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I would have rather kept the azurefs_internal.{h,cc} as that's a useful separation, and it makes reading the headers easier.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even if that requires exposing more symbols that are now private to azurefs.cc? I will need to expose:

  • ExceptionToStatus (which is a template on my fork at the moment)
  • IsDfsEmulator
  • IsContainerNotFound

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The solution to avoiding exposing extra symbols is moving the CheckIfHierarchicalNamespaceIsEnabled to azurefs_internal.h, but implementing it in azurefs.cc. I will have that done in the next PR I push.

@felipecrv

Copy link
Copy Markdown
ContributorAuthor

@pitrou@Tom-Newton follow-up PR addressing your feedback and simplifying error messages #39323

@conbench-apache-arrow

Copy link
Copy Markdown

After merging your PR, Conbench analyzed the 6 benchmarking runs that have been run so far on merge-commit 7265689.

There were 6 benchmark results indicating a performance regression:

The full Conbench report has more details. It also includes information about 1 possible false positive for unstable benchmarks that are known to sometimes produce them.

dgreiss pushed a commit to dgreiss/arrow that referenced this pull request Feb 19, 2024
…en checking for HNS support (apache#39298)
### Rationale for this change
An operation checking for Hierarchical Namespace support shouldn't fail completely when the reason for the check failing is the container not existing. We can allow the caller to decide what to do in that situation by returning a result that indicates the check didn't succeed because the container doesn't exist.
### What changes are included in this PR?
- Removal of the `azurefs_intern.h/cc` files
- Implementation of the check as a free-function instead of a class
- Memoization of the result in the `AzureFileSystem` class
### Are these changes tested?
Yes. The tests were improved to cover all cases.
* Closes: apache#39297
Authored-by: Felipe Oliveira Carvalho <felipekde@gmail.com>
Signed-off-by: Felipe Oliveira Carvalho <felipekde@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[C++] Inform caller of Azure Storage container not-existing when checking for HNS support

4 participants

@felipecrv@Tom-Newton@kou@pitrou
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

GH-39297: [C++][FS]: Inform caller of container not-existing when checking for HNS support - #39298

Merged
felipecrv merged 5 commits into
apache:mainfrom
felipecrv:hns_check
Dec 20, 2023
Merged

GH-39297: [C++][FS]: Inform caller of container not-existing when checking for HNS support#39298
felipecrv merged 5 commits into
apache:mainfrom
felipecrv:hns_check

Conversation

@felipecrv

@felipecrvfelipecrv commented Dec 19, 2023

Copy link
Copy Markdown
Contributor

Rationale for this change

An operation checking for Hierarchical Namespace support shouldn't fail completely when the reason for the check failing is the container not existing. We can allow the caller to decide what to do in that situation by returning a result that indicates the check didn't succeed because the container doesn't exist.

What changes are included in this PR?

  • Removal of the azurefs_intern.h/cc files
  • Implementation of the check as a free-function instead of a class
  • Memoization of the result in the AzureFileSystem class

Are these changes tested?

Yes. The tests were improved to cover all cases.

@github-actions

Copy link
Copy Markdown

⚠️ GitHub issue #39297has been automatically assigned in GitHub to PR creator.

if (hns_support == HNSSupport::kContainerNotFound ||
hns_support == HNSSupport::kEnabled) {
// If the hierarchical namespace is enabled, then the storage account will
// have explicit directories. Neither a file nor a directory was found.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These refactorings preserve the existing semantics as the goal of this PR is just rewriting the HNS check, but I'm changing the semantics of directory operations in a follow-up PR.

@github-actionsgithub-actionsBot added awaiting committer review Awaiting committer review and removed awaiting review Awaiting review labels Dec 19, 2023
@felipecrv

Copy link
Copy Markdown
ContributorAuthor

@kou@Tom-Newton

@Tom-Newton

Tom-Newton commented Dec 19, 2023

Copy link
Copy Markdown
Contributor

Is there a specific reason to combine everything back into a single file? Personally, I thought we should probably move more stuff into azurefs_internal.cc given the size of azurefs.cc.

@Tom-NewtonTom-Newton left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There were a some things I liked about the old implementation but as a C++ noob my opinion probably doesn't have much weight here.

std::unique_ptr<DataLake::DataLakeServiceClient> datalake_service_client_;
std::unique_ptr<Blobs::BlobServiceClient> blob_service_client_;
internal::HierarchicalNamespaceDetector hns_detector_;
HNSSupport cached_hns_support_ = HNSSupport::kUnknown;

@Tom-NewtonTom-NewtonDec 19, 2023

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally, I liked having the separate detector class so that the cached value could be kept private from the implementation of the filesystem to prevent inadvertent misuse of the cache.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This split separates the stateful part of HNS checking from the request and error handling logic. To counter the possibility of inadvertent misuse of the value, I renamed it to cached_.... There are valid uses for this value directly and the name describes that it's a cached value that could contain much more than the two states of a boolean.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are valid uses for this value directly

Can you give some examples? I can't think of any

@felipecrvfelipecrvDec 20, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An operation could decide to use the DataLakeFileSystemClient if cached_hns_support in kUnknown/kContainerNotFound/kEnabled and set the value of cached_hns_support_ based on the error/success handling of that operation before falling back to the Blob API. This would save the mandatory extra request in the uncached case.

Another scenario is if we were to add threads to the mix, we would like to avoid having multiple HNS check requests going in parallel by having cached_hns_support_ be some kind of atomic variable or protected by a mutex that also protects other member variables in the AzureFileSystem::Impl class.

@Tom-NewtonTom-NewtonDec 20, 2023

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be honest I'm not really convinced by either of these, but it probably doesn't matter.

Technically you could avoid the call to check for hierarchical NS but I don't think it really makes sense because of the very small performance cost and the high added complexity cost. DataLakeFileSystemClient largely works on flat NS accounts so it would require extra error handling on every call and as we know from the hierarchical namespace detection code Azure often gives strange responses and its difficult to determine if the failure is genuine or if the error is just because hierarchical namespace is detected.

I don't really see why we would need to protect other member variables of AzureFileSystem::Impl behind the same mutex. I would have kept the separate detector class which could have just one mutex. When AzureFileSystem::Impl tries to check whether hierarchical NS is enabled in concurrently it would hit the mutex but otherwise I would want AzureFileSystem::Impl to be free to make other calls to blob storage without any mutexs getting in the way. Additionally, I was under the impression that AzureFileSystem would never be used in multiple threads. I think only RandomAccessFile::ReadAt is used concurrently.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will consider extracting the memoized HierarchicalNamespaceSupport() check to a separate class (added to my TODO list together with splitting the azurefs.cc file), but I maintain that having an underlying function that doesn't do any mutable state manipulation (just the request to the backend) makes it easier to reason about the correctness and cost of the calls.

AzureFileSystem would never be used in multiple threads. I think only RandomAccessFile::ReadAt is used concurrently.

I meant AzureFileSystem itself would be using multiple threads to run the operations.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...its difficult to determine if the failure is genuine or if the error is just because hierarchical namespace is detected.

I noticed this and I'm working on changes that puts us in a position where we never have to make that distinction. Because we can never cover all possible cases and Azurite being very broken when we make Data Lake Storage API calls to it makes it even worse.

Comment threadcpp/src/arrow/filesystem/azurefs.cc Outdated
Comment threadcpp/src/arrow/filesystem/azurefs.cc Outdated
@github-actionsgithub-actionsBot added awaiting changes Awaiting changes and removed awaiting committer review Awaiting committer review labels Dec 19, 2023
@felipecrv

felipecrv commented Dec 19, 2023

Copy link
Copy Markdown
ContributorAuthor

Is there a specific reason to combine everything back into a single file? Personally, I thought we should probably move more stuff into azurefs_internal.cc given the size of azurefs.cc.

@Tom-Newton This split caused 2 ExceptionToStatus functions to exist and would force me to expose IsDfsEmulator and IsContainerNotFound in the azurefs_internal.h header since I need them to implement the HNS check and other filesystem operations that now live in azurefs.cc. I'm not opposed to partitioning azurefs.cc into smaller files, but that split should be one that minimizes the shared interfaces between the partitions that have to be announced in a header -- a more natural split will be more evident when we finish the implementation.

@github-actionsgithub-actionsBot added awaiting change review Awaiting change review and removed awaiting changes Awaiting changes labels Dec 20, 2023
@Tom-Newton

Copy link
Copy Markdown
Contributor

@Tom-Newton This split caused 2 ExceptionToStatus functions to exist and would force me to expose IsDfsEmulator and IsContainerNotFound in the azurefs_internal.h header since I need them to implement the HNS check and other filesystem operations that now live in azurefs.cc. I'm not opposed to partitioning azurefs.cc into smaller files, but that split should be one that minimizes the shared interfaces between the partitions that have to be announced in a header -- a more natural split will be more evident when we finish the implementation.

I think personally I would have moved IsDfsEmulator and IsContainerNotFound in the azurefs_internal.h but I don't feel strongly.


namespace internal {

enum class HNSSupport {

@Tom-NewtonTom-NewtonDec 20, 2023

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again I don't feel strongly, but I would not have abbreviated so much. Yes, the docstring explains in detail but someone who just sees that name and Googles "HNS" will find themselves learning about the Croatian Football Federation 😄

@felipecrvfelipecrvDec 20, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I abbreviated the enum class because it gets repeated a lot, but kept the function names with the full name :-)

HNS is used in Microsoft documentation together with NFS, SFTP... so it's not so bad.

https://learn.microsoft.com/en-us/azure/storage/blobs/storage-feature-support-in-storage-accounts

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather have the full name as well, even if unfortunately long.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can I at least alias it in azurefs.cc?

@github-actionsgithub-actionsBot added awaiting changes Awaiting changes and removed awaiting change review Awaiting change review labels Dec 20, 2023
We don't need to say "Azure error" because ExceptionToStatus will do
that for us at the end of the message.
We don't need to say "unexpected" because if we are reporting the error,
it is unexpected.
@felipecrv
felipecrv requested a review from kouDecember 20, 2023 01:50
@github-actionsgithub-actionsBot added awaiting change review Awaiting change review and removed awaiting changes Awaiting changes labels Dec 20, 2023
@felipecrv

Copy link
Copy Markdown
ContributorAuthor

@kou can you look again? I had forgotten to push the unit test fixing commit before. Note that I added some error message cleanups as well.

kou
kou approved these changes Dec 20, 2023

@koukou left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

I think that we can merge this after @felipecrv and @Tom-Newton reach a consensus (and apply necessary changes if needed).
I don't have strong opinion for on going discussion.

@github-actionsgithub-actionsBot added awaiting merge Awaiting merge and removed awaiting change review Awaiting change review labels Dec 20, 2023
@Tom-Newton

Tom-Newton commented Dec 20, 2023

Copy link
Copy Markdown
Contributor

I would have done this differently but I don't feel strongly. @felipecrv feel free to merge

@felipecrv
felipecrv merged commit 7265689 into apache:mainDec 20, 2023
@felipecrvfelipecrv removed the awaiting merge Awaiting merge label Dec 20, 2023
@felipecrv
felipecrv deleted the hns_check branch December 20, 2023 13:43
@github-actionsgithub-actionsBot added the awaiting committer review Awaiting committer review label Dec 20, 2023
/// account.
/// \return kEnabled/kDisabled/kContainerNotFound (kUnknown is never
/// returned).
Result<HNSSupport> CheckIfHierarchicalNamespaceIsEnabled(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand why this is exposed in azurefs.h? Normally the user wouldn't interact with Azure SDK types directly, only through the FileSystem abstraction.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because this is called from tests. But note that it's in the internal namespace.

I removed azurefs_internal.h and moved everything to azurefs.cc to minimize the export of utilities that mention Azure SDK types and this was the only one left in the internal namespace because it's called directly from unit tests (cc @Tom-Newton).

@felipecrvfelipecrvDec 20, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And the types are only forward-declared here. No header-bloat from the SDK.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I would have rather kept the azurefs_internal.{h,cc} as that's a useful separation, and it makes reading the headers easier.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even if that requires exposing more symbols that are now private to azurefs.cc? I will need to expose:

  • ExceptionToStatus (which is a template on my fork at the moment)
  • IsDfsEmulator
  • IsContainerNotFound

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The solution to avoiding exposing extra symbols is moving the CheckIfHierarchicalNamespaceIsEnabled to azurefs_internal.h, but implementing it in azurefs.cc. I will have that done in the next PR I push.

@felipecrv

Copy link
Copy Markdown
ContributorAuthor

@pitrou@Tom-Newton follow-up PR addressing your feedback and simplifying error messages #39323

@conbench-apache-arrow

Copy link
Copy Markdown

After merging your PR, Conbench analyzed the 6 benchmarking runs that have been run so far on merge-commit 7265689.

There were 6 benchmark results indicating a performance regression:

The full Conbench report has more details. It also includes information about 1 possible false positive for unstable benchmarks that are known to sometimes produce them.

dgreiss pushed a commit to dgreiss/arrow that referenced this pull request Feb 19, 2024
…en checking for HNS support (apache#39298)
### Rationale for this change
An operation checking for Hierarchical Namespace support shouldn't fail completely when the reason for the check failing is the container not existing. We can allow the caller to decide what to do in that situation by returning a result that indicates the check didn't succeed because the container doesn't exist.
### What changes are included in this PR?
- Removal of the `azurefs_intern.h/cc` files
- Implementation of the check as a free-function instead of a class
- Memoization of the result in the `AzureFileSystem` class
### Are these changes tested?
Yes. The tests were improved to cover all cases.
* Closes: apache#39297
Authored-by: Felipe Oliveira Carvalho <felipekde@gmail.com>
Signed-off-by: Felipe Oliveira Carvalho <felipekde@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[C++] Inform caller of Azure Storage container not-existing when checking for HNS support

4 participants

@felipecrv@Tom-Newton@kou@pitrou
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

GH-39297: [C++][FS]: Inform caller of container not-existing when checking for HNS support - #39298

Merged
felipecrv merged 5 commits into
apache:mainfrom
felipecrv:hns_check
Dec 20, 2023
Merged

GH-39297: [C++][FS]: Inform caller of container not-existing when checking for HNS support#39298
felipecrv merged 5 commits into
apache:mainfrom
felipecrv:hns_check

Conversation

@felipecrv

@felipecrvfelipecrv commented Dec 19, 2023

Copy link
Copy Markdown
Contributor

Rationale for this change

An operation checking for Hierarchical Namespace support shouldn't fail completely when the reason for the check failing is the container not existing. We can allow the caller to decide what to do in that situation by returning a result that indicates the check didn't succeed because the container doesn't exist.

What changes are included in this PR?

  • Removal of the azurefs_intern.h/cc files
  • Implementation of the check as a free-function instead of a class
  • Memoization of the result in the AzureFileSystem class

Are these changes tested?

Yes. The tests were improved to cover all cases.

@github-actions

Copy link
Copy Markdown

⚠️ GitHub issue #39297has been automatically assigned in GitHub to PR creator.

if (hns_support == HNSSupport::kContainerNotFound ||
hns_support == HNSSupport::kEnabled) {
// If the hierarchical namespace is enabled, then the storage account will
// have explicit directories. Neither a file nor a directory was found.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These refactorings preserve the existing semantics as the goal of this PR is just rewriting the HNS check, but I'm changing the semantics of directory operations in a follow-up PR.

@github-actionsgithub-actionsBot added awaiting committer review Awaiting committer review and removed awaiting review Awaiting review labels Dec 19, 2023
@felipecrv

Copy link
Copy Markdown
ContributorAuthor

@kou@Tom-Newton

@Tom-Newton

Tom-Newton commented Dec 19, 2023

Copy link
Copy Markdown
Contributor

Is there a specific reason to combine everything back into a single file? Personally, I thought we should probably move more stuff into azurefs_internal.cc given the size of azurefs.cc.

@Tom-NewtonTom-Newton left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There were a some things I liked about the old implementation but as a C++ noob my opinion probably doesn't have much weight here.

std::unique_ptr<DataLake::DataLakeServiceClient> datalake_service_client_;
std::unique_ptr<Blobs::BlobServiceClient> blob_service_client_;
internal::HierarchicalNamespaceDetector hns_detector_;
HNSSupport cached_hns_support_ = HNSSupport::kUnknown;

@Tom-NewtonTom-NewtonDec 19, 2023

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally, I liked having the separate detector class so that the cached value could be kept private from the implementation of the filesystem to prevent inadvertent misuse of the cache.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This split separates the stateful part of HNS checking from the request and error handling logic. To counter the possibility of inadvertent misuse of the value, I renamed it to cached_.... There are valid uses for this value directly and the name describes that it's a cached value that could contain much more than the two states of a boolean.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are valid uses for this value directly

Can you give some examples? I can't think of any

@felipecrvfelipecrvDec 20, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An operation could decide to use the DataLakeFileSystemClient if cached_hns_support in kUnknown/kContainerNotFound/kEnabled and set the value of cached_hns_support_ based on the error/success handling of that operation before falling back to the Blob API. This would save the mandatory extra request in the uncached case.

Another scenario is if we were to add threads to the mix, we would like to avoid having multiple HNS check requests going in parallel by having cached_hns_support_ be some kind of atomic variable or protected by a mutex that also protects other member variables in the AzureFileSystem::Impl class.

@Tom-NewtonTom-NewtonDec 20, 2023

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be honest I'm not really convinced by either of these, but it probably doesn't matter.

Technically you could avoid the call to check for hierarchical NS but I don't think it really makes sense because of the very small performance cost and the high added complexity cost. DataLakeFileSystemClient largely works on flat NS accounts so it would require extra error handling on every call and as we know from the hierarchical namespace detection code Azure often gives strange responses and its difficult to determine if the failure is genuine or if the error is just because hierarchical namespace is detected.

I don't really see why we would need to protect other member variables of AzureFileSystem::Impl behind the same mutex. I would have kept the separate detector class which could have just one mutex. When AzureFileSystem::Impl tries to check whether hierarchical NS is enabled in concurrently it would hit the mutex but otherwise I would want AzureFileSystem::Impl to be free to make other calls to blob storage without any mutexs getting in the way. Additionally, I was under the impression that AzureFileSystem would never be used in multiple threads. I think only RandomAccessFile::ReadAt is used concurrently.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will consider extracting the memoized HierarchicalNamespaceSupport() check to a separate class (added to my TODO list together with splitting the azurefs.cc file), but I maintain that having an underlying function that doesn't do any mutable state manipulation (just the request to the backend) makes it easier to reason about the correctness and cost of the calls.

AzureFileSystem would never be used in multiple threads. I think only RandomAccessFile::ReadAt is used concurrently.

I meant AzureFileSystem itself would be using multiple threads to run the operations.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...its difficult to determine if the failure is genuine or if the error is just because hierarchical namespace is detected.

I noticed this and I'm working on changes that puts us in a position where we never have to make that distinction. Because we can never cover all possible cases and Azurite being very broken when we make Data Lake Storage API calls to it makes it even worse.

Comment threadcpp/src/arrow/filesystem/azurefs.cc Outdated
Comment threadcpp/src/arrow/filesystem/azurefs.cc Outdated
@github-actionsgithub-actionsBot added awaiting changes Awaiting changes and removed awaiting committer review Awaiting committer review labels Dec 19, 2023
@felipecrv

felipecrv commented Dec 19, 2023

Copy link
Copy Markdown
ContributorAuthor

Is there a specific reason to combine everything back into a single file? Personally, I thought we should probably move more stuff into azurefs_internal.cc given the size of azurefs.cc.

@Tom-Newton This split caused 2 ExceptionToStatus functions to exist and would force me to expose IsDfsEmulator and IsContainerNotFound in the azurefs_internal.h header since I need them to implement the HNS check and other filesystem operations that now live in azurefs.cc. I'm not opposed to partitioning azurefs.cc into smaller files, but that split should be one that minimizes the shared interfaces between the partitions that have to be announced in a header -- a more natural split will be more evident when we finish the implementation.

@github-actionsgithub-actionsBot added awaiting change review Awaiting change review and removed awaiting changes Awaiting changes labels Dec 20, 2023
@Tom-Newton

Copy link
Copy Markdown
Contributor

@Tom-Newton This split caused 2 ExceptionToStatus functions to exist and would force me to expose IsDfsEmulator and IsContainerNotFound in the azurefs_internal.h header since I need them to implement the HNS check and other filesystem operations that now live in azurefs.cc. I'm not opposed to partitioning azurefs.cc into smaller files, but that split should be one that minimizes the shared interfaces between the partitions that have to be announced in a header -- a more natural split will be more evident when we finish the implementation.

I think personally I would have moved IsDfsEmulator and IsContainerNotFound in the azurefs_internal.h but I don't feel strongly.


namespace internal {

enum class HNSSupport {

@Tom-NewtonTom-NewtonDec 20, 2023

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again I don't feel strongly, but I would not have abbreviated so much. Yes, the docstring explains in detail but someone who just sees that name and Googles "HNS" will find themselves learning about the Croatian Football Federation 😄

@felipecrvfelipecrvDec 20, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I abbreviated the enum class because it gets repeated a lot, but kept the function names with the full name :-)

HNS is used in Microsoft documentation together with NFS, SFTP... so it's not so bad.

https://learn.microsoft.com/en-us/azure/storage/blobs/storage-feature-support-in-storage-accounts

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather have the full name as well, even if unfortunately long.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can I at least alias it in azurefs.cc?

@github-actionsgithub-actionsBot added awaiting changes Awaiting changes and removed awaiting change review Awaiting change review labels Dec 20, 2023
We don't need to say "Azure error" because ExceptionToStatus will do
that for us at the end of the message.
We don't need to say "unexpected" because if we are reporting the error,
it is unexpected.
@felipecrv
felipecrv requested a review from kouDecember 20, 2023 01:50
@github-actionsgithub-actionsBot added awaiting change review Awaiting change review and removed awaiting changes Awaiting changes labels Dec 20, 2023
@felipecrv

Copy link
Copy Markdown
ContributorAuthor

@kou can you look again? I had forgotten to push the unit test fixing commit before. Note that I added some error message cleanups as well.

kou
kou approved these changes Dec 20, 2023

@koukou left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

I think that we can merge this after @felipecrv and @Tom-Newton reach a consensus (and apply necessary changes if needed).
I don't have strong opinion for on going discussion.

@github-actionsgithub-actionsBot added awaiting merge Awaiting merge and removed awaiting change review Awaiting change review labels Dec 20, 2023
@Tom-Newton

Tom-Newton commented Dec 20, 2023

Copy link
Copy Markdown
Contributor

I would have done this differently but I don't feel strongly. @felipecrv feel free to merge

@felipecrv
felipecrv merged commit 7265689 into apache:mainDec 20, 2023
@felipecrvfelipecrv removed the awaiting merge Awaiting merge label Dec 20, 2023
@felipecrv
felipecrv deleted the hns_check branch December 20, 2023 13:43
@github-actionsgithub-actionsBot added the awaiting committer review Awaiting committer review label Dec 20, 2023
/// account.
/// \return kEnabled/kDisabled/kContainerNotFound (kUnknown is never
/// returned).
Result<HNSSupport> CheckIfHierarchicalNamespaceIsEnabled(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand why this is exposed in azurefs.h? Normally the user wouldn't interact with Azure SDK types directly, only through the FileSystem abstraction.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because this is called from tests. But note that it's in the internal namespace.

I removed azurefs_internal.h and moved everything to azurefs.cc to minimize the export of utilities that mention Azure SDK types and this was the only one left in the internal namespace because it's called directly from unit tests (cc @Tom-Newton).

@felipecrvfelipecrvDec 20, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And the types are only forward-declared here. No header-bloat from the SDK.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I would have rather kept the azurefs_internal.{h,cc} as that's a useful separation, and it makes reading the headers easier.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even if that requires exposing more symbols that are now private to azurefs.cc? I will need to expose:

  • ExceptionToStatus (which is a template on my fork at the moment)
  • IsDfsEmulator
  • IsContainerNotFound

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The solution to avoiding exposing extra symbols is moving the CheckIfHierarchicalNamespaceIsEnabled to azurefs_internal.h, but implementing it in azurefs.cc. I will have that done in the next PR I push.

@felipecrv

Copy link
Copy Markdown
ContributorAuthor

@pitrou@Tom-Newton follow-up PR addressing your feedback and simplifying error messages #39323

@conbench-apache-arrow

Copy link
Copy Markdown

After merging your PR, Conbench analyzed the 6 benchmarking runs that have been run so far on merge-commit 7265689.

There were 6 benchmark results indicating a performance regression:

The full Conbench report has more details. It also includes information about 1 possible false positive for unstable benchmarks that are known to sometimes produce them.

dgreiss pushed a commit to dgreiss/arrow that referenced this pull request Feb 19, 2024
…en checking for HNS support (apache#39298)
### Rationale for this change
An operation checking for Hierarchical Namespace support shouldn't fail completely when the reason for the check failing is the container not existing. We can allow the caller to decide what to do in that situation by returning a result that indicates the check didn't succeed because the container doesn't exist.
### What changes are included in this PR?
- Removal of the `azurefs_intern.h/cc` files
- Implementation of the check as a free-function instead of a class
- Memoization of the result in the `AzureFileSystem` class
### Are these changes tested?
Yes. The tests were improved to cover all cases.
* Closes: apache#39297
Authored-by: Felipe Oliveira Carvalho <felipekde@gmail.com>
Signed-off-by: Felipe Oliveira Carvalho <felipekde@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[C++] Inform caller of Azure Storage container not-existing when checking for HNS support

4 participants

@felipecrv@Tom-Newton@kou@pitrou
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

GH-39297: [C++][FS]: Inform caller of container not-existing when checking for HNS support - #39298

Merged
felipecrv merged 5 commits into
apache:mainfrom
felipecrv:hns_check
Dec 20, 2023
Merged

GH-39297: [C++][FS]: Inform caller of container not-existing when checking for HNS support#39298
felipecrv merged 5 commits into
apache:mainfrom
felipecrv:hns_check

Conversation

@felipecrv

@felipecrvfelipecrv commented Dec 19, 2023

Copy link
Copy Markdown
Contributor

Rationale for this change

An operation checking for Hierarchical Namespace support shouldn't fail completely when the reason for the check failing is the container not existing. We can allow the caller to decide what to do in that situation by returning a result that indicates the check didn't succeed because the container doesn't exist.

What changes are included in this PR?

  • Removal of the azurefs_intern.h/cc files
  • Implementation of the check as a free-function instead of a class
  • Memoization of the result in the AzureFileSystem class

Are these changes tested?

Yes. The tests were improved to cover all cases.

@github-actions

Copy link
Copy Markdown

⚠️ GitHub issue #39297has been automatically assigned in GitHub to PR creator.

if (hns_support == HNSSupport::kContainerNotFound ||
hns_support == HNSSupport::kEnabled) {
// If the hierarchical namespace is enabled, then the storage account will
// have explicit directories. Neither a file nor a directory was found.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These refactorings preserve the existing semantics as the goal of this PR is just rewriting the HNS check, but I'm changing the semantics of directory operations in a follow-up PR.

@github-actionsgithub-actionsBot added awaiting committer review Awaiting committer review and removed awaiting review Awaiting review labels Dec 19, 2023
@felipecrv

Copy link
Copy Markdown
ContributorAuthor

@kou@Tom-Newton

@Tom-Newton

Tom-Newton commented Dec 19, 2023

Copy link
Copy Markdown
Contributor

Is there a specific reason to combine everything back into a single file? Personally, I thought we should probably move more stuff into azurefs_internal.cc given the size of azurefs.cc.

@Tom-NewtonTom-Newton left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There were a some things I liked about the old implementation but as a C++ noob my opinion probably doesn't have much weight here.

std::unique_ptr<DataLake::DataLakeServiceClient> datalake_service_client_;
std::unique_ptr<Blobs::BlobServiceClient> blob_service_client_;
internal::HierarchicalNamespaceDetector hns_detector_;
HNSSupport cached_hns_support_ = HNSSupport::kUnknown;

@Tom-NewtonTom-NewtonDec 19, 2023

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally, I liked having the separate detector class so that the cached value could be kept private from the implementation of the filesystem to prevent inadvertent misuse of the cache.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This split separates the stateful part of HNS checking from the request and error handling logic. To counter the possibility of inadvertent misuse of the value, I renamed it to cached_.... There are valid uses for this value directly and the name describes that it's a cached value that could contain much more than the two states of a boolean.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are valid uses for this value directly

Can you give some examples? I can't think of any

@felipecrvfelipecrvDec 20, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An operation could decide to use the DataLakeFileSystemClient if cached_hns_support in kUnknown/kContainerNotFound/kEnabled and set the value of cached_hns_support_ based on the error/success handling of that operation before falling back to the Blob API. This would save the mandatory extra request in the uncached case.

Another scenario is if we were to add threads to the mix, we would like to avoid having multiple HNS check requests going in parallel by having cached_hns_support_ be some kind of atomic variable or protected by a mutex that also protects other member variables in the AzureFileSystem::Impl class.

@Tom-NewtonTom-NewtonDec 20, 2023

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be honest I'm not really convinced by either of these, but it probably doesn't matter.

Technically you could avoid the call to check for hierarchical NS but I don't think it really makes sense because of the very small performance cost and the high added complexity cost. DataLakeFileSystemClient largely works on flat NS accounts so it would require extra error handling on every call and as we know from the hierarchical namespace detection code Azure often gives strange responses and its difficult to determine if the failure is genuine or if the error is just because hierarchical namespace is detected.

I don't really see why we would need to protect other member variables of AzureFileSystem::Impl behind the same mutex. I would have kept the separate detector class which could have just one mutex. When AzureFileSystem::Impl tries to check whether hierarchical NS is enabled in concurrently it would hit the mutex but otherwise I would want AzureFileSystem::Impl to be free to make other calls to blob storage without any mutexs getting in the way. Additionally, I was under the impression that AzureFileSystem would never be used in multiple threads. I think only RandomAccessFile::ReadAt is used concurrently.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will consider extracting the memoized HierarchicalNamespaceSupport() check to a separate class (added to my TODO list together with splitting the azurefs.cc file), but I maintain that having an underlying function that doesn't do any mutable state manipulation (just the request to the backend) makes it easier to reason about the correctness and cost of the calls.

AzureFileSystem would never be used in multiple threads. I think only RandomAccessFile::ReadAt is used concurrently.

I meant AzureFileSystem itself would be using multiple threads to run the operations.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...its difficult to determine if the failure is genuine or if the error is just because hierarchical namespace is detected.

I noticed this and I'm working on changes that puts us in a position where we never have to make that distinction. Because we can never cover all possible cases and Azurite being very broken when we make Data Lake Storage API calls to it makes it even worse.

Comment threadcpp/src/arrow/filesystem/azurefs.cc Outdated
Comment threadcpp/src/arrow/filesystem/azurefs.cc Outdated
@github-actionsgithub-actionsBot added awaiting changes Awaiting changes and removed awaiting committer review Awaiting committer review labels Dec 19, 2023
@felipecrv

felipecrv commented Dec 19, 2023

Copy link
Copy Markdown
ContributorAuthor

Is there a specific reason to combine everything back into a single file? Personally, I thought we should probably move more stuff into azurefs_internal.cc given the size of azurefs.cc.

@Tom-Newton This split caused 2 ExceptionToStatus functions to exist and would force me to expose IsDfsEmulator and IsContainerNotFound in the azurefs_internal.h header since I need them to implement the HNS check and other filesystem operations that now live in azurefs.cc. I'm not opposed to partitioning azurefs.cc into smaller files, but that split should be one that minimizes the shared interfaces between the partitions that have to be announced in a header -- a more natural split will be more evident when we finish the implementation.

@github-actionsgithub-actionsBot added awaiting change review Awaiting change review and removed awaiting changes Awaiting changes labels Dec 20, 2023
@Tom-Newton

Copy link
Copy Markdown
Contributor

@Tom-Newton This split caused 2 ExceptionToStatus functions to exist and would force me to expose IsDfsEmulator and IsContainerNotFound in the azurefs_internal.h header since I need them to implement the HNS check and other filesystem operations that now live in azurefs.cc. I'm not opposed to partitioning azurefs.cc into smaller files, but that split should be one that minimizes the shared interfaces between the partitions that have to be announced in a header -- a more natural split will be more evident when we finish the implementation.

I think personally I would have moved IsDfsEmulator and IsContainerNotFound in the azurefs_internal.h but I don't feel strongly.


namespace internal {

enum class HNSSupport {

@Tom-NewtonTom-NewtonDec 20, 2023

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again I don't feel strongly, but I would not have abbreviated so much. Yes, the docstring explains in detail but someone who just sees that name and Googles "HNS" will find themselves learning about the Croatian Football Federation 😄

@felipecrvfelipecrvDec 20, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I abbreviated the enum class because it gets repeated a lot, but kept the function names with the full name :-)

HNS is used in Microsoft documentation together with NFS, SFTP... so it's not so bad.

https://learn.microsoft.com/en-us/azure/storage/blobs/storage-feature-support-in-storage-accounts

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather have the full name as well, even if unfortunately long.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can I at least alias it in azurefs.cc?

@github-actionsgithub-actionsBot added awaiting changes Awaiting changes and removed awaiting change review Awaiting change review labels Dec 20, 2023
We don't need to say "Azure error" because ExceptionToStatus will do
that for us at the end of the message.
We don't need to say "unexpected" because if we are reporting the error,
it is unexpected.
@felipecrv
felipecrv requested a review from kouDecember 20, 2023 01:50
@github-actionsgithub-actionsBot added awaiting change review Awaiting change review and removed awaiting changes Awaiting changes labels Dec 20, 2023
@felipecrv

Copy link
Copy Markdown
ContributorAuthor

@kou can you look again? I had forgotten to push the unit test fixing commit before. Note that I added some error message cleanups as well.

kou
kou approved these changes Dec 20, 2023

@koukou left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

I think that we can merge this after @felipecrv and @Tom-Newton reach a consensus (and apply necessary changes if needed).
I don't have strong opinion for on going discussion.

@github-actionsgithub-actionsBot added awaiting merge Awaiting merge and removed awaiting change review Awaiting change review labels Dec 20, 2023
@Tom-Newton

Tom-Newton commented Dec 20, 2023

Copy link
Copy Markdown
Contributor

I would have done this differently but I don't feel strongly. @felipecrv feel free to merge

@felipecrv
felipecrv merged commit 7265689 into apache:mainDec 20, 2023
@felipecrvfelipecrv removed the awaiting merge Awaiting merge label Dec 20, 2023
@felipecrv
felipecrv deleted the hns_check branch December 20, 2023 13:43
@github-actionsgithub-actionsBot added the awaiting committer review Awaiting committer review label Dec 20, 2023
/// account.
/// \return kEnabled/kDisabled/kContainerNotFound (kUnknown is never
/// returned).
Result<HNSSupport> CheckIfHierarchicalNamespaceIsEnabled(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand why this is exposed in azurefs.h? Normally the user wouldn't interact with Azure SDK types directly, only through the FileSystem abstraction.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because this is called from tests. But note that it's in the internal namespace.

I removed azurefs_internal.h and moved everything to azurefs.cc to minimize the export of utilities that mention Azure SDK types and this was the only one left in the internal namespace because it's called directly from unit tests (cc @Tom-Newton).

@felipecrvfelipecrvDec 20, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And the types are only forward-declared here. No header-bloat from the SDK.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I would have rather kept the azurefs_internal.{h,cc} as that's a useful separation, and it makes reading the headers easier.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even if that requires exposing more symbols that are now private to azurefs.cc? I will need to expose:

  • ExceptionToStatus (which is a template on my fork at the moment)
  • IsDfsEmulator
  • IsContainerNotFound

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The solution to avoiding exposing extra symbols is moving the CheckIfHierarchicalNamespaceIsEnabled to azurefs_internal.h, but implementing it in azurefs.cc. I will have that done in the next PR I push.

@felipecrv

Copy link
Copy Markdown
ContributorAuthor

@pitrou@Tom-Newton follow-up PR addressing your feedback and simplifying error messages #39323

@conbench-apache-arrow

Copy link
Copy Markdown

After merging your PR, Conbench analyzed the 6 benchmarking runs that have been run so far on merge-commit 7265689.

There were 6 benchmark results indicating a performance regression:

The full Conbench report has more details. It also includes information about 1 possible false positive for unstable benchmarks that are known to sometimes produce them.

dgreiss pushed a commit to dgreiss/arrow that referenced this pull request Feb 19, 2024
…en checking for HNS support (apache#39298)
### Rationale for this change
An operation checking for Hierarchical Namespace support shouldn't fail completely when the reason for the check failing is the container not existing. We can allow the caller to decide what to do in that situation by returning a result that indicates the check didn't succeed because the container doesn't exist.
### What changes are included in this PR?
- Removal of the `azurefs_intern.h/cc` files
- Implementation of the check as a free-function instead of a class
- Memoization of the result in the `AzureFileSystem` class
### Are these changes tested?
Yes. The tests were improved to cover all cases.
* Closes: apache#39297
Authored-by: Felipe Oliveira Carvalho <felipekde@gmail.com>
Signed-off-by: Felipe Oliveira Carvalho <felipekde@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[C++] Inform caller of Azure Storage container not-existing when checking for HNS support

4 participants

@felipecrv@Tom-Newton@kou@pitrou
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

GH-39297: [C++][FS]: Inform caller of container not-existing when checking for HNS support - #39298

Merged
felipecrv merged 5 commits into
apache:mainfrom
felipecrv:hns_check
Dec 20, 2023
Merged

GH-39297: [C++][FS]: Inform caller of container not-existing when checking for HNS support#39298
felipecrv merged 5 commits into
apache:mainfrom
felipecrv:hns_check

Conversation

@felipecrv

@felipecrvfelipecrv commented Dec 19, 2023

Copy link
Copy Markdown
Contributor

Rationale for this change

An operation checking for Hierarchical Namespace support shouldn't fail completely when the reason for the check failing is the container not existing. We can allow the caller to decide what to do in that situation by returning a result that indicates the check didn't succeed because the container doesn't exist.

What changes are included in this PR?

  • Removal of the azurefs_intern.h/cc files
  • Implementation of the check as a free-function instead of a class
  • Memoization of the result in the AzureFileSystem class

Are these changes tested?

Yes. The tests were improved to cover all cases.

@github-actions

Copy link
Copy Markdown

⚠️ GitHub issue #39297has been automatically assigned in GitHub to PR creator.

if (hns_support == HNSSupport::kContainerNotFound ||
hns_support == HNSSupport::kEnabled) {
// If the hierarchical namespace is enabled, then the storage account will
// have explicit directories. Neither a file nor a directory was found.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These refactorings preserve the existing semantics as the goal of this PR is just rewriting the HNS check, but I'm changing the semantics of directory operations in a follow-up PR.

@github-actionsgithub-actionsBot added awaiting committer review Awaiting committer review and removed awaiting review Awaiting review labels Dec 19, 2023
@felipecrv

Copy link
Copy Markdown
ContributorAuthor

@kou@Tom-Newton

@Tom-Newton

Tom-Newton commented Dec 19, 2023

Copy link
Copy Markdown
Contributor

Is there a specific reason to combine everything back into a single file? Personally, I thought we should probably move more stuff into azurefs_internal.cc given the size of azurefs.cc.

@Tom-NewtonTom-Newton left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There were a some things I liked about the old implementation but as a C++ noob my opinion probably doesn't have much weight here.

std::unique_ptr<DataLake::DataLakeServiceClient> datalake_service_client_;
std::unique_ptr<Blobs::BlobServiceClient> blob_service_client_;
internal::HierarchicalNamespaceDetector hns_detector_;
HNSSupport cached_hns_support_ = HNSSupport::kUnknown;

@Tom-NewtonTom-NewtonDec 19, 2023

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally, I liked having the separate detector class so that the cached value could be kept private from the implementation of the filesystem to prevent inadvertent misuse of the cache.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This split separates the stateful part of HNS checking from the request and error handling logic. To counter the possibility of inadvertent misuse of the value, I renamed it to cached_.... There are valid uses for this value directly and the name describes that it's a cached value that could contain much more than the two states of a boolean.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are valid uses for this value directly

Can you give some examples? I can't think of any

@felipecrvfelipecrvDec 20, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An operation could decide to use the DataLakeFileSystemClient if cached_hns_support in kUnknown/kContainerNotFound/kEnabled and set the value of cached_hns_support_ based on the error/success handling of that operation before falling back to the Blob API. This would save the mandatory extra request in the uncached case.

Another scenario is if we were to add threads to the mix, we would like to avoid having multiple HNS check requests going in parallel by having cached_hns_support_ be some kind of atomic variable or protected by a mutex that also protects other member variables in the AzureFileSystem::Impl class.

@Tom-NewtonTom-NewtonDec 20, 2023

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be honest I'm not really convinced by either of these, but it probably doesn't matter.

Technically you could avoid the call to check for hierarchical NS but I don't think it really makes sense because of the very small performance cost and the high added complexity cost. DataLakeFileSystemClient largely works on flat NS accounts so it would require extra error handling on every call and as we know from the hierarchical namespace detection code Azure often gives strange responses and its difficult to determine if the failure is genuine or if the error is just because hierarchical namespace is detected.

I don't really see why we would need to protect other member variables of AzureFileSystem::Impl behind the same mutex. I would have kept the separate detector class which could have just one mutex. When AzureFileSystem::Impl tries to check whether hierarchical NS is enabled in concurrently it would hit the mutex but otherwise I would want AzureFileSystem::Impl to be free to make other calls to blob storage without any mutexs getting in the way. Additionally, I was under the impression that AzureFileSystem would never be used in multiple threads. I think only RandomAccessFile::ReadAt is used concurrently.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will consider extracting the memoized HierarchicalNamespaceSupport() check to a separate class (added to my TODO list together with splitting the azurefs.cc file), but I maintain that having an underlying function that doesn't do any mutable state manipulation (just the request to the backend) makes it easier to reason about the correctness and cost of the calls.

AzureFileSystem would never be used in multiple threads. I think only RandomAccessFile::ReadAt is used concurrently.

I meant AzureFileSystem itself would be using multiple threads to run the operations.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...its difficult to determine if the failure is genuine or if the error is just because hierarchical namespace is detected.

I noticed this and I'm working on changes that puts us in a position where we never have to make that distinction. Because we can never cover all possible cases and Azurite being very broken when we make Data Lake Storage API calls to it makes it even worse.

Comment threadcpp/src/arrow/filesystem/azurefs.cc Outdated
Comment threadcpp/src/arrow/filesystem/azurefs.cc Outdated
@github-actionsgithub-actionsBot added awaiting changes Awaiting changes and removed awaiting committer review Awaiting committer review labels Dec 19, 2023
@felipecrv

felipecrv commented Dec 19, 2023

Copy link
Copy Markdown
ContributorAuthor

Is there a specific reason to combine everything back into a single file? Personally, I thought we should probably move more stuff into azurefs_internal.cc given the size of azurefs.cc.

@Tom-Newton This split caused 2 ExceptionToStatus functions to exist and would force me to expose IsDfsEmulator and IsContainerNotFound in the azurefs_internal.h header since I need them to implement the HNS check and other filesystem operations that now live in azurefs.cc. I'm not opposed to partitioning azurefs.cc into smaller files, but that split should be one that minimizes the shared interfaces between the partitions that have to be announced in a header -- a more natural split will be more evident when we finish the implementation.

@github-actionsgithub-actionsBot added awaiting change review Awaiting change review and removed awaiting changes Awaiting changes labels Dec 20, 2023
@Tom-Newton

Copy link
Copy Markdown
Contributor

@Tom-Newton This split caused 2 ExceptionToStatus functions to exist and would force me to expose IsDfsEmulator and IsContainerNotFound in the azurefs_internal.h header since I need them to implement the HNS check and other filesystem operations that now live in azurefs.cc. I'm not opposed to partitioning azurefs.cc into smaller files, but that split should be one that minimizes the shared interfaces between the partitions that have to be announced in a header -- a more natural split will be more evident when we finish the implementation.

I think personally I would have moved IsDfsEmulator and IsContainerNotFound in the azurefs_internal.h but I don't feel strongly.


namespace internal {

enum class HNSSupport {

@Tom-NewtonTom-NewtonDec 20, 2023

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again I don't feel strongly, but I would not have abbreviated so much. Yes, the docstring explains in detail but someone who just sees that name and Googles "HNS" will find themselves learning about the Croatian Football Federation 😄

@felipecrvfelipecrvDec 20, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I abbreviated the enum class because it gets repeated a lot, but kept the function names with the full name :-)

HNS is used in Microsoft documentation together with NFS, SFTP... so it's not so bad.

https://learn.microsoft.com/en-us/azure/storage/blobs/storage-feature-support-in-storage-accounts

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather have the full name as well, even if unfortunately long.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can I at least alias it in azurefs.cc?

@github-actionsgithub-actionsBot added awaiting changes Awaiting changes and removed awaiting change review Awaiting change review labels Dec 20, 2023
We don't need to say "Azure error" because ExceptionToStatus will do
that for us at the end of the message.
We don't need to say "unexpected" because if we are reporting the error,
it is unexpected.
@felipecrv
felipecrv requested a review from kouDecember 20, 2023 01:50
@github-actionsgithub-actionsBot added awaiting change review Awaiting change review and removed awaiting changes Awaiting changes labels Dec 20, 2023
@felipecrv

Copy link
Copy Markdown
ContributorAuthor

@kou can you look again? I had forgotten to push the unit test fixing commit before. Note that I added some error message cleanups as well.

kou
kou approved these changes Dec 20, 2023

@koukou left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

I think that we can merge this after @felipecrv and @Tom-Newton reach a consensus (and apply necessary changes if needed).
I don't have strong opinion for on going discussion.

@github-actionsgithub-actionsBot added awaiting merge Awaiting merge and removed awaiting change review Awaiting change review labels Dec 20, 2023
@Tom-Newton

Tom-Newton commented Dec 20, 2023

Copy link
Copy Markdown
Contributor

I would have done this differently but I don't feel strongly. @felipecrv feel free to merge

@felipecrv
felipecrv merged commit 7265689 into apache:mainDec 20, 2023
@felipecrvfelipecrv removed the awaiting merge Awaiting merge label Dec 20, 2023
@felipecrv
felipecrv deleted the hns_check branch December 20, 2023 13:43
@github-actionsgithub-actionsBot added the awaiting committer review Awaiting committer review label Dec 20, 2023
/// account.
/// \return kEnabled/kDisabled/kContainerNotFound (kUnknown is never
/// returned).
Result<HNSSupport> CheckIfHierarchicalNamespaceIsEnabled(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand why this is exposed in azurefs.h? Normally the user wouldn't interact with Azure SDK types directly, only through the FileSystem abstraction.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because this is called from tests. But note that it's in the internal namespace.

I removed azurefs_internal.h and moved everything to azurefs.cc to minimize the export of utilities that mention Azure SDK types and this was the only one left in the internal namespace because it's called directly from unit tests (cc @Tom-Newton).

@felipecrvfelipecrvDec 20, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And the types are only forward-declared here. No header-bloat from the SDK.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I would have rather kept the azurefs_internal.{h,cc} as that's a useful separation, and it makes reading the headers easier.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even if that requires exposing more symbols that are now private to azurefs.cc? I will need to expose:

  • ExceptionToStatus (which is a template on my fork at the moment)
  • IsDfsEmulator
  • IsContainerNotFound

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The solution to avoiding exposing extra symbols is moving the CheckIfHierarchicalNamespaceIsEnabled to azurefs_internal.h, but implementing it in azurefs.cc. I will have that done in the next PR I push.

@felipecrv

Copy link
Copy Markdown
ContributorAuthor

@pitrou@Tom-Newton follow-up PR addressing your feedback and simplifying error messages #39323

@conbench-apache-arrow

Copy link
Copy Markdown

After merging your PR, Conbench analyzed the 6 benchmarking runs that have been run so far on merge-commit 7265689.

There were 6 benchmark results indicating a performance regression:

The full Conbench report has more details. It also includes information about 1 possible false positive for unstable benchmarks that are known to sometimes produce them.

dgreiss pushed a commit to dgreiss/arrow that referenced this pull request Feb 19, 2024
…en checking for HNS support (apache#39298)
### Rationale for this change
An operation checking for Hierarchical Namespace support shouldn't fail completely when the reason for the check failing is the container not existing. We can allow the caller to decide what to do in that situation by returning a result that indicates the check didn't succeed because the container doesn't exist.
### What changes are included in this PR?
- Removal of the `azurefs_intern.h/cc` files
- Implementation of the check as a free-function instead of a class
- Memoization of the result in the `AzureFileSystem` class
### Are these changes tested?
Yes. The tests were improved to cover all cases.
* Closes: apache#39297
Authored-by: Felipe Oliveira Carvalho <felipekde@gmail.com>
Signed-off-by: Felipe Oliveira Carvalho <felipekde@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[C++] Inform caller of Azure Storage container not-existing when checking for HNS support

4 participants

@felipecrv@Tom-Newton@kou@pitrou
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

GH-39297: [C++][FS]: Inform caller of container not-existing when checking for HNS support - #39298

Merged
felipecrv merged 5 commits into
apache:mainfrom
felipecrv:hns_check
Dec 20, 2023
Merged

GH-39297: [C++][FS]: Inform caller of container not-existing when checking for HNS support#39298
felipecrv merged 5 commits into
apache:mainfrom
felipecrv:hns_check

Conversation

@felipecrv

@felipecrvfelipecrv commented Dec 19, 2023

Copy link
Copy Markdown
Contributor

Rationale for this change

An operation checking for Hierarchical Namespace support shouldn't fail completely when the reason for the check failing is the container not existing. We can allow the caller to decide what to do in that situation by returning a result that indicates the check didn't succeed because the container doesn't exist.

What changes are included in this PR?

  • Removal of the azurefs_intern.h/cc files
  • Implementation of the check as a free-function instead of a class
  • Memoization of the result in the AzureFileSystem class

Are these changes tested?

Yes. The tests were improved to cover all cases.

@github-actions

Copy link
Copy Markdown

⚠️ GitHub issue #39297has been automatically assigned in GitHub to PR creator.

if (hns_support == HNSSupport::kContainerNotFound ||
hns_support == HNSSupport::kEnabled) {
// If the hierarchical namespace is enabled, then the storage account will
// have explicit directories. Neither a file nor a directory was found.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These refactorings preserve the existing semantics as the goal of this PR is just rewriting the HNS check, but I'm changing the semantics of directory operations in a follow-up PR.

@github-actionsgithub-actionsBot added awaiting committer review Awaiting committer review and removed awaiting review Awaiting review labels Dec 19, 2023
@felipecrv

Copy link
Copy Markdown
ContributorAuthor

@kou@Tom-Newton

@Tom-Newton

Tom-Newton commented Dec 19, 2023

Copy link
Copy Markdown
Contributor

Is there a specific reason to combine everything back into a single file? Personally, I thought we should probably move more stuff into azurefs_internal.cc given the size of azurefs.cc.

@Tom-NewtonTom-Newton left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There were a some things I liked about the old implementation but as a C++ noob my opinion probably doesn't have much weight here.

std::unique_ptr<DataLake::DataLakeServiceClient> datalake_service_client_;
std::unique_ptr<Blobs::BlobServiceClient> blob_service_client_;
internal::HierarchicalNamespaceDetector hns_detector_;
HNSSupport cached_hns_support_ = HNSSupport::kUnknown;

@Tom-NewtonTom-NewtonDec 19, 2023

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally, I liked having the separate detector class so that the cached value could be kept private from the implementation of the filesystem to prevent inadvertent misuse of the cache.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This split separates the stateful part of HNS checking from the request and error handling logic. To counter the possibility of inadvertent misuse of the value, I renamed it to cached_.... There are valid uses for this value directly and the name describes that it's a cached value that could contain much more than the two states of a boolean.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are valid uses for this value directly

Can you give some examples? I can't think of any

@felipecrvfelipecrvDec 20, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An operation could decide to use the DataLakeFileSystemClient if cached_hns_support in kUnknown/kContainerNotFound/kEnabled and set the value of cached_hns_support_ based on the error/success handling of that operation before falling back to the Blob API. This would save the mandatory extra request in the uncached case.

Another scenario is if we were to add threads to the mix, we would like to avoid having multiple HNS check requests going in parallel by having cached_hns_support_ be some kind of atomic variable or protected by a mutex that also protects other member variables in the AzureFileSystem::Impl class.

@Tom-NewtonTom-NewtonDec 20, 2023

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be honest I'm not really convinced by either of these, but it probably doesn't matter.

Technically you could avoid the call to check for hierarchical NS but I don't think it really makes sense because of the very small performance cost and the high added complexity cost. DataLakeFileSystemClient largely works on flat NS accounts so it would require extra error handling on every call and as we know from the hierarchical namespace detection code Azure often gives strange responses and its difficult to determine if the failure is genuine or if the error is just because hierarchical namespace is detected.

I don't really see why we would need to protect other member variables of AzureFileSystem::Impl behind the same mutex. I would have kept the separate detector class which could have just one mutex. When AzureFileSystem::Impl tries to check whether hierarchical NS is enabled in concurrently it would hit the mutex but otherwise I would want AzureFileSystem::Impl to be free to make other calls to blob storage without any mutexs getting in the way. Additionally, I was under the impression that AzureFileSystem would never be used in multiple threads. I think only RandomAccessFile::ReadAt is used concurrently.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will consider extracting the memoized HierarchicalNamespaceSupport() check to a separate class (added to my TODO list together with splitting the azurefs.cc file), but I maintain that having an underlying function that doesn't do any mutable state manipulation (just the request to the backend) makes it easier to reason about the correctness and cost of the calls.

AzureFileSystem would never be used in multiple threads. I think only RandomAccessFile::ReadAt is used concurrently.

I meant AzureFileSystem itself would be using multiple threads to run the operations.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...its difficult to determine if the failure is genuine or if the error is just because hierarchical namespace is detected.

I noticed this and I'm working on changes that puts us in a position where we never have to make that distinction. Because we can never cover all possible cases and Azurite being very broken when we make Data Lake Storage API calls to it makes it even worse.

Comment threadcpp/src/arrow/filesystem/azurefs.cc Outdated
Comment threadcpp/src/arrow/filesystem/azurefs.cc Outdated
@github-actionsgithub-actionsBot added awaiting changes Awaiting changes and removed awaiting committer review Awaiting committer review labels Dec 19, 2023
@felipecrv

felipecrv commented Dec 19, 2023

Copy link
Copy Markdown
ContributorAuthor

Is there a specific reason to combine everything back into a single file? Personally, I thought we should probably move more stuff into azurefs_internal.cc given the size of azurefs.cc.

@Tom-Newton This split caused 2 ExceptionToStatus functions to exist and would force me to expose IsDfsEmulator and IsContainerNotFound in the azurefs_internal.h header since I need them to implement the HNS check and other filesystem operations that now live in azurefs.cc. I'm not opposed to partitioning azurefs.cc into smaller files, but that split should be one that minimizes the shared interfaces between the partitions that have to be announced in a header -- a more natural split will be more evident when we finish the implementation.

@github-actionsgithub-actionsBot added awaiting change review Awaiting change review and removed awaiting changes Awaiting changes labels Dec 20, 2023
@Tom-Newton

Copy link
Copy Markdown
Contributor

@Tom-Newton This split caused 2 ExceptionToStatus functions to exist and would force me to expose IsDfsEmulator and IsContainerNotFound in the azurefs_internal.h header since I need them to implement the HNS check and other filesystem operations that now live in azurefs.cc. I'm not opposed to partitioning azurefs.cc into smaller files, but that split should be one that minimizes the shared interfaces between the partitions that have to be announced in a header -- a more natural split will be more evident when we finish the implementation.

I think personally I would have moved IsDfsEmulator and IsContainerNotFound in the azurefs_internal.h but I don't feel strongly.


namespace internal {

enum class HNSSupport {

@Tom-NewtonTom-NewtonDec 20, 2023

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again I don't feel strongly, but I would not have abbreviated so much. Yes, the docstring explains in detail but someone who just sees that name and Googles "HNS" will find themselves learning about the Croatian Football Federation 😄

@felipecrvfelipecrvDec 20, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I abbreviated the enum class because it gets repeated a lot, but kept the function names with the full name :-)

HNS is used in Microsoft documentation together with NFS, SFTP... so it's not so bad.

https://learn.microsoft.com/en-us/azure/storage/blobs/storage-feature-support-in-storage-accounts

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather have the full name as well, even if unfortunately long.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can I at least alias it in azurefs.cc?

@github-actionsgithub-actionsBot added awaiting changes Awaiting changes and removed awaiting change review Awaiting change review labels Dec 20, 2023
We don't need to say "Azure error" because ExceptionToStatus will do
that for us at the end of the message.
We don't need to say "unexpected" because if we are reporting the error,
it is unexpected.
@felipecrv
felipecrv requested a review from kouDecember 20, 2023 01:50
@github-actionsgithub-actionsBot added awaiting change review Awaiting change review and removed awaiting changes Awaiting changes labels Dec 20, 2023
@felipecrv

Copy link
Copy Markdown
ContributorAuthor

@kou can you look again? I had forgotten to push the unit test fixing commit before. Note that I added some error message cleanups as well.

kou
kou approved these changes Dec 20, 2023

@koukou left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

I think that we can merge this after @felipecrv and @Tom-Newton reach a consensus (and apply necessary changes if needed).
I don't have strong opinion for on going discussion.

@github-actionsgithub-actionsBot added awaiting merge Awaiting merge and removed awaiting change review Awaiting change review labels Dec 20, 2023
@Tom-Newton

Tom-Newton commented Dec 20, 2023

Copy link
Copy Markdown
Contributor

I would have done this differently but I don't feel strongly. @felipecrv feel free to merge

@felipecrv
felipecrv merged commit 7265689 into apache:mainDec 20, 2023
@felipecrvfelipecrv removed the awaiting merge Awaiting merge label Dec 20, 2023
@felipecrv
felipecrv deleted the hns_check branch December 20, 2023 13:43
@github-actionsgithub-actionsBot added the awaiting committer review Awaiting committer review label Dec 20, 2023
/// account.
/// \return kEnabled/kDisabled/kContainerNotFound (kUnknown is never
/// returned).
Result<HNSSupport> CheckIfHierarchicalNamespaceIsEnabled(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand why this is exposed in azurefs.h? Normally the user wouldn't interact with Azure SDK types directly, only through the FileSystem abstraction.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because this is called from tests. But note that it's in the internal namespace.

I removed azurefs_internal.h and moved everything to azurefs.cc to minimize the export of utilities that mention Azure SDK types and this was the only one left in the internal namespace because it's called directly from unit tests (cc @Tom-Newton).

@felipecrvfelipecrvDec 20, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And the types are only forward-declared here. No header-bloat from the SDK.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I would have rather kept the azurefs_internal.{h,cc} as that's a useful separation, and it makes reading the headers easier.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even if that requires exposing more symbols that are now private to azurefs.cc? I will need to expose:

  • ExceptionToStatus (which is a template on my fork at the moment)
  • IsDfsEmulator
  • IsContainerNotFound

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The solution to avoiding exposing extra symbols is moving the CheckIfHierarchicalNamespaceIsEnabled to azurefs_internal.h, but implementing it in azurefs.cc. I will have that done in the next PR I push.

@felipecrv

Copy link
Copy Markdown
ContributorAuthor

@pitrou@Tom-Newton follow-up PR addressing your feedback and simplifying error messages #39323

@conbench-apache-arrow

Copy link
Copy Markdown

After merging your PR, Conbench analyzed the 6 benchmarking runs that have been run so far on merge-commit 7265689.

There were 6 benchmark results indicating a performance regression:

The full Conbench report has more details. It also includes information about 1 possible false positive for unstable benchmarks that are known to sometimes produce them.

dgreiss pushed a commit to dgreiss/arrow that referenced this pull request Feb 19, 2024
…en checking for HNS support (apache#39298)
### Rationale for this change
An operation checking for Hierarchical Namespace support shouldn't fail completely when the reason for the check failing is the container not existing. We can allow the caller to decide what to do in that situation by returning a result that indicates the check didn't succeed because the container doesn't exist.
### What changes are included in this PR?
- Removal of the `azurefs_intern.h/cc` files
- Implementation of the check as a free-function instead of a class
- Memoization of the result in the `AzureFileSystem` class
### Are these changes tested?
Yes. The tests were improved to cover all cases.
* Closes: apache#39297
Authored-by: Felipe Oliveira Carvalho <felipekde@gmail.com>
Signed-off-by: Felipe Oliveira Carvalho <felipekde@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[C++] Inform caller of Azure Storage container not-existing when checking for HNS support

4 participants

@felipecrv@Tom-Newton@kou@pitrou
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

GH-39297: [C++][FS]: Inform caller of container not-existing when checking for HNS support - #39298

Merged
felipecrv merged 5 commits into
apache:mainfrom
felipecrv:hns_check
Dec 20, 2023
Merged

GH-39297: [C++][FS]: Inform caller of container not-existing when checking for HNS support#39298
felipecrv merged 5 commits into
apache:mainfrom
felipecrv:hns_check

Conversation

@felipecrv

@felipecrvfelipecrv commented Dec 19, 2023

Copy link
Copy Markdown
Contributor

Rationale for this change

An operation checking for Hierarchical Namespace support shouldn't fail completely when the reason for the check failing is the container not existing. We can allow the caller to decide what to do in that situation by returning a result that indicates the check didn't succeed because the container doesn't exist.

What changes are included in this PR?

  • Removal of the azurefs_intern.h/cc files
  • Implementation of the check as a free-function instead of a class
  • Memoization of the result in the AzureFileSystem class

Are these changes tested?

Yes. The tests were improved to cover all cases.

@github-actions

Copy link
Copy Markdown

⚠️ GitHub issue #39297has been automatically assigned in GitHub to PR creator.

if (hns_support == HNSSupport::kContainerNotFound ||
hns_support == HNSSupport::kEnabled) {
// If the hierarchical namespace is enabled, then the storage account will
// have explicit directories. Neither a file nor a directory was found.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These refactorings preserve the existing semantics as the goal of this PR is just rewriting the HNS check, but I'm changing the semantics of directory operations in a follow-up PR.

@github-actionsgithub-actionsBot added awaiting committer review Awaiting committer review and removed awaiting review Awaiting review labels Dec 19, 2023
@felipecrv

Copy link
Copy Markdown
ContributorAuthor

@kou@Tom-Newton

@Tom-Newton

Tom-Newton commented Dec 19, 2023

Copy link
Copy Markdown
Contributor

Is there a specific reason to combine everything back into a single file? Personally, I thought we should probably move more stuff into azurefs_internal.cc given the size of azurefs.cc.

@Tom-NewtonTom-Newton left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There were a some things I liked about the old implementation but as a C++ noob my opinion probably doesn't have much weight here.

std::unique_ptr<DataLake::DataLakeServiceClient> datalake_service_client_;
std::unique_ptr<Blobs::BlobServiceClient> blob_service_client_;
internal::HierarchicalNamespaceDetector hns_detector_;
HNSSupport cached_hns_support_ = HNSSupport::kUnknown;

@Tom-NewtonTom-NewtonDec 19, 2023

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally, I liked having the separate detector class so that the cached value could be kept private from the implementation of the filesystem to prevent inadvertent misuse of the cache.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This split separates the stateful part of HNS checking from the request and error handling logic. To counter the possibility of inadvertent misuse of the value, I renamed it to cached_.... There are valid uses for this value directly and the name describes that it's a cached value that could contain much more than the two states of a boolean.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are valid uses for this value directly

Can you give some examples? I can't think of any

@felipecrvfelipecrvDec 20, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An operation could decide to use the DataLakeFileSystemClient if cached_hns_support in kUnknown/kContainerNotFound/kEnabled and set the value of cached_hns_support_ based on the error/success handling of that operation before falling back to the Blob API. This would save the mandatory extra request in the uncached case.

Another scenario is if we were to add threads to the mix, we would like to avoid having multiple HNS check requests going in parallel by having cached_hns_support_ be some kind of atomic variable or protected by a mutex that also protects other member variables in the AzureFileSystem::Impl class.

@Tom-NewtonTom-NewtonDec 20, 2023

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be honest I'm not really convinced by either of these, but it probably doesn't matter.

Technically you could avoid the call to check for hierarchical NS but I don't think it really makes sense because of the very small performance cost and the high added complexity cost. DataLakeFileSystemClient largely works on flat NS accounts so it would require extra error handling on every call and as we know from the hierarchical namespace detection code Azure often gives strange responses and its difficult to determine if the failure is genuine or if the error is just because hierarchical namespace is detected.

I don't really see why we would need to protect other member variables of AzureFileSystem::Impl behind the same mutex. I would have kept the separate detector class which could have just one mutex. When AzureFileSystem::Impl tries to check whether hierarchical NS is enabled in concurrently it would hit the mutex but otherwise I would want AzureFileSystem::Impl to be free to make other calls to blob storage without any mutexs getting in the way. Additionally, I was under the impression that AzureFileSystem would never be used in multiple threads. I think only RandomAccessFile::ReadAt is used concurrently.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will consider extracting the memoized HierarchicalNamespaceSupport() check to a separate class (added to my TODO list together with splitting the azurefs.cc file), but I maintain that having an underlying function that doesn't do any mutable state manipulation (just the request to the backend) makes it easier to reason about the correctness and cost of the calls.

AzureFileSystem would never be used in multiple threads. I think only RandomAccessFile::ReadAt is used concurrently.

I meant AzureFileSystem itself would be using multiple threads to run the operations.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...its difficult to determine if the failure is genuine or if the error is just because hierarchical namespace is detected.

I noticed this and I'm working on changes that puts us in a position where we never have to make that distinction. Because we can never cover all possible cases and Azurite being very broken when we make Data Lake Storage API calls to it makes it even worse.

Comment threadcpp/src/arrow/filesystem/azurefs.cc Outdated
Comment threadcpp/src/arrow/filesystem/azurefs.cc Outdated
@github-actionsgithub-actionsBot added awaiting changes Awaiting changes and removed awaiting committer review Awaiting committer review labels Dec 19, 2023
@felipecrv

felipecrv commented Dec 19, 2023

Copy link
Copy Markdown
ContributorAuthor

Is there a specific reason to combine everything back into a single file? Personally, I thought we should probably move more stuff into azurefs_internal.cc given the size of azurefs.cc.

@Tom-Newton This split caused 2 ExceptionToStatus functions to exist and would force me to expose IsDfsEmulator and IsContainerNotFound in the azurefs_internal.h header since I need them to implement the HNS check and other filesystem operations that now live in azurefs.cc. I'm not opposed to partitioning azurefs.cc into smaller files, but that split should be one that minimizes the shared interfaces between the partitions that have to be announced in a header -- a more natural split will be more evident when we finish the implementation.

@github-actionsgithub-actionsBot added awaiting change review Awaiting change review and removed awaiting changes Awaiting changes labels Dec 20, 2023
@Tom-Newton

Copy link
Copy Markdown
Contributor

@Tom-Newton This split caused 2 ExceptionToStatus functions to exist and would force me to expose IsDfsEmulator and IsContainerNotFound in the azurefs_internal.h header since I need them to implement the HNS check and other filesystem operations that now live in azurefs.cc. I'm not opposed to partitioning azurefs.cc into smaller files, but that split should be one that minimizes the shared interfaces between the partitions that have to be announced in a header -- a more natural split will be more evident when we finish the implementation.

I think personally I would have moved IsDfsEmulator and IsContainerNotFound in the azurefs_internal.h but I don't feel strongly.


namespace internal {

enum class HNSSupport {

@Tom-NewtonTom-NewtonDec 20, 2023

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again I don't feel strongly, but I would not have abbreviated so much. Yes, the docstring explains in detail but someone who just sees that name and Googles "HNS" will find themselves learning about the Croatian Football Federation 😄

@felipecrvfelipecrvDec 20, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I abbreviated the enum class because it gets repeated a lot, but kept the function names with the full name :-)

HNS is used in Microsoft documentation together with NFS, SFTP... so it's not so bad.

https://learn.microsoft.com/en-us/azure/storage/blobs/storage-feature-support-in-storage-accounts

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather have the full name as well, even if unfortunately long.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can I at least alias it in azurefs.cc?

@github-actionsgithub-actionsBot added awaiting changes Awaiting changes and removed awaiting change review Awaiting change review labels Dec 20, 2023
We don't need to say "Azure error" because ExceptionToStatus will do
that for us at the end of the message.
We don't need to say "unexpected" because if we are reporting the error,
it is unexpected.
@felipecrv
felipecrv requested a review from kouDecember 20, 2023 01:50
@github-actionsgithub-actionsBot added awaiting change review Awaiting change review and removed awaiting changes Awaiting changes labels Dec 20, 2023
@felipecrv

Copy link
Copy Markdown
ContributorAuthor

@kou can you look again? I had forgotten to push the unit test fixing commit before. Note that I added some error message cleanups as well.

kou
kou approved these changes Dec 20, 2023

@koukou left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

I think that we can merge this after @felipecrv and @Tom-Newton reach a consensus (and apply necessary changes if needed).
I don't have strong opinion for on going discussion.

@github-actionsgithub-actionsBot added awaiting merge Awaiting merge and removed awaiting change review Awaiting change review labels Dec 20, 2023
@Tom-Newton

Tom-Newton commented Dec 20, 2023

Copy link
Copy Markdown
Contributor

I would have done this differently but I don't feel strongly. @felipecrv feel free to merge

@felipecrv
felipecrv merged commit 7265689 into apache:mainDec 20, 2023
@felipecrvfelipecrv removed the awaiting merge Awaiting merge label Dec 20, 2023
@felipecrv
felipecrv deleted the hns_check branch December 20, 2023 13:43
@github-actionsgithub-actionsBot added the awaiting committer review Awaiting committer review label Dec 20, 2023
/// account.
/// \return kEnabled/kDisabled/kContainerNotFound (kUnknown is never
/// returned).
Result<HNSSupport> CheckIfHierarchicalNamespaceIsEnabled(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand why this is exposed in azurefs.h? Normally the user wouldn't interact with Azure SDK types directly, only through the FileSystem abstraction.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because this is called from tests. But note that it's in the internal namespace.

I removed azurefs_internal.h and moved everything to azurefs.cc to minimize the export of utilities that mention Azure SDK types and this was the only one left in the internal namespace because it's called directly from unit tests (cc @Tom-Newton).

@felipecrvfelipecrvDec 20, 2023

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And the types are only forward-declared here. No header-bloat from the SDK.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I would have rather kept the azurefs_internal.{h,cc} as that's a useful separation, and it makes reading the headers easier.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even if that requires exposing more symbols that are now private to azurefs.cc? I will need to expose:

  • ExceptionToStatus (which is a template on my fork at the moment)
  • IsDfsEmulator
  • IsContainerNotFound

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The solution to avoiding exposing extra symbols is moving the CheckIfHierarchicalNamespaceIsEnabled to azurefs_internal.h, but implementing it in azurefs.cc. I will have that done in the next PR I push.

@felipecrv

Copy link
Copy Markdown
ContributorAuthor

@pitrou@Tom-Newton follow-up PR addressing your feedback and simplifying error messages #39323

@conbench-apache-arrow

Copy link
Copy Markdown

After merging your PR, Conbench analyzed the 6 benchmarking runs that have been run so far on merge-commit 7265689.

There were 6 benchmark results indicating a performance regression:

The full Conbench report has more details. It also includes information about 1 possible false positive for unstable benchmarks that are known to sometimes produce them.

dgreiss pushed a commit to dgreiss/arrow that referenced this pull request Feb 19, 2024
…en checking for HNS support (apache#39298)
### Rationale for this change
An operation checking for Hierarchical Namespace support shouldn't fail completely when the reason for the check failing is the container not existing. We can allow the caller to decide what to do in that situation by returning a result that indicates the check didn't succeed because the container doesn't exist.
### What changes are included in this PR?
- Removal of the `azurefs_intern.h/cc` files
- Implementation of the check as a free-function instead of a class
- Memoization of the result in the `AzureFileSystem` class
### Are these changes tested?
Yes. The tests were improved to cover all cases.
* Closes: apache#39297
Authored-by: Felipe Oliveira Carvalho <felipekde@gmail.com>
Signed-off-by: Felipe Oliveira Carvalho <felipekde@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[C++] Inform caller of Azure Storage container not-existing when checking for HNS support

4 participants

@felipecrv@Tom-Newton@kou@pitrou