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