Caffe2 - C++ API
A deep learning, cross platform ML framework
file_store_handler.cc
1 #include "file_store_handler_op.h"
2 
3 #include <errno.h>
4 #include <fcntl.h>
5 #include <limits.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <sys/stat.h>
9 
10 #include <array>
11 #include <chrono>
12 #include <iostream>
13 #include <thread>
14 
15 #if defined(_MSC_VER)
16 #include <direct.h> // for _mkdir
17 #endif
18 
19 #include "c10/util/StringUtil.h"
20 
21 #include "caffe2/utils/murmur_hash3.h"
22 
23 namespace caffe2 {
24 
25 static std::string encodeName(const std::string& name) {
26  std::array<uint64_t, 2> out;
27  MurmurHash3_x64_128(name.data(), name.size(), 0xcafef00d, out.data());
28 
29  // Size is 33 to have space for final NUL
30  std::array<char, 33> buf;
31  for (int i = 0; i < 16; i++) {
32  snprintf(&buf[i * 2], buf.size() - (i * 2), "%02x", ((char*)out.data())[i]);
33  }
34 
35  // Return everything but the final NUL
36  return std::string(buf.data(), buf.size() - 1);
37 }
38 
39 FileStoreHandler::FileStoreHandler(
40  const std::string& path,
41  const std::string& prefix) {
42  basePath_ = realPath(path);
43  if (!prefix.empty()) {
44  basePath_ = basePath_ + "/" + encodeName(prefix);
45  }
46 #if defined(_MSC_VER)
47  auto ret = _mkdir(basePath_.c_str());
48 #else
49  auto ret = mkdir(basePath_.c_str(), 0777);
50 #endif // defined(_MSC_VER)
51  if (ret == -1) {
52  CHECK_EQ(errno, EEXIST) << "mkdir: " << strerror(errno);
53  }
54 }
55 
56 FileStoreHandler::~FileStoreHandler() {}
57 
58 std::string FileStoreHandler::realPath(const std::string& path) {
59 #if defined(_MSC_VER)
60  std::array<char, _MAX_PATH> buf;
61  auto ret = _fullpath(buf.data(), path.c_str(), buf.size());
62 #else
63  std::array<char, PATH_MAX> buf;
64  auto ret = realpath(path.c_str(), buf.data());
65 #endif
66  CHECK_EQ(buf.data(), ret) << "realpath: " << strerror(errno);
67  return std::string(buf.data());
68 }
69 
70 std::string FileStoreHandler::tmpPath(const std::string& name) {
71  return basePath_ + "/." + encodeName(name);
72 }
73 
74 std::string FileStoreHandler::objectPath(const std::string& name) {
75  return basePath_ + "/" + encodeName(name);
76 }
77 
78 void FileStoreHandler::set(const std::string& name, const std::string& data) {
79  auto tmp = tmpPath(name);
80  auto path = objectPath(name);
81 
82  {
83  std::ofstream ofs(tmp.c_str(), std::ios::out | std::ios::trunc);
84  if (!ofs.is_open()) {
85  CAFFE_ENFORCE(
86  false, "File cannot be created: ", tmp, " (", ofs.rdstate(), ")");
87  }
88  ofs << data;
89  }
90 
91  // Atomically movve result to final location
92  auto rv = rename(tmp.c_str(), path.c_str());
93  CAFFE_ENFORCE_EQ(rv, 0, "rename: ", strerror(errno));
94 }
95 
96 std::string FileStoreHandler::get(
97  const std::string& name,
98  const std::chrono::milliseconds& timeout) {
99  auto path = objectPath(name);
100  std::string result;
101 
102  // Block until key is set
103  wait({name}, timeout);
104 
105  std::ifstream ifs(path.c_str(), std::ios::in);
106  if (!ifs) {
107  CAFFE_ENFORCE(
108  false, "File cannot be opened: ", path, " (", ifs.rdstate(), ")");
109  }
110  ifs.seekg(0, std::ios::end);
111  size_t n = ifs.tellg();
112  result.resize(n);
113  ifs.seekg(0);
114  ifs.read(&result[0], n);
115  return result;
116 }
117 
118 int64_t FileStoreHandler::add(
119  const std::string& /* unused */,
120  int64_t /* unused */) {
121  CHECK(false) << "add not implemented for FileStoreHandler";
122  return 0;
123 }
124 
125 bool FileStoreHandler::check(const std::vector<std::string>& names) {
126  std::vector<std::string> paths;
127  for (const auto& name : names) {
128  paths.push_back(objectPath(name));
129  }
130 
131  for (const auto& path : paths) {
132  int fd = open(path.c_str(), O_RDONLY);
133  if (fd == -1) {
134  // Only deal with files that don't exist.
135  // Anything else is a problem.
136  CHECK_EQ(errno, ENOENT);
137 
138  // One of the paths doesn't exist; return early
139  return false;
140  }
141 
142  close(fd);
143  }
144 
145  return true;
146 }
147 
148 void FileStoreHandler::wait(
149  const std::vector<std::string>& names,
150  const std::chrono::milliseconds& timeout) {
151  // Not using inotify because it doesn't work on many
152  // shared filesystems (such as NFS).
153  const auto start = std::chrono::steady_clock::now();
154  while (!check(names)) {
155  const auto elapsed = std::chrono::duration_cast<std::chrono::seconds>(
156  std::chrono::steady_clock::now() - start);
157  if (timeout != kNoTimeout && elapsed > timeout) {
158  STORE_HANDLER_TIMEOUT(
159  "Wait timeout for name(s): ", c10::Join(" ", names));
160  }
161  /* sleep override */
162  std::this_thread::sleep_for(std::chrono::milliseconds(10));
163  }
164 }
165 }
A global dictionary that holds information about what Caffe2 modules have been loaded in the current ...
Definition: blob.h:13