Skip to content

Commit

Permalink
apacheGH-38700: [C++][FS][Azure] Implement DeleteDir()
Browse files Browse the repository at this point in the history
  • Loading branch information
kou committed Nov 20, 2023
1 parent 68ba49d commit 7e25d13
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 1 deletion.
56 changes: 55 additions & 1 deletion cpp/src/arrow/filesystem/azurefs.cc
Original file line number Diff line number Diff line change
Expand Up @@ -724,6 +724,59 @@ class AzureFileSystem::Impl {

return Status::OK();
}

Status DeleteDir(const AzureLocation& location) {
if (location.container.empty()) {
return Status::Invalid("Cannot delete an empty container");
}

if (location.path.empty()) {
auto container_client =
blob_service_client_->GetBlobContainerClient(location.container);
try {
auto response = container_client.Delete();
if (response.Value.Deleted) {
return Status::OK();
} else {
return StatusFromErrorResponse(
container_client.GetUrl(), response.RawResponse.get(),
"Failed to delete a container: " + location.container);
}
} catch (const Azure::Storage::StorageException& exception) {
return internal::ExceptionToStatus(
"Failed to delete a container: " + location.container + ": " +
container_client.GetUrl(),
exception);
}
}

ARROW_ASSIGN_OR_RAISE(auto hierarchical_namespace_enabled,
hierarchical_namespace_.Enabled(location.container));
if (!hierarchical_namespace_enabled) {
// Without hierarchical namespace enabled Azure blob storage has no directories.
// Therefore we can't, and don't need to delete one.
return Status::OK();
}

auto directory_client =
datalake_service_client_->GetFileSystemClient(location.container)
.GetDirectoryClient(location.path);
try {
auto response = directory_client.DeleteRecursive();
if (response.Value.Deleted) {
return Status::OK();
} else {
return StatusFromErrorResponse(directory_client.GetUrl(),
response.RawResponse.get(),
"Failed to delete a directory: " + location.path);
}
} catch (const Azure::Storage::StorageException& exception) {
return internal::ExceptionToStatus(
"Failed to delete a directory: " + location.path + ": " +
directory_client.GetUrl(),
exception);
}
}
};

const AzureOptions& AzureFileSystem::options() const { return impl_->options(); }
Expand Down Expand Up @@ -758,7 +811,8 @@ Status AzureFileSystem::CreateDir(const std::string& path, bool recursive) {
}

Status AzureFileSystem::DeleteDir(const std::string& path) {
return Status::NotImplemented("The Azure FileSystem is not fully implemented");
ARROW_ASSIGN_OR_RAISE(auto location, AzureLocation::FromString(path));
return impl_->DeleteDir(location);
}

Status AzureFileSystem::DeleteDirContents(const std::string& path, bool missing_dir_ok) {
Expand Down
35 changes: 35 additions & 0 deletions cpp/src/arrow/filesystem/azurefs_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,41 @@ TEST_F(AzuriteFileSystemTest, CreateDirUri) {
ASSERT_RAISES(Invalid, fs_->CreateDir("abfs://" + RandomContainerName(), true));
}

TEST_F(AzuriteFileSystemTest, DeleteContainerDirSuccess) {
auto container_name = RandomContainerName();
ASSERT_OK(fs_->CreateDir(container_name));
ASSERT_OK(fs_->DeleteDir(container_name));
}

TEST_F(AzuriteFileSystemTest, DeleteDirSuccess) {
const auto path =
internal::ConcatAbstractPath(PreexistingContainerName(), RandomDirectoryName());
// There is only virtual directory without hierarchical namespace
// support. So the DeleteDir() does nothing.
ASSERT_OK(fs_->DeleteDir(path));
arrow::fs::AssertFileInfo(fs_.get(), path, FileType::NotFound);
}

TEST_F(AzureHierarchicalNamespaceFileSystemTest, DeleteDirSuccess) {
const auto parent =
internal::ConcatAbstractPath(PreexistingContainerName(), RandomDirectoryName());
const auto path = internal::ConcatAbstractPath(parent, "new-sub");
ASSERT_OK(fs_->CreateDir(path, true));
ASSERT_OK(fs_->DeleteDir(parent));
arrow::fs::AssertFileInfo(fs_.get(), path, FileType::NotFound);
arrow::fs::AssertFileInfo(fs_.get(), parent, FileType::NotFound);
}

TEST_F(AzureHierarchicalNamespaceFileSystemTest, DeleteDirFailureNonexistent) {
const auto path =
internal::ConcatAbstractPath(PreexistingContainerName(), RandomDirectoryName());
ASSERT_RAISES(IOError, fs_->DeleteDir(path));
}

TEST_F(AzuriteFileSystemTest, DeleteDirUri) {
ASSERT_RAISES(Invalid, fs_->DeleteDir("abfs://" + PreexistingContainerPath()));
}

TEST_F(AzuriteFileSystemTest, OpenInputStreamString) {
std::shared_ptr<io::InputStream> stream;
ASSERT_OK_AND_ASSIGN(stream, fs_->OpenInputStream(PreexistingObjectPath()));
Expand Down

0 comments on commit 7e25d13

Please sign in to comment.