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