]> git.proxmox.com Git - ceph.git/blob - ceph/src/common/map_cacher.hpp
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / common / map_cacher.hpp
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
18 #include <boost/scoped_ptr.hpp>
19 #include <boost/optional/optional_io.hpp>
20 #include "include/memory.h"
21 #include <set>
22 #include <map>
23 #include <utility>
24 #include <string>
25 #include <errno.h>
26
27 #include "include/Context.h"
28 #include "common/sharedptr_registry.hpp"
29
30 namespace MapCacher {
31 /**
32 * Abstraction for ordering key updates
33 */
34 template<typename K, typename V>
35 class Transaction {
36 public:
37 /// Set keys according to map
38 virtual void set_keys(
39 const std::map<K, V> &keys ///< [in] keys/values to set
40 ) = 0;
41
42 /// Remove keys
43 virtual void remove_keys(
44 const std::set<K> &to_remove ///< [in] keys to remove
45 ) = 0;
46
47 /// Add context to fire when data is readable
48 virtual void add_callback(
49 Context *c ///< [in] Context to fire on readable
50 ) = 0;
51 virtual ~Transaction() {}
52 };
53
54 /**
55 * Abstraction for fetching keys
56 */
57 template<typename K, typename V>
58 class StoreDriver {
59 public:
60 /// Returns requested key values
61 virtual int get_keys(
62 const std::set<K> &keys, ///< [in] keys requested
63 std::map<K, V> *got ///< [out] values for keys obtained
64 ) = 0; ///< @return error value
65
66 /// Returns next key
67 virtual int get_next(
68 const K &key, ///< [in] key after which to get next
69 pair<K, V> *next ///< [out] first key after key
70 ) = 0; ///< @return 0 on success, -ENOENT if there is no next
71
72 virtual ~StoreDriver() {}
73 };
74
75 /**
76 * Uses SharedPtrRegistry to cache objects of in progress writes
77 * allowing the user to read/write a consistent view of the map
78 * without flushing writes.
79 */
80 template<typename K, typename V>
81 class MapCacher {
82 private:
83 StoreDriver<K, V> *driver;
84
85 SharedPtrRegistry<K, boost::optional<V> > in_progress;
86 typedef typename SharedPtrRegistry<K, boost::optional<V> >::VPtr VPtr;
87 typedef ContainerContext<set<VPtr> > TransHolder;
88
89 public:
90 MapCacher(StoreDriver<K, V> *driver) : driver(driver) {}
91
92 /// Fetch first key/value pair after specified key
93 int get_next(
94 K key, ///< [in] key after which to get next
95 pair<K, V> *next ///< [out] next key
96 ) {
97 while (true) {
98 pair<K, boost::optional<V> > cached;
99 pair<K, V> store;
100 bool got_cached = in_progress.get_next(key, &cached);
101
102 bool got_store = false;
103 int r = driver->get_next(key, &store);
104 if (r < 0 && r != -ENOENT) {
105 return r;
106 } else if (r == 0) {
107 got_store = true;
108 }
109
110 if (!got_cached && !got_store) {
111 return -ENOENT;
112 } else if (
113 got_cached &&
114 (!got_store || store.first >= cached.first)) {
115 if (cached.second) {
116 if (next)
117 *next = make_pair(cached.first, cached.second.get());
118 return 0;
119 } else {
120 key = cached.first;
121 continue; // value was cached as removed, recurse
122 }
123 } else {
124 if (next)
125 *next = store;
126 return 0;
127 }
128 }
129 ceph_abort(); // not reachable
130 return -EINVAL;
131 } ///< @return error value, 0 on success, -ENOENT if no more entries
132
133 /// Adds operation setting keys to Transaction
134 void set_keys(
135 const map<K, V> &keys, ///< [in] keys/values to set
136 Transaction<K, V> *t ///< [out] transaction to use
137 ) {
138 std::set<VPtr> vptrs;
139 for (typename map<K, V>::const_iterator i = keys.begin();
140 i != keys.end();
141 ++i) {
142 VPtr ip = in_progress.lookup_or_create(i->first, i->second);
143 *ip = i->second;
144 vptrs.insert(ip);
145 }
146 t->set_keys(keys);
147 t->add_callback(new TransHolder(vptrs));
148 }
149
150 /// Adds operation removing keys to Transaction
151 void remove_keys(
152 const set<K> &keys, ///< [in]
153 Transaction<K, V> *t ///< [out] transaction to use
154 ) {
155 std::set<VPtr> vptrs;
156 for (typename set<K>::const_iterator i = keys.begin();
157 i != keys.end();
158 ++i) {
159 boost::optional<V> empty;
160 VPtr ip = in_progress.lookup_or_create(*i, empty);
161 *ip = empty;
162 vptrs.insert(ip);
163 }
164 t->remove_keys(keys);
165 t->add_callback(new TransHolder(vptrs));
166 }
167
168 /// Gets keys, uses cached values for unstable keys
169 int get_keys(
170 const set<K> &keys_to_get, ///< [in] set of keys to fetch
171 map<K, V> *got ///< [out] keys gotten
172 ) {
173 set<K> to_get;
174 map<K, V> _got;
175 for (typename set<K>::const_iterator i = keys_to_get.begin();
176 i != keys_to_get.end();
177 ++i) {
178 VPtr val = in_progress.lookup(*i);
179 if (val) {
180 if (*val)
181 got->insert(make_pair(*i, val->get()));
182 //else: value cached is empty, key doesn't exist
183 } else {
184 to_get.insert(*i);
185 }
186 }
187 int r = driver->get_keys(to_get, &_got);
188 if (r < 0)
189 return r;
190 for (typename map<K, V>::iterator i = _got.begin();
191 i != _got.end();
192 ++i) {
193 got->insert(*i);
194 }
195 return 0;
196 } ///< @return error value, 0 on success
197 };
198 } // namespace
199
200 #endif