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 "include/Context.h"
19 #include "common/sharedptr_registry.hpp"
23 * Abstraction for ordering key updates
25 template<typename K, typename V>
28 /// Std::set keys according to map
29 virtual void set_keys(
30 const std::map<K, V> &keys ///< [in] keys/values to std::set
34 virtual void remove_keys(
35 const std::set<K> &to_remove ///< [in] keys to remove
38 /// Add context to fire when data is readable
39 virtual void add_callback(
40 Context *c ///< [in] Context to fire on readable
42 virtual ~Transaction() {}
46 * Abstraction for fetching keys
48 template<typename K, typename V>
51 /// Returns requested key values
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
59 const K &key, ///< [in] key after which to get next
60 std::pair<K, V> *next ///< [out] first key after key
61 ) = 0; ///< @return 0 on success, -ENOENT if there is no next
63 virtual ~StoreDriver() {}
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.
71 template<typename K, typename V>
74 StoreDriver<K, V> *driver;
76 SharedPtrRegistry<K, boost::optional<V> > in_progress;
77 typedef typename SharedPtrRegistry<K, boost::optional<V> >::VPtr VPtr;
78 typedef ContainerContext<std::set<VPtr> > TransHolder;
81 MapCacher(StoreDriver<K, V> *driver) : driver(driver) {}
83 /// Fetch first key/value std::pair after specified key
85 K key, ///< [in] key after which to get next
86 std::pair<K, V> *next ///< [out] next key
89 std::pair<K, boost::optional<V> > cached;
90 std::pair<K, V> store;
91 bool got_cached = in_progress.get_next(key, &cached);
93 bool got_store = false;
94 int r = driver->get_next(key, &store);
95 if (r < 0 && r != -ENOENT) {
101 if (!got_cached && !got_store) {
105 (!got_store || store.first >= cached.first)) {
108 *next = make_pair(cached.first, cached.second.get());
112 continue; // value was cached as removed, recurse
120 ceph_abort(); // not reachable
122 } ///< @return error value, 0 on success, -ENOENT if no more entries
124 /// Adds operation setting keys to Transaction
126 const std::map<K, V> &keys, ///< [in] keys/values to std::set
127 Transaction<K, V> *t ///< [out] transaction to use
129 std::set<VPtr> vptrs;
130 for (auto i = keys.begin(); i != keys.end(); ++i) {
131 VPtr ip = in_progress.lookup_or_create(i->first, i->second);
136 t->add_callback(new TransHolder(vptrs));
139 /// Adds operation removing keys to Transaction
141 const std::set<K> &keys, ///< [in]
142 Transaction<K, V> *t ///< [out] transaction to use
144 std::set<VPtr> vptrs;
145 for (auto i = keys.begin(); i != keys.end(); ++i) {
146 boost::optional<V> empty;
147 VPtr ip = in_progress.lookup_or_create(*i, empty);
151 t->remove_keys(keys);
152 t->add_callback(new TransHolder(vptrs));
155 /// Gets keys, uses cached values for unstable keys
157 const std::set<K> &keys_to_get, ///< [in] std::set of keys to fetch
158 std::map<K, V> *got ///< [out] keys gotten
162 for (auto i = keys_to_get.begin();
163 i != keys_to_get.end();
165 VPtr val = in_progress.lookup(*i);
168 got->insert(make_pair(*i, val->get()));
169 //else: value cached is empty, key doesn't exist
174 int r = driver->get_keys(to_get, &_got);
177 for (auto i = _got.begin(); i != _got.end(); ++i) {
181 } ///< @return error value, 0 on success