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
24namespace core
25{
26
117template <typename K, typename V, typename M = std::string>
119{
120public:
124 typedef std::unique_ptr<PersistentCache<K, V, M>> UPtr;
125
129 struct Data
130 {
135
141 };
142
146 //{@
147
159
161
165 //{@
168
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
247
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
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
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
377
379
380private:
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
393template <typename K, typename V, typename M>
394PersistentCache<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
401template <typename K, typename V, typename M>
402PersistentCache<K, V, M>::PersistentCache(std::string const& cache_path)
403 : p_(PersistentStringCache::open(cache_path))
404{
405}
406
407template <typename K, typename V, typename M>
408typename 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
415template <typename K, typename V, typename M>
416typename PersistentCache<K, V, M>::UPtr PersistentCache<K, V, M>::open(std::string const& cache_path)
417{
418 return PersistentCache<K, V, M>::UPtr(new PersistentCache<K, V, M>(cache_path));
419}
420
421template <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
428template <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
439template <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
446template <typename K, typename V, typename M>
447bool PersistentCache<K, V, M>::contains_key(K const& key) const
448{
449 return p_->contains_key(CacheCodec<K>::encode(key));
450}
451
452template <typename K, typename V, typename M>
453int64_t PersistentCache<K, V, M>::size() const noexcept
454{
455 return p_->size();
456}
457
458template <typename K, typename V, typename M>
459int64_t PersistentCache<K, V, M>::size_in_bytes() const noexcept
460{
461 return p_->size_in_bytes();
462}
463
464template <typename K, typename V, typename M>
465int64_t PersistentCache<K, V, M>::max_size_in_bytes() const noexcept
466{
467 return p_->max_size_in_bytes();
468}
469
470template <typename K, typename V, typename M>
472{
473 return p_->disk_size_in_bytes();
474}
475
476template <typename K, typename V, typename M>
478{
479 return p_->discard_policy();
480}
481
482template <typename K, typename V, typename M>
483PersistentCacheStats PersistentCache<K, V, M>::stats() const
484{
485 return p_->stats();
486}
487
488template <typename K, typename V, typename M>
489bool 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
496template <typename K, typename V, typename M>
497bool 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
506template <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
519template <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
536template <typename K, typename V, typename M>
537bool 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
542template <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
549template <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
560template <typename K, typename V, typename M>
562{
563 return p_->invalidate(CacheCodec<K>::encode(key));
564}
565
566template <typename K, typename V, typename M>
567void PersistentCache<K, V, M>::invalidate(std::vector<K> const& keys)
568{
569 invalidate(keys.begin(), keys.end());
570}
571
572template <typename K, typename V, typename M>
573template <typename It>
574void 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
584template <typename K, typename V, typename M>
585void PersistentCache<K, V, M>::invalidate(std::initializer_list<K> const& keys)
586{
587 invalidate(keys.begin(), keys.end());
588}
589
590template <typename K, typename V, typename M>
592{
593 p_->invalidate();
594}
595
596template <typename K, typename V, typename M>
597bool 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
602template <typename K, typename V, typename M>
604{
605 p_->clear_stats();
606}
607
608template <typename K, typename V, typename M>
609void PersistentCache<K, V, M>::resize(int64_t size_in_bytes)
610{
611 p_->resize(size_in_bytes);
612}
613
614template <typename K, typename V, typename M>
615void PersistentCache<K, V, M>::trim_to(int64_t used_size_in_bytes)
616{
617 p_->trim_to(used_size_in_bytes);
618}
619
620template <typename K, typename V, typename M>
622{
623 p_->compact();
624}
625
626template <typename K, typename V, typename M>
627void PersistentCache<K, V, M>::set_handler(CacheEvent events, EventCallback cb)
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
648template <typename V, typename M>
649class PersistentCache<std::string, V, M>
650{
651public:
652 typedef std::unique_ptr<PersistentCache<std::string, V, M>> UPtr;
653
654 typedef Optional<std::string> OptionalKey;
655 typedef Optional<V> OptionalValue;
656 typedef Optional<M> OptionalMetadata;
657
658 struct Data
659 {
660 V value;
661 M metadata;
662 };
663 typedef Optional<Data> OptionalData;
664
665 PersistentCache(PersistentCache const&) = delete;
666 PersistentCache& operator=(PersistentCache const&) = delete;
667
668 PersistentCache(PersistentCache&&) = default;
669 PersistentCache& operator=(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
721private:
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
728template <typename V, typename M>
729PersistentCache<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
736template <typename V, typename M>
737PersistentCache<std::string, V, M>::PersistentCache(std::string const& cache_path)
738 : p_(PersistentStringCache::open(cache_path))
739{
740}
741
742template <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
750template <typename V, typename M>
752 std::string const& cache_path)
753{
754 return PersistentCache<std::string, V, M>::UPtr(new PersistentCache<std::string, V, M>(cache_path));
755}
756
757template <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
765template <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
777template <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
785template <typename V, typename M>
786bool PersistentCache<std::string, V, M>::contains_key(std::string const& key) const
787{
788 return p_->contains_key(key);
789}
790
791template <typename V, typename M>
792int64_t PersistentCache<std::string, V, M>::size() const noexcept
793{
794 return p_->size();
795}
796
797template <typename V, typename M>
799{
800 return p_->size_in_bytes();
801}
802
803template <typename V, typename M>
805{
806 return p_->max_size_in_bytes();
807}
808
809template <typename V, typename M>
811{
812 return p_->disk_size_in_bytes();
813}
814
815template <typename V, typename M>
817{
818 return p_->discard_policy();
819}
820
821template <typename V, typename M>
822PersistentCacheStats PersistentCache<std::string, V, M>::stats() const
823{
824 return p_->stats();
825}
826
827template <typename V, typename M>
828bool 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
835template <typename V, typename M>
836bool 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
844template <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
856template <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
872template <typename V, typename M>
873bool 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
878template <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
886template <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
898template <typename V, typename M>
899bool PersistentCache<std::string, V, M>::invalidate(std::string const& key)
900{
901 return p_->invalidate(key);
902}
903
904template <typename V, typename M>
905void PersistentCache<std::string, V, M>::invalidate(std::vector<std::string> const& keys)
906{
907 invalidate(keys.begin(), keys.end());
908}
909
910template <typename V, typename M>
911template <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
922template <typename V, typename M>
923void PersistentCache<std::string, V, M>::invalidate(std::initializer_list<std::string> const& keys)
924{
925 invalidate(keys.begin(), keys.end());
926}
927
928template <typename V, typename M>
930{
931 p_->invalidate();
932}
933
934template <typename V, typename M>
935bool 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
941template <typename V, typename M>
943{
944 p_->clear_stats();
945}
946
947template <typename V, typename M>
948void PersistentCache<std::string, V, M>::resize(int64_t size_in_bytes)
949{
950 p_->resize(size_in_bytes);
951}
952
953template <typename V, typename M>
954void PersistentCache<std::string, V, M>::trim_to(int64_t used_size_in_bytes)
955{
956 p_->trim_to(used_size_in_bytes);
957}
958
959template <typename V, typename M>
961{
962 p_->compact();
963}
964
965template <typename V, typename M>
967{
968 p_->set_handler(events, cb);
969}
970
971// Specialization for V = std::string.
972
973template <typename K, typename M>
974class PersistentCache<K, std::string, M>
975{
976public:
977 typedef std::unique_ptr<PersistentCache<K, std::string, M>> UPtr;
978
979 typedef Optional<K> OptionalKey;
980 typedef Optional<std::string> OptionalValue;
981 typedef Optional<M> OptionalMetadata;
982
983 struct Data
984 {
985 std::string value;
986 M metadata;
987 };
988 typedef Optional<Data> OptionalData;
989
990 PersistentCache(PersistentCache const&) = delete;
991 PersistentCache& operator=(PersistentCache const&) = delete;
992
993 PersistentCache(PersistentCache&&) = default;
994 PersistentCache& operator=(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
1055private:
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
1062template <typename K, typename M>
1063PersistentCache<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
1070template <typename K, typename M>
1071PersistentCache<K, std::string, M>::PersistentCache(std::string const& cache_path)
1072 : p_(PersistentStringCache::open(cache_path))
1073{
1074}
1075
1076template <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
1084template <typename K, typename M>
1086 std::string const& cache_path)
1087{
1088 return PersistentCache<K, std::string, M>::UPtr(new PersistentCache<K, std::string, M>(cache_path));
1089}
1090
1091template <typename K, typename M>
1093{
1094 auto const& svalue = p_->get(CacheCodec<K>::encode(key));
1095 return svalue ? OptionalValue(*svalue) : OptionalValue();
1096}
1097
1098template <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
1110template <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
1118template <typename K, typename M>
1120{
1121 return p_->contains_key(CacheCodec<K>::encode(key));
1122}
1123
1124template <typename K, typename M>
1125int64_t PersistentCache<K, std::string, M>::size() const noexcept
1126{
1127 return p_->size();
1128}
1129
1130template <typename K, typename M>
1132{
1133 return p_->size_in_bytes();
1134}
1135
1136template <typename K, typename M>
1138{
1139 return p_->max_size_in_bytes();
1140}
1141
1142template <typename K, typename M>
1144{
1145 return p_->disk_size_in_bytes();
1146}
1147
1148template <typename K, typename M>
1150{
1151 return p_->discard_policy();
1152}
1153
1154template <typename K, typename M>
1155PersistentCacheStats PersistentCache<K, std::string, M>::stats() const
1156{
1157 return p_->stats();
1158}
1159
1160template <typename K, typename M>
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
1168template <typename K, typename M>
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
1177template <typename K, typename M>
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
1186template <typename K, typename M>
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
1197template <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
1210template <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
1227template <typename K, typename M>
1228bool 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
1233template <typename K, typename M>
1235{
1236 auto svalue = p_->take(CacheCodec<K>::encode(key));
1237 return svalue ? OptionalValue(*svalue) : OptionalValue();
1238}
1239
1240template <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
1252template <typename K, typename M>
1254{
1255 return p_->invalidate(CacheCodec<K>::encode(key));
1256}
1257
1258template <typename K, typename M>
1259void PersistentCache<K, std::string, M>::invalidate(std::vector<K> const& keys)
1260{
1261 invalidate(keys.begin(), keys.end());
1262}
1263
1264template <typename K, typename M>
1265template <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
1276template <typename K, typename M>
1277void PersistentCache<K, std::string, M>::invalidate(std::initializer_list<K> const& keys)
1278{
1279 invalidate(keys.begin(), keys.end());
1280}
1281
1282template <typename K, typename M>
1284{
1285 p_->invalidate();
1286}
1287
1288template <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
1295template <typename K, typename M>
1297{
1298 p_->clear_stats();
1299}
1300
1301template <typename K, typename M>
1302void PersistentCache<K, std::string, M>::resize(int64_t size_in_bytes)
1303{
1304 p_->resize(size_in_bytes);
1305}
1306
1307template <typename K, typename M>
1308void PersistentCache<K, std::string, M>::trim_to(int64_t used_size_in_bytes)
1309{
1310 p_->trim_to(used_size_in_bytes);
1311}
1312
1313template <typename K, typename M>
1315{
1316 p_->compact();
1317}
1318
1319template <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
1331template <typename K, typename V>
1332class PersistentCache<K, V, std::string>
1333{
1334public:
1335 typedef std::unique_ptr<PersistentCache<K, V, std::string>> UPtr;
1336
1337 typedef Optional<K> OptionalKey;
1338 typedef Optional<V> OptionalValue;
1339 typedef Optional<std::string> OptionalMetadata;
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;
1352 PersistentCache& operator=(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
1410private:
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
1417template <typename K, typename V>
1418PersistentCache<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
1425template <typename K, typename V>
1426PersistentCache<K, V, std::string>::PersistentCache(std::string const& cache_path)
1427 : p_(PersistentStringCache::open(cache_path))
1428{
1429}
1430
1431template <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
1439template <typename K, typename V>
1441 std::string const& cache_path)
1442{
1443 return PersistentCache<K, V, std::string>::UPtr(new PersistentCache<K, V, std::string>(cache_path));
1444}
1445
1446template <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
1453template <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
1465template <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
1473template <typename K, typename V>
1475{
1476 return p_->contains_key(CacheCodec<K>::encode(key));
1477}
1478
1479template <typename K, typename V>
1480int64_t PersistentCache<K, V, std::string>::size() const noexcept
1481{
1482 return p_->size();
1483}
1484
1485template <typename K, typename V>
1487{
1488 return p_->size_in_bytes();
1489}
1490
1491template <typename K, typename V>
1493{
1494 return p_->max_size_in_bytes();
1495}
1496
1497template <typename K, typename V>
1499{
1500 return p_->disk_size_in_bytes();
1501}
1502
1503template <typename K, typename V>
1505{
1506 return p_->discard_policy();
1507}
1508
1509template <typename K, typename V>
1510PersistentCacheStats PersistentCache<K, V, std::string>::stats() const
1511{
1512 return p_->stats();
1513}
1514
1515template <typename K, typename V>
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
1523template <typename K, typename V>
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
1533template <typename K, typename V>
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
1544template <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
1557template <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
1574template <typename K, typename V>
1575bool 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
1580template <typename K, typename V>
1581bool 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
1586template <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
1593template <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
1605template <typename K, typename V>
1607{
1608 return p_->invalidate(CacheCodec<K>::encode(key));
1609}
1610
1611template <typename K, typename V>
1612void PersistentCache<K, V, std::string>::invalidate(std::vector<K> const& keys)
1613{
1614 invalidate(keys.begin(), keys.end());
1615}
1616
1617template <typename K, typename V>
1618template <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
1629template <typename K, typename V>
1630void PersistentCache<K, V, std::string>::invalidate(std::initializer_list<K> const& keys)
1631{
1632 invalidate(keys.begin(), keys.end());
1633}
1634
1635template <typename K, typename V>
1637{
1638 p_->invalidate();
1639}
1640
1641template <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
1648template <typename K, typename V>
1650{
1651 p_->clear_stats();
1652}
1653
1654template <typename K, typename V>
1655void PersistentCache<K, V, std::string>::resize(int64_t size_in_bytes)
1656{
1657 p_->resize(size_in_bytes);
1658}
1659
1660template <typename K, typename V>
1661void PersistentCache<K, V, std::string>::trim_to(int64_t used_size_in_bytes)
1662{
1663 p_->trim_to(used_size_in_bytes);
1664}
1665
1666template <typename K, typename V>
1668{
1669 p_->compact();
1670}
1671
1672template <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
1684template <typename M>
1685class PersistentCache<std::string, std::string, M>
1686{
1687public:
1688 typedef std::unique_ptr<PersistentCache<std::string, std::string, M>> UPtr;
1689
1690 typedef Optional<std::string> OptionalKey;
1691 typedef Optional<std::string> OptionalValue;
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;
1705 PersistentCache& operator=(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
1766private:
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
1773template <typename M>
1774PersistentCache<std::string, std::string, M>::PersistentCache(std::string const& cache_path,
1775 int64_t max_size_in_bytes,
1776 CacheDiscardPolicy policy)
1777 : p_(PersistentStringCache::open(cache_path, max_size_in_bytes, policy))
1778{
1779}
1780
1781template <typename M>
1783 : p_(PersistentStringCache::open(cache_path))
1784{
1785}
1786
1787template <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
1795template <typename M>
1797 std::string const& cache_path)
1798{
1800 new PersistentCache<std::string, std::string, M>(cache_path));
1801}
1802
1803template <typename M>
1805 std::string const& key) const
1806{
1807 auto const& svalue = p_->get(key);
1808 return svalue ? OptionalValue(*svalue) : OptionalValue();
1809}
1810
1811template <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
1823template <typename M>
1826{
1827 auto smeta = p_->get_metadata(key);
1828 return smeta ? OptionalMetadata(CacheCodec<M>::decode(*smeta)) : OptionalMetadata();
1829}
1830
1831template <typename M>
1832bool PersistentCache<std::string, std::string, M>::contains_key(std::string const& key) const
1833{
1834 return p_->contains_key(key);
1835}
1836
1837template <typename M>
1839{
1840 return p_->size();
1841}
1842
1843template <typename M>
1845{
1846 return p_->size_in_bytes();
1847}
1848
1849template <typename M>
1851{
1852 return p_->max_size_in_bytes();
1853}
1854
1855template <typename M>
1857{
1858 return p_->disk_size_in_bytes();
1859}
1860
1861template <typename M>
1863{
1864 return p_->discard_policy();
1865}
1866
1867template <typename M>
1868PersistentCacheStats PersistentCache<std::string, std::string, M>::stats() const
1869{
1870 return p_->stats();
1871}
1872
1873template <typename M>
1874bool 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
1881template <typename M>
1882bool 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
1890template <typename M>
1891bool 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
1899template <typename M>
1900bool 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
1910template <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
1923template <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
1940template <typename M>
1941bool 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
1946template <typename M>
1948 std::string const& key)
1949{
1950 auto svalue = p_->take(key);
1951 return svalue ? OptionalValue(*svalue) : OptionalValue();
1952}
1953
1954template <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
1966template <typename M>
1968{
1969 return p_->invalidate(key);
1970}
1971
1972template <typename M>
1973void PersistentCache<std::string, std::string, M>::invalidate(std::vector<std::string> const& keys)
1974{
1975 invalidate(keys.begin(), keys.end());
1976}
1977
1978template <typename M>
1979template <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
1990template <typename M>
1991void PersistentCache<std::string, std::string, M>::invalidate(std::initializer_list<std::string> const& keys)
1992{
1993 invalidate(keys.begin(), keys.end());
1994}
1995
1996template <typename M>
1998{
1999 p_->invalidate();
2000}
2001
2002template <typename M>
2003bool 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
2009template <typename M>
2011{
2012 p_->clear_stats();
2013}
2014
2015template <typename M>
2017{
2018 p_->resize(size_in_bytes);
2019}
2020
2021template <typename M>
2022void 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
2027template <typename M>
2029{
2030 p_->compact();
2031}
2032
2033template <typename M>
2035{
2036 p_->set_handler(events, cb);
2037}
2038
2039// Specialization for K and M = std::string.
2040
2041template <typename V>
2042class PersistentCache<std::string, V, std::string>
2043{
2044public:
2045 typedef std::unique_ptr<PersistentCache<std::string, V, std::string>> UPtr;
2046
2047 typedef Optional<std::string> OptionalKey;
2048 typedef Optional<V> OptionalValue;
2049 typedef Optional<std::string> OptionalMetadata;
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;
2062 PersistentCache& operator=(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
2120private:
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
2127template <typename V>
2128PersistentCache<std::string, V, std::string>::PersistentCache(std::string const& cache_path,
2129 int64_t max_size_in_bytes,
2130 CacheDiscardPolicy policy)
2131 : p_(PersistentStringCache::open(cache_path, max_size_in_bytes, policy))
2132{
2133}
2134
2135template <typename V>
2137 : p_(PersistentStringCache::open(cache_path))
2138{
2139}
2140
2141template <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
2149template <typename V>
2151 std::string const& cache_path)
2152{
2154 new PersistentCache<std::string, V, std::string>(cache_path));
2155}
2156
2157template <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
2165template <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
2177template <typename V>
2180{
2181 auto smeta = p_->get_metadata(key);
2182 return smeta ? OptionalMetadata(*smeta) : OptionalMetadata();
2183}
2184
2185template <typename V>
2186bool PersistentCache<std::string, V, std::string>::contains_key(std::string const& key) const
2187{
2188 return p_->contains_key(key);
2189}
2190
2191template <typename V>
2193{
2194 return p_->size();
2195}
2196
2197template <typename V>
2199{
2200 return p_->size_in_bytes();
2201}
2202
2203template <typename V>
2205{
2206 return p_->max_size_in_bytes();
2207}
2208
2209template <typename V>
2211{
2212 return p_->disk_size_in_bytes();
2213}
2214
2215template <typename V>
2217{
2218 return p_->discard_policy();
2219}
2220
2221template <typename V>
2222PersistentCacheStats PersistentCache<std::string, V, std::string>::stats() const
2223{
2224 return p_->stats();
2225}
2226
2227template <typename V>
2228bool 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
2235template <typename V>
2236bool 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
2245template <typename V>
2246bool 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
2256template <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
2269template <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
2286template <typename V>
2287bool 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
2292template <typename V>
2294 char const* metadata,
2295 int64_t size)
2296{
2297 return p_->put_metadata(key, metadata, size);
2298}
2299
2300template <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
2308template <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
2320template <typename V>
2322{
2323 return p_->invalidate(key);
2324}
2325
2326template <typename V>
2327void PersistentCache<std::string, V, std::string>::invalidate(std::vector<std::string> const& keys)
2328{
2329 invalidate(keys.begin(), keys.end());
2330}
2331
2332template <typename V>
2333template <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
2344template <typename V>
2345void PersistentCache<std::string, V, std::string>::invalidate(std::initializer_list<std::string> const& keys)
2346{
2347 invalidate(keys.begin(), keys.end());
2348}
2349
2350template <typename V>
2352{
2353 p_->invalidate();
2354}
2355
2356template <typename V>
2357bool 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
2363template <typename V>
2365{
2366 p_->clear_stats();
2367}
2368
2369template <typename V>
2371{
2372 p_->resize(size_in_bytes);
2373}
2374
2375template <typename V>
2376void 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
2381template <typename V>
2383{
2384 p_->compact();
2385}
2386
2387template <typename V>
2389{
2390 p_->set_handler(events, cb);
2391}
2392
2393// Specialization for V and M = std::string.
2394
2395template <typename K>
2396class PersistentCache<K, std::string, std::string>
2397{
2398public:
2399 typedef std::unique_ptr<PersistentCache<K, std::string, std::string>> UPtr;
2400
2401 typedef Optional<K> OptionalKey;
2402 typedef Optional<std::string> OptionalValue;
2403 typedef Optional<std::string> OptionalMetadata;
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;
2416 PersistentCache& operator=(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
2479private:
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
2486template <typename K>
2487PersistentCache<K, std::string, std::string>::PersistentCache(std::string const& cache_path,
2488 int64_t max_size_in_bytes,
2489 CacheDiscardPolicy policy)
2490 : p_(PersistentStringCache::open(cache_path, max_size_in_bytes, policy))
2491{
2492}
2493
2494template <typename K>
2496 : p_(PersistentStringCache::open(cache_path))
2497{
2498}
2499
2500template <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
2508template <typename K>
2510 std::string const& cache_path)
2511{
2513 new PersistentCache<K, std::string, std::string>(cache_path));
2514}
2515
2516template <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
2524template <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
2536template <typename K>
2539{
2540 auto smeta = p_->get_metadata(CacheCodec<K>::encode(key));
2541 return smeta ? OptionalMetadata(*smeta) : OptionalMetadata();
2542}
2543
2544template <typename K>
2546{
2547 return p_->contains_key(CacheCodec<K>::encode(key));
2548}
2549
2550template <typename K>
2552{
2553 return p_->size();
2554}
2555
2556template <typename K>
2558{
2559 return p_->size_in_bytes();
2560}
2561
2562template <typename K>
2564{
2565 return p_->max_size_in_bytes();
2566}
2567
2568template <typename K>
2570{
2571 return p_->disk_size_in_bytes();
2572}
2573
2574template <typename K>
2576{
2577 return p_->discard_policy();
2578}
2579
2580template <typename K>
2581PersistentCacheStats PersistentCache<K, std::string, std::string>::stats() const
2582{
2583 return p_->stats();
2584}
2585
2586template <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
2594template <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
2603template <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
2612template <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
2623template <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
2637template <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
2655template <typename K>
2656bool 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
2661template <typename K>
2662bool 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
2667template <typename K>
2669 K const& key)
2670{
2671 auto svalue = p_->take(CacheCodec<K>::encode(key));
2672 return svalue ? OptionalValue(*svalue) : OptionalValue();
2673}
2674
2675template <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
2687template <typename K>
2689{
2690 return p_->invalidate(CacheCodec<K>::encode(key));
2691}
2692
2693template <typename K>
2694void PersistentCache<K, std::string, std::string>::invalidate(std::vector<K> const& keys)
2695{
2696 invalidate(keys.begin(), keys.end());
2697}
2698
2699template <typename K>
2700template <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
2711template <typename K>
2712void PersistentCache<K, std::string, std::string>::invalidate(std::initializer_list<K> const& keys)
2713{
2714 invalidate(keys.begin(), keys.end());
2715}
2716
2717template <typename K>
2719{
2720 p_->invalidate();
2721}
2722
2723template <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
2730template <typename K>
2732{
2733 p_->clear_stats();
2734}
2735
2736template <typename K>
2738{
2739 p_->resize(size_in_bytes);
2740}
2741
2742template <typename K>
2743void 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
2748template <typename K>
2750{
2751 p_->compact();
2752}
2753
2754template <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
2766template <>
2767class PersistentCache<std::string, std::string, std::string>
2768{
2769public:
2770 typedef std::unique_ptr<PersistentCache<std::string, std::string, std::string>> UPtr;
2771
2772 typedef Optional<std::string> OptionalKey;
2773 typedef Optional<std::string> OptionalValue;
2774 typedef Optional<std::string> OptionalMetadata;
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;
2787 PersistentCache& operator=(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
2851private:
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
2858PersistentCache<std::string, std::string, std::string>::PersistentCache(std::string const& cache_path,
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{
2883 new PersistentCache<std::string, std::string, std::string>(cache_path));
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
3045void PersistentCache<std::string, std::string, std::string>::invalidate(std::vector<std::string> const& keys)
3046{
3047 invalidate(keys.begin(), keys.end());
3048}
3049
3050template <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
3061void 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
Class that provides (read-only) access to cache statistics and settings.
Definition persistent_cache_stats.h:43
A persistent cache of key-value pairs and metadata of user-defined type.
Definition persistent_cache.h:119
CacheDiscardPolicy discard_policy() const noexcept
Returns the discard policy of the cache.
OptionalData get_data(K const &key) const
Returns the data for an entry in the cache, provided the entry has not expired.
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.
OptionalValue get(K const &key) const
Returns the value of an entry in the cache, provided the entry has not expired.
OptionalData take_data(K const &key)
Removes an entry and returns its value and metadata.
Optional< K > OptionalKey
Convenience typedefs for returning nullable values.
Definition persistent_cache.h:155
std::unique_ptr< PersistentCache< K, V, M > > UPtr
Definition persistent_cache.h:124
int64_t size() const noexcept
Returns the number of entries in the cache.
static UPtr open(std::string const &cache_path)
Opens an existing PersistentCache.
void trim_to(int64_t used_size_in_bytes)
Expires entries.
void set_handler(CacheEvent events, EventCallback cb)
Installs a handler for one or more events.
Optional< M > OptionalMetadata
Definition persistent_cache.h:157
static UPtr open(std::string const &cache_path, int64_t max_size_in_bytes, CacheDiscardPolicy policy)
Creates or opens a PersistentCache.
void compact()
Compacts the database.
OptionalData get_or_put_data(K const &key, Loader const &load_func)
Atomically retrieves or stores a cache entry.
Optional< Data > OptionalData
Definition persistent_cache.h:158
int64_t max_size_in_bytes() const noexcept
Returns the maximum size of the cache in bytes.
int64_t disk_size_in_bytes() const
Returns an estimate of the disk space consumed by the cache.
std::function< void(K const &key, CacheEvent ev, PersistentCacheStats const &stats)> EventCallback
The type of a handler function.
Definition persistent_cache.h:371
bool contains_key(K const &key) const
Tests if an (unexpired) entry is in the cache.
PersistentCache & operator=(PersistentCache &&)=default
PersistentCache(PersistentCache const &)=delete
PersistentCache & operator=(PersistentCache const &)=delete
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
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* ...
OptionalMetadata get_metadata(K const &key) const
Returns the metadata for an entry in the cache, provided the entry has not expired.
PersistentCacheStats stats() const
Returns statistics for the cache.
PersistentCache(PersistentCache &&)=default
OptionalValue take(K const &key)
Removes an entry and returns its value.
void invalidate()
Deletes all entries from the cache.
OptionalValue get_or_put(K const &key, Loader const &load_func)
Atomically retrieves or stores a cache entry.
int64_t size_in_bytes() const noexcept
Returns the number of bytes consumed by entries in the cache.
void resize(int64_t size_in_bytes)
Changes the maximum size of the cache.
Optional< V > OptionalValue
Definition persistent_cache.h:156
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* ...
void clear_stats()
Resets all statistics counters.
~PersistentCache()=default
A cache of key-value pairs with persistent storage.
Definition persistent_string_cache.h:69
Top-level namespace for core functionality.
Definition cache_codec.h:24
CacheDiscardPolicy
Indicates the discard policy to make room for entries when the cache is full.
Definition cache_discard_policy.h:36
CacheEvent
Event types that can be monitored.
Definition cache_events.h:39
@ put
An entry was added by a call to put() or get_or_put().
@ get
An entry was returned by a call to get(), get_or_put(), take(), or take_data().
@ touch
An entry was refreshed by a call to touch().
@ invalidate
An entry was removed by a call to invalidate(), take(), or take_data().
boost::optional< T > Optional
Convenience typedef for nullable values.
Definition optional.h:39
static T decode(std::string const &s)
Converts a string into a value of custom type T.
static std::string encode(T const &value)
Converts a value of custom type T into a string.
Simple pair of value and metadata.
Definition persistent_cache.h:130
V value
Stores the value of an entry.
Definition persistent_cache.h:134
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