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 "common/sharedptr_registry.hpp"
22 * Abstraction for ordering key updates
24 template<typename K, typename V>
27 /// Set keys according to map
28 virtual void set_keys(
29 const std::map<K, V> &keys ///< [in] keys/values to set
33 virtual void remove_keys(
34 const std::set<K> &to_remove ///< [in] keys to remove
37 /// Add context to fire when data is readable
38 virtual void add_callback(
39 Context *c ///< [in] Context to fire on readable
41 virtual ~Transaction() {}
45 * Abstraction for fetching keys
47 template<typename K, typename V>
50 /// Returns requested key values
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
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
62 virtual ~StoreDriver() {}
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.
70 template<typename K, typename V>
73 StoreDriver<K, V> *driver;
75 SharedPtrRegistry<K, boost::optional<V> > in_progress;
76 typedef typename SharedPtrRegistry<K, boost::optional<V> >::VPtr VPtr;
77 typedef ContainerContext<set<VPtr> > TransHolder;
80 MapCacher(StoreDriver<K, V> *driver) : driver(driver) {}
82 /// Fetch first key/value pair after specified key
84 K key, ///< [in] key after which to get next
85 pair<K, V> *next ///< [out] next key
88 pair<K, boost::optional<V> > cached;
90 bool got_cached = in_progress.get_next(key, &cached);
92 bool got_store = false;
93 int r = driver->get_next(key, &store);
94 if (r < 0 && r != -ENOENT) {
100 if (!got_cached && !got_store) {
104 (!got_store || store.first >= cached.first)) {
107 *next = make_pair(cached.first, cached.second.get());
111 continue; // value was cached as removed, recurse
119 ceph_abort(); // not reachable
121 } ///< @return error value, 0 on success, -ENOENT if no more entries
123 /// Adds operation setting keys to Transaction
125 const map<K, V> &keys, ///< [in] keys/values to set
126 Transaction<K, V> *t ///< [out] transaction to use
128 std::set<VPtr> vptrs;
129 for (typename map<K, V>::const_iterator i = keys.begin();
132 VPtr ip = in_progress.lookup_or_create(i->first, i->second);
137 t->add_callback(new TransHolder(vptrs));
140 /// Adds operation removing keys to Transaction
142 const set<K> &keys, ///< [in]
143 Transaction<K, V> *t ///< [out] transaction to use
145 std::set<VPtr> vptrs;
146 for (typename set<K>::const_iterator i = keys.begin();
149 boost::optional<V> empty;
150 VPtr ip = in_progress.lookup_or_create(*i, empty);
154 t->remove_keys(keys);
155 t->add_callback(new TransHolder(vptrs));
158 /// Gets keys, uses cached values for unstable keys
160 const set<K> &keys_to_get, ///< [in] set of keys to fetch
161 map<K, V> *got ///< [out] keys gotten
165 for (typename set<K>::const_iterator i = keys_to_get.begin();
166 i != keys_to_get.end();
168 VPtr val = in_progress.lookup(*i);
171 got->insert(make_pair(*i, val->get()));
172 //else: value cached is empty, key doesn't exist
177 int r = driver->get_keys(to_get, &_got);
180 for (typename map<K, V>::iterator i = _got.begin();
186 } ///< @return error value, 0 on success