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