]> git.proxmox.com Git - ceph.git/blame - ceph/src/cls/timeindex/cls_timeindex.cc
update sources to v12.1.0
[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
7c673cae
FG
4#include <errno.h>
5
7c673cae
FG
6#include "objclass/objclass.h"
7
7c673cae
FG
8#include "cls_timeindex_ops.h"
9
7c673cae
FG
10#include "include/compat.h"
11
12CLS_VER(1,0)
13CLS_NAME(timeindex)
14
15static const size_t MAX_LIST_ENTRIES = 1000;
16static const size_t MAX_TRIM_ENTRIES = 1000;
17
18static const string TIMEINDEX_PREFIX = "1_";
19
20static 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
32static 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
41static 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
55static 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
88static 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 int rc = cls_cxx_map_get_vals(hctx, from_index, TIMEINDEX_PREFIX,
124 max_entries + 1, &keys);
125 if (rc < 0) {
126 return rc;
127 }
128
129 cls_timeindex_list_ret ret;
130
131 list<cls_timeindex_entry>& entries = ret.entries;
132 map<string, bufferlist>::iterator iter = keys.begin();
133
134 bool done = false;
135 string marker;
136
137 for (size_t i = 0; i < max_entries && iter != keys.end(); ++i, ++iter) {
138 const string& index = iter->first;
139 bufferlist& bl = iter->second;
140
141 marker = index;
142 if (use_time_boundary && index.compare(0, to_index.size(), to_index) >= 0) {
143 CLS_LOG(20, "DEBUG: cls_timeindex_list: finishing on to_index=%s",
144 to_index.c_str());
145 done = true;
146 break;
147 }
148
149 cls_timeindex_entry e;
150
151 if (parse_index(index, e.key_ts, e.key_ext) < 0) {
152 CLS_LOG(0, "ERROR: cls_timeindex_list: could not parse index=%s",
153 index.c_str());
154 } else {
155 CLS_LOG(20, "DEBUG: cls_timeindex_list: index=%s, key_ext=%s, bl.len = %d",
156 index.c_str(), e.key_ext.c_str(), bl.length());
157 e.value = bl;
158 entries.push_back(e);
159 }
160 }
161
162 if (iter == keys.end()) {
163 done = true;
164 }
165
166 ret.marker = marker;
167 ret.truncated = !done;
168
169 ::encode(ret, *out);
170
171 return 0;
172}
173
174
175static int cls_timeindex_trim(cls_method_context_t hctx,
176 bufferlist * const in,
177 bufferlist * const out)
178{
179 bufferlist::iterator in_iter = in->begin();
180
181 cls_timeindex_trim_op op;
182 try {
183 ::decode(op, in_iter);
184 } catch (buffer::error& err) {
185 CLS_LOG(1, "ERROR: cls_timeindex_trim: failed to decode entry");
186 return -EINVAL;
187 }
188
189 map<string, bufferlist> keys;
190
191 string from_index;
192 string to_index;
193
194 if (op.from_marker.empty()) {
195 get_index_time_prefix(op.from_time, from_index);
196 } else {
197 from_index = op.from_marker;
198 }
199
200 if (op.to_marker.empty()) {
201 get_index_time_prefix(op.to_time, to_index);
202 } else {
203 to_index = op.to_marker;
204 }
205
206 int rc = cls_cxx_map_get_vals(hctx, from_index, TIMEINDEX_PREFIX,
207 MAX_TRIM_ENTRIES, &keys);
208 if (rc < 0) {
209 return rc;
210 }
211
212 map<string, bufferlist>::iterator iter = keys.begin();
213
214 bool removed = false;
215 for (size_t i = 0; i < MAX_TRIM_ENTRIES && iter != keys.end(); ++i, ++iter) {
216 const string& index = iter->first;
217
218 CLS_LOG(20, "index=%s to_index=%s", index.c_str(), to_index.c_str());
219
220 if (index.compare(0, to_index.size(), to_index) > 0) {
221 CLS_LOG(20, "DEBUG: cls_timeindex_trim: finishing on to_index=%s",
222 to_index.c_str());
223 break;
224 }
225
226 CLS_LOG(20, "removing key: index=%s", index.c_str());
227
228 int rc = cls_cxx_map_remove_key(hctx, index);
229 if (rc < 0) {
230 CLS_LOG(1, "ERROR: cls_cxx_map_remove_key failed rc=%d", rc);
231 return rc;
232 }
233
234 removed = true;
235 }
236
237 if (!removed) {
238 return -ENODATA;
239 }
240
241 return 0;
242}
243
244CLS_INIT(timeindex)
245{
246 CLS_LOG(1, "Loaded timeindex class!");
247
248 cls_handle_t h_class;
249 cls_method_handle_t h_timeindex_add;
250 cls_method_handle_t h_timeindex_list;
251 cls_method_handle_t h_timeindex_trim;
252
253 cls_register("timeindex", &h_class);
254
255 /* timeindex */
256 cls_register_cxx_method(h_class, "add", CLS_METHOD_RD | CLS_METHOD_WR,
257 cls_timeindex_add, &h_timeindex_add);
258 cls_register_cxx_method(h_class, "list", CLS_METHOD_RD,
259 cls_timeindex_list, &h_timeindex_list);
260 cls_register_cxx_method(h_class, "trim", CLS_METHOD_RD | CLS_METHOD_WR,
261 cls_timeindex_trim, &h_timeindex_trim);
262
263 return;
264}
265