| 3100 | } |
| 3101 | |
| 3102 | Status MovePathWithDataLakeAPI( |
| 3103 | const DataLake::DataLakeFileSystemClient& src_adlfs_client, |
| 3104 | const AzureLocation& src, const AzureLocation& dest) { |
| 3105 | DCHECK(!src.container.empty() && !src.path.empty()); |
| 3106 | DCHECK(!dest.container.empty() && !dest.path.empty()); |
| 3107 | const auto src_path = std::string{internal::RemoveTrailingSlash(src.path)}; |
| 3108 | const auto dest_path = std::string{internal::RemoveTrailingSlash(dest.path)}; |
| 3109 | |
| 3110 | // Ensure that src exists and, if path has a trailing slash, that it's a directory. |
| 3111 | ARROW_ASSIGN_OR_RAISE(auto src_lease_client, |
| 3112 | AcquireBlobLease(src, kLeaseDuration, /*allow_missing=*/false)); |
| 3113 | LeaseGuard src_lease_guard{std::move(src_lease_client), kLeaseDuration}; |
| 3114 | // It might be necessary to check src is a directory 0-3 times in this function, |
| 3115 | // so we use a lazy evaluation function to avoid redundant calls to GetFileInfo(). |
| 3116 | std::optional<bool> src_is_dir_opt{}; |
| 3117 | auto src_is_dir_lazy = [&]() -> Result<bool> { |
| 3118 | if (src_is_dir_opt.has_value()) { |
| 3119 | return *src_is_dir_opt; |
| 3120 | } |
| 3121 | ARROW_ASSIGN_OR_RAISE( |
| 3122 | auto src_info, GetFileInfo(src_adlfs_client, src, src_lease_guard.LeaseId())); |
| 3123 | src_is_dir_opt = src_info.type() == FileType::Directory; |
| 3124 | return *src_is_dir_opt; |
| 3125 | }; |
| 3126 | // src must be a directory if it has a trailing slash. |
| 3127 | if (internal::HasTrailingSlash(src.path)) { |
| 3128 | ARROW_ASSIGN_OR_RAISE(auto src_is_dir, src_is_dir_lazy()); |
| 3129 | if (!src_is_dir) { |
| 3130 | return NotADir(src); |
| 3131 | } |
| 3132 | } |
| 3133 | // The Azure SDK and the backend don't perform many important checks, so we have to |
| 3134 | // do them ourselves. Additionally, based on many tests on a default-configuration |
| 3135 | // storage account, if the destination is an empty directory, the rename operation |
| 3136 | // will most likely fail due to a timeout. Providing both leases -- to source and |
| 3137 | // destination -- seems to have made things work. |
| 3138 | ARROW_ASSIGN_OR_RAISE(auto dest_lease_client, |
| 3139 | AcquireBlobLease(dest, kLeaseDuration, /*allow_missing=*/true)); |
| 3140 | std::optional<LeaseGuard> dest_lease_guard; |
| 3141 | if (dest_lease_client) { |
| 3142 | dest_lease_guard.emplace(std::move(dest_lease_client), kLeaseDuration); |
| 3143 | // Perform all the checks on dest (and src) before proceeding with the rename. |
| 3144 | auto dest_adlfs_client = GetFileSystemClient(dest.container); |
| 3145 | ARROW_ASSIGN_OR_RAISE(auto dest_info, GetFileInfo(dest_adlfs_client, dest, |
| 3146 | dest_lease_guard->LeaseId())); |
| 3147 | if (dest_info.type() == FileType::Directory) { |
| 3148 | ARROW_ASSIGN_OR_RAISE(auto src_is_dir, src_is_dir_lazy()); |
| 3149 | if (!src_is_dir) { |
| 3150 | // If src is a regular file, complain that dest is a directory |
| 3151 | // like POSIX rename() does. |
| 3152 | return internal::IsADir(dest.all); |
| 3153 | } |
| 3154 | } else { |
| 3155 | if (internal::HasTrailingSlash(dest.path)) { |
| 3156 | return NotADir(dest); |
| 3157 | } |
| 3158 | } |
| 3159 | } else { |
no test coverage detected