Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / common / map_cacher.hpp
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
18 #include "common/sharedptr_registry.hpp"
19
20 namespace MapCacher {
21 /**
22  * Abstraction for ordering key updates
23  */
24 template<typename K, typename V>
25 class Transaction {
26 public:
27   /// Set keys according to map
28   virtual void set_keys(
29     const std::map<K, V> &keys ///< [in] keys/values to set
30     ) = 0;
31
32   /// Remove keys
33   virtual void remove_keys(
34     const std::set<K> &to_remove ///< [in] keys to remove
35     ) = 0;
36
37   /// Add context to fire when data is readable
38   virtual void add_callback(
39     Context *c ///< [in] Context to fire on readable
40     ) = 0;
41   virtual ~Transaction() {}
42 };
43
44 /**
45  * Abstraction for fetching keys
46  */
47 template<typename K, typename V>
48 class StoreDriver {
49 public:
50   /// Returns requested key values
51   virtual int get_keys(
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
55
56   /// Returns next key
57   virtual int get_next(
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
61
62   virtual ~StoreDriver() {}
63 };
64
65 /**
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.
69  */
70 template<typename K, typename V>
71 class MapCacher {
72 private:
73   StoreDriver<K, V> *driver;
74
75   SharedPtrRegistry<K, boost::optional<V> > in_progress;
76   typedef typename SharedPtrRegistry<K, boost::optional<V> >::VPtr VPtr;
77   typedef ContainerContext<set<VPtr> > TransHolder;
78
79 public:
80   MapCacher(StoreDriver<K, V> *driver) : driver(driver) {}
81
82   /// Fetch first key/value pair after specified key
83   int get_next(
84     K key,               ///< [in] key after which to get next
85     pair<K, V> *next     ///< [out] next key
86     ) {
87     while (true) {
88       pair<K, boost::optional<V> > cached;
89       pair<K, V> store;
90       bool got_cached = in_progress.get_next(key, &cached);
91
92       bool got_store = false;
93       int r = driver->get_next(key, &store);
94       if (r < 0 && r != -ENOENT) {
95         return r;
96       } else if (r == 0) {
97         got_store = true;
98       }
99
100       if (!got_cached && !got_store) {
101         return -ENOENT;
102       } else if (
103         got_cached &&
104         (!got_store || store.first >= cached.first)) {
105         if (cached.second) {
106           if (next)
107             *next = make_pair(cached.first, cached.second.get());
108           return 0;
109         } else {
110           key = cached.first;
111           continue; // value was cached as removed, recurse
112         }
113       } else {
114         if (next)
115           *next = store;
116         return 0;
117       }
118     }
119     ceph_abort(); // not reachable
120     return -EINVAL;
121   } ///< @return error value, 0 on success, -ENOENT if no more entries
122
123   /// Adds operation setting keys to Transaction
124   void set_keys(
125     const map<K, V> &keys,  ///< [in] keys/values to set
126     Transaction<K, V> *t    ///< [out] transaction to use
127     ) {
128     std::set<VPtr> vptrs;
129     for (typename map<K, V>::const_iterator i = keys.begin();
130          i != keys.end();
131          ++i) {
132       VPtr ip = in_progress.lookup_or_create(i->first, i->second);
133       *ip = i->second;
134       vptrs.insert(ip);
135     }
136     t->set_keys(keys);
137     t->add_callback(new TransHolder(vptrs));
138   }
139
140   /// Adds operation removing keys to Transaction
141   void remove_keys(
142     const set<K> &keys,  ///< [in]
143     Transaction<K, V> *t ///< [out] transaction to use
144     ) {
145     std::set<VPtr> vptrs;
146     for (typename set<K>::const_iterator i = keys.begin();
147          i != keys.end();
148          ++i) {
149       boost::optional<V> empty;
150       VPtr ip = in_progress.lookup_or_create(*i, empty);
151       *ip = empty;
152       vptrs.insert(ip);
153     }
154     t->remove_keys(keys);
155     t->add_callback(new TransHolder(vptrs));
156   }
157
158   /// Gets keys, uses cached values for unstable keys
159   int get_keys(
160     const set<K> &keys_to_get, ///< [in] set of keys to fetch
161     map<K, V> *got             ///< [out] keys gotten
162     ) {
163     set<K> to_get;
164     map<K, V> _got;
165     for (typename set<K>::const_iterator i = keys_to_get.begin();
166          i != keys_to_get.end();
167          ++i) {
168       VPtr val = in_progress.lookup(*i);
169       if (val) {
170         if (*val)
171           got->insert(make_pair(*i, val->get()));
172         //else: value cached is empty, key doesn't exist
173       } else {
174         to_get.insert(*i);
175       }
176     }
177     int r = driver->get_keys(to_get, &_got);
178     if (r < 0)
179       return r;
180     for (typename map<K, V>::iterator i = _got.begin();
181          i != _got.end();
182          ++i) {
183       got->insert(*i);
184     }
185     return 0;
186   } ///< @return error value, 0 on success
187 };
188 } // namespace
189
190 #endif