| 196 | } |
| 197 | |
| 198 | Status TimezoneDatabase::LoadZoneInfoFromHdfs(const string& hdfs_zone_info_zip, |
| 199 | const string& local_dir) { |
| 200 | DCHECK(!hdfs_zone_info_zip.empty()); |
| 201 | |
| 202 | hdfsFS hdfs_conn, local_conn; |
| 203 | RETURN_IF_ERROR(HdfsFsCache::instance()->GetConnection(hdfs_zone_info_zip, &hdfs_conn)); |
| 204 | RETURN_IF_ERROR(HdfsFsCache::instance()->GetLocalConnection(&local_conn)); |
| 205 | |
| 206 | // Create a temporary directory to copy the timezone db to. The CCTZ interface only |
| 207 | // loads timezone info from a directory. We abort the startup if this initialization |
| 208 | // fails for some reason. |
| 209 | string pathname = JoinPathSegments(local_dir, "impala.tzdb.XXXXXXX"); |
| 210 | |
| 211 | // mkdtemp operates in place, so we need a mutable array. |
| 212 | vector<char> local_path(pathname.c_str(), pathname.c_str() + pathname.size() + 1); |
| 213 | if (mkdtemp(local_path.data()) == nullptr) { |
| 214 | return Status(Substitute("Could not create temporary timezone directory: $0. Check " |
| 215 | "that the directory $1 is writable by the user running Impala.", |
| 216 | local_path.data(), local_dir)); |
| 217 | } |
| 218 | |
| 219 | Status status = CopyHdfsFile(hdfs_conn, hdfs_zone_info_zip, local_conn, |
| 220 | local_path.data()); |
| 221 | if (!status.ok()) { |
| 222 | discard_result(FileSystemUtil::RemovePaths({local_path.data()})); |
| 223 | return status; |
| 224 | } |
| 225 | |
| 226 | // Extract files from the zip archive. |
| 227 | string archive_file = JoinPathSegments(local_path.data(), |
| 228 | GetBaseName(hdfs_zone_info_zip.c_str())); |
| 229 | string destination_dir = JoinPathSegments(local_path.data(), "tzdb"); |
| 230 | |
| 231 | status = ZipUtil::ExtractFiles(archive_file, destination_dir); |
| 232 | if (!status.ok()) { |
| 233 | Status rm_status = FileSystemUtil::RemovePaths({local_path.data()}); |
| 234 | if (!rm_status.ok()) LOG(WARNING) << rm_status.GetDetail(); |
| 235 | return status; |
| 236 | } |
| 237 | |
| 238 | // Find the root directory to load the time-zone db from. |
| 239 | // - If 'destination_dir' contains only one subdirectory, root directory should be set |
| 240 | // to that subdirectory. |
| 241 | // - Otherwise, root directory is 'destination_dir'. |
| 242 | vector<string> entry_names; |
| 243 | status = FileSystemUtil::Directory::GetEntryNames(destination_dir, &entry_names, 2); |
| 244 | if (!status.ok()) { |
| 245 | Status rm_status = FileSystemUtil::RemovePaths({local_path.data()}); |
| 246 | if (!rm_status.ok()) LOG(WARNING) << rm_status.GetDetail(); |
| 247 | return status; |
| 248 | } |
| 249 | |
| 250 | string zone_info_root_dir = destination_dir; |
| 251 | if (entry_names.size() == 1) { |
| 252 | string entry_path = JoinPathSegments(destination_dir, entry_names[0]); |
| 253 | Status is_dir = FileSystemUtil::VerifyIsDirectory(entry_path); |
| 254 | if (is_dir.ok()) zone_info_root_dir = entry_path; |
| 255 | } |
nothing calls this directly
no test coverage detected