]> git.proxmox.com Git - ceph.git/blame - ceph/src/cls/statelog/cls_statelog.cc
update sources to v12.1.2
[ceph.git] / ceph / src / cls / statelog / cls_statelog.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_statelog_ops.h"
9
7c673cae
FG
10
11CLS_VER(1,0)
12CLS_NAME(statelog)
13
14static string statelog_index_by_client_prefix = "1_";
15static string statelog_index_by_object_prefix = "2_";
16
17
18static int write_statelog_entry(cls_method_context_t hctx, const string& index, const cls_statelog_entry& entry)
19{
20 bufferlist bl;
21 ::encode(entry, bl);
22
23 int ret = cls_cxx_map_set_val(hctx, index, &bl);
24 if (ret < 0)
25 return ret;
26
27 return 0;
28}
29
30static void get_index_by_client(const string& client_id, const string& op_id, string& index)
31{
32 index = statelog_index_by_client_prefix;
33 index.append(client_id + "_" + op_id);
34}
35
36static void get_index_by_client(cls_statelog_entry& entry, string& index)
37{
38 get_index_by_client(entry.client_id, entry.op_id, index);
39}
40
41static void get_index_by_object(const string& object, const string& op_id, string& index)
42{
43 char buf[16];
44 snprintf(buf, sizeof(buf), "%d_", (int)object.size());
45
46 index = statelog_index_by_object_prefix + buf; /* append object length to ensure uniqueness */
47 index.append(object + "_" + op_id);
48}
49
50static void get_index_by_object(cls_statelog_entry& entry, string& index)
51{
52 get_index_by_object(entry.object, entry.op_id, index);
53}
54
55static int get_existing_entry(cls_method_context_t hctx, const string& client_id,
56 const string& op_id, const string& object,
57 cls_statelog_entry& entry)
58{
59 if ((object.empty() && client_id.empty()) || op_id.empty()) {
60 return -EINVAL;
61 }
62
63 string obj_index;
64 if (!object.empty()) {
65 get_index_by_object(object, op_id, obj_index);
66 } else {
67 get_index_by_client(client_id, op_id, obj_index);
68 }
69
70 bufferlist bl;
71 int rc = cls_cxx_map_get_val(hctx, obj_index, &bl);
72 if (rc < 0) {
73 CLS_LOG(0, "could not find entry %s", obj_index.c_str());
74 return rc;
75 }
76 try {
77 bufferlist::iterator iter = bl.begin();
78 ::decode(entry, iter);
79 } catch (buffer::error& err) {
80 CLS_LOG(0, "ERROR: failed to decode entry %s", obj_index.c_str());
81 return -EIO;
82 }
83
84 if ((!object.empty() && entry.object != object) ||
85 (!client_id.empty() && entry.client_id != client_id)){
86 /* ouch, we were passed inconsistent client_id / object */
87 CLS_LOG(0, "data mismatch: object=%s client_id=%s entry: object=%s client_id=%s",
88 object.c_str(), client_id.c_str(), entry.object.c_str(), entry.client_id.c_str());
89 return -EINVAL;
90 }
91
92 return 0;
93}
94
95static int cls_statelog_add(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
96{
97 bufferlist::iterator in_iter = in->begin();
98
99 cls_statelog_add_op op;
100 try {
101 ::decode(op, in_iter);
102 } catch (buffer::error& err) {
103 CLS_LOG(1, "ERROR: cls_statelog_add_op(): failed to decode op");
104 return -EINVAL;
105 }
106
107 for (list<cls_statelog_entry>::iterator iter = op.entries.begin();
108 iter != op.entries.end(); ++iter) {
109 cls_statelog_entry& entry = *iter;
110
111 string index_by_client;
112
113 get_index_by_client(entry, index_by_client);
114
115 CLS_LOG(0, "storing entry by client/op at %s", index_by_client.c_str());
116
117 int ret = write_statelog_entry(hctx, index_by_client, entry);
118 if (ret < 0)
119 return ret;
120
121 string index_by_obj;
122
123 get_index_by_object(entry, index_by_obj);
124
125 CLS_LOG(0, "storing entry by object at %s", index_by_obj.c_str());
126 ret = write_statelog_entry(hctx, index_by_obj, entry);
127 if (ret < 0)
128 return ret;
129
130 }
131
132 return 0;
133}
134
135static int cls_statelog_list(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
136{
137 bufferlist::iterator in_iter = in->begin();
138
139 cls_statelog_list_op op;
140 try {
141 ::decode(op, in_iter);
142 } catch (buffer::error& err) {
143 CLS_LOG(1, "ERROR: cls_statelog_list_op(): failed to decode op");
144 return -EINVAL;
145 }
146
147 map<string, bufferlist> keys;
148
149 string from_index;
150 string match_prefix;
151
152 if (!op.client_id.empty()) {
153 get_index_by_client(op.client_id, op.op_id, match_prefix);
154 } else if (!op.object.empty()) {
155 get_index_by_object(op.object, op.op_id, match_prefix);
156 } else {
157 match_prefix = statelog_index_by_object_prefix;
158 }
159
160 if (op.marker.empty()) {
161 from_index = match_prefix;
162 } else {
163 from_index = op.marker;
164 }
165
166#define MAX_ENTRIES 1000
167 size_t max_entries = op.max_entries;
168 if (!max_entries || max_entries > MAX_ENTRIES)
169 max_entries = MAX_ENTRIES;
170
c07f9fc5
FG
171 cls_statelog_list_ret ret;
172
173 int rc = cls_cxx_map_get_vals(hctx, from_index, match_prefix, max_entries, &keys, &ret.truncated);
7c673cae
FG
174 if (rc < 0)
175 return rc;
176
177 CLS_LOG(20, "from_index=%s match_prefix=%s", from_index.c_str(), match_prefix.c_str());
7c673cae
FG
178
179 list<cls_statelog_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
188 bufferlist& bl = iter->second;
189 bufferlist::iterator biter = bl.begin();
190 try {
191 cls_statelog_entry e;
192 ::decode(e, biter);
193 entries.push_back(e);
194 } catch (buffer::error& err) {
195 CLS_LOG(0, "ERROR: cls_statelog_list: could not decode entry, index=%s", index.c_str());
196 }
197 }
198
c07f9fc5 199 if (ret.truncated) {
7c673cae 200 ret.marker = marker;
c07f9fc5 201 }
7c673cae
FG
202
203 ::encode(ret, *out);
204
205 return 0;
206}
207
208static int cls_statelog_remove(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
209{
210 bufferlist::iterator in_iter = in->begin();
211
212 cls_statelog_remove_op op;
213 try {
214 ::decode(op, in_iter);
215 } catch (buffer::error& err) {
216 CLS_LOG(1, "ERROR: cls_statelog_remove_op(): failed to decode op");
217 return -EINVAL;
218 }
219
220 cls_statelog_entry entry;
221
222 int rc = get_existing_entry(hctx, op.client_id, op.op_id, op.object, entry);
223 if (rc < 0)
224 return rc;
225
226 string obj_index;
227 get_index_by_object(entry.object, entry.op_id, obj_index);
228
229 rc = cls_cxx_map_remove_key(hctx, obj_index);
230 if (rc < 0) {
231 CLS_LOG(0, "ERROR: failed to remove key");
232 return rc;
233 }
234
235 string client_index;
236 get_index_by_client(entry.client_id, entry.op_id, client_index);
237
238 rc = cls_cxx_map_remove_key(hctx, client_index);
239 if (rc < 0) {
240 CLS_LOG(0, "ERROR: failed to remove key");
241 return rc;
242 }
243
244 return 0;
245}
246
247static int cls_statelog_check_state(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
248{
249 bufferlist::iterator in_iter = in->begin();
250
251 cls_statelog_check_state_op op;
252 try {
253 ::decode(op, in_iter);
254 } catch (buffer::error& err) {
255 CLS_LOG(1, "ERROR: cls_statelog_check_state_op(): failed to decode op");
256 return -EINVAL;
257 }
258
259 if (op.object.empty() || op.op_id.empty()) {
260 CLS_LOG(0, "object name or op id not specified");
261 return -EINVAL;
262 }
263
264
265 cls_statelog_entry entry;
266
267 int rc = get_existing_entry(hctx, op.client_id, op.op_id, op.object, entry);
268 if (rc < 0)
269 return rc;
270
271 if (entry.state != op.state)
272 return -ECANCELED;
273
274 return 0;
275}
276
277CLS_INIT(statelog)
278{
279 CLS_LOG(1, "Loaded log class!");
280
281 cls_handle_t h_class;
282 cls_method_handle_t h_statelog_add;
283 cls_method_handle_t h_statelog_list;
284 cls_method_handle_t h_statelog_remove;
285 cls_method_handle_t h_statelog_check_state;
286
287 cls_register("statelog", &h_class);
288
289 /* log */
290 cls_register_cxx_method(h_class, "add", CLS_METHOD_RD | CLS_METHOD_WR, cls_statelog_add, &h_statelog_add);
291 cls_register_cxx_method(h_class, "list", CLS_METHOD_RD, cls_statelog_list, &h_statelog_list);
292 cls_register_cxx_method(h_class, "remove", CLS_METHOD_RD | CLS_METHOD_WR, cls_statelog_remove, &h_statelog_remove);
293 cls_register_cxx_method(h_class, "check_state", CLS_METHOD_RD, cls_statelog_check_state, &h_statelog_check_state);
294
295 return;
296}
297