proxygen
LRUPersistentCache.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 #include <atomic>
19 #include <chrono>
20 #include <condition_variable>
21 #include <future>
22 #include <map>
23 #include <thread>
24 
25 #include <boost/noncopyable.hpp>
26 #include <folly/Executor.h>
27 #include <folly/dynamic.h>
31 
32 namespace wangle {
33 
38 template<typename K, typename V>
40  public:
42 
43  virtual ~CachePersistence() = default;
44 
50  const folly::dynamic& kvPairs, const CacheDataVersion& version) {
51  auto result = persist(kvPairs);
52  if (result) {
54  }
55  return result;
56  }
57 
62  return persistedVersion_;
63  }
64 
71  }
72 
77  virtual bool persist(const folly::dynamic& kvPairs) noexcept = 0;
78 
83  virtual folly::Optional<folly::dynamic> load() noexcept = 0;
84 
88  virtual void clear() = 0;
89 
90  private:
92 };
93 
94 namespace client {
95 namespace persistence {
96 constexpr std::chrono::milliseconds DEFAULT_CACHE_SYNC_INTERVAL =
97  std::chrono::milliseconds(5000);
98 constexpr int DEFAULT_CACHE_SYNC_RETRIES = 3;
99 } // namespace persistence
100 } // namespace client
101 
118 template <typename K, typename V, typename MutexT = std::mutex>
120  : public PersistentCache<K, V>,
121  public std::enable_shared_from_this<LRUPersistentCache<K, V, MutexT>>,
122  private boost::noncopyable {
123  public:
124  using Ptr = std::shared_ptr<LRUPersistentCache<K, V, MutexT>>;
125 
144  explicit LRUPersistentCache(
145  std::size_t cacheCapacity,
146  std::chrono::milliseconds syncInterval =
149  std::unique_ptr<CachePersistence<K, V>> persistence = nullptr);
150 
152  std::shared_ptr<folly::Executor> executor,
153  std::size_t cacheCapacity,
154  std::chrono::milliseconds syncInterval,
155  int nSyncRetries,
156  std::unique_ptr<CachePersistence<K, V>> persistence);
157 
164  ~LRUPersistentCache() override;
165 
169  bool hasPendingUpdates();
170 
174  folly::Optional<V> get(const K& key) override {
175  return cache_.get(key);
176  }
177 
178  void put(const K& key, const V& val) override;
179 
180  bool remove(const K& key) override {
181  return cache_.remove(key);
182  }
183 
184  void clear(bool clearPersistence = false) override {
185  cache_.clear();
186  if (clearPersistence) {
187  auto persistence = getPersistence();
188  if (persistence) {
189  persistence->clear();
190  }
191  }
192  }
193 
194  size_t size() override {
195  return cache_.size();
196  }
197 
198  void setSyncOnDestroy(bool syncOnDestroy) {
199  syncOnDestroy_ = syncOnDestroy;
200  }
201 
208  void setPersistence(std::unique_ptr<CachePersistence<K, V>> persistence);
209 
210  private:
215  void setPersistenceHelper(
216  std::unique_ptr<CachePersistence<K, V>> persistence,
217  bool syncVersion) noexcept;
218 
231 
236  void sync();
237  void oneShotSync();
238  static void* syncThreadMain(void* arg);
239 
247  bool syncNow(CachePersistence<K, V>& persistence);
248 
253  std::shared_ptr<CachePersistence<K, V>> getPersistence();
254 
255  private:
256  // Our threadsafe in memory cache
258 
259  // used to signal syncer thread
260  bool stopSyncer_{false};
261  // mutex used to synchronize syncer_ on destruction, tied to stopSyncerCV_
263  // condvar used to wakeup syncer on exit
264  std::condition_variable stopSyncerCV_;
265 
266  // We do not schedule the same task more than one to the executor
267  std::atomic_flag executorScheduled_ = ATOMIC_FLAG_INIT;
268 
269  // sync interval in milliseconds
270  const std::chrono::milliseconds syncInterval_{
272  // limit on no. of sync attempts
274  // Sync try count across executor tasks
275  int nSyncTries_{0};
276  std::chrono::steady_clock::time_point lastExecutorScheduleTime_;
277 
278  // Whether or not to do 1 sync before destruction.
279  bool syncOnDestroy_{false};
280 
281  // persistence layer
282  // we use a shared pointer since the syncer thread might be operating on
283  // it when the client decides to set a new one
284  std::shared_ptr<CachePersistence<K, V>> persistence_;
285  // for locking access to persistence set/get
287 
288  // thread for periodic sync
289  std::thread syncer_;
290 
291  // executor for periodic sync.
292  std::shared_ptr<folly::Executor> executor_;
293 };
294 
295 }
296 
std::shared_ptr< CachePersistence< K, V > > persistence_
std::shared_ptr< LRUPersistentCache< K, V, M >> Ptr
std::condition_variable stopSyncerCV_
virtual void clear()=0
uint64_t CacheDataVersion
double val
Definition: String.cpp:273
std::shared_ptr< folly::Executor > executor_
requires E e noexcept(noexcept(s.error(std::move(e))))
PUSHMI_INLINE_VAR constexpr __adl::get_executor_fn executor
std::chrono::steady_clock::time_point lastExecutorScheduleTime_
ProtocolVersion version
virtual void setPersistedVersion(CacheDataVersion version) noexcept
CacheDataVersion persistedVersion_
bool persistVersionedData(const folly::dynamic &kvPairs, const CacheDataVersion &version)
LRUInMemoryCache< K, V, MutexT > cache_
constexpr std::chrono::milliseconds DEFAULT_CACHE_SYNC_INTERVAL
std::mutex mutex
constexpr int DEFAULT_CACHE_SYNC_RETRIES
void clear(bool clearPersistence=false) override
void setSyncOnDestroy(bool syncOnDestroy)
virtual bool persist(const folly::dynamic &kvPairs) noexcept=0
virtual CacheDataVersion getLastPersistedVersion() const
virtual ~CachePersistence()=default
virtual folly::Optional< folly::dynamic > load() noexcept=0