Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / cls / timeindex / cls_timeindex.cc
1 // -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
4 #include <errno.h>
5
6 #include "objclass/objclass.h"
7
8 #include "cls_timeindex_ops.h"
9
10 #include "include/compat.h"
11
12 CLS_VER(1,0)
13 CLS_NAME(timeindex)
14
15 static const size_t MAX_LIST_ENTRIES = 1000;
16 static const size_t MAX_TRIM_ENTRIES = 1000;
17
18 static const string TIMEINDEX_PREFIX = "1_";
19
20 static void get_index_time_prefix(const utime_t& ts,
21                                   string& index)
22 {
23   char buf[32];
24
25   snprintf(buf, sizeof(buf), "%s%010ld.%06ld_", TIMEINDEX_PREFIX.c_str(),
26           (long)ts.sec(), (long)ts.usec());
27   buf[sizeof(buf) - 1] = '\0';
28
29   index = buf;
30 }
31
32 static void get_index(cls_method_context_t hctx,
33                       const utime_t& key_ts,
34                       const string& key_ext,
35                       string& index)
36 {
37   get_index_time_prefix(key_ts, index);
38   index.append(key_ext);
39 }
40
41 static int parse_index(const string& index,
42                        utime_t& key_ts,
43                        string& key_ext)
44 {
45   int sec, usec;
46   char keyext[256];
47
48   int ret = sscanf(index.c_str(), "1_%d.%d_%255s", &sec, &usec, keyext);
49
50   key_ts  = utime_t(sec, usec);
51   key_ext = string(keyext);
52   return ret;
53 }
54
55 static int cls_timeindex_add(cls_method_context_t hctx,
56                              bufferlist * const in,
57                              bufferlist * const out)
58 {
59   bufferlist::iterator in_iter = in->begin();
60
61   cls_timeindex_add_op op;
62   try {
63     ::decode(op, in_iter);
64   } catch (buffer::error& err) {
65     CLS_LOG(1, "ERROR: cls_timeindex_add_op(): failed to decode op");
66     return -EINVAL;
67   }
68
69   for (list<cls_timeindex_entry>::iterator iter = op.entries.begin();
70        iter != op.entries.end();
71        ++iter) {
72     cls_timeindex_entry& entry = *iter;
73
74     string index;
75     get_index(hctx, entry.key_ts, entry.key_ext, index);
76
77     CLS_LOG(20, "storing entry at %s", index.c_str());
78
79     int ret = cls_cxx_map_set_val(hctx, index, &entry.value);
80     if (ret < 0) {
81       return ret;
82     }
83   }
84
85   return 0;
86 }
87
88 static int cls_timeindex_list(cls_method_context_t hctx,
89                               bufferlist * const in,
90                               bufferlist * const out)
91 {
92   bufferlist::iterator in_iter = in->begin();
93
94   cls_timeindex_list_op op;
95   try {
96     ::decode(op, in_iter);
97   } catch (buffer::error& err) {
98     CLS_LOG(1, "ERROR: cls_timeindex_list_op(): failed to decode op");
99     return -EINVAL;
100   }
101
102   map<string, bufferlist> keys;
103
104   string from_index;
105   string to_index;
106
107   if (op.marker.empty()) {
108     get_index_time_prefix(op.from_time, from_index);
109   } else {
110     from_index = op.marker;
111   }
112   const bool use_time_boundary = (op.to_time >= op.from_time);
113
114   if (use_time_boundary) {
115     get_index_time_prefix(op.to_time, to_index);
116   }
117
118   size_t max_entries = op.max_entries;
119   if (max_entries > MAX_LIST_ENTRIES) {
120     max_entries = MAX_LIST_ENTRIES;
121   }
122
123   cls_timeindex_list_ret ret;
124
125   int rc = cls_cxx_map_get_vals(hctx, from_index, TIMEINDEX_PREFIX,
126           max_entries, &keys, &ret.truncated);
127   if (rc < 0) {
128     return rc;
129   }
130
131   list<cls_timeindex_entry>& entries = ret.entries;
132   map<string, bufferlist>::iterator iter = keys.begin();
133
134   string marker;
135
136   for (; iter != keys.end(); ++iter) {
137     const string& index = iter->first;
138     bufferlist& bl = iter->second;
139
140     marker = index;
141     if (use_time_boundary && index.compare(0, to_index.size(), to_index) >= 0) {
142       CLS_LOG(20, "DEBUG: cls_timeindex_list: finishing on to_index=%s",
143               to_index.c_str());
144       ret.truncated = false;
145       break;
146     }
147
148     cls_timeindex_entry e;
149
150     if (parse_index(index, e.key_ts, e.key_ext) < 0) {
151       CLS_LOG(0, "ERROR: cls_timeindex_list: could not parse index=%s",
152               index.c_str());
153     } else {
154       CLS_LOG(20, "DEBUG: cls_timeindex_list: index=%s, key_ext=%s, bl.len = %d",
155               index.c_str(), e.key_ext.c_str(), bl.length());
156       e.value = bl;
157       entries.push_back(e);
158     }
159   }
160
161   ret.marker = marker;
162
163   ::encode(ret, *out);
164
165   return 0;
166 }
167
168
169 static int cls_timeindex_trim(cls_method_context_t hctx,
170                               bufferlist * const in,
171                               bufferlist * const out)
172 {
173   bufferlist::iterator in_iter = in->begin();
174
175   cls_timeindex_trim_op op;
176   try {
177     ::decode(op, in_iter);
178   } catch (buffer::error& err) {
179     CLS_LOG(1, "ERROR: cls_timeindex_trim: failed to decode entry");
180     return -EINVAL;
181   }
182
183   map<string, bufferlist> keys;
184
185   string from_index;
186   string to_index;
187
188   if (op.from_marker.empty()) {
189     get_index_time_prefix(op.from_time, from_index);
190   } else {
191     from_index = op.from_marker;
192   }
193
194   if (op.to_marker.empty()) {
195     get_index_time_prefix(op.to_time, to_index);
196   } else {
197     to_index = op.to_marker;
198   }
199
200   bool more;
201
202   int rc = cls_cxx_map_get_vals(hctx, from_index, TIMEINDEX_PREFIX,
203           MAX_TRIM_ENTRIES, &keys, &more);
204   if (rc < 0) {
205     return rc;
206   }
207
208   map<string, bufferlist>::iterator iter = keys.begin();
209
210   bool removed = false;
211   for (; iter != keys.end(); ++iter) {
212     const string& index = iter->first;
213
214     CLS_LOG(20, "index=%s to_index=%s", index.c_str(), to_index.c_str());
215
216     if (index.compare(0, to_index.size(), to_index) > 0) {
217       CLS_LOG(20, "DEBUG: cls_timeindex_trim: finishing on to_index=%s",
218               to_index.c_str());
219       break;
220     }
221
222     CLS_LOG(20, "removing key: index=%s", index.c_str());
223
224     int rc = cls_cxx_map_remove_key(hctx, index);
225     if (rc < 0) {
226       CLS_LOG(1, "ERROR: cls_cxx_map_remove_key failed rc=%d", rc);
227       return rc;
228     }
229
230     removed = true;
231   }
232
233   if (!removed) {
234     return -ENODATA;
235   }
236
237   return 0;
238 }
239
240 CLS_INIT(timeindex)
241 {
242   CLS_LOG(1, "Loaded timeindex class!");
243
244   cls_handle_t h_class;
245   cls_method_handle_t h_timeindex_add;
246   cls_method_handle_t h_timeindex_list;
247   cls_method_handle_t h_timeindex_trim;
248
249   cls_register("timeindex", &h_class);
250
251   /* timeindex */
252   cls_register_cxx_method(h_class, "add", CLS_METHOD_RD | CLS_METHOD_WR,
253           cls_timeindex_add, &h_timeindex_add);
254   cls_register_cxx_method(h_class, "list", CLS_METHOD_RD,
255           cls_timeindex_list, &h_timeindex_list);
256   cls_register_cxx_method(h_class, "trim", CLS_METHOD_RD | CLS_METHOD_WR,
257           cls_timeindex_trim, &h_timeindex_trim);
258
259   return;
260 }
261