Skip to content

ARROW-15114: [C++] GcsFileSystem uses metadata for directory markers - #11996

Closed
coryan wants to merge 5 commits into
apache:masterfrom
coryan:ARROW-15114-gcsfs-use-metadata-for-directory-markers
Closed

ARROW-15114: [C++] GcsFileSystem uses metadata for directory markers#11996
coryan wants to merge 5 commits into
apache:masterfrom
coryan:ARROW-15114-gcsfs-use-metadata-for-directory-markers

Conversation

@coryan

Copy link
Copy Markdown
Contributor

No description provided.

@github-actions

Copy link
Copy Markdown

@coryan

Copy link
Copy Markdown
ContributorAuthor

The appveyor failures look unrelated.

@coryan
coryan marked this pull request as ready for review December 20, 2021 15:32
@coryan

Copy link
Copy Markdown
ContributorAuthor

Rebased to resolve conflicts.

@coryan

Copy link
Copy Markdown
ContributorAuthor

The failure on Java JNI / AMD64 Debian 9 Java JNI (Gandiva, Plasma, ORC, Dataset) looks unrelated, please take a look.

@coryan

Copy link
Copy Markdown
ContributorAuthor

Ping

@coryan

Copy link
Copy Markdown
ContributorAuthor

@emkornfield can you take a look?

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
const google::cloud::Status& status) {
using ::google::cloud::StatusCode;
auto canonical = internal::EnsureTrailingSlash(path.full_path);
static bool IsDirectory(gcs::ObjectMetadata const& o) {

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.

Suggested change
staticboolIsDirectory(gcs::ObjectMetadataconst& o) {
staticboolIsDirectory(constgcs::ObjectMetadata& o) {

nit

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.

Fixed

@emkornfieldemkornfield 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.

It seems like there might be a lot more branches add here then tested in the changes, not sure how critical these are if they are covered by the generic file system tests?

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
"arrow/gcsfs", "directory")))
.status();
const auto canonical = internal::RemoveTrailingSlash(name).to_string();
auto object = client_.InsertObject(

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.

nit, I think it would be clearer to spell out type.

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.

Fixed.

if (status.code() == GcsCode::kAlreadyExists) {
break;
if (dir.empty()) {
// We could not find any of the parent directories in the bucket, the last step is

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.

is this consistent with what the s3 connector does. bucket creation seems pretty heavy weight to maybe do it accidentally

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.

Seems like this is what you do for s3 too:

// Create object
if (recursive) {
// Ensure bucket exists
ARROW_ASSIGN_OR_RAISE(bool bucket_exists, impl_->BucketExists(path.bucket));
if (!bucket_exists) {
RETURN_NOT_OK(impl_->CreateBucket(path.bucket));
}

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
if (dir.empty()) {
// We could not find any of the parent directories in the bucket, the last step is
// to find out if the bucket exists, and if necessary, create it
auto b = client_.GetBucketMetadata(bucket);

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.

spelling out type here would be more readable I think.

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.

Done. Come join the almost-always-auto world, it is nice here 😀

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.

its not that it isn't tempting, just not in the style guide used for this project.

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
Status Move(const GcsPath& src, const GcsPath& dest) {
if (src.full_path.empty() || src.object.empty() ||
src.object.back() == internal::kSep) {
if (src == dest) return {};

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.

nit: return Status::OK() is more idiomatic for the code base

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.

Fixed here and elsewhere.

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
if (!info.IsFile()) {
return Status::IOError("Only files can be opened as input streams");
if (info.IsDirectory()) {
return Status::IOError("Cannot open a directory as an input stream");

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.

maybe include the path requested here?

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.

Fixed. I also searched for any other places where I was not returning the affected path with the IOError.

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
Result<std::shared_ptr<io::RandomAccessFile>> GcsFileSystem::OpenInputFile(
const FileInfo& info) {
if (info.IsDirectory()) {
return Status::IOError("Cannot open a directory as an input stream");

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.

same comment above about providing the path?

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.

Fixed too.

@emkornfield

Copy link
Copy Markdown
Contributor

Looks like all failures are unrelated. I'll merge this on Monday if there are no further comments.

@pitroupitrou 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.

My main concern here is: does this reduce interoperability with filesystem "hierarchies" created by other GCS clients?

// To find out if the directory exists we need to perform an additional query.
ARROW_ASSIGN_OR_RAISE(auto directory, GetFileInfo(p));
if (directory.IsDirectory()) return result;
return Status::IOError("No such file or directory '", select.base_dir, "'");

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.

If the error message accurate? If base_dir is an existing file, do we still get this message?

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.

Fixed.

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
if (!status.ok()) {
return status;
}
for (auto d = missing_parents.rbegin(); d != missing_parents.rend(); ++d) {

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.

For the record, is it useful to iterate these in reverse order? Is it to avoid creating a/b if a exists as a file?

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.

Yes. Added a comment to explain that.

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.

Is the comment a bit off? It seems missing_parents is created in reverse depth order (from child to parent), so iterating it in reverse order visits the ancestors first and the descendents last?

[](FileInfo const& info) {
if (!info.IsDirectory()) return info;
return Dir(internal::RemoveTrailingSlash(info.path()).to_string());
});

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.

This is non-trivial enough to be factored out in a separate function, IMHO.

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.

Done.

@coryan

Copy link
Copy Markdown
ContributorAuthor

My main concern here is: does this reduce interoperability with filesystem "hierarchies" created by other GCS clients?

This is how I understand the problem:

  • The Apache/Arrow APIs want to be able to query if a directory "exists", even if empty.
  • That means we need to put some kind of marker in the GCS file system or any query will return kNotFound (even listing)
  • Most tools and libraries using GCS natively do not bother with these markers at all, so whatever we do will need to work when there are no markers (by basically listing all the files prefixed with directory/ whether a marker is found or not).
  • We can use markers using a trailing slash name/, that makes things more similar to the GCS UI.
  • That breaks the generic FS tests, and one may need two RPCs to check if name is a file or a directory.
    • And still get in trouble because something could create name and name/ in GCS (and name// for that matter).
  • Using metadata works for the generic FS tests, requires fewer RPCs, and generally seems to fit the APIs in Apache "better"
    • It makes things less similar to the GCS UI 🤷

That is, both solutions have downsides. If you want things to be more compatible with the GCS UI we can certainly do that. I think the really interesting case is working when there are no markers at all, which we can get to work in both cases.

@pitrou

Copy link
Copy Markdown
Member

I think the really interesting case is working when there are no markers at all, which we can get to work in both cases.

Great, I have no problem with this approach then.

@pitroupitrou 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, thank you @coryan

@ursabot

ursabot commented Jan 11, 2022

Copy link
Copy Markdown

Benchmark runs are scheduled for baseline = aa59d17 and contender = 2164b0b. 2164b0b is a master commit associated with this PR. Results will be available as each benchmark for each run completes.
Conbench compare runs links:
[Finished ⬇️0.0% ⬆️0.0%] ec2-t3-xlarge-us-east-2
[Finished ⬇️0.45% ⬆️0.0%] ursa-i9-9960x
[Failed ⬇️0.04% ⬆️0.09%] ursa-thinkcentre-m75q
Supported benchmarks:
ec2-t3-xlarge-us-east-2: Supported benchmark langs: Python. Runs only benchmarks with cloud = True
ursa-i9-9960x: Supported benchmark langs: Python, R, JavaScript
ursa-thinkcentre-m75q: Supported benchmark langs: C++, Java

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@coryan@emkornfield@pitrou@ursabot
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
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;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
ARROW-15114: [C++] GcsFileSystem uses metadata for directory markers by coryan · Pull Request #11996 · apache/arrow · GitHub
Skip to content

ARROW-15114: [C++] GcsFileSystem uses metadata for directory markers - #11996

Closed
coryan wants to merge 5 commits into
apache:masterfrom
coryan:ARROW-15114-gcsfs-use-metadata-for-directory-markers
Closed

ARROW-15114: [C++] GcsFileSystem uses metadata for directory markers#11996
coryan wants to merge 5 commits into
apache:masterfrom
coryan:ARROW-15114-gcsfs-use-metadata-for-directory-markers

Conversation

@coryan

Copy link
Copy Markdown
Contributor

No description provided.

@github-actions

Copy link
Copy Markdown

@coryan

Copy link
Copy Markdown
ContributorAuthor

The appveyor failures look unrelated.

@coryan
coryan marked this pull request as ready for review December 20, 2021 15:32
@coryan

Copy link
Copy Markdown
ContributorAuthor

Rebased to resolve conflicts.

@coryan

Copy link
Copy Markdown
ContributorAuthor

The failure on Java JNI / AMD64 Debian 9 Java JNI (Gandiva, Plasma, ORC, Dataset) looks unrelated, please take a look.

@coryan

Copy link
Copy Markdown
ContributorAuthor

Ping

@coryan

Copy link
Copy Markdown
ContributorAuthor

@emkornfield can you take a look?

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
const google::cloud::Status& status) {
using ::google::cloud::StatusCode;
auto canonical = internal::EnsureTrailingSlash(path.full_path);
static bool IsDirectory(gcs::ObjectMetadata const& o) {

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.

Suggested change
staticboolIsDirectory(gcs::ObjectMetadataconst& o) {
staticboolIsDirectory(constgcs::ObjectMetadata& o) {

nit

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.

Fixed

@emkornfieldemkornfield 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.

It seems like there might be a lot more branches add here then tested in the changes, not sure how critical these are if they are covered by the generic file system tests?

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
"arrow/gcsfs", "directory")))
.status();
const auto canonical = internal::RemoveTrailingSlash(name).to_string();
auto object = client_.InsertObject(

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.

nit, I think it would be clearer to spell out type.

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.

Fixed.

if (status.code() == GcsCode::kAlreadyExists) {
break;
if (dir.empty()) {
// We could not find any of the parent directories in the bucket, the last step is

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.

is this consistent with what the s3 connector does. bucket creation seems pretty heavy weight to maybe do it accidentally

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.

Seems like this is what you do for s3 too:

// Create object
if (recursive) {
// Ensure bucket exists
ARROW_ASSIGN_OR_RAISE(bool bucket_exists, impl_->BucketExists(path.bucket));
if (!bucket_exists) {
RETURN_NOT_OK(impl_->CreateBucket(path.bucket));
}

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
if (dir.empty()) {
// We could not find any of the parent directories in the bucket, the last step is
// to find out if the bucket exists, and if necessary, create it
auto b = client_.GetBucketMetadata(bucket);

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.

spelling out type here would be more readable I think.

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.

Done. Come join the almost-always-auto world, it is nice here 😀

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.

its not that it isn't tempting, just not in the style guide used for this project.

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
Status Move(const GcsPath& src, const GcsPath& dest) {
if (src.full_path.empty() || src.object.empty() ||
src.object.back() == internal::kSep) {
if (src == dest) return {};

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.

nit: return Status::OK() is more idiomatic for the code base

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.

Fixed here and elsewhere.

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
if (!info.IsFile()) {
return Status::IOError("Only files can be opened as input streams");
if (info.IsDirectory()) {
return Status::IOError("Cannot open a directory as an input stream");

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.

maybe include the path requested here?

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.

Fixed. I also searched for any other places where I was not returning the affected path with the IOError.

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
Result<std::shared_ptr<io::RandomAccessFile>> GcsFileSystem::OpenInputFile(
const FileInfo& info) {
if (info.IsDirectory()) {
return Status::IOError("Cannot open a directory as an input stream");

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.

same comment above about providing the path?

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.

Fixed too.

@emkornfield

Copy link
Copy Markdown
Contributor

Looks like all failures are unrelated. I'll merge this on Monday if there are no further comments.

@pitroupitrou 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.

My main concern here is: does this reduce interoperability with filesystem "hierarchies" created by other GCS clients?

// To find out if the directory exists we need to perform an additional query.
ARROW_ASSIGN_OR_RAISE(auto directory, GetFileInfo(p));
if (directory.IsDirectory()) return result;
return Status::IOError("No such file or directory '", select.base_dir, "'");

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.

If the error message accurate? If base_dir is an existing file, do we still get this message?

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.

Fixed.

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
if (!status.ok()) {
return status;
}
for (auto d = missing_parents.rbegin(); d != missing_parents.rend(); ++d) {

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.

For the record, is it useful to iterate these in reverse order? Is it to avoid creating a/b if a exists as a file?

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.

Yes. Added a comment to explain that.

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.

Is the comment a bit off? It seems missing_parents is created in reverse depth order (from child to parent), so iterating it in reverse order visits the ancestors first and the descendents last?

[](FileInfo const& info) {
if (!info.IsDirectory()) return info;
return Dir(internal::RemoveTrailingSlash(info.path()).to_string());
});

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.

This is non-trivial enough to be factored out in a separate function, IMHO.

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.

Done.

@coryan

Copy link
Copy Markdown
ContributorAuthor

My main concern here is: does this reduce interoperability with filesystem "hierarchies" created by other GCS clients?

This is how I understand the problem:

  • The Apache/Arrow APIs want to be able to query if a directory "exists", even if empty.
  • That means we need to put some kind of marker in the GCS file system or any query will return kNotFound (even listing)
  • Most tools and libraries using GCS natively do not bother with these markers at all, so whatever we do will need to work when there are no markers (by basically listing all the files prefixed with directory/ whether a marker is found or not).
  • We can use markers using a trailing slash name/, that makes things more similar to the GCS UI.
  • That breaks the generic FS tests, and one may need two RPCs to check if name is a file or a directory.
    • And still get in trouble because something could create name and name/ in GCS (and name// for that matter).
  • Using metadata works for the generic FS tests, requires fewer RPCs, and generally seems to fit the APIs in Apache "better"
    • It makes things less similar to the GCS UI 🤷

That is, both solutions have downsides. If you want things to be more compatible with the GCS UI we can certainly do that. I think the really interesting case is working when there are no markers at all, which we can get to work in both cases.

@pitrou

Copy link
Copy Markdown
Member

I think the really interesting case is working when there are no markers at all, which we can get to work in both cases.

Great, I have no problem with this approach then.

@pitroupitrou 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, thank you @coryan

@ursabot

ursabot commented Jan 11, 2022

Copy link
Copy Markdown

Benchmark runs are scheduled for baseline = aa59d17 and contender = 2164b0b. 2164b0b is a master commit associated with this PR. Results will be available as each benchmark for each run completes.
Conbench compare runs links:
[Finished ⬇️0.0% ⬆️0.0%] ec2-t3-xlarge-us-east-2
[Finished ⬇️0.45% ⬆️0.0%] ursa-i9-9960x
[Failed ⬇️0.04% ⬆️0.09%] ursa-thinkcentre-m75q
Supported benchmarks:
ec2-t3-xlarge-us-east-2: Supported benchmark langs: Python. Runs only benchmarks with cloud = True
ursa-i9-9960x: Supported benchmark langs: Python, R, JavaScript
ursa-thinkcentre-m75q: Supported benchmark langs: C++, Java

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@coryan@emkornfield@pitrou@ursabot
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' ARROW-15114: [C++] GcsFileSystem uses metadata for directory markers by coryan · Pull Request #11996 · apache/arrow · GitHub
Skip to content

ARROW-15114: [C++] GcsFileSystem uses metadata for directory markers - #11996

Closed
coryan wants to merge 5 commits into
apache:masterfrom
coryan:ARROW-15114-gcsfs-use-metadata-for-directory-markers
Closed

ARROW-15114: [C++] GcsFileSystem uses metadata for directory markers#11996
coryan wants to merge 5 commits into
apache:masterfrom
coryan:ARROW-15114-gcsfs-use-metadata-for-directory-markers

Conversation

@coryan

Copy link
Copy Markdown
Contributor

No description provided.

@github-actions

Copy link
Copy Markdown

@coryan

Copy link
Copy Markdown
ContributorAuthor

The appveyor failures look unrelated.

@coryan
coryan marked this pull request as ready for review December 20, 2021 15:32
@coryan

Copy link
Copy Markdown
ContributorAuthor

Rebased to resolve conflicts.

@coryan

Copy link
Copy Markdown
ContributorAuthor

The failure on Java JNI / AMD64 Debian 9 Java JNI (Gandiva, Plasma, ORC, Dataset) looks unrelated, please take a look.

@coryan

Copy link
Copy Markdown
ContributorAuthor

Ping

@coryan

Copy link
Copy Markdown
ContributorAuthor

@emkornfield can you take a look?

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
const google::cloud::Status& status) {
using ::google::cloud::StatusCode;
auto canonical = internal::EnsureTrailingSlash(path.full_path);
static bool IsDirectory(gcs::ObjectMetadata const& o) {

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.

Suggested change
staticboolIsDirectory(gcs::ObjectMetadataconst& o) {
staticboolIsDirectory(constgcs::ObjectMetadata& o) {

nit

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.

Fixed

@emkornfieldemkornfield 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.

It seems like there might be a lot more branches add here then tested in the changes, not sure how critical these are if they are covered by the generic file system tests?

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
"arrow/gcsfs", "directory")))
.status();
const auto canonical = internal::RemoveTrailingSlash(name).to_string();
auto object = client_.InsertObject(

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.

nit, I think it would be clearer to spell out type.

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.

Fixed.

if (status.code() == GcsCode::kAlreadyExists) {
break;
if (dir.empty()) {
// We could not find any of the parent directories in the bucket, the last step is

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.

is this consistent with what the s3 connector does. bucket creation seems pretty heavy weight to maybe do it accidentally

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.

Seems like this is what you do for s3 too:

// Create object
if (recursive) {
// Ensure bucket exists
ARROW_ASSIGN_OR_RAISE(bool bucket_exists, impl_->BucketExists(path.bucket));
if (!bucket_exists) {
RETURN_NOT_OK(impl_->CreateBucket(path.bucket));
}

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
if (dir.empty()) {
// We could not find any of the parent directories in the bucket, the last step is
// to find out if the bucket exists, and if necessary, create it
auto b = client_.GetBucketMetadata(bucket);

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.

spelling out type here would be more readable I think.

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.

Done. Come join the almost-always-auto world, it is nice here 😀

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.

its not that it isn't tempting, just not in the style guide used for this project.

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
Status Move(const GcsPath& src, const GcsPath& dest) {
if (src.full_path.empty() || src.object.empty() ||
src.object.back() == internal::kSep) {
if (src == dest) return {};

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.

nit: return Status::OK() is more idiomatic for the code base

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.

Fixed here and elsewhere.

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
if (!info.IsFile()) {
return Status::IOError("Only files can be opened as input streams");
if (info.IsDirectory()) {
return Status::IOError("Cannot open a directory as an input stream");

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.

maybe include the path requested here?

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.

Fixed. I also searched for any other places where I was not returning the affected path with the IOError.

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
Result<std::shared_ptr<io::RandomAccessFile>> GcsFileSystem::OpenInputFile(
const FileInfo& info) {
if (info.IsDirectory()) {
return Status::IOError("Cannot open a directory as an input stream");

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.

same comment above about providing the path?

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.

Fixed too.

@emkornfield

Copy link
Copy Markdown
Contributor

Looks like all failures are unrelated. I'll merge this on Monday if there are no further comments.

@pitroupitrou 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.

My main concern here is: does this reduce interoperability with filesystem "hierarchies" created by other GCS clients?

// To find out if the directory exists we need to perform an additional query.
ARROW_ASSIGN_OR_RAISE(auto directory, GetFileInfo(p));
if (directory.IsDirectory()) return result;
return Status::IOError("No such file or directory '", select.base_dir, "'");

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.

If the error message accurate? If base_dir is an existing file, do we still get this message?

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.

Fixed.

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
if (!status.ok()) {
return status;
}
for (auto d = missing_parents.rbegin(); d != missing_parents.rend(); ++d) {

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.

For the record, is it useful to iterate these in reverse order? Is it to avoid creating a/b if a exists as a file?

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.

Yes. Added a comment to explain that.

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.

Is the comment a bit off? It seems missing_parents is created in reverse depth order (from child to parent), so iterating it in reverse order visits the ancestors first and the descendents last?

[](FileInfo const& info) {
if (!info.IsDirectory()) return info;
return Dir(internal::RemoveTrailingSlash(info.path()).to_string());
});

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.

This is non-trivial enough to be factored out in a separate function, IMHO.

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.

Done.

@coryan

Copy link
Copy Markdown
ContributorAuthor

My main concern here is: does this reduce interoperability with filesystem "hierarchies" created by other GCS clients?

This is how I understand the problem:

  • The Apache/Arrow APIs want to be able to query if a directory "exists", even if empty.
  • That means we need to put some kind of marker in the GCS file system or any query will return kNotFound (even listing)
  • Most tools and libraries using GCS natively do not bother with these markers at all, so whatever we do will need to work when there are no markers (by basically listing all the files prefixed with directory/ whether a marker is found or not).
  • We can use markers using a trailing slash name/, that makes things more similar to the GCS UI.
  • That breaks the generic FS tests, and one may need two RPCs to check if name is a file or a directory.
    • And still get in trouble because something could create name and name/ in GCS (and name// for that matter).
  • Using metadata works for the generic FS tests, requires fewer RPCs, and generally seems to fit the APIs in Apache "better"
    • It makes things less similar to the GCS UI 🤷

That is, both solutions have downsides. If you want things to be more compatible with the GCS UI we can certainly do that. I think the really interesting case is working when there are no markers at all, which we can get to work in both cases.

@pitrou

Copy link
Copy Markdown
Member

I think the really interesting case is working when there are no markers at all, which we can get to work in both cases.

Great, I have no problem with this approach then.

@pitroupitrou 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, thank you @coryan

@ursabot

ursabot commented Jan 11, 2022

Copy link
Copy Markdown

Benchmark runs are scheduled for baseline = aa59d17 and contender = 2164b0b. 2164b0b is a master commit associated with this PR. Results will be available as each benchmark for each run completes.
Conbench compare runs links:
[Finished ⬇️0.0% ⬆️0.0%] ec2-t3-xlarge-us-east-2
[Finished ⬇️0.45% ⬆️0.0%] ursa-i9-9960x
[Failed ⬇️0.04% ⬆️0.09%] ursa-thinkcentre-m75q
Supported benchmarks:
ec2-t3-xlarge-us-east-2: Supported benchmark langs: Python. Runs only benchmarks with cloud = True
ursa-i9-9960x: Supported benchmark langs: Python, R, JavaScript
ursa-thinkcentre-m75q: Supported benchmark langs: C++, Java

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

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

ARROW-15114: [C++] GcsFileSystem uses metadata for directory markers - #11996

Closed
coryan wants to merge 5 commits into
apache:masterfrom
coryan:ARROW-15114-gcsfs-use-metadata-for-directory-markers
Closed

ARROW-15114: [C++] GcsFileSystem uses metadata for directory markers#11996
coryan wants to merge 5 commits into
apache:masterfrom
coryan:ARROW-15114-gcsfs-use-metadata-for-directory-markers

Conversation

@coryan

Copy link
Copy Markdown
Contributor

No description provided.

@github-actions

Copy link
Copy Markdown

@coryan

Copy link
Copy Markdown
ContributorAuthor

The appveyor failures look unrelated.

@coryan
coryan marked this pull request as ready for review December 20, 2021 15:32
@coryan

Copy link
Copy Markdown
ContributorAuthor

Rebased to resolve conflicts.

@coryan

Copy link
Copy Markdown
ContributorAuthor

The failure on Java JNI / AMD64 Debian 9 Java JNI (Gandiva, Plasma, ORC, Dataset) looks unrelated, please take a look.

@coryan

Copy link
Copy Markdown
ContributorAuthor

Ping

@coryan

Copy link
Copy Markdown
ContributorAuthor

@emkornfield can you take a look?

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
const google::cloud::Status& status) {
using ::google::cloud::StatusCode;
auto canonical = internal::EnsureTrailingSlash(path.full_path);
static bool IsDirectory(gcs::ObjectMetadata const& o) {

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.

Suggested change
staticboolIsDirectory(gcs::ObjectMetadataconst& o) {
staticboolIsDirectory(constgcs::ObjectMetadata& o) {

nit

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.

Fixed

@emkornfieldemkornfield 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.

It seems like there might be a lot more branches add here then tested in the changes, not sure how critical these are if they are covered by the generic file system tests?

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
"arrow/gcsfs", "directory")))
.status();
const auto canonical = internal::RemoveTrailingSlash(name).to_string();
auto object = client_.InsertObject(

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.

nit, I think it would be clearer to spell out type.

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.

Fixed.

if (status.code() == GcsCode::kAlreadyExists) {
break;
if (dir.empty()) {
// We could not find any of the parent directories in the bucket, the last step is

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.

is this consistent with what the s3 connector does. bucket creation seems pretty heavy weight to maybe do it accidentally

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.

Seems like this is what you do for s3 too:

// Create object
if (recursive) {
// Ensure bucket exists
ARROW_ASSIGN_OR_RAISE(bool bucket_exists, impl_->BucketExists(path.bucket));
if (!bucket_exists) {
RETURN_NOT_OK(impl_->CreateBucket(path.bucket));
}

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
if (dir.empty()) {
// We could not find any of the parent directories in the bucket, the last step is
// to find out if the bucket exists, and if necessary, create it
auto b = client_.GetBucketMetadata(bucket);

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.

spelling out type here would be more readable I think.

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.

Done. Come join the almost-always-auto world, it is nice here 😀

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.

its not that it isn't tempting, just not in the style guide used for this project.

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
Status Move(const GcsPath& src, const GcsPath& dest) {
if (src.full_path.empty() || src.object.empty() ||
src.object.back() == internal::kSep) {
if (src == dest) return {};

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.

nit: return Status::OK() is more idiomatic for the code base

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.

Fixed here and elsewhere.

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
if (!info.IsFile()) {
return Status::IOError("Only files can be opened as input streams");
if (info.IsDirectory()) {
return Status::IOError("Cannot open a directory as an input stream");

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.

maybe include the path requested here?

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.

Fixed. I also searched for any other places where I was not returning the affected path with the IOError.

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
Result<std::shared_ptr<io::RandomAccessFile>> GcsFileSystem::OpenInputFile(
const FileInfo& info) {
if (info.IsDirectory()) {
return Status::IOError("Cannot open a directory as an input stream");

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.

same comment above about providing the path?

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.

Fixed too.

@emkornfield

Copy link
Copy Markdown
Contributor

Looks like all failures are unrelated. I'll merge this on Monday if there are no further comments.

@pitroupitrou 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.

My main concern here is: does this reduce interoperability with filesystem "hierarchies" created by other GCS clients?

// To find out if the directory exists we need to perform an additional query.
ARROW_ASSIGN_OR_RAISE(auto directory, GetFileInfo(p));
if (directory.IsDirectory()) return result;
return Status::IOError("No such file or directory '", select.base_dir, "'");

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.

If the error message accurate? If base_dir is an existing file, do we still get this message?

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.

Fixed.

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
if (!status.ok()) {
return status;
}
for (auto d = missing_parents.rbegin(); d != missing_parents.rend(); ++d) {

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.

For the record, is it useful to iterate these in reverse order? Is it to avoid creating a/b if a exists as a file?

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.

Yes. Added a comment to explain that.

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.

Is the comment a bit off? It seems missing_parents is created in reverse depth order (from child to parent), so iterating it in reverse order visits the ancestors first and the descendents last?

[](FileInfo const& info) {
if (!info.IsDirectory()) return info;
return Dir(internal::RemoveTrailingSlash(info.path()).to_string());
});

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.

This is non-trivial enough to be factored out in a separate function, IMHO.

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.

Done.

@coryan

Copy link
Copy Markdown
ContributorAuthor

My main concern here is: does this reduce interoperability with filesystem "hierarchies" created by other GCS clients?

This is how I understand the problem:

  • The Apache/Arrow APIs want to be able to query if a directory "exists", even if empty.
  • That means we need to put some kind of marker in the GCS file system or any query will return kNotFound (even listing)
  • Most tools and libraries using GCS natively do not bother with these markers at all, so whatever we do will need to work when there are no markers (by basically listing all the files prefixed with directory/ whether a marker is found or not).
  • We can use markers using a trailing slash name/, that makes things more similar to the GCS UI.
  • That breaks the generic FS tests, and one may need two RPCs to check if name is a file or a directory.
    • And still get in trouble because something could create name and name/ in GCS (and name// for that matter).
  • Using metadata works for the generic FS tests, requires fewer RPCs, and generally seems to fit the APIs in Apache "better"
    • It makes things less similar to the GCS UI 🤷

That is, both solutions have downsides. If you want things to be more compatible with the GCS UI we can certainly do that. I think the really interesting case is working when there are no markers at all, which we can get to work in both cases.

@pitrou

Copy link
Copy Markdown
Member

I think the really interesting case is working when there are no markers at all, which we can get to work in both cases.

Great, I have no problem with this approach then.

@pitroupitrou 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, thank you @coryan

@ursabot

ursabot commented Jan 11, 2022

Copy link
Copy Markdown

Benchmark runs are scheduled for baseline = aa59d17 and contender = 2164b0b. 2164b0b is a master commit associated with this PR. Results will be available as each benchmark for each run completes.
Conbench compare runs links:
[Finished ⬇️0.0% ⬆️0.0%] ec2-t3-xlarge-us-east-2
[Finished ⬇️0.45% ⬆️0.0%] ursa-i9-9960x
[Failed ⬇️0.04% ⬆️0.09%] ursa-thinkcentre-m75q
Supported benchmarks:
ec2-t3-xlarge-us-east-2: Supported benchmark langs: Python. Runs only benchmarks with cloud = True
ursa-i9-9960x: Supported benchmark langs: Python, R, JavaScript
ursa-thinkcentre-m75q: Supported benchmark langs: C++, Java

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

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

ARROW-15114: [C++] GcsFileSystem uses metadata for directory markers - #11996

Closed
coryan wants to merge 5 commits into
apache:masterfrom
coryan:ARROW-15114-gcsfs-use-metadata-for-directory-markers
Closed

ARROW-15114: [C++] GcsFileSystem uses metadata for directory markers#11996
coryan wants to merge 5 commits into
apache:masterfrom
coryan:ARROW-15114-gcsfs-use-metadata-for-directory-markers

Conversation

@coryan

Copy link
Copy Markdown
Contributor

No description provided.

@github-actions

Copy link
Copy Markdown

@coryan

Copy link
Copy Markdown
ContributorAuthor

The appveyor failures look unrelated.

@coryan
coryan marked this pull request as ready for review December 20, 2021 15:32
@coryan

Copy link
Copy Markdown
ContributorAuthor

Rebased to resolve conflicts.

@coryan

Copy link
Copy Markdown
ContributorAuthor

The failure on Java JNI / AMD64 Debian 9 Java JNI (Gandiva, Plasma, ORC, Dataset) looks unrelated, please take a look.

@coryan

Copy link
Copy Markdown
ContributorAuthor

Ping

@coryan

Copy link
Copy Markdown
ContributorAuthor

@emkornfield can you take a look?

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
const google::cloud::Status& status) {
using ::google::cloud::StatusCode;
auto canonical = internal::EnsureTrailingSlash(path.full_path);
static bool IsDirectory(gcs::ObjectMetadata const& o) {

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.

Suggested change
staticboolIsDirectory(gcs::ObjectMetadataconst& o) {
staticboolIsDirectory(constgcs::ObjectMetadata& o) {

nit

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.

Fixed

@emkornfieldemkornfield 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.

It seems like there might be a lot more branches add here then tested in the changes, not sure how critical these are if they are covered by the generic file system tests?

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
"arrow/gcsfs", "directory")))
.status();
const auto canonical = internal::RemoveTrailingSlash(name).to_string();
auto object = client_.InsertObject(

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.

nit, I think it would be clearer to spell out type.

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.

Fixed.

if (status.code() == GcsCode::kAlreadyExists) {
break;
if (dir.empty()) {
// We could not find any of the parent directories in the bucket, the last step is

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.

is this consistent with what the s3 connector does. bucket creation seems pretty heavy weight to maybe do it accidentally

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.

Seems like this is what you do for s3 too:

// Create object
if (recursive) {
// Ensure bucket exists
ARROW_ASSIGN_OR_RAISE(bool bucket_exists, impl_->BucketExists(path.bucket));
if (!bucket_exists) {
RETURN_NOT_OK(impl_->CreateBucket(path.bucket));
}

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
if (dir.empty()) {
// We could not find any of the parent directories in the bucket, the last step is
// to find out if the bucket exists, and if necessary, create it
auto b = client_.GetBucketMetadata(bucket);

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.

spelling out type here would be more readable I think.

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.

Done. Come join the almost-always-auto world, it is nice here 😀

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.

its not that it isn't tempting, just not in the style guide used for this project.

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
Status Move(const GcsPath& src, const GcsPath& dest) {
if (src.full_path.empty() || src.object.empty() ||
src.object.back() == internal::kSep) {
if (src == dest) return {};

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.

nit: return Status::OK() is more idiomatic for the code base

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.

Fixed here and elsewhere.

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
if (!info.IsFile()) {
return Status::IOError("Only files can be opened as input streams");
if (info.IsDirectory()) {
return Status::IOError("Cannot open a directory as an input stream");

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.

maybe include the path requested here?

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.

Fixed. I also searched for any other places where I was not returning the affected path with the IOError.

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
Result<std::shared_ptr<io::RandomAccessFile>> GcsFileSystem::OpenInputFile(
const FileInfo& info) {
if (info.IsDirectory()) {
return Status::IOError("Cannot open a directory as an input stream");

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.

same comment above about providing the path?

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.

Fixed too.

@emkornfield

Copy link
Copy Markdown
Contributor

Looks like all failures are unrelated. I'll merge this on Monday if there are no further comments.

@pitroupitrou 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.

My main concern here is: does this reduce interoperability with filesystem "hierarchies" created by other GCS clients?

// To find out if the directory exists we need to perform an additional query.
ARROW_ASSIGN_OR_RAISE(auto directory, GetFileInfo(p));
if (directory.IsDirectory()) return result;
return Status::IOError("No such file or directory '", select.base_dir, "'");

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.

If the error message accurate? If base_dir is an existing file, do we still get this message?

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.

Fixed.

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
if (!status.ok()) {
return status;
}
for (auto d = missing_parents.rbegin(); d != missing_parents.rend(); ++d) {

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.

For the record, is it useful to iterate these in reverse order? Is it to avoid creating a/b if a exists as a file?

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.

Yes. Added a comment to explain that.

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.

Is the comment a bit off? It seems missing_parents is created in reverse depth order (from child to parent), so iterating it in reverse order visits the ancestors first and the descendents last?

[](FileInfo const& info) {
if (!info.IsDirectory()) return info;
return Dir(internal::RemoveTrailingSlash(info.path()).to_string());
});

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.

This is non-trivial enough to be factored out in a separate function, IMHO.

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.

Done.

@coryan

Copy link
Copy Markdown
ContributorAuthor

My main concern here is: does this reduce interoperability with filesystem "hierarchies" created by other GCS clients?

This is how I understand the problem:

  • The Apache/Arrow APIs want to be able to query if a directory "exists", even if empty.
  • That means we need to put some kind of marker in the GCS file system or any query will return kNotFound (even listing)
  • Most tools and libraries using GCS natively do not bother with these markers at all, so whatever we do will need to work when there are no markers (by basically listing all the files prefixed with directory/ whether a marker is found or not).
  • We can use markers using a trailing slash name/, that makes things more similar to the GCS UI.
  • That breaks the generic FS tests, and one may need two RPCs to check if name is a file or a directory.
    • And still get in trouble because something could create name and name/ in GCS (and name// for that matter).
  • Using metadata works for the generic FS tests, requires fewer RPCs, and generally seems to fit the APIs in Apache "better"
    • It makes things less similar to the GCS UI 🤷

That is, both solutions have downsides. If you want things to be more compatible with the GCS UI we can certainly do that. I think the really interesting case is working when there are no markers at all, which we can get to work in both cases.

@pitrou

Copy link
Copy Markdown
Member

I think the really interesting case is working when there are no markers at all, which we can get to work in both cases.

Great, I have no problem with this approach then.

@pitroupitrou 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, thank you @coryan

@ursabot

ursabot commented Jan 11, 2022

Copy link
Copy Markdown

Benchmark runs are scheduled for baseline = aa59d17 and contender = 2164b0b. 2164b0b is a master commit associated with this PR. Results will be available as each benchmark for each run completes.
Conbench compare runs links:
[Finished ⬇️0.0% ⬆️0.0%] ec2-t3-xlarge-us-east-2
[Finished ⬇️0.45% ⬆️0.0%] ursa-i9-9960x
[Failed ⬇️0.04% ⬆️0.09%] ursa-thinkcentre-m75q
Supported benchmarks:
ec2-t3-xlarge-us-east-2: Supported benchmark langs: Python. Runs only benchmarks with cloud = True
ursa-i9-9960x: Supported benchmark langs: Python, R, JavaScript
ursa-thinkcentre-m75q: Supported benchmark langs: C++, Java

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@coryan@emkornfield@pitrou@ursabot
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' ARROW-15114: [C++] GcsFileSystem uses metadata for directory markers by coryan · Pull Request #11996 · apache/arrow · GitHub
Skip to content

ARROW-15114: [C++] GcsFileSystem uses metadata for directory markers - #11996

Closed
coryan wants to merge 5 commits into
apache:masterfrom
coryan:ARROW-15114-gcsfs-use-metadata-for-directory-markers
Closed

ARROW-15114: [C++] GcsFileSystem uses metadata for directory markers#11996
coryan wants to merge 5 commits into
apache:masterfrom
coryan:ARROW-15114-gcsfs-use-metadata-for-directory-markers

Conversation

@coryan

Copy link
Copy Markdown
Contributor

No description provided.

@github-actions

Copy link
Copy Markdown

@coryan

Copy link
Copy Markdown
ContributorAuthor

The appveyor failures look unrelated.

@coryan
coryan marked this pull request as ready for review December 20, 2021 15:32
@coryan

Copy link
Copy Markdown
ContributorAuthor

Rebased to resolve conflicts.

@coryan

Copy link
Copy Markdown
ContributorAuthor

The failure on Java JNI / AMD64 Debian 9 Java JNI (Gandiva, Plasma, ORC, Dataset) looks unrelated, please take a look.

@coryan

Copy link
Copy Markdown
ContributorAuthor

Ping

@coryan

Copy link
Copy Markdown
ContributorAuthor

@emkornfield can you take a look?

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
const google::cloud::Status& status) {
using ::google::cloud::StatusCode;
auto canonical = internal::EnsureTrailingSlash(path.full_path);
static bool IsDirectory(gcs::ObjectMetadata const& o) {

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.

Suggested change
staticboolIsDirectory(gcs::ObjectMetadataconst& o) {
staticboolIsDirectory(constgcs::ObjectMetadata& o) {

nit

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.

Fixed

@emkornfieldemkornfield 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.

It seems like there might be a lot more branches add here then tested in the changes, not sure how critical these are if they are covered by the generic file system tests?

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
"arrow/gcsfs", "directory")))
.status();
const auto canonical = internal::RemoveTrailingSlash(name).to_string();
auto object = client_.InsertObject(

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.

nit, I think it would be clearer to spell out type.

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.

Fixed.

if (status.code() == GcsCode::kAlreadyExists) {
break;
if (dir.empty()) {
// We could not find any of the parent directories in the bucket, the last step is

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.

is this consistent with what the s3 connector does. bucket creation seems pretty heavy weight to maybe do it accidentally

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.

Seems like this is what you do for s3 too:

// Create object
if (recursive) {
// Ensure bucket exists
ARROW_ASSIGN_OR_RAISE(bool bucket_exists, impl_->BucketExists(path.bucket));
if (!bucket_exists) {
RETURN_NOT_OK(impl_->CreateBucket(path.bucket));
}

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
if (dir.empty()) {
// We could not find any of the parent directories in the bucket, the last step is
// to find out if the bucket exists, and if necessary, create it
auto b = client_.GetBucketMetadata(bucket);

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.

spelling out type here would be more readable I think.

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.

Done. Come join the almost-always-auto world, it is nice here 😀

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.

its not that it isn't tempting, just not in the style guide used for this project.

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
Status Move(const GcsPath& src, const GcsPath& dest) {
if (src.full_path.empty() || src.object.empty() ||
src.object.back() == internal::kSep) {
if (src == dest) return {};

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.

nit: return Status::OK() is more idiomatic for the code base

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.

Fixed here and elsewhere.

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
if (!info.IsFile()) {
return Status::IOError("Only files can be opened as input streams");
if (info.IsDirectory()) {
return Status::IOError("Cannot open a directory as an input stream");

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.

maybe include the path requested here?

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.

Fixed. I also searched for any other places where I was not returning the affected path with the IOError.

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
Result<std::shared_ptr<io::RandomAccessFile>> GcsFileSystem::OpenInputFile(
const FileInfo& info) {
if (info.IsDirectory()) {
return Status::IOError("Cannot open a directory as an input stream");

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.

same comment above about providing the path?

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.

Fixed too.

@emkornfield

Copy link
Copy Markdown
Contributor

Looks like all failures are unrelated. I'll merge this on Monday if there are no further comments.

@pitroupitrou 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.

My main concern here is: does this reduce interoperability with filesystem "hierarchies" created by other GCS clients?

// To find out if the directory exists we need to perform an additional query.
ARROW_ASSIGN_OR_RAISE(auto directory, GetFileInfo(p));
if (directory.IsDirectory()) return result;
return Status::IOError("No such file or directory '", select.base_dir, "'");

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.

If the error message accurate? If base_dir is an existing file, do we still get this message?

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.

Fixed.

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
if (!status.ok()) {
return status;
}
for (auto d = missing_parents.rbegin(); d != missing_parents.rend(); ++d) {

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.

For the record, is it useful to iterate these in reverse order? Is it to avoid creating a/b if a exists as a file?

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.

Yes. Added a comment to explain that.

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.

Is the comment a bit off? It seems missing_parents is created in reverse depth order (from child to parent), so iterating it in reverse order visits the ancestors first and the descendents last?

[](FileInfo const& info) {
if (!info.IsDirectory()) return info;
return Dir(internal::RemoveTrailingSlash(info.path()).to_string());
});

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.

This is non-trivial enough to be factored out in a separate function, IMHO.

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.

Done.

@coryan

Copy link
Copy Markdown
ContributorAuthor

My main concern here is: does this reduce interoperability with filesystem "hierarchies" created by other GCS clients?

This is how I understand the problem:

  • The Apache/Arrow APIs want to be able to query if a directory "exists", even if empty.
  • That means we need to put some kind of marker in the GCS file system or any query will return kNotFound (even listing)
  • Most tools and libraries using GCS natively do not bother with these markers at all, so whatever we do will need to work when there are no markers (by basically listing all the files prefixed with directory/ whether a marker is found or not).
  • We can use markers using a trailing slash name/, that makes things more similar to the GCS UI.
  • That breaks the generic FS tests, and one may need two RPCs to check if name is a file or a directory.
    • And still get in trouble because something could create name and name/ in GCS (and name// for that matter).
  • Using metadata works for the generic FS tests, requires fewer RPCs, and generally seems to fit the APIs in Apache "better"
    • It makes things less similar to the GCS UI 🤷

That is, both solutions have downsides. If you want things to be more compatible with the GCS UI we can certainly do that. I think the really interesting case is working when there are no markers at all, which we can get to work in both cases.

@pitrou

Copy link
Copy Markdown
Member

I think the really interesting case is working when there are no markers at all, which we can get to work in both cases.

Great, I have no problem with this approach then.

@pitroupitrou 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, thank you @coryan

@ursabot

ursabot commented Jan 11, 2022

Copy link
Copy Markdown

Benchmark runs are scheduled for baseline = aa59d17 and contender = 2164b0b. 2164b0b is a master commit associated with this PR. Results will be available as each benchmark for each run completes.
Conbench compare runs links:
[Finished ⬇️0.0% ⬆️0.0%] ec2-t3-xlarge-us-east-2
[Finished ⬇️0.45% ⬆️0.0%] ursa-i9-9960x
[Failed ⬇️0.04% ⬆️0.09%] ursa-thinkcentre-m75q
Supported benchmarks:
ec2-t3-xlarge-us-east-2: Supported benchmark langs: Python. Runs only benchmarks with cloud = True
ursa-i9-9960x: Supported benchmark langs: Python, R, JavaScript
ursa-thinkcentre-m75q: Supported benchmark langs: C++, Java

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@coryan@emkornfield@pitrou@ursabot
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' ARROW-15114: [C++] GcsFileSystem uses metadata for directory markers by coryan · Pull Request #11996 · apache/arrow · GitHub
Skip to content

ARROW-15114: [C++] GcsFileSystem uses metadata for directory markers - #11996

Closed
coryan wants to merge 5 commits into
apache:masterfrom
coryan:ARROW-15114-gcsfs-use-metadata-for-directory-markers
Closed

ARROW-15114: [C++] GcsFileSystem uses metadata for directory markers#11996
coryan wants to merge 5 commits into
apache:masterfrom
coryan:ARROW-15114-gcsfs-use-metadata-for-directory-markers

Conversation

@coryan

Copy link
Copy Markdown
Contributor

No description provided.

@github-actions

Copy link
Copy Markdown

@coryan

Copy link
Copy Markdown
ContributorAuthor

The appveyor failures look unrelated.

@coryan
coryan marked this pull request as ready for review December 20, 2021 15:32
@coryan

Copy link
Copy Markdown
ContributorAuthor

Rebased to resolve conflicts.

@coryan

Copy link
Copy Markdown
ContributorAuthor

The failure on Java JNI / AMD64 Debian 9 Java JNI (Gandiva, Plasma, ORC, Dataset) looks unrelated, please take a look.

@coryan

Copy link
Copy Markdown
ContributorAuthor

Ping

@coryan

Copy link
Copy Markdown
ContributorAuthor

@emkornfield can you take a look?

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
const google::cloud::Status& status) {
using ::google::cloud::StatusCode;
auto canonical = internal::EnsureTrailingSlash(path.full_path);
static bool IsDirectory(gcs::ObjectMetadata const& o) {

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.

Suggested change
staticboolIsDirectory(gcs::ObjectMetadataconst& o) {
staticboolIsDirectory(constgcs::ObjectMetadata& o) {

nit

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.

Fixed

@emkornfieldemkornfield 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.

It seems like there might be a lot more branches add here then tested in the changes, not sure how critical these are if they are covered by the generic file system tests?

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
"arrow/gcsfs", "directory")))
.status();
const auto canonical = internal::RemoveTrailingSlash(name).to_string();
auto object = client_.InsertObject(

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.

nit, I think it would be clearer to spell out type.

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.

Fixed.

if (status.code() == GcsCode::kAlreadyExists) {
break;
if (dir.empty()) {
// We could not find any of the parent directories in the bucket, the last step is

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.

is this consistent with what the s3 connector does. bucket creation seems pretty heavy weight to maybe do it accidentally

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.

Seems like this is what you do for s3 too:

// Create object
if (recursive) {
// Ensure bucket exists
ARROW_ASSIGN_OR_RAISE(bool bucket_exists, impl_->BucketExists(path.bucket));
if (!bucket_exists) {
RETURN_NOT_OK(impl_->CreateBucket(path.bucket));
}

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
if (dir.empty()) {
// We could not find any of the parent directories in the bucket, the last step is
// to find out if the bucket exists, and if necessary, create it
auto b = client_.GetBucketMetadata(bucket);

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.

spelling out type here would be more readable I think.

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.

Done. Come join the almost-always-auto world, it is nice here 😀

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.

its not that it isn't tempting, just not in the style guide used for this project.

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
Status Move(const GcsPath& src, const GcsPath& dest) {
if (src.full_path.empty() || src.object.empty() ||
src.object.back() == internal::kSep) {
if (src == dest) return {};

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.

nit: return Status::OK() is more idiomatic for the code base

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.

Fixed here and elsewhere.

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
if (!info.IsFile()) {
return Status::IOError("Only files can be opened as input streams");
if (info.IsDirectory()) {
return Status::IOError("Cannot open a directory as an input stream");

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.

maybe include the path requested here?

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.

Fixed. I also searched for any other places where I was not returning the affected path with the IOError.

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
Result<std::shared_ptr<io::RandomAccessFile>> GcsFileSystem::OpenInputFile(
const FileInfo& info) {
if (info.IsDirectory()) {
return Status::IOError("Cannot open a directory as an input stream");

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.

same comment above about providing the path?

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.

Fixed too.

@emkornfield

Copy link
Copy Markdown
Contributor

Looks like all failures are unrelated. I'll merge this on Monday if there are no further comments.

@pitroupitrou 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.

My main concern here is: does this reduce interoperability with filesystem "hierarchies" created by other GCS clients?

// To find out if the directory exists we need to perform an additional query.
ARROW_ASSIGN_OR_RAISE(auto directory, GetFileInfo(p));
if (directory.IsDirectory()) return result;
return Status::IOError("No such file or directory '", select.base_dir, "'");

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.

If the error message accurate? If base_dir is an existing file, do we still get this message?

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.

Fixed.

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
if (!status.ok()) {
return status;
}
for (auto d = missing_parents.rbegin(); d != missing_parents.rend(); ++d) {

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.

For the record, is it useful to iterate these in reverse order? Is it to avoid creating a/b if a exists as a file?

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.

Yes. Added a comment to explain that.

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.

Is the comment a bit off? It seems missing_parents is created in reverse depth order (from child to parent), so iterating it in reverse order visits the ancestors first and the descendents last?

[](FileInfo const& info) {
if (!info.IsDirectory()) return info;
return Dir(internal::RemoveTrailingSlash(info.path()).to_string());
});

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.

This is non-trivial enough to be factored out in a separate function, IMHO.

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.

Done.

@coryan

Copy link
Copy Markdown
ContributorAuthor

My main concern here is: does this reduce interoperability with filesystem "hierarchies" created by other GCS clients?

This is how I understand the problem:

  • The Apache/Arrow APIs want to be able to query if a directory "exists", even if empty.
  • That means we need to put some kind of marker in the GCS file system or any query will return kNotFound (even listing)
  • Most tools and libraries using GCS natively do not bother with these markers at all, so whatever we do will need to work when there are no markers (by basically listing all the files prefixed with directory/ whether a marker is found or not).
  • We can use markers using a trailing slash name/, that makes things more similar to the GCS UI.
  • That breaks the generic FS tests, and one may need two RPCs to check if name is a file or a directory.
    • And still get in trouble because something could create name and name/ in GCS (and name// for that matter).
  • Using metadata works for the generic FS tests, requires fewer RPCs, and generally seems to fit the APIs in Apache "better"
    • It makes things less similar to the GCS UI 🤷

That is, both solutions have downsides. If you want things to be more compatible with the GCS UI we can certainly do that. I think the really interesting case is working when there are no markers at all, which we can get to work in both cases.

@pitrou

Copy link
Copy Markdown
Member

I think the really interesting case is working when there are no markers at all, which we can get to work in both cases.

Great, I have no problem with this approach then.

@pitroupitrou 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, thank you @coryan

@ursabot

ursabot commented Jan 11, 2022

Copy link
Copy Markdown

Benchmark runs are scheduled for baseline = aa59d17 and contender = 2164b0b. 2164b0b is a master commit associated with this PR. Results will be available as each benchmark for each run completes.
Conbench compare runs links:
[Finished ⬇️0.0% ⬆️0.0%] ec2-t3-xlarge-us-east-2
[Finished ⬇️0.45% ⬆️0.0%] ursa-i9-9960x
[Failed ⬇️0.04% ⬆️0.09%] ursa-thinkcentre-m75q
Supported benchmarks:
ec2-t3-xlarge-us-east-2: Supported benchmark langs: Python. Runs only benchmarks with cloud = True
ursa-i9-9960x: Supported benchmark langs: Python, R, JavaScript
ursa-thinkcentre-m75q: Supported benchmark langs: C++, Java

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

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

ARROW-15114: [C++] GcsFileSystem uses metadata for directory markers - #11996

Closed
coryan wants to merge 5 commits into
apache:masterfrom
coryan:ARROW-15114-gcsfs-use-metadata-for-directory-markers
Closed

ARROW-15114: [C++] GcsFileSystem uses metadata for directory markers#11996
coryan wants to merge 5 commits into
apache:masterfrom
coryan:ARROW-15114-gcsfs-use-metadata-for-directory-markers

Conversation

@coryan

Copy link
Copy Markdown
Contributor

No description provided.

@github-actions

Copy link
Copy Markdown

@coryan

Copy link
Copy Markdown
ContributorAuthor

The appveyor failures look unrelated.

@coryan
coryan marked this pull request as ready for review December 20, 2021 15:32
@coryan

Copy link
Copy Markdown
ContributorAuthor

Rebased to resolve conflicts.

@coryan

Copy link
Copy Markdown
ContributorAuthor

The failure on Java JNI / AMD64 Debian 9 Java JNI (Gandiva, Plasma, ORC, Dataset) looks unrelated, please take a look.

@coryan

Copy link
Copy Markdown
ContributorAuthor

Ping

@coryan

Copy link
Copy Markdown
ContributorAuthor

@emkornfield can you take a look?

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
const google::cloud::Status& status) {
using ::google::cloud::StatusCode;
auto canonical = internal::EnsureTrailingSlash(path.full_path);
static bool IsDirectory(gcs::ObjectMetadata const& o) {

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.

Suggested change
staticboolIsDirectory(gcs::ObjectMetadataconst& o) {
staticboolIsDirectory(constgcs::ObjectMetadata& o) {

nit

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.

Fixed

@emkornfieldemkornfield 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.

It seems like there might be a lot more branches add here then tested in the changes, not sure how critical these are if they are covered by the generic file system tests?

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
"arrow/gcsfs", "directory")))
.status();
const auto canonical = internal::RemoveTrailingSlash(name).to_string();
auto object = client_.InsertObject(

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.

nit, I think it would be clearer to spell out type.

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.

Fixed.

if (status.code() == GcsCode::kAlreadyExists) {
break;
if (dir.empty()) {
// We could not find any of the parent directories in the bucket, the last step is

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.

is this consistent with what the s3 connector does. bucket creation seems pretty heavy weight to maybe do it accidentally

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.

Seems like this is what you do for s3 too:

// Create object
if (recursive) {
// Ensure bucket exists
ARROW_ASSIGN_OR_RAISE(bool bucket_exists, impl_->BucketExists(path.bucket));
if (!bucket_exists) {
RETURN_NOT_OK(impl_->CreateBucket(path.bucket));
}

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
if (dir.empty()) {
// We could not find any of the parent directories in the bucket, the last step is
// to find out if the bucket exists, and if necessary, create it
auto b = client_.GetBucketMetadata(bucket);

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.

spelling out type here would be more readable I think.

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.

Done. Come join the almost-always-auto world, it is nice here 😀

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.

its not that it isn't tempting, just not in the style guide used for this project.

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
Status Move(const GcsPath& src, const GcsPath& dest) {
if (src.full_path.empty() || src.object.empty() ||
src.object.back() == internal::kSep) {
if (src == dest) return {};

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.

nit: return Status::OK() is more idiomatic for the code base

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.

Fixed here and elsewhere.

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
if (!info.IsFile()) {
return Status::IOError("Only files can be opened as input streams");
if (info.IsDirectory()) {
return Status::IOError("Cannot open a directory as an input stream");

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.

maybe include the path requested here?

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.

Fixed. I also searched for any other places where I was not returning the affected path with the IOError.

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
Result<std::shared_ptr<io::RandomAccessFile>> GcsFileSystem::OpenInputFile(
const FileInfo& info) {
if (info.IsDirectory()) {
return Status::IOError("Cannot open a directory as an input stream");

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.

same comment above about providing the path?

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.

Fixed too.

@emkornfield

Copy link
Copy Markdown
Contributor

Looks like all failures are unrelated. I'll merge this on Monday if there are no further comments.

@pitroupitrou 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.

My main concern here is: does this reduce interoperability with filesystem "hierarchies" created by other GCS clients?

// To find out if the directory exists we need to perform an additional query.
ARROW_ASSIGN_OR_RAISE(auto directory, GetFileInfo(p));
if (directory.IsDirectory()) return result;
return Status::IOError("No such file or directory '", select.base_dir, "'");

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.

If the error message accurate? If base_dir is an existing file, do we still get this message?

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.

Fixed.

Comment threadcpp/src/arrow/filesystem/gcsfs.cc Outdated
if (!status.ok()) {
return status;
}
for (auto d = missing_parents.rbegin(); d != missing_parents.rend(); ++d) {

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.

For the record, is it useful to iterate these in reverse order? Is it to avoid creating a/b if a exists as a file?

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.

Yes. Added a comment to explain that.

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.

Is the comment a bit off? It seems missing_parents is created in reverse depth order (from child to parent), so iterating it in reverse order visits the ancestors first and the descendents last?

[](FileInfo const& info) {
if (!info.IsDirectory()) return info;
return Dir(internal::RemoveTrailingSlash(info.path()).to_string());
});

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.

This is non-trivial enough to be factored out in a separate function, IMHO.

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.

Done.

@coryan

Copy link
Copy Markdown
ContributorAuthor

My main concern here is: does this reduce interoperability with filesystem "hierarchies" created by other GCS clients?

This is how I understand the problem:

  • The Apache/Arrow APIs want to be able to query if a directory "exists", even if empty.
  • That means we need to put some kind of marker in the GCS file system or any query will return kNotFound (even listing)
  • Most tools and libraries using GCS natively do not bother with these markers at all, so whatever we do will need to work when there are no markers (by basically listing all the files prefixed with directory/ whether a marker is found or not).
  • We can use markers using a trailing slash name/, that makes things more similar to the GCS UI.
  • That breaks the generic FS tests, and one may need two RPCs to check if name is a file or a directory.
    • And still get in trouble because something could create name and name/ in GCS (and name// for that matter).
  • Using metadata works for the generic FS tests, requires fewer RPCs, and generally seems to fit the APIs in Apache "better"
    • It makes things less similar to the GCS UI 🤷

That is, both solutions have downsides. If you want things to be more compatible with the GCS UI we can certainly do that. I think the really interesting case is working when there are no markers at all, which we can get to work in both cases.

@pitrou

Copy link
Copy Markdown
Member

I think the really interesting case is working when there are no markers at all, which we can get to work in both cases.

Great, I have no problem with this approach then.

@pitroupitrou 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, thank you @coryan

@ursabot

ursabot commented Jan 11, 2022

Copy link
Copy Markdown

Benchmark runs are scheduled for baseline = aa59d17 and contender = 2164b0b. 2164b0b is a master commit associated with this PR. Results will be available as each benchmark for each run completes.
Conbench compare runs links:
[Finished ⬇️0.0% ⬆️0.0%] ec2-t3-xlarge-us-east-2
[Finished ⬇️0.45% ⬆️0.0%] ursa-i9-9960x
[Failed ⬇️0.04% ⬆️0.09%] ursa-thinkcentre-m75q
Supported benchmarks:
ec2-t3-xlarge-us-east-2: Supported benchmark langs: Python. Runs only benchmarks with cloud = True
ursa-i9-9960x: Supported benchmark langs: Python, R, JavaScript
ursa-thinkcentre-m75q: Supported benchmark langs: C++, Java

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@coryan@emkornfield@pitrou@ursabot