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