proxygen
FilePersistentCache-inl.h
Go to the documentation of this file.
1 /*
2  * Copyright 2017-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #pragma once
17 
18 
19 #include <folly/FileUtil.h>
21 #include <folly/json.h>
22 
23 namespace wangle {
24 
25 template<typename K, typename V>
26 class FilePersistenceLayer : public CachePersistence<K, V> {
27  public:
28  explicit FilePersistenceLayer(const std::string& file) : file_(file) {}
29  ~FilePersistenceLayer() override {}
30 
31  bool persist(const folly::dynamic& arrayOfKvPairs) noexcept override;
32 
33  folly::Optional<folly::dynamic> load() noexcept override;
34 
35  void clear() override;
36 
37  private:
39 };
40 
41 template<typename K, typename V>
43  const folly::dynamic& dynObj) noexcept {
44  std::string serializedCache;
45  try {
47  opts.allow_non_string_keys = true;
48  serializedCache = folly::json::serialize(dynObj, opts);
49  } catch (const std::exception& err) {
50  LOG(ERROR) << "Serializing to JSON failed with error: " << err.what();
51  return false;
52  }
53  bool persisted = false;
54  const auto fd = folly::openNoInt(
55  file_.c_str(),
56  O_WRONLY | O_CREAT | O_TRUNC,
57  S_IRUSR | S_IWUSR
58  );
59  if (fd == -1) {
60  return false;
61  }
62  const auto nWritten = folly::writeFull(
63  fd,
64  serializedCache.data(),
65  serializedCache.size()
66  );
67  persisted = nWritten >= 0 &&
68  (static_cast<size_t>(nWritten) == serializedCache.size());
69  if (!persisted) {
70  LOG(ERROR) << "Failed to write to " << file_ << ":";
71  if (nWritten == -1) {
72  LOG(ERROR) << "write failed with errno " << errno;
73  }
74  }
75  if (folly::fdatasyncNoInt(fd) != 0) {
76  LOG(ERROR) << "Failed to sync " << file_ << ": errno " << errno;
77  persisted = false;
78  }
79  if (folly::closeNoInt(fd) != 0) {
80  LOG(ERROR) << "Failed to close " << file_ << ": errno " << errno;
81  persisted = false;
82  }
83  return persisted;
84 }
85 
86 template<typename K, typename V>
88  std::string serializedCache;
89  // not being able to read the backing storage means we just
90  // start with an empty cache. Failing to deserialize, or write,
91  // is a real error so we report errors there.
92  if (!folly::readFile(file_.c_str(), serializedCache)) {
93  return folly::none;
94  }
95 
96  try {
98  opts.allow_non_string_keys = true;
99  return folly::parseJson(serializedCache, opts);
100  } catch (const std::exception& err) {
101  LOG(ERROR) << "Deserialization of cache file " << file_
102  << " failed with parse error: " << err.what();
103  }
104  return folly::none;
105 }
106 
107 template<typename K, typename V>
109  // This may fail but it's ok
110  ::unlink(file_.c_str());
111 }
112 
113 template <typename K, typename V, typename M>
115  const std::string& file,
116  std::size_t cacheCapacity,
117  std::chrono::seconds syncInterval,
118  int nSyncRetries)
119  : cache_(std::make_shared<LRUPersistentCache<K, V, M>>(
120  cacheCapacity,
121  std::chrono::duration_cast<std::chrono::milliseconds>(syncInterval),
122  nSyncRetries,
123  std::make_unique<FilePersistenceLayer<K, V>>(file))) {}
124 
125 template <typename K, typename V, typename M>
127  std::shared_ptr<folly::Executor> executor,
128  const std::string& file,
129  std::size_t cacheCapacity,
130  std::chrono::seconds syncInterval,
131  int nSyncRetries)
132  : cache_(std::make_shared<LRUPersistentCache<K, V, M>>(
133  std::move(executor),
134  cacheCapacity,
135  std::chrono::duration_cast<std::chrono::milliseconds>(syncInterval),
136  nSyncRetries,
137  std::make_unique<FilePersistenceLayer<K, V>>(file))) {}
138 } // namespace wangle
chrono
Definition: CMakeCache.txt:563
LRUPersistentCache< K, V, M >::Ptr cache_
bool readFile(int fd, Container &out, size_t num_bytes=std::numeric_limits< size_t >::max())
Definition: FileUtil.h:125
dynamic parseJson(StringPiece range)
Definition: json.cpp:900
int closeNoInt(int fd)
Definition: FileUtil.cpp:56
int fdatasyncNoInt(int fd)
Definition: FileUtil.cpp:76
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
STL namespace.
requires E e noexcept(noexcept(s.error(std::move(e))))
PUSHMI_INLINE_VAR constexpr __adl::get_executor_fn executor
FilePersistenceLayer(const std::string &file)
folly::Optional< folly::dynamic > load() noexceptoverride
FilePersistentCache(const std::string &file, std::size_t cacheCapacity, std::chrono::seconds syncInterval=std::chrono::duration_cast< std::chrono::seconds >(client::persistence::DEFAULT_CACHE_SYNC_INTERVAL), int nSyncRetries=client::persistence::DEFAULT_CACHE_SYNC_RETRIES)
ssize_t writeFull(int fd, const void *buf, size_t count)
Definition: FileUtil.cpp:134
std::enable_if<!std::is_array< T >::value, std::unique_ptr< T > >::type make_unique(Args &&...args)
Definition: Memory.h:259
**Optimized Holders **The template hazptr_array< M > provides most of the functionality *of M hazptr_holder s but with faster construction destruction *for M
Definition: Hazptr.h:104
int openNoInt(const char *name, int flags, mode_t mode)
Definition: FileUtil.cpp:36
const char * string
Definition: Conv.cpp:212
bool persist(const folly::dynamic &arrayOfKvPairs) noexceptoverride
std::string serialize(dynamic const &dyn, serialization_opts const &opts)
Definition: json.cpp:621
constexpr None none
Definition: Optional.h:87