]> git.proxmox.com Git - ceph.git/blame - ceph/src/common/map_cacher.hpp
bump version to 18.2.4-pve3
[ceph.git] / ceph / src / common / map_cacher.hpp
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3/*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2013 Inktank Storage, Inc.
7 *
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
12 *
13 */
14
15#ifndef MAPCACHER_H
16#define MAPCACHER_H
17
11fdf7f2 18#include "include/Context.h"
7c673cae
FG
19#include "common/sharedptr_registry.hpp"
20
21namespace MapCacher {
22/**
23 * Abstraction for ordering key updates
24 */
25template<typename K, typename V>
26class Transaction {
27public:
f67539c2 28 /// Std::set keys according to map
7c673cae 29 virtual void set_keys(
f67539c2 30 const std::map<K, V> &keys ///< [in] keys/values to std::set
7c673cae
FG
31 ) = 0;
32
33 /// Remove keys
34 virtual void remove_keys(
35 const std::set<K> &to_remove ///< [in] keys to remove
36 ) = 0;
37
38 /// Add context to fire when data is readable
39 virtual void add_callback(
40 Context *c ///< [in] Context to fire on readable
41 ) = 0;
42 virtual ~Transaction() {}
43};
44
45/**
46 * Abstraction for fetching keys
47 */
48template<typename K, typename V>
49class StoreDriver {
50public:
51 /// Returns requested key values
52 virtual int get_keys(
53 const std::set<K> &keys, ///< [in] keys requested
54 std::map<K, V> *got ///< [out] values for keys obtained
55 ) = 0; ///< @return error value
56
57 /// Returns next key
58 virtual int get_next(
59 const K &key, ///< [in] key after which to get next
f67539c2 60 std::pair<K, V> *next ///< [out] first key after key
7c673cae
FG
61 ) = 0; ///< @return 0 on success, -ENOENT if there is no next
62
1e59de90
TL
63 virtual int get_next_or_current(
64 const K &key, ///< [in] key at-which-or-after to get
65 std::pair<K, V> *next_or_current
66 ) = 0; ///< @return 0 on success, -ENOENT if there is no next
67
7c673cae
FG
68 virtual ~StoreDriver() {}
69};
70
71/**
72 * Uses SharedPtrRegistry to cache objects of in progress writes
73 * allowing the user to read/write a consistent view of the map
74 * without flushing writes.
75 */
76template<typename K, typename V>
77class MapCacher {
78private:
79 StoreDriver<K, V> *driver;
80
81 SharedPtrRegistry<K, boost::optional<V> > in_progress;
82 typedef typename SharedPtrRegistry<K, boost::optional<V> >::VPtr VPtr;
f67539c2 83 typedef ContainerContext<std::set<VPtr> > TransHolder;
7c673cae
FG
84
85public:
86 MapCacher(StoreDriver<K, V> *driver) : driver(driver) {}
87
f67539c2 88 /// Fetch first key/value std::pair after specified key
7c673cae
FG
89 int get_next(
90 K key, ///< [in] key after which to get next
f67539c2 91 std::pair<K, V> *next ///< [out] next key
7c673cae
FG
92 ) {
93 while (true) {
f67539c2
TL
94 std::pair<K, boost::optional<V> > cached;
95 std::pair<K, V> store;
7c673cae
FG
96 bool got_cached = in_progress.get_next(key, &cached);
97
98 bool got_store = false;
99 int r = driver->get_next(key, &store);
100 if (r < 0 && r != -ENOENT) {
101 return r;
102 } else if (r == 0) {
103 got_store = true;
104 }
105
106 if (!got_cached && !got_store) {
107 return -ENOENT;
108 } else if (
109 got_cached &&
110 (!got_store || store.first >= cached.first)) {
111 if (cached.second) {
112 if (next)
113 *next = make_pair(cached.first, cached.second.get());
114 return 0;
115 } else {
116 key = cached.first;
117 continue; // value was cached as removed, recurse
118 }
119 } else {
120 if (next)
121 *next = store;
122 return 0;
123 }
124 }
125 ceph_abort(); // not reachable
126 return -EINVAL;
127 } ///< @return error value, 0 on success, -ENOENT if no more entries
128
129 /// Adds operation setting keys to Transaction
130 void set_keys(
f67539c2 131 const std::map<K, V> &keys, ///< [in] keys/values to std::set
7c673cae
FG
132 Transaction<K, V> *t ///< [out] transaction to use
133 ) {
134 std::set<VPtr> vptrs;
f67539c2 135 for (auto i = keys.begin(); i != keys.end(); ++i) {
7c673cae
FG
136 VPtr ip = in_progress.lookup_or_create(i->first, i->second);
137 *ip = i->second;
138 vptrs.insert(ip);
139 }
140 t->set_keys(keys);
141 t->add_callback(new TransHolder(vptrs));
142 }
143
144 /// Adds operation removing keys to Transaction
145 void remove_keys(
f67539c2 146 const std::set<K> &keys, ///< [in]
7c673cae
FG
147 Transaction<K, V> *t ///< [out] transaction to use
148 ) {
149 std::set<VPtr> vptrs;
f67539c2 150 for (auto i = keys.begin(); i != keys.end(); ++i) {
7c673cae
FG
151 boost::optional<V> empty;
152 VPtr ip = in_progress.lookup_or_create(*i, empty);
153 *ip = empty;
154 vptrs.insert(ip);
155 }
156 t->remove_keys(keys);
157 t->add_callback(new TransHolder(vptrs));
158 }
159
160 /// Gets keys, uses cached values for unstable keys
161 int get_keys(
f67539c2
TL
162 const std::set<K> &keys_to_get, ///< [in] std::set of keys to fetch
163 std::map<K, V> *got ///< [out] keys gotten
7c673cae 164 ) {
f67539c2
TL
165 std::set<K> to_get;
166 std::map<K, V> _got;
167 for (auto i = keys_to_get.begin();
7c673cae
FG
168 i != keys_to_get.end();
169 ++i) {
170 VPtr val = in_progress.lookup(*i);
171 if (val) {
172 if (*val)
173 got->insert(make_pair(*i, val->get()));
174 //else: value cached is empty, key doesn't exist
175 } else {
176 to_get.insert(*i);
177 }
178 }
179 int r = driver->get_keys(to_get, &_got);
180 if (r < 0)
181 return r;
f67539c2 182 for (auto i = _got.begin(); i != _got.end(); ++i) {
7c673cae
FG
183 got->insert(*i);
184 }
185 return 0;
186 } ///< @return error value, 0 on success
187};
188} // namespace
189
190#endif