persistent-cache-cpp
persistent_cache.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2015 Canonical Ltd.
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License version 3 as
6  * published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU Lesser General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this program. If not, see <http://www.gnu.org/licenses/>.
15  *
16  * Authored by: Michi Henning <michi.henning@canonical.com>
17  */
18 
19 #pragma once
20 
21 #include <core/cache_codec.h>
23 
24 namespace core
25 {
26 
117 template <typename K, typename V, typename M = std::string>
119 {
120 public:
124  typedef std::unique_ptr<PersistentCache<K, V, M>> UPtr;
125 
129  struct Data
130  {
134  V value;
135 
141  };
142 
146  //{@
147 
159 
161 
165  //{@
166  PersistentCache(PersistentCache const&) = delete;
167  PersistentCache& operator=(PersistentCache const&) = delete;
168 
169  PersistentCache(PersistentCache&&) = default;
172 
179  ~PersistentCache() = default;
180 
184  //{@
185 
189  static UPtr open(std::string const& cache_path, int64_t max_size_in_bytes, CacheDiscardPolicy policy);
190 
194  static UPtr open(std::string const& cache_path);
195 
197 
201  //{@
202 
206  OptionalValue get(K const& key) const;
207 
211  OptionalData get_data(K const& key) const;
212 
216  OptionalMetadata get_metadata(K const& key) const;
217 
221  bool contains_key(K const& key) const;
222 
226  int64_t size() const noexcept;
227 
231  int64_t size_in_bytes() const noexcept;
232 
236  int64_t max_size_in_bytes() const noexcept;
237 
241  int64_t disk_size_in_bytes() const;
242 
246  CacheDiscardPolicy discard_policy() const noexcept;
247 
251  PersistentCacheStats stats() const;
252 
254 
258  //{@
259 
264  bool put(K const& key,
265  V const& value,
266  std::chrono::time_point<std::chrono::system_clock> expiry_time = std::chrono::system_clock::time_point());
267 
272  bool put(K const& key,
273  V const& value,
274  M const& metadata,
275  std::chrono::time_point<std::chrono::system_clock> expiry_time = std::chrono::system_clock::time_point());
276 
280  typedef std::function<void(K const& key, PersistentCache<K, V, M>& cache)> Loader;
281 
285  OptionalValue get_or_put(K const& key, Loader const& load_func);
286 
290  OptionalData get_or_put_data(K const& key, Loader const& load_func);
291 
296  bool put_metadata(K const& key, M const& metadata);
297 
301  OptionalValue take(K const& key);
302 
306  OptionalData take_data(K const& key);
307 
311  bool invalidate(K const& key);
312 
316  void invalidate(std::vector<K> const& keys);
317 
321  template <typename It>
322  void invalidate(It begin, It end);
323 
327  void invalidate(std::initializer_list<K> const& keys);
328 
332  void invalidate();
333 
337  bool touch(
338  K const& key,
339  std::chrono::time_point<std::chrono::system_clock> expiry_time = std::chrono::system_clock::time_point());
340 
344  void clear_stats();
345 
349  void resize(int64_t size_in_bytes);
350 
354  void trim_to(int64_t used_size_in_bytes);
355 
359  void compact();
360 
362 
366  //{@
367 
371  typedef std::function<void(K const& key, CacheEvent ev, PersistentCacheStats const& stats)> EventCallback;
372 
376  void set_handler(CacheEvent events, EventCallback cb);
377 
379 
380 private:
381  // @cond
382  PersistentCache(std::string const& cache_path, int64_t max_size_in_bytes, CacheDiscardPolicy policy);
383  PersistentCache(std::string const& cache_path);
384 
385  std::unique_ptr<PersistentStringCache> p_;
386  // @endcond
387 };
388 
389 // @cond
390 
391 // Method implementations. Out-of-line because, otherwise, things become completely unreadable.
392 
393 template <typename K, typename V, typename M>
394 PersistentCache<K, V, M>::PersistentCache(std::string const& cache_path,
395  int64_t max_size_in_bytes,
396  CacheDiscardPolicy policy)
397  : p_(PersistentStringCache::open(cache_path, max_size_in_bytes, policy))
398 {
399 }
400 
401 template <typename K, typename V, typename M>
402 PersistentCache<K, V, M>::PersistentCache(std::string const& cache_path)
403  : p_(PersistentStringCache::open(cache_path))
404 {
405 }
406 
407 template <typename K, typename V, typename M>
408 typename PersistentCache<K, V, M>::UPtr PersistentCache<K, V, M>::open(std::string const& cache_path,
409  int64_t max_size_in_bytes,
410  CacheDiscardPolicy policy)
411 {
412  return PersistentCache<K, V, M>::UPtr(new PersistentCache<K, V, M>(cache_path, max_size_in_bytes, policy));
413 }
414 
415 template <typename K, typename V, typename M>
416 typename PersistentCache<K, V, M>::UPtr PersistentCache<K, V, M>::open(std::string const& cache_path)
417 {
419 }
420 
421 template <typename K, typename V, typename M>
423 {
424  auto const& svalue = p_->get(CacheCodec<K>::encode(key));
425  return svalue ? OptionalValue(CacheCodec<V>::decode(*svalue)) : OptionalValue();
426 }
427 
428 template <typename K, typename V, typename M>
430 {
431  auto sdata = p_->get_data(CacheCodec<K>::encode(key));
432  if (!sdata)
433  {
434  return OptionalData();
435  }
436  return OptionalData({CacheCodec<V>::decode(sdata->value), CacheCodec<M>::decode(sdata->metadata)});
437 }
438 
439 template <typename K, typename V, typename M>
441 {
442  auto smeta = p_->get_metadata(CacheCodec<K>::encode(key));
443  return smeta ? OptionalMetadata(CacheCodec<M>::decode(*smeta)) : OptionalMetadata();
444 }
445 
446 template <typename K, typename V, typename M>
447 bool PersistentCache<K, V, M>::contains_key(K const& key) const
448 {
449  return p_->contains_key(CacheCodec<K>::encode(key));
450 }
451 
452 template <typename K, typename V, typename M>
453 int64_t PersistentCache<K, V, M>::size() const noexcept
454 {
455  return p_->size();
456 }
457 
458 template <typename K, typename V, typename M>
459 int64_t PersistentCache<K, V, M>::size_in_bytes() const noexcept
460 {
461  return p_->size_in_bytes();
462 }
463 
464 template <typename K, typename V, typename M>
465 int64_t PersistentCache<K, V, M>::max_size_in_bytes() const noexcept
466 {
467  return p_->max_size_in_bytes();
468 }
469 
470 template <typename K, typename V, typename M>
472 {
473  return p_->disk_size_in_bytes();
474 }
475 
476 template <typename K, typename V, typename M>
478 {
479  return p_->discard_policy();
480 }
481 
482 template <typename K, typename V, typename M>
484 {
485  return p_->stats();
486 }
487 
488 template <typename K, typename V, typename M>
489 bool PersistentCache<K, V, M>::put(K const& key,
490  V const& value,
491  std::chrono::time_point<std::chrono::system_clock> expiry_time)
492 {
493  return p_->put(CacheCodec<K>::encode(key), CacheCodec<V>::encode(value), expiry_time);
494 }
495 
496 template <typename K, typename V, typename M>
497 bool PersistentCache<K, V, M>::put(K const& key,
498  V const& value,
499  M const& metadata,
500  std::chrono::time_point<std::chrono::system_clock> expiry_time)
501 {
502  return p_->put(CacheCodec<K>::encode(key), CacheCodec<V>::encode(value), CacheCodec<M>::encode(metadata),
503  expiry_time);
504 }
505 
506 template <typename K, typename V, typename M>
508  K const& key, PersistentCache<K, V, M>::Loader const& load_func)
509 {
510  std::string const& skey = CacheCodec<K>::encode(key);
511  auto sload_func = [&](std::string const&, PersistentStringCache const&)
512  {
513  load_func(key, *this);
514  };
515  auto svalue = p_->get_or_put(skey, sload_func);
516  return svalue ? OptionalValue(CacheCodec<V>::decode(*svalue)) : OptionalValue();
517 }
518 
519 template <typename K, typename V, typename M>
521  K const& key, PersistentCache<K, V, M>::Loader const& load_func)
522 {
523  std::string const& skey = CacheCodec<K>::encode(key);
524  auto sload_func = [&](std::string const&, PersistentStringCache const&)
525  {
526  load_func(key, *this);
527  };
528  auto sdata = p_->get_or_put_data(skey, sload_func);
529  if (!sdata)
530  {
531  return OptionalData();
532  }
533  return OptionalData({CacheCodec<V>::decode(sdata->value), CacheCodec<M>::decode(sdata->metadata)});
534 }
535 
536 template <typename K, typename V, typename M>
537 bool PersistentCache<K, V, M>::put_metadata(K const& key, M const& metadata)
538 {
539  return p_->put_metadata(CacheCodec<K>::encode(key), CacheCodec<M>::encode(metadata));
540 }
541 
542 template <typename K, typename V, typename M>
544 {
545  auto svalue = p_->take(CacheCodec<K>::encode(key));
546  return svalue ? OptionalValue(CacheCodec<V>::decode(*svalue)) : OptionalValue();
547 }
548 
549 template <typename K, typename V, typename M>
551 {
552  auto sdata = p_->take_data(CacheCodec<K>::encode(key));
553  if (!sdata)
554  {
555  return OptionalData();
556  }
557  return OptionalData({CacheCodec<V>::decode(sdata->value), CacheCodec<M>::decode(sdata->metadata)});
558 }
559 
560 template <typename K, typename V, typename M>
561 bool PersistentCache<K, V, M>::invalidate(K const& key)
562 {
563  return p_->invalidate(CacheCodec<K>::encode(key));
564 }
565 
566 template <typename K, typename V, typename M>
567 void PersistentCache<K, V, M>::invalidate(std::vector<K> const& keys)
568 {
569  invalidate(keys.begin(), keys.end());
570 }
571 
572 template <typename K, typename V, typename M>
573 template <typename It>
574 void PersistentCache<K, V, M>::invalidate(It begin, It end)
575 {
576  std::vector<std::string> skeys;
577  for (auto&& it = begin; it < end; ++it)
578  {
579  skeys.push_back(CacheCodec<K>::encode(*it));
580  }
581  p_->invalidate(skeys.begin(), skeys.end());
582 }
583 
584 template <typename K, typename V, typename M>
585 void PersistentCache<K, V, M>::invalidate(std::initializer_list<K> const& keys)
586 {
587  invalidate(keys.begin(), keys.end());
588 }
589 
590 template <typename K, typename V, typename M>
592 {
593  p_->invalidate();
594 }
595 
596 template <typename K, typename V, typename M>
597 bool PersistentCache<K, V, M>::touch(K const& key, std::chrono::time_point<std::chrono::system_clock> expiry_time)
598 {
599  return p_->touch(CacheCodec<K>::encode(key), expiry_time);
600 }
601 
602 template <typename K, typename V, typename M>
604 {
605  p_->clear_stats();
606 }
607 
608 template <typename K, typename V, typename M>
610 {
611  p_->resize(size_in_bytes);
612 }
613 
614 template <typename K, typename V, typename M>
615 void PersistentCache<K, V, M>::trim_to(int64_t used_size_in_bytes)
616 {
617  p_->trim_to(used_size_in_bytes);
618 }
619 
620 template <typename K, typename V, typename M>
622 {
623  p_->compact();
624 }
625 
626 template <typename K, typename V, typename M>
628 {
629  auto scb = [cb](std::string const& key, CacheEvent ev, PersistentCacheStats const& c)
630  {
631  cb(CacheCodec<K>::decode(key), ev, c);
632  };
633  p_->set_handler(events, scb);
634 }
635 
636 // Below are specializations for the various combinations of one or more of K, V, and M
637 // being of type std::string. Without this, we would end up calling through a string-to-string
638 // codec, which would force a copy for everything of type string, which is brutally inefficient.
639 //
640 // This is verbose because we must specialize the class template in order to avoid
641 // calling the CacheCodec methods for type string. The combinations that follow are
642 // <s,V,M>, <K,s,M>, <K,V,s>, <s,s,M>, <s,V,s>, <K,s,s>, and <s,s,s>.
643 // The code is identical, except that, where we know that K, V, or M are std::string,
644 // it avoids calling the encode()/decode() methods.
645 
646 // Specialization for K = std::string.
647 
648 template <typename V, typename M>
649 class PersistentCache<std::string, V, M>
650 {
651 public:
652  typedef std::unique_ptr<PersistentCache<std::string, V, M>> UPtr;
653 
655  typedef Optional<V> OptionalValue;
657 
658  struct Data
659  {
660  V value;
661  M metadata;
662  };
664 
665  PersistentCache(PersistentCache const&) = delete;
666  PersistentCache& operator=(PersistentCache const&) = delete;
667 
668  PersistentCache(PersistentCache&&) = default;
670 
671  ~PersistentCache() = default;
672 
673  static UPtr open(std::string const& cache_path, int64_t max_size_in_bytes, CacheDiscardPolicy policy);
674  static UPtr open(std::string const& cache_path);
675 
676  OptionalValue get(std::string const& key) const;
677  OptionalData get_data(std::string const& key) const;
678  OptionalMetadata get_metadata(std::string const& key) const;
679  bool contains_key(std::string const& key) const;
680  int64_t size() const noexcept;
681  int64_t size_in_bytes() const noexcept;
682  int64_t max_size_in_bytes() const noexcept;
683  int64_t disk_size_in_bytes() const;
684  CacheDiscardPolicy discard_policy() const noexcept;
685  PersistentCacheStats stats() const;
686 
687  bool put(std::string const& key,
688  V const& value,
689  std::chrono::time_point<std::chrono::system_clock> expiry_time = std::chrono::system_clock::time_point());
690  bool put(std::string const& key,
691  V const& value,
692  M const& metadata,
693  std::chrono::time_point<std::chrono::system_clock> expiry_time = std::chrono::system_clock::time_point());
694 
695  typedef std::function<void(std::string const& key, PersistentCache<std::string, V, M>& cache)> Loader;
696 
697  OptionalValue get_or_put(std::string const& key, Loader const& load_func);
698  OptionalData get_or_put_data(std::string const& key, Loader const& load_func);
699 
700  bool put_metadata(std::string const& key, M const& metadata);
701  OptionalValue take(std::string const& key);
702  OptionalData take_data(std::string const& key);
703  bool invalidate(std::string const& key);
704  void invalidate(std::vector<std::string> const& keys);
705  template <typename It>
706  void invalidate(It begin, It end);
707  void invalidate(std::initializer_list<std::string> const& keys);
708  void invalidate();
709  bool touch(
710  std::string const& key,
711  std::chrono::time_point<std::chrono::system_clock> expiry_time = std::chrono::system_clock::time_point());
712  void clear_stats();
713  void resize(int64_t size_in_bytes);
714  void trim_to(int64_t used_size_in_bytes);
715  void compact();
716 
717  typedef std::function<void(std::string const& key, CacheEvent ev, PersistentCacheStats const& stats)> EventCallback;
718 
719  void set_handler(CacheEvent events, EventCallback cb);
720 
721 private:
722  PersistentCache(std::string const& cache_path, int64_t max_size_in_bytes, CacheDiscardPolicy policy);
723  PersistentCache(std::string const& cache_path);
724 
725  std::unique_ptr<PersistentStringCache> p_;
726 };
727 
728 template <typename V, typename M>
729 PersistentCache<std::string, V, M>::PersistentCache(std::string const& cache_path,
730  int64_t max_size_in_bytes,
731  CacheDiscardPolicy policy)
732  : p_(PersistentStringCache::open(cache_path, max_size_in_bytes, policy))
733 {
734 }
735 
736 template <typename V, typename M>
737 PersistentCache<std::string, V, M>::PersistentCache(std::string const& cache_path)
738  : p_(PersistentStringCache::open(cache_path))
739 {
740 }
741 
742 template <typename V, typename M>
744  std::string const& cache_path, int64_t max_size_in_bytes, CacheDiscardPolicy policy)
745 {
747  new PersistentCache<std::string, V, M>(cache_path, max_size_in_bytes, policy));
748 }
749 
750 template <typename V, typename M>
752  std::string const& cache_path)
753 {
755 }
756 
757 template <typename V, typename M>
759  std::string const& key) const
760 {
761  auto const& svalue = p_->get(key);
762  return svalue ? OptionalValue(CacheCodec<V>::decode(*svalue)) : OptionalValue();
763 }
764 
765 template <typename V, typename M>
767  std::string const& key) const
768 {
769  auto sdata = p_->get_data(key);
770  if (!sdata)
771  {
772  return OptionalData();
773  }
774  return OptionalData({CacheCodec<V>::decode(sdata->value), CacheCodec<M>::decode(sdata->metadata)});
775 }
776 
777 template <typename V, typename M>
779  std::string const& key) const
780 {
781  auto smeta = p_->get_metadata(key);
782  return smeta ? OptionalMetadata(CacheCodec<M>::decode(*smeta)) : OptionalMetadata();
783 }
784 
785 template <typename V, typename M>
786 bool PersistentCache<std::string, V, M>::contains_key(std::string const& key) const
787 {
788  return p_->contains_key(key);
789 }
790 
791 template <typename V, typename M>
792 int64_t PersistentCache<std::string, V, M>::size() const noexcept
793 {
794  return p_->size();
795 }
796 
797 template <typename V, typename M>
799 {
800  return p_->size_in_bytes();
801 }
802 
803 template <typename V, typename M>
805 {
806  return p_->max_size_in_bytes();
807 }
808 
809 template <typename V, typename M>
811 {
812  return p_->disk_size_in_bytes();
813 }
814 
815 template <typename V, typename M>
817 {
818  return p_->discard_policy();
819 }
820 
821 template <typename V, typename M>
823 {
824  return p_->stats();
825 }
826 
827 template <typename V, typename M>
828 bool PersistentCache<std::string, V, M>::put(std::string const& key,
829  V const& value,
830  std::chrono::time_point<std::chrono::system_clock> expiry_time)
831 {
832  return p_->put(key, CacheCodec<V>::encode(value), expiry_time);
833 }
834 
835 template <typename V, typename M>
836 bool PersistentCache<std::string, V, M>::put(std::string const& key,
837  V const& value,
838  M const& metadata,
839  std::chrono::time_point<std::chrono::system_clock> expiry_time)
840 {
841  return p_->put(key, CacheCodec<V>::encode(value), CacheCodec<M>::encode(metadata), expiry_time);
842 }
843 
844 template <typename V, typename M>
846  std::string const& key, PersistentCache<std::string, V, M>::Loader const& load_func)
847 {
848  auto sload_func = [&](std::string const&, PersistentStringCache const&)
849  {
850  load_func(key, *this);
851  };
852  auto svalue = p_->get_or_put(key, sload_func);
853  return svalue ? OptionalValue(CacheCodec<V>::decode(*svalue)) : OptionalValue();
854 }
855 
856 template <typename V, typename M>
858  std::string const& key, PersistentCache<std::string, V, M>::Loader const& load_func)
859 {
860  auto sload_func = [&](std::string const&, PersistentStringCache const&)
861  {
862  load_func(key, *this);
863  };
864  auto sdata = p_->get_or_put_data(key, sload_func);
865  if (!sdata)
866  {
867  return OptionalData();
868  }
869  return OptionalData({CacheCodec<V>::decode(sdata->value), CacheCodec<M>::decode(sdata->metadata)});
870 }
871 
872 template <typename V, typename M>
873 bool PersistentCache<std::string, V, M>::put_metadata(std::string const& key, M const& metadata)
874 {
875  return p_->put_metadata(key, CacheCodec<M>::encode(metadata));
876 }
877 
878 template <typename V, typename M>
880  std::string const& key)
881 {
882  auto svalue = p_->take(key);
883  return svalue ? OptionalValue(CacheCodec<V>::decode(*svalue)) : OptionalValue();
884 }
885 
886 template <typename V, typename M>
888  std::string const& key)
889 {
890  auto sdata = p_->take_data(key);
891  if (!sdata)
892  {
893  return OptionalData();
894  }
895  return OptionalData({CacheCodec<V>::decode(sdata->value), CacheCodec<M>::decode(sdata->metadata)});
896 }
897 
898 template <typename V, typename M>
899 bool PersistentCache<std::string, V, M>::invalidate(std::string const& key)
900 {
901  return p_->invalidate(key);
902 }
903 
904 template <typename V, typename M>
905 void PersistentCache<std::string, V, M>::invalidate(std::vector<std::string> const& keys)
906 {
907  invalidate(keys.begin(), keys.end());
908 }
909 
910 template <typename V, typename M>
911 template <typename It>
913 {
914  std::vector<std::string> skeys;
915  for (auto&& it = begin; it < end; ++it)
916  {
917  skeys.push_back(*it);
918  }
919  p_->invalidate(skeys.begin(), skeys.end());
920 }
921 
922 template <typename V, typename M>
923 void PersistentCache<std::string, V, M>::invalidate(std::initializer_list<std::string> const& keys)
924 {
925  invalidate(keys.begin(), keys.end());
926 }
927 
928 template <typename V, typename M>
930 {
931  p_->invalidate();
932 }
933 
934 template <typename V, typename M>
935 bool PersistentCache<std::string, V, M>::touch(std::string const& key,
936  std::chrono::time_point<std::chrono::system_clock> expiry_time)
937 {
938  return p_->touch(key, expiry_time);
939 }
940 
941 template <typename V, typename M>
943 {
944  p_->clear_stats();
945 }
946 
947 template <typename V, typename M>
948 void PersistentCache<std::string, V, M>::resize(int64_t size_in_bytes)
949 {
950  p_->resize(size_in_bytes);
951 }
952 
953 template <typename V, typename M>
954 void PersistentCache<std::string, V, M>::trim_to(int64_t used_size_in_bytes)
955 {
956  p_->trim_to(used_size_in_bytes);
957 }
958 
959 template <typename V, typename M>
961 {
962  p_->compact();
963 }
964 
965 template <typename V, typename M>
967 {
968  p_->set_handler(events, cb);
969 }
970 
971 // Specialization for V = std::string.
972 
973 template <typename K, typename M>
974 class PersistentCache<K, std::string, M>
975 {
976 public:
977  typedef std::unique_ptr<PersistentCache<K, std::string, M>> UPtr;
978 
979  typedef Optional<K> OptionalKey;
982 
983  struct Data
984  {
985  std::string value;
986  M metadata;
987  };
989 
990  PersistentCache(PersistentCache const&) = delete;
991  PersistentCache& operator=(PersistentCache const&) = delete;
992 
993  PersistentCache(PersistentCache&&) = default;
995 
996  ~PersistentCache() = default;
997 
998  static UPtr open(std::string const& cache_path, int64_t max_size_in_bytes, CacheDiscardPolicy policy);
999  static UPtr open(std::string const& cache_path);
1000 
1001  OptionalValue get(K const& key) const;
1002  OptionalData get_data(K const& key) const;
1003  OptionalMetadata get_metadata(K const& key) const;
1004  bool contains_key(K const& key) const;
1005  int64_t size() const noexcept;
1006  int64_t size_in_bytes() const noexcept;
1007  int64_t max_size_in_bytes() const noexcept;
1008  int64_t disk_size_in_bytes() const;
1009  CacheDiscardPolicy discard_policy() const noexcept;
1010  PersistentCacheStats stats() const;
1011 
1012  bool put(K const& key,
1013  std::string const& value,
1014  std::chrono::time_point<std::chrono::system_clock> expiry_time = std::chrono::system_clock::time_point());
1015  bool put(K const& key,
1016  char const* value,
1017  int64_t size,
1018  std::chrono::time_point<std::chrono::system_clock> expiry_time = std::chrono::system_clock::time_point());
1019  bool put(K const& key,
1020  std::string const& value,
1021  M const& metadata,
1022  std::chrono::time_point<std::chrono::system_clock> expiry_time = std::chrono::system_clock::time_point());
1023  bool put(K const& key,
1024  char const* value,
1025  int64_t value_size,
1026  M const& metadata,
1027  std::chrono::time_point<std::chrono::system_clock> expiry_time = std::chrono::system_clock::time_point());
1028 
1029  typedef std::function<void(K const& key, PersistentCache<K, std::string, M>& cache)> Loader;
1030 
1031  OptionalValue get_or_put(K const& key, Loader const& load_func);
1032  OptionalData get_or_put_data(K const& key, Loader const& load_func);
1033 
1034  bool put_metadata(K const& key, M const& metadata);
1035  OptionalValue take(K const& key);
1036  OptionalData take_data(K const& key);
1037  bool invalidate(K const& key);
1038  void invalidate(std::vector<K> const& keys);
1039  template <typename It>
1040  void invalidate(It begin, It end);
1041  void invalidate(std::initializer_list<K> const& keys);
1042  void invalidate();
1043  bool touch(
1044  K const& key,
1045  std::chrono::time_point<std::chrono::system_clock> expiry_time = std::chrono::system_clock::time_point());
1046  void clear_stats();
1047  void resize(int64_t size_in_bytes);
1048  void trim_to(int64_t used_size_in_bytes);
1049  void compact();
1050 
1051  typedef std::function<void(K const& key, CacheEvent ev, PersistentCacheStats const& stats)> EventCallback;
1052 
1053  void set_handler(CacheEvent events, EventCallback cb);
1054 
1055 private:
1056  PersistentCache(std::string const& cache_path, int64_t max_size_in_bytes, CacheDiscardPolicy policy);
1057  PersistentCache(std::string const& cache_path);
1058 
1059  std::unique_ptr<PersistentStringCache> p_;
1060 };
1061 
1062 template <typename K, typename M>
1063 PersistentCache<K, std::string, M>::PersistentCache(std::string const& cache_path,
1064  int64_t max_size_in_bytes,
1065  CacheDiscardPolicy policy)
1066  : p_(PersistentStringCache::open(cache_path, max_size_in_bytes, policy))
1067 {
1068 }
1069 
1070 template <typename K, typename M>
1071 PersistentCache<K, std::string, M>::PersistentCache(std::string const& cache_path)
1072  : p_(PersistentStringCache::open(cache_path))
1073 {
1074 }
1075 
1076 template <typename K, typename M>
1078  std::string const& cache_path, int64_t max_size_in_bytes, CacheDiscardPolicy policy)
1079 {
1081  new PersistentCache<K, std::string, M>(cache_path, max_size_in_bytes, policy));
1082 }
1083 
1084 template <typename K, typename M>
1086  std::string const& cache_path)
1087 {
1089 }
1090 
1091 template <typename K, typename M>
1093 {
1094  auto const& svalue = p_->get(CacheCodec<K>::encode(key));
1095  return svalue ? OptionalValue(*svalue) : OptionalValue();
1096 }
1097 
1098 template <typename K, typename M>
1100  K const& key) const
1101 {
1102  auto sdata = p_->get_data(CacheCodec<K>::encode(key));
1103  if (!sdata)
1104  {
1105  return OptionalData();
1106  }
1107  return OptionalData({sdata->value, CacheCodec<M>::decode(sdata->metadata)});
1108 }
1109 
1110 template <typename K, typename M>
1112  K const& key) const
1113 {
1114  auto smeta = p_->get_metadata(CacheCodec<K>::encode(key));
1115  return smeta ? OptionalMetadata(CacheCodec<M>::decode(*smeta)) : OptionalMetadata();
1116 }
1117 
1118 template <typename K, typename M>
1119 bool PersistentCache<K, std::string, M>::contains_key(K const& key) const
1120 {
1121  return p_->contains_key(CacheCodec<K>::encode(key));
1122 }
1123 
1124 template <typename K, typename M>
1125 int64_t PersistentCache<K, std::string, M>::size() const noexcept
1126 {
1127  return p_->size();
1128 }
1129 
1130 template <typename K, typename M>
1132 {
1133  return p_->size_in_bytes();
1134 }
1135 
1136 template <typename K, typename M>
1138 {
1139  return p_->max_size_in_bytes();
1140 }
1141 
1142 template <typename K, typename M>
1144 {
1145  return p_->disk_size_in_bytes();
1146 }
1147 
1148 template <typename K, typename M>
1150 {
1151  return p_->discard_policy();
1152 }
1153 
1154 template <typename K, typename M>
1156 {
1157  return p_->stats();
1158 }
1159 
1160 template <typename K, typename M>
1161 bool PersistentCache<K, std::string, M>::put(K const& key,
1162  std::string const& value,
1163  std::chrono::time_point<std::chrono::system_clock> expiry_time)
1164 {
1165  return p_->put(CacheCodec<K>::encode(key), value, expiry_time);
1166 }
1167 
1168 template <typename K, typename M>
1169 bool PersistentCache<K, std::string, M>::put(K const& key,
1170  char const* value,
1171  int64_t size,
1172  std::chrono::time_point<std::chrono::system_clock> expiry_time)
1173 {
1174  return p_->put(CacheCodec<K>::encode(key), value, size, expiry_time);
1175 }
1176 
1177 template <typename K, typename M>
1178 bool PersistentCache<K, std::string, M>::put(K const& key,
1179  std::string const& value,
1180  M const& metadata,
1181  std::chrono::time_point<std::chrono::system_clock> expiry_time)
1182 {
1183  return p_->put(CacheCodec<K>::encode(key), value, CacheCodec<M>::encode(metadata), expiry_time);
1184 }
1185 
1186 template <typename K, typename M>
1187 bool PersistentCache<K, std::string, M>::put(K const& key,
1188  char const* value,
1189  int64_t size,
1190  M const& metadata,
1191  std::chrono::time_point<std::chrono::system_clock> expiry_time)
1192 {
1193  std::string md = CacheCodec<M>::encode(metadata);
1194  return p_->put(CacheCodec<K>::encode(key), value, size, md.data(), md.size(), expiry_time);
1195 }
1196 
1197 template <typename K, typename M>
1199  K const& key, PersistentCache<K, std::string, M>::Loader const& load_func)
1200 {
1201  std::string const& skey = CacheCodec<K>::encode(key);
1202  auto sload_func = [&](std::string const&, PersistentStringCache const&)
1203  {
1204  load_func(key, *this);
1205  };
1206  auto svalue = p_->get_or_put(skey, sload_func);
1207  return svalue ? OptionalValue(*svalue) : OptionalValue();
1208 }
1209 
1210 template <typename K, typename M>
1212  K const& key, PersistentCache<K, std::string, M>::Loader const& load_func)
1213 {
1214  std::string const& skey = CacheCodec<K>::encode(key);
1215  auto sload_func = [&](std::string const&, PersistentStringCache const&)
1216  {
1217  load_func(key, *this);
1218  };
1219  auto sdata = p_->get_or_put_data(skey, sload_func);
1220  if (!sdata)
1221  {
1222  return OptionalData();
1223  }
1224  return OptionalData({sdata->value, CacheCodec<M>::decode(sdata->metadata)});
1225 }
1226 
1227 template <typename K, typename M>
1228 bool PersistentCache<K, std::string, M>::put_metadata(K const& key, M const& metadata)
1229 {
1230  return p_->put_metadata(CacheCodec<K>::encode(key), CacheCodec<M>::encode(metadata));
1231 }
1232 
1233 template <typename K, typename M>
1235 {
1236  auto svalue = p_->take(CacheCodec<K>::encode(key));
1237  return svalue ? OptionalValue(*svalue) : OptionalValue();
1238 }
1239 
1240 template <typename K, typename M>
1242  K const& key)
1243 {
1244  auto sdata = p_->take_data(CacheCodec<K>::encode(key));
1245  if (!sdata)
1246  {
1247  return OptionalData();
1248  }
1249  return OptionalData({sdata->value, CacheCodec<M>::decode(sdata->metadata)});
1250 }
1251 
1252 template <typename K, typename M>
1254 {
1255  return p_->invalidate(CacheCodec<K>::encode(key));
1256 }
1257 
1258 template <typename K, typename M>
1259 void PersistentCache<K, std::string, M>::invalidate(std::vector<K> const& keys)
1260 {
1261  invalidate(keys.begin(), keys.end());
1262 }
1263 
1264 template <typename K, typename M>
1265 template <typename It>
1267 {
1268  std::vector<std::string> skeys;
1269  for (auto&& it = begin; it < end; ++it)
1270  {
1271  skeys.push_back(CacheCodec<K>::encode(*it));
1272  }
1273  p_->invalidate(skeys.begin(), skeys.end());
1274 }
1275 
1276 template <typename K, typename M>
1277 void PersistentCache<K, std::string, M>::invalidate(std::initializer_list<K> const& keys)
1278 {
1279  invalidate(keys.begin(), keys.end());
1280 }
1281 
1282 template <typename K, typename M>
1284 {
1285  p_->invalidate();
1286 }
1287 
1288 template <typename K, typename M>
1290  std::chrono::time_point<std::chrono::system_clock> expiry_time)
1291 {
1292  return p_->touch(CacheCodec<K>::encode(key), expiry_time);
1293 }
1294 
1295 template <typename K, typename M>
1297 {
1298  p_->clear_stats();
1299 }
1300 
1301 template <typename K, typename M>
1302 void PersistentCache<K, std::string, M>::resize(int64_t size_in_bytes)
1303 {
1304  p_->resize(size_in_bytes);
1305 }
1306 
1307 template <typename K, typename M>
1308 void PersistentCache<K, std::string, M>::trim_to(int64_t used_size_in_bytes)
1309 {
1310  p_->trim_to(used_size_in_bytes);
1311 }
1312 
1313 template <typename K, typename M>
1315 {
1316  p_->compact();
1317 }
1318 
1319 template <typename K, typename M>
1321 {
1322  auto scb = [cb](std::string const& key, CacheEvent ev, PersistentCacheStats const& c)
1323  {
1324  cb(CacheCodec<K>::decode(key), ev, c);
1325  };
1326  p_->set_handler(events, scb);
1327 }
1328 
1329 // Specialization for M = std::string.
1330 
1331 template <typename K, typename V>
1332 class PersistentCache<K, V, std::string>
1333 {
1334 public:
1335  typedef std::unique_ptr<PersistentCache<K, V, std::string>> UPtr;
1336 
1337  typedef Optional<K> OptionalKey;
1338  typedef Optional<V> OptionalValue;
1340 
1341  struct Data
1342  {
1343  V value;
1344  std::string metadata;
1345  };
1346  typedef Optional<Data> OptionalData;
1347 
1348  PersistentCache(PersistentCache const&) = delete;
1349  PersistentCache& operator=(PersistentCache const&) = delete;
1350 
1351  PersistentCache(PersistentCache&&) = default;
1353 
1354  ~PersistentCache() = default;
1355 
1356  static UPtr open(std::string const& cache_path, int64_t max_size_in_bytes, CacheDiscardPolicy policy);
1357  static UPtr open(std::string const& cache_path);
1358 
1359  OptionalValue get(K const& key) const;
1360  OptionalData get_data(K const& key) const;
1361  OptionalMetadata get_metadata(K const& key) const;
1362  bool contains_key(K const& key) const;
1363  int64_t size() const noexcept;
1364  int64_t size_in_bytes() const noexcept;
1365  int64_t max_size_in_bytes() const noexcept;
1366  int64_t disk_size_in_bytes() const;
1367  CacheDiscardPolicy discard_policy() const noexcept;
1368  PersistentCacheStats stats() const;
1369 
1370  bool put(K const& key,
1371  V const& value,
1372  std::chrono::time_point<std::chrono::system_clock> expiry_time = std::chrono::system_clock::time_point());
1373  bool put(K const& key,
1374  V const& value,
1375  std::string const& metadata,
1376  std::chrono::time_point<std::chrono::system_clock> expiry_time = std::chrono::system_clock::time_point());
1377  bool put(K const& key,
1378  V const& value,
1379  char const* metadata,
1380  int64_t size,
1381  std::chrono::time_point<std::chrono::system_clock> expiry_time = std::chrono::system_clock::time_point());
1382 
1383  typedef std::function<void(K const& key, PersistentCache<K, V, std::string>& cache)> Loader;
1384 
1385  OptionalValue get_or_put(K const& key, Loader const& load_func);
1386  OptionalData get_or_put_data(K const& key, Loader const& load_func);
1387 
1388  bool put_metadata(K const& key, std::string const& metadata);
1389  bool put_metadata(K const& key, char const* metadata, int64_t size);
1390  OptionalValue take(K const& key);
1391  OptionalData take_data(K const& key);
1392  bool invalidate(K const& key);
1393  void invalidate(std::vector<K> const& keys);
1394  template <typename It>
1395  void invalidate(It begin, It end);
1396  void invalidate(std::initializer_list<K> const& keys);
1397  void invalidate();
1398  bool touch(
1399  K const& key,
1400  std::chrono::time_point<std::chrono::system_clock> expiry_time = std::chrono::system_clock::time_point());
1401  void clear_stats();
1402  void resize(int64_t size_in_bytes);
1403  void trim_to(int64_t used_size_in_bytes);
1404  void compact();
1405 
1406  typedef std::function<void(K const& key, CacheEvent ev, PersistentCacheStats const& stats)> EventCallback;
1407 
1408  void set_handler(CacheEvent events, EventCallback cb);
1409 
1410 private:
1411  PersistentCache(std::string const& cache_path, int64_t max_size_in_bytes, CacheDiscardPolicy policy);
1412  PersistentCache(std::string const& cache_path);
1413 
1414  std::unique_ptr<PersistentStringCache> p_;
1415 };
1416 
1417 template <typename K, typename V>
1418 PersistentCache<K, V, std::string>::PersistentCache(std::string const& cache_path,
1419  int64_t max_size_in_bytes,
1420  CacheDiscardPolicy policy)
1421  : p_(PersistentStringCache::open(cache_path, max_size_in_bytes, policy))
1422 {
1423 }
1424 
1425 template <typename K, typename V>
1426 PersistentCache<K, V, std::string>::PersistentCache(std::string const& cache_path)
1427  : p_(PersistentStringCache::open(cache_path))
1428 {
1429 }
1430 
1431 template <typename K, typename V>
1433  std::string const& cache_path, int64_t max_size_in_bytes, CacheDiscardPolicy policy)
1434 {
1436  new PersistentCache<K, V, std::string>(cache_path, max_size_in_bytes, policy));
1437 }
1438 
1439 template <typename K, typename V>
1441  std::string const& cache_path)
1442 {
1444 }
1445 
1446 template <typename K, typename V>
1448 {
1449  auto const& svalue = p_->get(CacheCodec<K>::encode(key));
1450  return svalue ? OptionalValue(CacheCodec<V>::decode(*svalue)) : OptionalValue();
1451 }
1452 
1453 template <typename K, typename V>
1455  K const& key) const
1456 {
1457  auto sdata = p_->get_data(CacheCodec<K>::encode(key));
1458  if (!sdata)
1459  {
1460  return OptionalData();
1461  }
1462  return OptionalData({CacheCodec<V>::decode(sdata->value), sdata->metadata});
1463 }
1464 
1465 template <typename K, typename V>
1467  K const& key) const
1468 {
1469  auto smeta = p_->get_metadata(CacheCodec<K>::encode(key));
1470  return smeta ? OptionalMetadata(*smeta) : OptionalMetadata();
1471 }
1472 
1473 template <typename K, typename V>
1474 bool PersistentCache<K, V, std::string>::contains_key(K const& key) const
1475 {
1476  return p_->contains_key(CacheCodec<K>::encode(key));
1477 }
1478 
1479 template <typename K, typename V>
1480 int64_t PersistentCache<K, V, std::string>::size() const noexcept
1481 {
1482  return p_->size();
1483 }
1484 
1485 template <typename K, typename V>
1487 {
1488  return p_->size_in_bytes();
1489 }
1490 
1491 template <typename K, typename V>
1493 {
1494  return p_->max_size_in_bytes();
1495 }
1496 
1497 template <typename K, typename V>
1499 {
1500  return p_->disk_size_in_bytes();
1501 }
1502 
1503 template <typename K, typename V>
1505 {
1506  return p_->discard_policy();
1507 }
1508 
1509 template <typename K, typename V>
1511 {
1512  return p_->stats();
1513 }
1514 
1515 template <typename K, typename V>
1516 bool PersistentCache<K, V, std::string>::put(K const& key,
1517  V const& value,
1518  std::chrono::time_point<std::chrono::system_clock> expiry_time)
1519 {
1520  return p_->put(CacheCodec<K>::encode(key), CacheCodec<V>::encode(value), expiry_time);
1521 }
1522 
1523 template <typename K, typename V>
1524 bool PersistentCache<K, V, std::string>::put(K const& key,
1525  V const& value,
1526  std::string const& metadata,
1527  std::chrono::time_point<std::chrono::system_clock> expiry_time)
1528 {
1529  std::string v = CacheCodec<V>::encode(value);
1530  return p_->put(CacheCodec<K>::encode(key), v.data(), v.size(), metadata.data(), metadata.size(), expiry_time);
1531 }
1532 
1533 template <typename K, typename V>
1534 bool PersistentCache<K, V, std::string>::put(K const& key,
1535  V const& value,
1536  char const* metadata,
1537  int64_t size,
1538  std::chrono::time_point<std::chrono::system_clock> expiry_time)
1539 {
1540  std::string v = CacheCodec<V>::encode(value);
1541  return p_->put(CacheCodec<K>::encode(key), v.data(), v.size(), metadata, size, expiry_time);
1542 }
1543 
1544 template <typename K, typename V>
1546  K const& key, PersistentCache<K, V, std::string>::Loader const& load_func)
1547 {
1548  std::string const& skey = CacheCodec<K>::encode(key);
1549  auto sload_func = [&](std::string const&, PersistentStringCache const&)
1550  {
1551  load_func(key, *this);
1552  };
1553  auto svalue = p_->get_or_put(skey, sload_func);
1554  return svalue ? OptionalValue(CacheCodec<V>::decode(*svalue)) : OptionalValue();
1555 }
1556 
1557 template <typename K, typename V>
1559  K const& key, PersistentCache<K, V, std::string>::Loader const& load_func)
1560 {
1561  std::string const& skey = CacheCodec<K>::encode(key);
1562  auto sload_func = [&](std::string const&, PersistentStringCache const&)
1563  {
1564  load_func(key, *this);
1565  };
1566  auto sdata = p_->get_or_put_data(skey, sload_func);
1567  if (!sdata)
1568  {
1569  return OptionalData();
1570  }
1571  return OptionalData({CacheCodec<V>::decode(sdata->value), sdata->metadata});
1572 }
1573 
1574 template <typename K, typename V>
1575 bool PersistentCache<K, V, std::string>::put_metadata(K const& key, std::string const& metadata)
1576 {
1577  return p_->put_metadata(CacheCodec<K>::encode(key), metadata);
1578 }
1579 
1580 template <typename K, typename V>
1581 bool PersistentCache<K, V, std::string>::put_metadata(K const& key, char const* metadata, int64_t size)
1582 {
1583  return p_->put_metadata(CacheCodec<K>::encode(key), metadata, size);
1584 }
1585 
1586 template <typename K, typename V>
1588 {
1589  auto svalue = p_->take(CacheCodec<K>::encode(key));
1590  return svalue ? OptionalValue(CacheCodec<V>::decode(*svalue)) : OptionalValue();
1591 }
1592 
1593 template <typename K, typename V>
1595  K const& key)
1596 {
1597  auto sdata = p_->take_data(CacheCodec<K>::encode(key));
1598  if (!sdata)
1599  {
1600  return OptionalData();
1601  }
1602  return OptionalData({CacheCodec<V>::decode(sdata->value), sdata->metadata});
1603 }
1604 
1605 template <typename K, typename V>
1607 {
1608  return p_->invalidate(CacheCodec<K>::encode(key));
1609 }
1610 
1611 template <typename K, typename V>
1612 void PersistentCache<K, V, std::string>::invalidate(std::vector<K> const& keys)
1613 {
1614  invalidate(keys.begin(), keys.end());
1615 }
1616 
1617 template <typename K, typename V>
1618 template <typename It>
1620 {
1621  std::vector<std::string> skeys;
1622  for (auto&& it = begin; it < end; ++it)
1623  {
1624  skeys.push_back(CacheCodec<K>::encode(*it));
1625  }
1626  p_->invalidate(skeys.begin(), skeys.end());
1627 }
1628 
1629 template <typename K, typename V>
1630 void PersistentCache<K, V, std::string>::invalidate(std::initializer_list<K> const& keys)
1631 {
1632  invalidate(keys.begin(), keys.end());
1633 }
1634 
1635 template <typename K, typename V>
1637 {
1638  p_->invalidate();
1639 }
1640 
1641 template <typename K, typename V>
1643  std::chrono::time_point<std::chrono::system_clock> expiry_time)
1644 {
1645  return p_->touch(CacheCodec<K>::encode(key), expiry_time);
1646 }
1647 
1648 template <typename K, typename V>
1650 {
1651  p_->clear_stats();
1652 }
1653 
1654 template <typename K, typename V>
1655 void PersistentCache<K, V, std::string>::resize(int64_t size_in_bytes)
1656 {
1657  p_->resize(size_in_bytes);
1658 }
1659 
1660 template <typename K, typename V>
1661 void PersistentCache<K, V, std::string>::trim_to(int64_t used_size_in_bytes)
1662 {
1663  p_->trim_to(used_size_in_bytes);
1664 }
1665 
1666 template <typename K, typename V>
1668 {
1669  p_->compact();
1670 }
1671 
1672 template <typename K, typename V>
1674 {
1675  auto scb = [cb](std::string const& key, CacheEvent ev, PersistentCacheStats const& c)
1676  {
1677  cb(CacheCodec<K>::decode(key), ev, c);
1678  };
1679  p_->set_handler(events, scb);
1680 }
1681 
1682 // Specialization for K and V = std::string.
1683 
1684 template <typename M>
1685 class PersistentCache<std::string, std::string, M>
1686 {
1687 public:
1688  typedef std::unique_ptr<PersistentCache<std::string, std::string, M>> UPtr;
1689 
1692  typedef Optional<M> OptionalMetadata;
1693 
1694  struct Data
1695  {
1696  std::string value;
1697  M metadata;
1698  };
1699  typedef Optional<Data> OptionalData;
1700 
1701  PersistentCache(PersistentCache const&) = delete;
1702  PersistentCache& operator=(PersistentCache const&) = delete;
1703 
1704  PersistentCache(PersistentCache&&) = default;
1706 
1707  ~PersistentCache() = default;
1708 
1709  static UPtr open(std::string const& cache_path, int64_t max_size_in_bytes, CacheDiscardPolicy policy);
1710  static UPtr open(std::string const& cache_path);
1711 
1712  OptionalValue get(std::string const& key) const;
1713  OptionalData get_data(std::string const& key) const;
1714  OptionalMetadata get_metadata(std::string const& key) const;
1715  bool contains_key(std::string const& key) const;
1716  int64_t size() const noexcept;
1717  int64_t size_in_bytes() const noexcept;
1718  int64_t max_size_in_bytes() const noexcept;
1719  int64_t disk_size_in_bytes() const;
1720  CacheDiscardPolicy discard_policy() const noexcept;
1721  PersistentCacheStats stats() const;
1722 
1723  bool put(std::string const& key,
1724  std::string const& value,
1725  std::chrono::time_point<std::chrono::system_clock> expiry_time = std::chrono::system_clock::time_point());
1726  bool put(std::string const& key,
1727  char const* value,
1728  int64_t size,
1729  std::chrono::time_point<std::chrono::system_clock> expiry_time = std::chrono::system_clock::time_point());
1730  bool put(std::string const& key,
1731  std::string const& value,
1732  M const& metadata,
1733  std::chrono::time_point<std::chrono::system_clock> expiry_time = std::chrono::system_clock::time_point());
1734  bool put(std::string const& key,
1735  char const* value,
1736  int64_t value_size,
1737  M const& metadata,
1738  std::chrono::time_point<std::chrono::system_clock> expiry_time = std::chrono::system_clock::time_point());
1739 
1740  typedef std::function<void(std::string const& key, PersistentCache<std::string, std::string, M>& cache)> Loader;
1741 
1742  OptionalValue get_or_put(std::string const& key, Loader const& load_func);
1743  OptionalData get_or_put_data(std::string const& key, Loader const& load_func);
1744 
1745  bool put_metadata(std::string const& key, M const& metadata);
1746  OptionalValue take(std::string const& key);
1747  OptionalData take_data(std::string const& key);
1748  bool invalidate(std::string const& key);
1749  void invalidate(std::vector<std::string> const& keys);
1750  template <typename It>
1751  void invalidate(It begin, It end);
1752  void invalidate(std::initializer_list<std::string> const& keys);
1753  void invalidate();
1754  bool touch(
1755  std::string const& key,
1756  std::chrono::time_point<std::chrono::system_clock> expiry_time = std::chrono::system_clock::time_point());
1757  void clear_stats();
1758  void resize(int64_t size_in_bytes);
1759  void trim_to(int64_t used_size_in_bytes);
1760  void compact();
1761 
1762  typedef std::function<void(std::string const& key, CacheEvent ev, PersistentCacheStats const& stats)> EventCallback;
1763 
1764  void set_handler(CacheEvent events, EventCallback cb);
1765 
1766 private:
1767  PersistentCache(std::string const& cache_path, int64_t max_size_in_bytes, CacheDiscardPolicy policy);
1768  PersistentCache(std::string const& cache_path);
1769 
1770  std::unique_ptr<PersistentStringCache> p_;
1771 };
1772 
1773 template <typename M>
1775  int64_t max_size_in_bytes,
1776  CacheDiscardPolicy policy)
1777  : p_(PersistentStringCache::open(cache_path, max_size_in_bytes, policy))
1778 {
1779 }
1780 
1781 template <typename M>
1783  : p_(PersistentStringCache::open(cache_path))
1784 {
1785 }
1786 
1787 template <typename M>
1789  std::string const& cache_path, int64_t max_size_in_bytes, CacheDiscardPolicy policy)
1790 {
1792  new PersistentCache<std::string, std::string, M>(cache_path, max_size_in_bytes, policy));
1793 }
1794 
1795 template <typename M>
1797  std::string const& cache_path)
1798 {
1801 }
1802 
1803 template <typename M>
1805  std::string const& key) const
1806 {
1807  auto const& svalue = p_->get(key);
1808  return svalue ? OptionalValue(*svalue) : OptionalValue();
1809 }
1810 
1811 template <typename M>
1813  PersistentCache<std::string, std::string, M>::get_data(std::string const& key) const
1814 {
1815  auto sdata = p_->get_data(key);
1816  if (!sdata)
1817  {
1818  return OptionalData();
1819  }
1820  return OptionalData({sdata->value, CacheCodec<M>::decode(sdata->metadata)});
1821 }
1822 
1823 template <typename M>
1826 {
1827  auto smeta = p_->get_metadata(key);
1828  return smeta ? OptionalMetadata(CacheCodec<M>::decode(*smeta)) : OptionalMetadata();
1829 }
1830 
1831 template <typename M>
1832 bool PersistentCache<std::string, std::string, M>::contains_key(std::string const& key) const
1833 {
1834  return p_->contains_key(key);
1835 }
1836 
1837 template <typename M>
1839 {
1840  return p_->size();
1841 }
1842 
1843 template <typename M>
1845 {
1846  return p_->size_in_bytes();
1847 }
1848 
1849 template <typename M>
1851 {
1852  return p_->max_size_in_bytes();
1853 }
1854 
1855 template <typename M>
1857 {
1858  return p_->disk_size_in_bytes();
1859 }
1860 
1861 template <typename M>
1863 {
1864  return p_->discard_policy();
1865 }
1866 
1867 template <typename M>
1869 {
1870  return p_->stats();
1871 }
1872 
1873 template <typename M>
1874 bool PersistentCache<std::string, std::string, M>::put(std::string const& key,
1875  std::string const& value,
1876  std::chrono::time_point<std::chrono::system_clock> expiry_time)
1877 {
1878  return p_->put(key, value, expiry_time);
1879 }
1880 
1881 template <typename M>
1882 bool PersistentCache<std::string, std::string, M>::put(std::string const& key,
1883  char const* value,
1884  int64_t size,
1885  std::chrono::time_point<std::chrono::system_clock> expiry_time)
1886 {
1887  return p_->put(key, value, size, nullptr, 0, expiry_time);
1888 }
1889 
1890 template <typename M>
1891 bool PersistentCache<std::string, std::string, M>::put(std::string const& key,
1892  std::string const& value,
1893  M const& metadata,
1894  std::chrono::time_point<std::chrono::system_clock> expiry_time)
1895 {
1896  return p_->put(key, value, CacheCodec<M>::encode(metadata), expiry_time);
1897 }
1898 
1899 template <typename M>
1900 bool PersistentCache<std::string, std::string, M>::put(std::string const& key,
1901  char const* value,
1902  int64_t size,
1903  M const& metadata,
1904  std::chrono::time_point<std::chrono::system_clock> expiry_time)
1905 {
1906  std::string md = CacheCodec<M>::encode(metadata);
1907  return p_->put(key, value, size, md.data(), md.size(), expiry_time);
1908 }
1909 
1910 template <typename M>
1913  std::string const& key, PersistentCache<std::string, std::string, M>::Loader const& load_func)
1914 {
1915  auto sload_func = [&](std::string const&, PersistentStringCache const&)
1916  {
1917  load_func(key, *this);
1918  };
1919  auto svalue = p_->get_or_put(key, sload_func);
1920  return svalue ? OptionalValue(*svalue) : OptionalValue();
1921 }
1922 
1923 template <typename M>
1926  std::string const& key, PersistentCache<std::string, std::string, M>::Loader const& load_func)
1927 {
1928  auto sload_func = [&](std::string const&, PersistentStringCache const&)
1929  {
1930  load_func(key, *this);
1931  };
1932  auto sdata = p_->get_or_put_data(key, sload_func);
1933  if (!sdata)
1934  {
1935  return OptionalData();
1936  }
1937  return OptionalData({sdata->value, CacheCodec<M>::decode(sdata->metadata)});
1938 }
1939 
1940 template <typename M>
1941 bool PersistentCache<std::string, std::string, M>::put_metadata(std::string const& key, M const& metadata)
1942 {
1943  return p_->put_metadata(key, CacheCodec<M>::encode(metadata));
1944 }
1945 
1946 template <typename M>
1948  std::string const& key)
1949 {
1950  auto svalue = p_->take(key);
1951  return svalue ? OptionalValue(*svalue) : OptionalValue();
1952 }
1953 
1954 template <typename M>
1957 {
1958  auto sdata = p_->take_data(key);
1959  if (!sdata)
1960  {
1961  return OptionalData();
1962  }
1963  return OptionalData({sdata->value, CacheCodec<M>::decode(sdata->metadata)});
1964 }
1965 
1966 template <typename M>
1968 {
1969  return p_->invalidate(key);
1970 }
1971 
1972 template <typename M>
1973 void PersistentCache<std::string, std::string, M>::invalidate(std::vector<std::string> const& keys)
1974 {
1975  invalidate(keys.begin(), keys.end());
1976 }
1977 
1978 template <typename M>
1979 template <typename It>
1981 {
1982  std::vector<std::string> skeys;
1983  for (auto&& it = begin; it < end; ++it)
1984  {
1985  skeys.push_back(*it);
1986  }
1987  p_->invalidate(skeys.begin(), skeys.end());
1988 }
1989 
1990 template <typename M>
1991 void PersistentCache<std::string, std::string, M>::invalidate(std::initializer_list<std::string> const& keys)
1992 {
1993  invalidate(keys.begin(), keys.end());
1994 }
1995 
1996 template <typename M>
1998 {
1999  p_->invalidate();
2000 }
2001 
2002 template <typename M>
2003 bool PersistentCache<std::string, std::string, M>::touch(std::string const& key,
2004  std::chrono::time_point<std::chrono::system_clock> expiry_time)
2005 {
2006  return p_->touch(key, expiry_time);
2007 }
2008 
2009 template <typename M>
2011 {
2012  p_->clear_stats();
2013 }
2014 
2015 template <typename M>
2016 void PersistentCache<std::string, std::string, M>::resize(int64_t size_in_bytes)
2017 {
2018  p_->resize(size_in_bytes);
2019 }
2020 
2021 template <typename M>
2022 void PersistentCache<std::string, std::string, M>::trim_to(int64_t used_size_in_bytes)
2023 {
2024  p_->trim_to(used_size_in_bytes);
2025 }
2026 
2027 template <typename M>
2029 {
2030  p_->compact();
2031 }
2032 
2033 template <typename M>
2035 {
2036  p_->set_handler(events, cb);
2037 }
2038 
2039 // Specialization for K and M = std::string.
2040 
2041 template <typename V>
2042 class PersistentCache<std::string, V, std::string>
2043 {
2044 public:
2045  typedef std::unique_ptr<PersistentCache<std::string, V, std::string>> UPtr;
2046 
2048  typedef Optional<V> OptionalValue;
2050 
2051  struct Data
2052  {
2053  V value;
2054  std::string metadata;
2055  };
2056  typedef Optional<Data> OptionalData;
2057 
2058  PersistentCache(PersistentCache const&) = delete;
2059  PersistentCache& operator=(PersistentCache const&) = delete;
2060 
2061  PersistentCache(PersistentCache&&) = default;
2063 
2064  ~PersistentCache() = default;
2065 
2066  static UPtr open(std::string const& cache_path, int64_t max_size_in_bytes, CacheDiscardPolicy policy);
2067  static UPtr open(std::string const& cache_path);
2068 
2069  OptionalValue get(std::string const& key) const;
2070  OptionalData get_data(std::string const& key) const;
2071  OptionalMetadata get_metadata(std::string const& key) const;
2072  bool contains_key(std::string const& key) const;
2073  int64_t size() const noexcept;
2074  int64_t size_in_bytes() const noexcept;
2075  int64_t max_size_in_bytes() const noexcept;
2076  int64_t disk_size_in_bytes() const;
2077  CacheDiscardPolicy discard_policy() const noexcept;
2078  PersistentCacheStats stats() const;
2079 
2080  bool put(std::string const& key,
2081  V const& value,
2082  std::chrono::time_point<std::chrono::system_clock> expiry_time = std::chrono::system_clock::time_point());
2083  bool put(std::string const& key,
2084  V const& value,
2085  std::string const& metadata,
2086  std::chrono::time_point<std::chrono::system_clock> expiry_time = std::chrono::system_clock::time_point());
2087  bool put(std::string const& key,
2088  V const& value,
2089  char const* metadata,
2090  int64_t size,
2091  std::chrono::time_point<std::chrono::system_clock> expiry_time = std::chrono::system_clock::time_point());
2092 
2093  typedef std::function<void(std::string const& key, PersistentCache<std::string, V, std::string>& cache)> Loader;
2094 
2095  OptionalValue get_or_put(std::string const& key, Loader const& load_func);
2096  OptionalData get_or_put_data(std::string const& key, Loader const& load_func);
2097 
2098  bool put_metadata(std::string const& key, std::string const& metadata);
2099  bool put_metadata(std::string const& key, char const* metadata, int64_t size);
2100  OptionalValue take(std::string const& key);
2101  OptionalData take_data(std::string const& key);
2102  bool invalidate(std::string const& key);
2103  void invalidate(std::vector<std::string> const& keys);
2104  template <typename It>
2105  void invalidate(It begin, It end);
2106  void invalidate(std::initializer_list<std::string> const& keys);
2107  void invalidate();
2108  bool touch(
2109  std::string const& key,
2110  std::chrono::time_point<std::chrono::system_clock> expiry_time = std::chrono::system_clock::time_point());
2111  void clear_stats();
2112  void resize(int64_t size_in_bytes);
2113  void trim_to(int64_t used_size_in_bytes);
2114  void compact();
2115 
2116  typedef std::function<void(std::string const& key, CacheEvent ev, PersistentCacheStats const& stats)> EventCallback;
2117 
2118  void set_handler(CacheEvent events, EventCallback cb);
2119 
2120 private:
2121  PersistentCache(std::string const& cache_path, int64_t max_size_in_bytes, CacheDiscardPolicy policy);
2122  PersistentCache(std::string const& cache_path);
2123 
2124  std::unique_ptr<PersistentStringCache> p_;
2125 };
2126 
2127 template <typename V>
2129  int64_t max_size_in_bytes,
2130  CacheDiscardPolicy policy)
2131  : p_(PersistentStringCache::open(cache_path, max_size_in_bytes, policy))
2132 {
2133 }
2134 
2135 template <typename V>
2137  : p_(PersistentStringCache::open(cache_path))
2138 {
2139 }
2140 
2141 template <typename V>
2143  std::string const& cache_path, int64_t max_size_in_bytes, CacheDiscardPolicy policy)
2144 {
2146  new PersistentCache<std::string, V, std::string>(cache_path, max_size_in_bytes, policy));
2147 }
2148 
2149 template <typename V>
2151  std::string const& cache_path)
2152 {
2155 }
2156 
2157 template <typename V>
2159  std::string const& key) const
2160 {
2161  auto const& svalue = p_->get(key);
2162  return svalue ? OptionalValue(CacheCodec<V>::decode(*svalue)) : OptionalValue();
2163 }
2164 
2165 template <typename V>
2167  PersistentCache<std::string, V, std::string>::get_data(std::string const& key) const
2168 {
2169  auto sdata = p_->get_data(key);
2170  if (!sdata)
2171  {
2172  return OptionalData();
2173  }
2174  return OptionalData({CacheCodec<V>::decode(sdata->value), sdata->metadata});
2175 }
2176 
2177 template <typename V>
2180 {
2181  auto smeta = p_->get_metadata(key);
2182  return smeta ? OptionalMetadata(*smeta) : OptionalMetadata();
2183 }
2184 
2185 template <typename V>
2186 bool PersistentCache<std::string, V, std::string>::contains_key(std::string const& key) const
2187 {
2188  return p_->contains_key(key);
2189 }
2190 
2191 template <typename V>
2193 {
2194  return p_->size();
2195 }
2196 
2197 template <typename V>
2199 {
2200  return p_->size_in_bytes();
2201 }
2202 
2203 template <typename V>
2205 {
2206  return p_->max_size_in_bytes();
2207 }
2208 
2209 template <typename V>
2211 {
2212  return p_->disk_size_in_bytes();
2213 }
2214 
2215 template <typename V>
2217 {
2218  return p_->discard_policy();
2219 }
2220 
2221 template <typename V>
2223 {
2224  return p_->stats();
2225 }
2226 
2227 template <typename V>
2228 bool PersistentCache<std::string, V, std::string>::put(std::string const& key,
2229  V const& value,
2230  std::chrono::time_point<std::chrono::system_clock> expiry_time)
2231 {
2232  return p_->put(key, CacheCodec<V>::encode(value), expiry_time);
2233 }
2234 
2235 template <typename V>
2236 bool PersistentCache<std::string, V, std::string>::put(std::string const& key,
2237  V const& value,
2238  std::string const& metadata,
2239  std::chrono::time_point<std::chrono::system_clock> expiry_time)
2240 {
2241  std::string v = CacheCodec<V>::encode(value);
2242  return p_->put(key, v.data(), v.size(), metadata.data(), metadata.size(), expiry_time);
2243 }
2244 
2245 template <typename V>
2246 bool PersistentCache<std::string, V, std::string>::put(std::string const& key,
2247  V const& value,
2248  char const* metadata,
2249  int64_t size,
2250  std::chrono::time_point<std::chrono::system_clock> expiry_time)
2251 {
2252  std::string v = CacheCodec<V>::encode(value);
2253  return p_->put(key, v.data(), v.size(), metadata, size, expiry_time);
2254 }
2255 
2256 template <typename V>
2259  std::string const& key, PersistentCache<std::string, V, std::string>::Loader const& load_func)
2260 {
2261  auto sload_func = [&](std::string const&, PersistentStringCache const&)
2262  {
2263  load_func(key, *this);
2264  };
2265  auto svalue = p_->get_or_put(key, sload_func);
2266  return svalue ? OptionalValue(CacheCodec<V>::decode(*svalue)) : OptionalValue();
2267 }
2268 
2269 template <typename V>
2272  std::string const& key, PersistentCache<std::string, V, std::string>::Loader const& load_func)
2273 {
2274  auto sload_func = [&](std::string const&, PersistentStringCache const&)
2275  {
2276  load_func(key, *this);
2277  };
2278  auto sdata = p_->get_or_put_data(key, sload_func);
2279  if (!sdata)
2280  {
2281  return OptionalData();
2282  }
2283  return OptionalData({CacheCodec<V>::decode(sdata->value), sdata->metadata});
2284 }
2285 
2286 template <typename V>
2287 bool PersistentCache<std::string, V, std::string>::put_metadata(std::string const& key, std::string const& metadata)
2288 {
2289  return p_->put_metadata(key, metadata);
2290 }
2291 
2292 template <typename V>
2294  char const* metadata,
2295  int64_t size)
2296 {
2297  return p_->put_metadata(key, metadata, size);
2298 }
2299 
2300 template <typename V>
2302  std::string const& key)
2303 {
2304  auto svalue = p_->take(key);
2305  return svalue ? OptionalValue(CacheCodec<V>::decode(*svalue)) : OptionalValue();
2306 }
2307 
2308 template <typename V>
2311 {
2312  auto sdata = p_->take_data(key);
2313  if (!sdata)
2314  {
2315  return OptionalData();
2316  }
2317  return OptionalData({CacheCodec<V>::decode(sdata->value), sdata->metadata});
2318 }
2319 
2320 template <typename V>
2322 {
2323  return p_->invalidate(key);
2324 }
2325 
2326 template <typename V>
2327 void PersistentCache<std::string, V, std::string>::invalidate(std::vector<std::string> const& keys)
2328 {
2329  invalidate(keys.begin(), keys.end());
2330 }
2331 
2332 template <typename V>
2333 template <typename It>
2335 {
2336  std::vector<std::string> skeys;
2337  for (auto&& it = begin; it < end; ++it)
2338  {
2339  skeys.push_back(*it);
2340  }
2341  p_->invalidate(skeys.begin(), skeys.end());
2342 }
2343 
2344 template <typename V>
2345 void PersistentCache<std::string, V, std::string>::invalidate(std::initializer_list<std::string> const& keys)
2346 {
2347  invalidate(keys.begin(), keys.end());
2348 }
2349 
2350 template <typename V>
2352 {
2353  p_->invalidate();
2354 }
2355 
2356 template <typename V>
2357 bool PersistentCache<std::string, V, std::string>::touch(std::string const& key,
2358  std::chrono::time_point<std::chrono::system_clock> expiry_time)
2359 {
2360  return p_->touch(key, expiry_time);
2361 }
2362 
2363 template <typename V>
2365 {
2366  p_->clear_stats();
2367 }
2368 
2369 template <typename V>
2370 void PersistentCache<std::string, V, std::string>::resize(int64_t size_in_bytes)
2371 {
2372  p_->resize(size_in_bytes);
2373 }
2374 
2375 template <typename V>
2376 void PersistentCache<std::string, V, std::string>::trim_to(int64_t used_size_in_bytes)
2377 {
2378  p_->trim_to(used_size_in_bytes);
2379 }
2380 
2381 template <typename V>
2383 {
2384  p_->compact();
2385 }
2386 
2387 template <typename V>
2389 {
2390  p_->set_handler(events, cb);
2391 }
2392 
2393 // Specialization for V and M = std::string.
2394 
2395 template <typename K>
2396 class PersistentCache<K, std::string, std::string>
2397 {
2398 public:
2399  typedef std::unique_ptr<PersistentCache<K, std::string, std::string>> UPtr;
2400 
2401  typedef Optional<K> OptionalKey;
2404 
2405  struct Data
2406  {
2407  std::string value;
2408  std::string metadata;
2409  };
2410  typedef Optional<Data> OptionalData;
2411 
2412  PersistentCache(PersistentCache const&) = delete;
2413  PersistentCache& operator=(PersistentCache const&) = delete;
2414 
2415  PersistentCache(PersistentCache&&) = default;
2417 
2418  ~PersistentCache() = default;
2419 
2420  static UPtr open(std::string const& cache_path, int64_t max_size_in_bytes, CacheDiscardPolicy policy);
2421  static UPtr open(std::string const& cache_path);
2422 
2423  OptionalValue get(K const& key) const;
2424  OptionalData get_data(K const& key) const;
2425  OptionalMetadata get_metadata(K const& key) const;
2426  bool contains_key(K const& key) const;
2427  int64_t size() const noexcept;
2428  int64_t size_in_bytes() const noexcept;
2429  int64_t max_size_in_bytes() const noexcept;
2430  int64_t disk_size_in_bytes() const;
2431  CacheDiscardPolicy discard_policy() const noexcept;
2432  PersistentCacheStats stats() const;
2433 
2434  bool put(K const& key,
2435  std::string const& value,
2436  std::chrono::time_point<std::chrono::system_clock> expiry_time = std::chrono::system_clock::time_point());
2437  bool put(K const& key,
2438  char const* value,
2439  int64_t size,
2440  std::chrono::time_point<std::chrono::system_clock> expiry_time = std::chrono::system_clock::time_point());
2441  bool put(K const& key,
2442  std::string const& value,
2443  std::string const& metadata,
2444  std::chrono::time_point<std::chrono::system_clock> expiry_time = std::chrono::system_clock::time_point());
2445  bool put(K const& key,
2446  char const* value,
2447  int64_t value_size,
2448  char const* metadata,
2449  int64_t metadata_size,
2450  std::chrono::time_point<std::chrono::system_clock> expiry_time = std::chrono::system_clock::time_point());
2451 
2452  typedef std::function<void(K const& key, PersistentCache<K, std::string, std::string>& cache)> Loader;
2453 
2454  OptionalValue get_or_put(K const& key, Loader const& load_func);
2455  OptionalData get_or_put_data(K const& key, Loader const& load_func);
2456 
2457  bool put_metadata(K const& key, std::string const& metadata);
2458  bool put_metadata(K const& key, char const* metadata, int64_t size);
2459  OptionalValue take(K const& key);
2460  OptionalData take_data(K const& key);
2461  bool invalidate(K const& key);
2462  void invalidate(std::vector<K> const& keys);
2463  template <typename It>
2464  void invalidate(It begin, It end);
2465  void invalidate(std::initializer_list<K> const& keys);
2466  void invalidate();
2467  bool touch(
2468  K const& key,
2469  std::chrono::time_point<std::chrono::system_clock> expiry_time = std::chrono::system_clock::time_point());
2470  void clear_stats();
2471  void resize(int64_t size_in_bytes);
2472  void trim_to(int64_t used_size_in_bytes);
2473  void compact();
2474 
2475  typedef std::function<void(K const& key, CacheEvent ev, PersistentCacheStats const& stats)> EventCallback;
2476 
2477  void set_handler(CacheEvent events, EventCallback cb);
2478 
2479 private:
2480  PersistentCache(std::string const& cache_path, int64_t max_size_in_bytes, CacheDiscardPolicy policy);
2481  PersistentCache(std::string const& cache_path);
2482 
2483  std::unique_ptr<PersistentStringCache> p_;
2484 };
2485 
2486 template <typename K>
2488  int64_t max_size_in_bytes,
2489  CacheDiscardPolicy policy)
2490  : p_(PersistentStringCache::open(cache_path, max_size_in_bytes, policy))
2491 {
2492 }
2493 
2494 template <typename K>
2496  : p_(PersistentStringCache::open(cache_path))
2497 {
2498 }
2499 
2500 template <typename K>
2502  std::string const& cache_path, int64_t max_size_in_bytes, CacheDiscardPolicy policy)
2503 {
2505  new PersistentCache<K, std::string, std::string>(cache_path, max_size_in_bytes, policy));
2506 }
2507 
2508 template <typename K>
2510  std::string const& cache_path)
2511 {
2514 }
2515 
2516 template <typename K>
2518  K const& key) const
2519 {
2520  auto const& svalue = p_->get(CacheCodec<K>::encode(key));
2521  return svalue ? OptionalValue(*svalue) : OptionalValue();
2522 }
2523 
2524 template <typename K>
2527 {
2528  auto sdata = p_->get_data(CacheCodec<K>::encode(key));
2529  if (!sdata)
2530  {
2531  return OptionalData();
2532  }
2533  return OptionalData({sdata->value, sdata->metadata});
2534 }
2535 
2536 template <typename K>
2539 {
2540  auto smeta = p_->get_metadata(CacheCodec<K>::encode(key));
2541  return smeta ? OptionalMetadata(*smeta) : OptionalMetadata();
2542 }
2543 
2544 template <typename K>
2546 {
2547  return p_->contains_key(CacheCodec<K>::encode(key));
2548 }
2549 
2550 template <typename K>
2552 {
2553  return p_->size();
2554 }
2555 
2556 template <typename K>
2558 {
2559  return p_->size_in_bytes();
2560 }
2561 
2562 template <typename K>
2564 {
2565  return p_->max_size_in_bytes();
2566 }
2567 
2568 template <typename K>
2570 {
2571  return p_->disk_size_in_bytes();
2572 }
2573 
2574 template <typename K>
2576 {
2577  return p_->discard_policy();
2578 }
2579 
2580 template <typename K>
2582 {
2583  return p_->stats();
2584 }
2585 
2586 template <typename K>
2588  std::string const& value,
2589  std::chrono::time_point<std::chrono::system_clock> expiry_time)
2590 {
2591  return p_->put(CacheCodec<K>::encode(key), value, expiry_time);
2592 }
2593 
2594 template <typename K>
2596  char const* value,
2597  int64_t size,
2598  std::chrono::time_point<std::chrono::system_clock> expiry_time)
2599 {
2600  return p_->put(CacheCodec<K>::encode(key), value, size, expiry_time);
2601 }
2602 
2603 template <typename K>
2605  std::string const& value,
2606  std::string const& metadata,
2607  std::chrono::time_point<std::chrono::system_clock> expiry_time)
2608 {
2609  return p_->put(CacheCodec<K>::encode(key), value, metadata, expiry_time);
2610 }
2611 
2612 template <typename K>
2614  char const* value,
2615  int64_t value_size,
2616  char const* metadata,
2617  int64_t metadata_size,
2618  std::chrono::time_point<std::chrono::system_clock> expiry_time)
2619 {
2620  return p_->put(CacheCodec<K>::encode(key), value, value_size, metadata, metadata_size, expiry_time);
2621 }
2622 
2623 template <typename K>
2626  K const& key, PersistentCache<K, std::string, std::string>::Loader const& load_func)
2627 {
2628  auto skey = CacheCodec<K>::encode(key);
2629  auto sload_func = [&](std::string const&, PersistentStringCache const&)
2630  {
2631  load_func(key, *this);
2632  };
2633  auto svalue = p_->get_or_put(skey, sload_func);
2634  return svalue ? OptionalValue(*svalue) : OptionalValue();
2635 }
2636 
2637 template <typename K>
2640  K const& key, PersistentCache<K, std::string, std::string>::Loader const& load_func)
2641 {
2642  auto skey = CacheCodec<K>::encode(key);
2643  auto sload_func = [&](std::string const&, PersistentStringCache const&)
2644  {
2645  load_func(key, *this);
2646  };
2647  auto sdata = p_->get_or_put_data(skey, sload_func);
2648  if (!sdata)
2649  {
2650  return OptionalData();
2651  }
2652  return OptionalData({sdata->value, sdata->metadata});
2653 }
2654 
2655 template <typename K>
2656 bool PersistentCache<K, std::string, std::string>::put_metadata(K const& key, std::string const& metadata)
2657 {
2658  return p_->put_metadata(CacheCodec<K>::encode(key), metadata);
2659 }
2660 
2661 template <typename K>
2662 bool PersistentCache<K, std::string, std::string>::put_metadata(K const& key, char const* metadata, int64_t size)
2663 {
2664  return p_->put_metadata(CacheCodec<K>::encode(key), metadata, size);
2665 }
2666 
2667 template <typename K>
2669  K const& key)
2670 {
2671  auto svalue = p_->take(CacheCodec<K>::encode(key));
2672  return svalue ? OptionalValue(*svalue) : OptionalValue();
2673 }
2674 
2675 template <typename K>
2678 {
2679  auto sdata = p_->take_data(CacheCodec<K>::encode(key));
2680  if (!sdata)
2681  {
2682  return OptionalData();
2683  }
2684  return OptionalData({sdata->value, sdata->metadata});
2685 }
2686 
2687 template <typename K>
2689 {
2690  return p_->invalidate(CacheCodec<K>::encode(key));
2691 }
2692 
2693 template <typename K>
2694 void PersistentCache<K, std::string, std::string>::invalidate(std::vector<K> const& keys)
2695 {
2696  invalidate(keys.begin(), keys.end());
2697 }
2698 
2699 template <typename K>
2700 template <typename It>
2702 {
2703  std::vector<std::string> skeys;
2704  for (auto&& it = begin; it < end; ++it)
2705  {
2706  skeys.push_back(CacheCodec<K>::encode(*it));
2707  }
2708  p_->invalidate(skeys.begin(), skeys.end());
2709 }
2710 
2711 template <typename K>
2712 void PersistentCache<K, std::string, std::string>::invalidate(std::initializer_list<K> const& keys)
2713 {
2714  invalidate(keys.begin(), keys.end());
2715 }
2716 
2717 template <typename K>
2719 {
2720  p_->invalidate();
2721 }
2722 
2723 template <typename K>
2725  std::chrono::time_point<std::chrono::system_clock> expiry_time)
2726 {
2727  return p_->touch(CacheCodec<K>::encode(key), expiry_time);
2728 }
2729 
2730 template <typename K>
2732 {
2733  p_->clear_stats();
2734 }
2735 
2736 template <typename K>
2737 void PersistentCache<K, std::string, std::string>::resize(int64_t size_in_bytes)
2738 {
2739  p_->resize(size_in_bytes);
2740 }
2741 
2742 template <typename K>
2743 void PersistentCache<K, std::string, std::string>::trim_to(int64_t used_size_in_bytes)
2744 {
2745  p_->trim_to(used_size_in_bytes);
2746 }
2747 
2748 template <typename K>
2750 {
2751  p_->compact();
2752 }
2753 
2754 template <typename K>
2756 {
2757  auto scb = [cb](std::string const& key, CacheEvent ev, PersistentCacheStats const& c)
2758  {
2759  cb(CacheCodec<K>::decode(key), ev, c);
2760  };
2761  p_->set_handler(events, scb);
2762 }
2763 
2764 // Specialization for K, V, and M = std::string.
2765 
2766 template <>
2767 class PersistentCache<std::string, std::string, std::string>
2768 {
2769 public:
2770  typedef std::unique_ptr<PersistentCache<std::string, std::string, std::string>> UPtr;
2771 
2775 
2776  struct Data
2777  {
2778  std::string value;
2779  std::string metadata;
2780  };
2781  typedef Optional<Data> OptionalData;
2782 
2783  PersistentCache(PersistentCache const&) = delete;
2784  PersistentCache& operator=(PersistentCache const&) = delete;
2785 
2786  PersistentCache(PersistentCache&&) = default;
2788 
2789  ~PersistentCache() = default;
2790 
2791  static UPtr open(std::string const& cache_path, int64_t max_size_in_bytes, CacheDiscardPolicy policy);
2792  static UPtr open(std::string const& cache_path);
2793 
2794  OptionalValue get(std::string const& key) const;
2795  OptionalData get_data(std::string const& key) const;
2796  OptionalMetadata get_metadata(std::string const& key) const;
2797  bool contains_key(std::string const& key) const;
2798  int64_t size() const noexcept;
2799  int64_t size_in_bytes() const noexcept;
2800  int64_t max_size_in_bytes() const noexcept;
2801  int64_t disk_size_in_bytes() const;
2802  CacheDiscardPolicy discard_policy() const noexcept;
2803  PersistentCacheStats stats() const;
2804 
2805  bool put(std::string const& key,
2806  std::string const& value,
2807  std::chrono::time_point<std::chrono::system_clock> expiry_time = std::chrono::system_clock::time_point());
2808  bool put(std::string const& key,
2809  char const* value,
2810  int64_t size,
2811  std::chrono::time_point<std::chrono::system_clock> expiry_time = std::chrono::system_clock::time_point());
2812  bool put(std::string const& key,
2813  std::string const& value,
2814  std::string const& metadata,
2815  std::chrono::time_point<std::chrono::system_clock> expiry_time = std::chrono::system_clock::time_point());
2816  bool put(std::string const& key,
2817  char const* value,
2818  int64_t value_size,
2819  char const* metadata,
2820  int64_t metadata_size,
2821  std::chrono::time_point<std::chrono::system_clock> expiry_time = std::chrono::system_clock::time_point());
2822 
2823  typedef std::function<void(std::string const& key, PersistentCache<std::string, std::string, std::string>& cache)>
2824  Loader;
2825 
2826  OptionalValue get_or_put(std::string const& key, Loader const& load_func);
2827  OptionalData get_or_put_data(std::string const& key, Loader const& load_func);
2828 
2829  bool put_metadata(std::string const& key, std::string const& metadata);
2830  bool put_metadata(std::string const& key, char const* metadata, int64_t size);
2831  OptionalValue take(std::string const& key);
2832  OptionalData take_data(std::string const& key);
2833  bool invalidate(std::string const& key);
2834  void invalidate(std::vector<std::string> const& keys);
2835  template <typename It>
2836  void invalidate(It begin, It end);
2837  void invalidate(std::initializer_list<std::string> const& keys);
2838  void invalidate();
2839  bool touch(
2840  std::string const& key,
2841  std::chrono::time_point<std::chrono::system_clock> expiry_time = std::chrono::system_clock::time_point());
2842  void clear_stats();
2843  void resize(int64_t size_in_bytes);
2844  void trim_to(int64_t used_size_in_bytes);
2845  void compact();
2846 
2847  typedef std::function<void(std::string const& key, CacheEvent ev, PersistentCacheStats const& stats)> EventCallback;
2848 
2849  void set_handler(CacheEvent events, EventCallback cb);
2850 
2851 private:
2852  PersistentCache(std::string const& cache_path, int64_t max_size_in_bytes, CacheDiscardPolicy policy);
2853  PersistentCache(std::string const& cache_path);
2854 
2855  std::unique_ptr<PersistentStringCache> p_;
2856 };
2857 
2859  int64_t max_size_in_bytes,
2860  CacheDiscardPolicy policy)
2861  : p_(PersistentStringCache::open(cache_path, max_size_in_bytes, policy))
2862 {
2863 }
2864 
2866  : p_(PersistentStringCache::open(cache_path))
2867 {
2868 }
2869 
2872  int64_t max_size_in_bytes,
2873  CacheDiscardPolicy policy)
2874 {
2876  new PersistentCache<std::string, std::string, std::string>(cache_path, max_size_in_bytes, policy));
2877 }
2878 
2881 {
2884 }
2885 
2888 {
2889  auto const& svalue = p_->get(key);
2890  return svalue ? OptionalValue(*svalue) : OptionalValue();
2891 }
2892 
2895 {
2896  auto sdata = p_->get_data(key);
2897  if (!sdata)
2898  {
2899  return OptionalData();
2900  }
2901  return OptionalData({sdata->value, sdata->metadata});
2902 }
2903 
2906 {
2907  auto smeta = p_->get_metadata(key);
2908  return smeta ? OptionalMetadata(*smeta) : OptionalMetadata();
2909 }
2910 
2912 {
2913  return p_->contains_key(key);
2914 }
2915 
2917 {
2918  return p_->size();
2919 }
2920 
2922 {
2923  return p_->size_in_bytes();
2924 }
2925 
2927 {
2928  return p_->max_size_in_bytes();
2929 }
2930 
2932 {
2933  return p_->disk_size_in_bytes();
2934 }
2935 
2937 {
2938  return p_->discard_policy();
2939 }
2940 
2942 {
2943  return p_->stats();
2944 }
2945 
2947  std::string const& key, std::string const& value, std::chrono::time_point<std::chrono::system_clock> expiry_time)
2948 {
2949  return p_->put(key, value, expiry_time);
2950 }
2951 
2953  std::string const& key,
2954  char const* value,
2955  int64_t size,
2956  std::chrono::time_point<std::chrono::system_clock> expiry_time)
2957 {
2958  return p_->put(key, value, size, expiry_time);
2959 }
2960 
2962  std::string const& key,
2963  std::string const& value,
2964  std::string const& metadata,
2965  std::chrono::time_point<std::chrono::system_clock> expiry_time)
2966 {
2967  return p_->put(key, value, metadata, expiry_time);
2968 }
2969 
2971  std::string const& key,
2972  char const* value,
2973  int64_t value_size,
2974  char const* metadata,
2975  int64_t metadata_size,
2976  std::chrono::time_point<std::chrono::system_clock> expiry_time)
2977 {
2978  return p_->put(key, value, value_size, metadata, metadata_size, expiry_time);
2979 }
2980 
2983  std::string const& key, PersistentCache<std::string, std::string, std::string>::Loader const& load_func)
2984 {
2985  auto sload_func = [&](std::string const&, PersistentStringCache const&)
2986  {
2987  load_func(key, *this);
2988  };
2989  auto svalue = p_->get_or_put(key, sload_func);
2990  return svalue ? OptionalValue(*svalue) : OptionalValue();
2991 }
2992 
2995  std::string const& key, PersistentCache<std::string, std::string, std::string>::Loader const& load_func)
2996 {
2997  auto sload_func = [&](std::string const&, PersistentStringCache const&)
2998  {
2999  load_func(key, *this);
3000  };
3001  auto sdata = p_->get_or_put_data(key, sload_func);
3002  if (!sdata)
3003  {
3004  return OptionalData();
3005  }
3006  return OptionalData({sdata->value, sdata->metadata});
3007 }
3008 
3010  std::string const& metadata)
3011 {
3012  return p_->put_metadata(key, metadata);
3013 }
3014 
3016  char const* metadata,
3017  int64_t size)
3018 {
3019  return p_->put_metadata(key, metadata, size);
3020 }
3021 
3024 {
3025  auto svalue = p_->take(key);
3026  return svalue ? OptionalValue(*svalue) : OptionalValue();
3027 }
3028 
3031 {
3032  auto sdata = p_->take_data(key);
3033  if (!sdata)
3034  {
3035  return OptionalData();
3036  }
3037  return OptionalData({sdata->value, sdata->metadata});
3038 }
3039 
3041 {
3042  return p_->invalidate(key);
3043 }
3044 
3045 void PersistentCache<std::string, std::string, std::string>::invalidate(std::vector<std::string> const& keys)
3046 {
3047  invalidate(keys.begin(), keys.end());
3048 }
3049 
3050 template <typename It>
3052 {
3053  std::vector<std::string> skeys;
3054  for (auto&& it = begin; it < end; ++it)
3055  {
3056  skeys.push_back(*it);
3057  }
3058  p_->invalidate(skeys.begin(), skeys.end());
3059 }
3060 
3061 void PersistentCache<std::string, std::string, std::string>::invalidate(std::initializer_list<std::string> const& keys)
3062 {
3063  invalidate(keys.begin(), keys.end());
3064 }
3065 
3067 {
3068  p_->invalidate();
3069 }
3070 
3072  std::string const& key, std::chrono::time_point<std::chrono::system_clock> expiry_time)
3073 {
3074  return p_->touch(key, expiry_time);
3075 }
3076 
3078 {
3079  p_->clear_stats();
3080 }
3081 
3083 {
3084  p_->resize(size_in_bytes);
3085 }
3086 
3088 {
3089  p_->trim_to(used_size_in_bytes);
3090 }
3091 
3093 {
3094  p_->compact();
3095 }
3096 
3098 {
3099  p_->set_handler(events, cb);
3100 }
3101 
3102 // @endcond
3103 
3104 } // namespace core
Simple pair of value and metadata.
Definition: persistent_cache.h:129
int64_t disk_size_in_bytes() const
Returns an estimate of the disk space consumed by the cache.
void trim_to(int64_t used_size_in_bytes)
Expires entries.
CacheEvent
Event types that can be monitored.
Definition: cache_events.h:38
Definition: cache_codec.h:38
bool touch(K const &key, std::chrono::time_point< std::chrono::system_clock > expiry_time=std::chrono::system_clock::time_point())
Updates the access time of an entry.
OptionalData get_data(K const &key) const
Returns the data for an entry in the cache, provided the entry has not expired.
Optional< V > OptionalValue
Definition: persistent_cache.h:156
Top-level namespace for core functionality.
Definition: cache_codec.h:23
A persistent cache of key-value pairs and metadata of user-defined type.
Definition: persistent_cache.h:118
static UPtr open(std::string const &cache_path, int64_t max_size_in_bytes, CacheDiscardPolicy policy)
Creates or opens a PersistentCache.
void resize(int64_t size_in_bytes)
Changes the maximum size of the cache.
M metadata
Stores the metadata of an entry. If no metadata exists for an entry, metadata is returned as the empt...
Definition: persistent_cache.h:140
Optional< M > OptionalMetadata
Definition: persistent_cache.h:157
STL namespace.
int64_t size() const noexcept
Returns the number of entries in the cache.
bool put_metadata(K const &key, M const &metadata)
Adds or replaces the metadata for an entry. If M = std::string, an overload that accepts const char* ...
OptionalData get_or_put_data(K const &key, Loader const &load_func)
Atomically retrieves or stores a cache entry.
PersistentCache & operator=(PersistentCache const &)=delete
std::function< void(K const &key, CacheEvent ev, PersistentCacheStats const &stats)> EventCallback
The type of a handler function.
Definition: persistent_cache.h:371
A cache of key-value pairs with persistent storage.
Definition: persistent_string_cache.h:68
CacheDiscardPolicy discard_policy() const noexcept
Returns the discard policy of the cache.
std::function< void(K const &key, PersistentCache< K, V, M > &cache)> Loader
Function called by the cache to load an entry after a cache miss.
Definition: persistent_cache.h:280
Optional< K > OptionalKey
Convenience typedefs for returning nullable values.
Definition: persistent_cache.h:155
V value
Stores the value of an entry.
Definition: persistent_cache.h:134
boost::optional< T > Optional
Convenience typedef for nullable values.
Definition: optional.h:39
void invalidate()
Deletes all entries from the cache.
int64_t max_size_in_bytes() const noexcept
Returns the maximum size of the cache in bytes.
bool contains_key(K const &key) const
Tests if an (unexpired) entry is in the cache.
OptionalValue take(K const &key)
Removes an entry and returns its value.
OptionalValue get_or_put(K const &key, Loader const &load_func)
Atomically retrieves or stores a cache entry.
Optional< Data > OptionalData
Definition: persistent_cache.h:158
int64_t size_in_bytes() const noexcept
Returns the number of bytes consumed by entries in the cache.
static UPtr open(std::string const &cache_path, int64_t max_size_in_bytes, CacheDiscardPolicy policy)
Creates or opens a PersistentStringCache.
static std::string encode(T const &value)
Converts a value of custom type T into a string.
bool put(K const &key, V const &value, std::chrono::time_point< std::chrono::system_clock > expiry_time=std::chrono::system_clock::time_point())
Adds or updates an entry. If V = std::string, the method is also overloaded to to accept char const* ...
std::unique_ptr< PersistentCache< K, V, M > > UPtr
Definition: persistent_cache.h:124
static T decode(std::string const &s)
Converts a string into a value of custom type T.
OptionalData take_data(K const &key)
Removes an entry and returns its value and metadata.
void set_handler(CacheEvent events, EventCallback cb)
Installs a handler for one or more events.
OptionalValue get(K const &key) const
Returns the value of an entry in the cache, provided the entry has not expired.
PersistentCache(PersistentCache const &)=delete
~PersistentCache()=default
void clear_stats()
Resets all statistics counters.
CacheDiscardPolicy
Indicates the discard policy to make room for entries when the cache is full.
Definition: cache_discard_policy.h:35
OptionalMetadata get_metadata(K const &key) const
Returns the metadata for an entry in the cache, provided the entry has not expired.
void compact()
Compacts the database.
Class that provides (read-only) access to cache statistics and settings.
Definition: persistent_cache_stats.h:42
PersistentCacheStats stats() const
Returns statistics for the cache.