1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2013 Inktank Storage, Inc.
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.
18 #include <boost/scoped_ptr.hpp>
19 #include <boost/optional/optional_io.hpp>
20 #include "include/memory.h"
27 #include "include/Context.h"
28 #include "common/sharedptr_registry.hpp"
32 * Abstraction for ordering key updates
34 template<typename K, typename V>
37 /// Set keys according to map
38 virtual void set_keys(
39 const std::map<K, V> &keys ///< [in] keys/values to set
43 virtual void remove_keys(
44 const std::set<K> &to_remove ///< [in] keys to remove
47 /// Add context to fire when data is readable
48 virtual void add_callback(
49 Context *c ///< [in] Context to fire on readable
51 virtual ~Transaction() {}
55 * Abstraction for fetching keys
57 template<typename K, typename V>
60 /// Returns requested key values
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
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
72 virtual ~StoreDriver() {}
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.
80 template<typename K, typename V>
83 StoreDriver<K, V> *driver;
85 SharedPtrRegistry<K, boost::optional<V> > in_progress;
86 typedef typename SharedPtrRegistry<K, boost::optional<V> >::VPtr VPtr;
87 typedef ContainerContext<set<VPtr> > TransHolder;
90 MapCacher(StoreDriver<K, V> *driver) : driver(driver) {}
92 /// Fetch first key/value pair after specified key
94 K key, ///< [in] key after which to get next
95 pair<K, V> *next ///< [out] next key
98 pair<K, boost::optional<V> > cached;
100 bool got_cached = in_progress.get_next(key, &cached);
102 bool got_store = false;
103 int r = driver->get_next(key, &store);
104 if (r < 0 && r != -ENOENT) {
110 if (!got_cached && !got_store) {
114 (!got_store || store.first >= cached.first)) {
117 *next = make_pair(cached.first, cached.second.get());
121 continue; // value was cached as removed, recurse
129 ceph_abort(); // not reachable
131 } ///< @return error value, 0 on success, -ENOENT if no more entries
133 /// Adds operation setting keys to Transaction
135 const map<K, V> &keys, ///< [in] keys/values to set
136 Transaction<K, V> *t ///< [out] transaction to use
138 std::set<VPtr> vptrs;
139 for (typename map<K, V>::const_iterator i = keys.begin();
142 VPtr ip = in_progress.lookup_or_create(i->first, i->second);
147 t->add_callback(new TransHolder(vptrs));
150 /// Adds operation removing keys to Transaction
152 const set<K> &keys, ///< [in]
153 Transaction<K, V> *t ///< [out] transaction to use
155 std::set<VPtr> vptrs;
156 for (typename set<K>::const_iterator i = keys.begin();
159 boost::optional<V> empty;
160 VPtr ip = in_progress.lookup_or_create(*i, empty);
164 t->remove_keys(keys);
165 t->add_callback(new TransHolder(vptrs));
168 /// Gets keys, uses cached values for unstable keys
170 const set<K> &keys_to_get, ///< [in] set of keys to fetch
171 map<K, V> *got ///< [out] keys gotten
175 for (typename set<K>::const_iterator i = keys_to_get.begin();
176 i != keys_to_get.end();
178 VPtr val = in_progress.lookup(*i);
181 got->insert(make_pair(*i, val->get()));
182 //else: value cached is empty, key doesn't exist
187 int r = driver->get_keys(to_get, &_got);
190 for (typename map<K, V>::iterator i = _got.begin();
196 } ///< @return error value, 0 on success