]> git.proxmox.com Git - ceph.git/blame - ceph/src/cls/log/cls_log.cc
import 15.2.0 Octopus source
[ceph.git] / ceph / src / cls / log / cls_log.cc
CommitLineData
11fdf7f2 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 "include/types.h"
5#include "include/utime.h"
6#include "objclass/objclass.h"
7
8#include "cls_log_types.h"
9#include "cls_log_ops.h"
10
11#include "global/global_context.h"
12#include "include/compat.h"
13
14CLS_VER(1,0)
15CLS_NAME(log)
16
17static string log_index_prefix = "1_";
18
19
20static int write_log_entry(cls_method_context_t hctx, string& index, cls_log_entry& entry)
21{
22 bufferlist bl;
11fdf7f2 23 encode(entry, bl);
7c673cae
FG
24
25 int ret = cls_cxx_map_set_val(hctx, index, &bl);
26 if (ret < 0)
27 return ret;
28
29 return 0;
30}
31
32static void get_index_time_prefix(utime_t& ts, string& index)
33{
34 char buf[32];
35 snprintf(buf, sizeof(buf), "%010ld.%06ld_", (long)ts.sec(), (long)ts.usec());
36
37 index = log_index_prefix + buf;
38}
39
40static int read_header(cls_method_context_t hctx, cls_log_header& header)
41{
42 bufferlist header_bl;
43
44 int ret = cls_cxx_map_read_header(hctx, &header_bl);
45 if (ret < 0)
46 return ret;
47
48 if (header_bl.length() == 0) {
49 header = cls_log_header();
50 return 0;
51 }
52
11fdf7f2 53 auto iter = header_bl.cbegin();
7c673cae 54 try {
11fdf7f2 55 decode(header, iter);
7c673cae
FG
56 } catch (buffer::error& err) {
57 CLS_LOG(0, "ERROR: read_header(): failed to decode header");
58 }
59
60 return 0;
61}
62
63static int write_header(cls_method_context_t hctx, cls_log_header& header)
64{
65 bufferlist header_bl;
11fdf7f2 66 encode(header, header_bl);
7c673cae
FG
67
68 int ret = cls_cxx_map_write_header(hctx, &header_bl);
69 if (ret < 0)
70 return ret;
71
72 return 0;
73}
74
75static void get_index(cls_method_context_t hctx, utime_t& ts, string& index)
76{
77 get_index_time_prefix(ts, index);
78
79 string unique_id;
80
81 cls_cxx_subop_version(hctx, &unique_id);
82
83 index.append(unique_id);
84}
85
86static int cls_log_add(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
87{
11fdf7f2 88 auto in_iter = in->cbegin();
7c673cae
FG
89
90 cls_log_add_op op;
91 try {
11fdf7f2 92 decode(op, in_iter);
7c673cae
FG
93 } catch (buffer::error& err) {
94 CLS_LOG(1, "ERROR: cls_log_add_op(): failed to decode op");
95 return -EINVAL;
96 }
97
98 cls_log_header header;
99
100 int ret = read_header(hctx, header);
101 if (ret < 0)
102 return ret;
103
104 for (list<cls_log_entry>::iterator iter = op.entries.begin();
105 iter != op.entries.end(); ++iter) {
106 cls_log_entry& entry = *iter;
107
108 string index;
109
110 utime_t timestamp = entry.timestamp;
111 if (op.monotonic_inc && timestamp < header.max_time)
112 timestamp = header.max_time;
113 else if (timestamp > header.max_time)
114 header.max_time = timestamp;
115
116 if (entry.id.empty()) {
117 get_index(hctx, timestamp, index);
118 entry.id = index;
119 } else {
120 index = entry.id;
121 }
122
123 CLS_LOG(20, "storing entry at %s", index.c_str());
124
125
126 if (index > header.max_marker)
127 header.max_marker = index;
128
129 ret = write_log_entry(hctx, index, entry);
130 if (ret < 0)
131 return ret;
132 }
133
134 ret = write_header(hctx, header);
135 if (ret < 0)
136 return ret;
137
138 return 0;
139}
140
141static int cls_log_list(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
142{
11fdf7f2 143 auto in_iter = in->cbegin();
7c673cae
FG
144
145 cls_log_list_op op;
146 try {
11fdf7f2 147 decode(op, in_iter);
7c673cae
FG
148 } catch (buffer::error& err) {
149 CLS_LOG(1, "ERROR: cls_log_list_op(): failed to decode op");
150 return -EINVAL;
151 }
152
153 map<string, bufferlist> keys;
154
155 string from_index;
156 string to_index;
157
158 if (op.marker.empty()) {
159 get_index_time_prefix(op.from_time, from_index);
160 } else {
161 from_index = op.marker;
162 }
163 bool use_time_boundary = (!op.from_time.is_zero() && (op.to_time >= op.from_time));
164
165 if (use_time_boundary)
166 get_index_time_prefix(op.to_time, to_index);
167
168#define MAX_ENTRIES 1000
169 size_t max_entries = op.max_entries;
170 if (!max_entries || max_entries > MAX_ENTRIES)
171 max_entries = MAX_ENTRIES;
172
c07f9fc5
FG
173 cls_log_list_ret ret;
174
175 int rc = cls_cxx_map_get_vals(hctx, from_index, log_index_prefix, max_entries, &keys, &ret.truncated);
7c673cae
FG
176 if (rc < 0)
177 return rc;
178
7c673cae
FG
179 list<cls_log_entry>& entries = ret.entries;
180 map<string, bufferlist>::iterator iter = keys.begin();
181
7c673cae
FG
182 string marker;
183
c07f9fc5 184 for (; iter != keys.end(); ++iter) {
7c673cae
FG
185 const string& index = iter->first;
186 marker = index;
187 if (use_time_boundary && index.compare(0, to_index.size(), to_index) >= 0) {
c07f9fc5 188 ret.truncated = false;
7c673cae
FG
189 break;
190 }
191
192 bufferlist& bl = iter->second;
11fdf7f2 193 auto biter = bl.cbegin();
7c673cae
FG
194 try {
195 cls_log_entry e;
11fdf7f2 196 decode(e, biter);
7c673cae
FG
197 entries.push_back(e);
198 } catch (buffer::error& err) {
199 CLS_LOG(0, "ERROR: cls_log_list: could not decode entry, index=%s", index.c_str());
200 }
201 }
202
b5b8bbf5 203 ret.marker = marker;
7c673cae 204
11fdf7f2 205 encode(ret, *out);
7c673cae
FG
206
207 return 0;
208}
209
210
211static int cls_log_trim(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
212{
11fdf7f2 213 auto in_iter = in->cbegin();
7c673cae
FG
214
215 cls_log_trim_op op;
216 try {
11fdf7f2 217 decode(op, in_iter);
7c673cae 218 } catch (buffer::error& err) {
9f95a23c 219 CLS_LOG(0, "ERROR: cls_log_trim(): failed to decode entry");
7c673cae
FG
220 return -EINVAL;
221 }
222
7c673cae
FG
223 string from_index;
224 string to_index;
225
226 if (op.from_marker.empty()) {
227 get_index_time_prefix(op.from_time, from_index);
228 } else {
229 from_index = op.from_marker;
230 }
9f95a23c
TL
231
232 // cls_cxx_map_remove_range() expects one-past-end
7c673cae 233 if (op.to_marker.empty()) {
9f95a23c
TL
234 auto t = op.to_time;
235 t.nsec_ref() += 1000; // equivalent to usec() += 1
236 t.normalize();
237 get_index_time_prefix(t, to_index);
7c673cae
FG
238 } else {
239 to_index = op.to_marker;
9f95a23c 240 to_index.append(1, '\0');
7c673cae
FG
241 }
242
9f95a23c
TL
243 // list a single key to detect whether the range is empty
244 const size_t max_entries = 1;
245 std::set<std::string> keys;
246 bool more = false;
7c673cae 247
9f95a23c
TL
248 int rc = cls_cxx_map_get_keys(hctx, from_index, max_entries, &keys, &more);
249 if (rc < 0) {
250 CLS_LOG(1, "ERROR: cls_cxx_map_get_keys failed rc=%d", rc);
7c673cae 251 return rc;
9f95a23c 252 }
7c673cae 253
9f95a23c
TL
254 if (keys.empty()) {
255 CLS_LOG(20, "range is empty from_index=%s", from_index.c_str());
256 return -ENODATA;
257 }
7c673cae 258
9f95a23c
TL
259 const std::string& first_key = *keys.begin();
260 if (to_index < first_key) {
261 CLS_LOG(20, "listed key %s past to_index=%s", first_key.c_str(), to_index.c_str());
262 return -ENODATA;
263 }
7c673cae 264
9f95a23c 265 CLS_LOG(20, "listed key %s, removing through %s", first_key.c_str(), to_index.c_str());
7c673cae 266
9f95a23c
TL
267 rc = cls_cxx_map_remove_range(hctx, first_key, to_index);
268 if (rc < 0) {
269 CLS_LOG(1, "ERROR: cls_cxx_map_remove_range failed rc=%d", rc);
270 return rc;
7c673cae
FG
271 }
272
7c673cae
FG
273 return 0;
274}
275
276static int cls_log_info(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
277{
11fdf7f2 278 auto in_iter = in->cbegin();
7c673cae
FG
279
280 cls_log_info_op op;
281 try {
11fdf7f2 282 decode(op, in_iter);
7c673cae
FG
283 } catch (buffer::error& err) {
284 CLS_LOG(1, "ERROR: cls_log_add_op(): failed to decode op");
285 return -EINVAL;
286 }
287
288 cls_log_info_ret ret;
289
290 int rc = read_header(hctx, ret.header);
291 if (rc < 0)
292 return rc;
293
11fdf7f2 294 encode(ret, *out);
7c673cae
FG
295
296 return 0;
297}
298
299CLS_INIT(log)
300{
301 CLS_LOG(1, "Loaded log class!");
302
303 cls_handle_t h_class;
304 cls_method_handle_t h_log_add;
305 cls_method_handle_t h_log_list;
306 cls_method_handle_t h_log_trim;
307 cls_method_handle_t h_log_info;
308
309 cls_register("log", &h_class);
310
311 /* log */
312 cls_register_cxx_method(h_class, "add", CLS_METHOD_RD | CLS_METHOD_WR, cls_log_add, &h_log_add);
313 cls_register_cxx_method(h_class, "list", CLS_METHOD_RD, cls_log_list, &h_log_list);
314 cls_register_cxx_method(h_class, "trim", CLS_METHOD_RD | CLS_METHOD_WR, cls_log_trim, &h_log_trim);
315 cls_register_cxx_method(h_class, "info", CLS_METHOD_RD, cls_log_info, &h_log_info);
316
317 return;
318}
319