]> git.proxmox.com Git - ceph.git/blame - ceph/src/common/map_cacher.hpp
import quincy beta 17.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
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
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;
f67539c2 78 typedef ContainerContext<std::set<VPtr> > TransHolder;
7c673cae
FG
79
80public:
81 MapCacher(StoreDriver<K, V> *driver) : driver(driver) {}
82
f67539c2 83 /// Fetch first key/value std::pair after specified key
7c673cae
FG
84 int get_next(
85 K key, ///< [in] key after which to get next
f67539c2 86 std::pair<K, V> *next ///< [out] next key
7c673cae
FG
87 ) {
88 while (true) {
f67539c2
TL
89 std::pair<K, boost::optional<V> > cached;
90 std::pair<K, V> store;
7c673cae
FG
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(
f67539c2 126 const std::map<K, V> &keys, ///< [in] keys/values to std::set
7c673cae
FG
127 Transaction<K, V> *t ///< [out] transaction to use
128 ) {
129 std::set<VPtr> vptrs;
f67539c2 130 for (auto i = keys.begin(); i != keys.end(); ++i) {
7c673cae
FG
131 VPtr ip = in_progress.lookup_or_create(i->first, i->second);
132 *ip = i->second;
133 vptrs.insert(ip);
134 }
135 t->set_keys(keys);
136 t->add_callback(new TransHolder(vptrs));
137 }
138
139 /// Adds operation removing keys to Transaction
140 void remove_keys(
f67539c2 141 const std::set<K> &keys, ///< [in]
7c673cae
FG
142 Transaction<K, V> *t ///< [out] transaction to use
143 ) {
144 std::set<VPtr> vptrs;
f67539c2 145 for (auto i = keys.begin(); i != keys.end(); ++i) {
7c673cae
FG
146 boost::optional<V> empty;
147 VPtr ip = in_progress.lookup_or_create(*i, empty);
148 *ip = empty;
149 vptrs.insert(ip);
150 }
151 t->remove_keys(keys);
152 t->add_callback(new TransHolder(vptrs));
153 }
154
155 /// Gets keys, uses cached values for unstable keys
156 int get_keys(
f67539c2
TL
157 const std::set<K> &keys_to_get, ///< [in] std::set of keys to fetch
158 std::map<K, V> *got ///< [out] keys gotten
7c673cae 159 ) {
f67539c2
TL
160 std::set<K> to_get;
161 std::map<K, V> _got;
162 for (auto i = keys_to_get.begin();
7c673cae
FG
163 i != keys_to_get.end();
164 ++i) {
165 VPtr val = in_progress.lookup(*i);
166 if (val) {
167 if (*val)
168 got->insert(make_pair(*i, val->get()));
169 //else: value cached is empty, key doesn't exist
170 } else {
171 to_get.insert(*i);
172 }
173 }
174 int r = driver->get_keys(to_get, &_got);
175 if (r < 0)
176 return r;
f67539c2 177 for (auto i = _got.begin(); i != _got.end(); ++i) {
7c673cae
FG
178 got->insert(*i);
179 }
180 return 0;
181 } ///< @return error value, 0 on success
182};
183} // namespace
184
185#endif