|  | #include "file_store_handler_op.h" | 
|  |  | 
|  | // NOLINTNEXTLINE(modernize-deprecated-headers) | 
|  | #include <errno.h> | 
|  | #include <fcntl.h> | 
|  | // NOLINTNEXTLINE(modernize-deprecated-headers) | 
|  | #include <limits.h> | 
|  | // NOLINTNEXTLINE(modernize-deprecated-headers) | 
|  | #include <stdio.h> | 
|  | // NOLINTNEXTLINE(modernize-deprecated-headers) | 
|  | #include <stdlib.h> | 
|  | #include <sys/stat.h> | 
|  |  | 
|  | #include <array> | 
|  | #include <chrono> | 
|  | #include <iostream> | 
|  | #include <thread> | 
|  |  | 
|  | #if defined(_MSC_VER) | 
|  | #include <direct.h> // for _mkdir | 
|  | #endif | 
|  |  | 
|  | #include "c10/util/StringUtil.h" | 
|  |  | 
|  | #include "caffe2/utils/murmur_hash3.h" | 
|  |  | 
|  | namespace caffe2 { | 
|  |  | 
|  | static std::string encodeName(const std::string& name) { | 
|  | // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) | 
|  | std::array<uint64_t, 2> out; | 
|  | MurmurHash3_x64_128(name.data(), name.size(), 0xcafef00d, out.data()); | 
|  |  | 
|  | // Size is 33 to have space for final NUL | 
|  | // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init,cppcoreguidelines-avoid-magic-numbers) | 
|  | std::array<char, 33> buf; | 
|  | for (int i = 0; i < 16; i++) { | 
|  | snprintf(&buf[i * 2], buf.size() - (i * 2), "%02x", ((char*)out.data())[i]); | 
|  | } | 
|  |  | 
|  | // Return everything but the final NUL | 
|  | return std::string(buf.data(), buf.size() - 1); | 
|  | } | 
|  |  | 
|  | FileStoreHandler::FileStoreHandler( | 
|  | const std::string& path, | 
|  | const std::string& prefix) { | 
|  | basePath_ = realPath(path); | 
|  | if (!prefix.empty()) { | 
|  | basePath_ = basePath_ + "/" + encodeName(prefix); | 
|  | } | 
|  | #if defined(_MSC_VER) | 
|  | auto ret = _mkdir(basePath_.c_str()); | 
|  | #else | 
|  | auto ret = mkdir(basePath_.c_str(), 0777); | 
|  | #endif // defined(_MSC_VER) | 
|  | if (ret == -1) { | 
|  | TORCH_CHECK_EQ(errno, EEXIST) << "mkdir: " << strerror(errno); | 
|  | } | 
|  | } | 
|  |  | 
|  | // NOLINTNEXTLINE(modernize-use-equals-default) | 
|  | FileStoreHandler::~FileStoreHandler() {} | 
|  |  | 
|  | std::string FileStoreHandler::realPath(const std::string& path) { | 
|  | #if defined(_MSC_VER) | 
|  | std::array<char, _MAX_PATH> buf; | 
|  | auto ret = _fullpath(buf.data(), path.c_str(), buf.size()); | 
|  | #else | 
|  | // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) | 
|  | std::array<char, PATH_MAX> buf; | 
|  | auto ret = realpath(path.c_str(), buf.data()); | 
|  | #endif | 
|  | TORCH_CHECK_EQ(buf.data(), ret) << "realpath: " << strerror(errno); | 
|  | return std::string(buf.data()); | 
|  | } | 
|  |  | 
|  | std::string FileStoreHandler::tmpPath(const std::string& name) { | 
|  | return basePath_ + "/." + encodeName(name); | 
|  | } | 
|  |  | 
|  | std::string FileStoreHandler::objectPath(const std::string& name) { | 
|  | return basePath_ + "/" + encodeName(name); | 
|  | } | 
|  |  | 
|  | void FileStoreHandler::set(const std::string& name, const std::string& data) { | 
|  | auto tmp = tmpPath(name); | 
|  | auto path = objectPath(name); | 
|  |  | 
|  | { | 
|  | std::ofstream ofs(tmp.c_str(), std::ios::out | std::ios::trunc); | 
|  | if (!ofs.is_open()) { | 
|  | CAFFE_ENFORCE( | 
|  | false, "File cannot be created: ", tmp, " (", ofs.rdstate(), ")"); | 
|  | } | 
|  | ofs << data; | 
|  | } | 
|  |  | 
|  | // Atomically movve result to final location | 
|  | auto rv = rename(tmp.c_str(), path.c_str()); | 
|  | CAFFE_ENFORCE_EQ(rv, 0, "rename: ", strerror(errno)); | 
|  | } | 
|  |  | 
|  | std::string FileStoreHandler::get( | 
|  | const std::string& name, | 
|  | const std::chrono::milliseconds& timeout) { | 
|  | auto path = objectPath(name); | 
|  | std::string result; | 
|  |  | 
|  | // Block until key is set | 
|  | wait({name}, timeout); | 
|  |  | 
|  | std::ifstream ifs(path.c_str(), std::ios::in); | 
|  | if (!ifs) { | 
|  | CAFFE_ENFORCE( | 
|  | false, "File cannot be opened: ", path, " (", ifs.rdstate(), ")"); | 
|  | } | 
|  | ifs.seekg(0, std::ios::end); | 
|  | size_t n = ifs.tellg(); | 
|  | result.resize(n); | 
|  | ifs.seekg(0); | 
|  | ifs.read(&result[0], n); | 
|  | return result; | 
|  | } | 
|  |  | 
|  | int64_t FileStoreHandler::add( | 
|  | const std::string& /* unused */, | 
|  | int64_t /* unused */) { | 
|  | CHECK(false) << "add not implemented for FileStoreHandler"; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int64_t FileStoreHandler::getNumKeys() { | 
|  | CHECK(false) << "getNumKeys not implemented for FileStoreHandler"; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | bool FileStoreHandler::deleteKey(const std::string& /* unused */) { | 
|  | CHECK(false) << "deleteKey not implemented for FileStoreHandler"; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool FileStoreHandler::check(const std::vector<std::string>& names) { | 
|  | std::vector<std::string> paths; | 
|  | for (const auto& name : names) { | 
|  | // NOLINTNEXTLINE(performance-inefficient-vector-operation) | 
|  | paths.push_back(objectPath(name)); | 
|  | } | 
|  |  | 
|  | for (const auto& path : paths) { | 
|  | int fd = open(path.c_str(), O_RDONLY); | 
|  | if (fd == -1) { | 
|  | // Only deal with files that don't exist. | 
|  | // Anything else is a problem. | 
|  | TORCH_CHECK_EQ(errno, ENOENT); | 
|  |  | 
|  | // One of the paths doesn't exist; return early | 
|  | return false; | 
|  | } | 
|  |  | 
|  | close(fd); | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | void FileStoreHandler::wait( | 
|  | const std::vector<std::string>& names, | 
|  | const std::chrono::milliseconds& timeout) { | 
|  | // Not using inotify because it doesn't work on many | 
|  | // shared filesystems (such as NFS). | 
|  | const auto start = std::chrono::steady_clock::now(); | 
|  | while (!check(names)) { | 
|  | const auto elapsed = std::chrono::duration_cast<std::chrono::seconds>( | 
|  | std::chrono::steady_clock::now() - start); | 
|  | if (timeout != kNoTimeout && elapsed > timeout) { | 
|  | STORE_HANDLER_TIMEOUT( | 
|  | "Wait timeout for name(s): ", c10::Join(" ", names)); | 
|  | } | 
|  | /* sleep override */ | 
|  | std::this_thread::sleep_for(std::chrono::milliseconds(10)); | 
|  | } | 
|  | } | 
|  | } // namespace caffe2 |