]> git.proxmox.com Git - ceph.git/blob - ceph/src/cls/version/cls_version.cc
update sources to v12.1.0
[ceph.git] / ceph / src / cls / version / cls_version.cc
1 // -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
4 #include <errno.h>
5
6 #include "objclass/objclass.h"
7
8 #include "cls/version/cls_version_ops.h"
9
10 #include "include/compat.h"
11
12 CLS_VER(1,0)
13 CLS_NAME(version)
14
15
16 #define VERSION_ATTR "ceph.objclass.version"
17
18 static int set_version(cls_method_context_t hctx, struct obj_version *objv)
19 {
20 bufferlist bl;
21
22 ::encode(*objv, bl);
23
24 CLS_LOG(20, "cls_version: set_version %s:%d", objv->tag.c_str(), (int)objv->ver);
25
26 int ret = cls_cxx_setxattr(hctx, VERSION_ATTR, &bl);
27 if (ret < 0)
28 return ret;
29
30 return 0;
31 }
32
33 static int init_version(cls_method_context_t hctx, struct obj_version *objv)
34 {
35 #define TAG_LEN 24
36 char buf[TAG_LEN + 1];
37
38 int ret = cls_gen_rand_base64(buf, sizeof(buf));
39 if (ret < 0)
40 return ret;
41
42 objv->ver = 1;
43 objv->tag = buf;
44
45 CLS_LOG(20, "cls_version: init_version %s:%d", objv->tag.c_str(), (int)objv->ver);
46
47 return set_version(hctx, objv);
48 }
49
50 /* implicit create should be true only if called from a write operation (set, inc), never from a read operation (read, check) */
51 static int read_version(cls_method_context_t hctx, obj_version *objv, bool implicit_create)
52 {
53 bufferlist bl;
54 int ret = cls_cxx_getxattr(hctx, VERSION_ATTR, &bl);
55 if (ret == -ENOENT || ret == -ENODATA) {
56 objv->ver = 0;
57
58 if (implicit_create) {
59 return init_version(hctx, objv);
60 }
61 return 0;
62 }
63 if (ret < 0)
64 return ret;
65
66 try {
67 bufferlist::iterator iter = bl.begin();
68 ::decode(*objv, iter);
69 } catch (buffer::error& err) {
70 CLS_LOG(0, "ERROR: read_version(): failed to decode version entry\n");
71 return -EIO;
72 }
73
74 return 0;
75 }
76
77 static int cls_version_set(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
78 {
79 bufferlist::iterator in_iter = in->begin();
80
81 cls_version_set_op op;
82 try {
83 ::decode(op, in_iter);
84 } catch (buffer::error& err) {
85 CLS_LOG(1, "ERROR: cls_version_get(): failed to decode entry\n");
86 return -EINVAL;
87 }
88
89 int ret = set_version(hctx, &op.objv);
90 if (ret < 0)
91 return ret;
92
93 return 0;
94 }
95
96 static bool check_conds(list<obj_version_cond>& conds, obj_version& objv)
97 {
98 if (conds.empty())
99 return true;
100
101 for (list<obj_version_cond>::iterator iter = conds.begin(); iter != conds.end(); ++iter) {
102 obj_version_cond& cond = *iter;
103 obj_version& v = cond.ver;
104 CLS_LOG(20, "cls_version: check_version %s:%d (cond=%d)", v.tag.c_str(), (int)v.ver, (int)cond.cond);
105
106 switch (cond.cond) {
107 case VER_COND_NONE:
108 break;
109 case VER_COND_EQ:
110 if (!objv.compare(&v))
111 return false;
112 break;
113 case VER_COND_GT:
114 if (!(objv.ver > v.ver))
115 return false;
116 break;
117 case VER_COND_GE:
118 if (!(objv.ver >= v.ver))
119 return false;
120 break;
121 case VER_COND_LT:
122 if (!(objv.ver < v.ver))
123 return false;
124 break;
125 case VER_COND_LE:
126 if (!(objv.ver <= v.ver))
127 return false;
128 break;
129 case VER_COND_TAG_EQ:
130 if (objv.tag.compare(v.tag) != 0)
131 return false;
132 break;
133 case VER_COND_TAG_NE:
134 if (objv.tag.compare(v.tag) == 0)
135 return false;
136 break;
137 }
138 }
139
140 return true;
141 }
142
143 static int cls_version_inc(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
144 {
145 bufferlist::iterator in_iter = in->begin();
146
147 cls_version_inc_op op;
148 try {
149 ::decode(op, in_iter);
150 } catch (buffer::error& err) {
151 CLS_LOG(1, "ERROR: cls_version_get(): failed to decode entry\n");
152 return -EINVAL;
153 }
154
155 obj_version objv;
156 int ret = read_version(hctx, &objv, true);
157 if (ret < 0)
158 return ret;
159
160 if (!check_conds(op.conds, objv)) {
161 return -ECANCELED;
162 }
163 objv.inc();
164
165 ret = set_version(hctx, &objv);
166 if (ret < 0)
167 return ret;
168
169 return 0;
170 }
171
172 static int cls_version_check(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
173 {
174 bufferlist::iterator in_iter = in->begin();
175
176 cls_version_check_op op;
177 try {
178 ::decode(op, in_iter);
179 } catch (buffer::error& err) {
180 CLS_LOG(1, "ERROR: cls_version_get(): failed to decode entry\n");
181 return -EINVAL;
182 }
183
184 obj_version objv;
185 int ret = read_version(hctx, &objv, false);
186 if (ret < 0)
187 return ret;
188 CLS_LOG(20, "cls_version: read_version %s:%d", objv.tag.c_str(), (int)objv.ver);
189
190 if (!check_conds(op.conds, objv)) {
191 CLS_LOG(20, "cls_version: failed condition check");
192 return -ECANCELED;
193 }
194
195 return 0;
196 }
197
198 static int cls_version_read(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
199 {
200 obj_version objv;
201
202 cls_version_read_ret read_ret;
203 int ret = read_version(hctx, &read_ret.objv, false);
204 if (ret < 0)
205 return ret;
206
207 ::encode(read_ret, *out);
208
209 return 0;
210 }
211
212 CLS_INIT(version)
213 {
214 CLS_LOG(1, "Loaded version class!");
215
216 cls_handle_t h_class;
217 cls_method_handle_t h_version_set;
218 cls_method_handle_t h_version_inc;
219 cls_method_handle_t h_version_inc_conds;
220 cls_method_handle_t h_version_read;
221 cls_method_handle_t h_version_check_conds;
222
223 cls_register("version", &h_class);
224
225 /* version */
226 cls_register_cxx_method(h_class, "set", CLS_METHOD_RD | CLS_METHOD_WR, cls_version_set, &h_version_set);
227 cls_register_cxx_method(h_class, "inc", CLS_METHOD_RD | CLS_METHOD_WR, cls_version_inc, &h_version_inc);
228 cls_register_cxx_method(h_class, "inc_conds", CLS_METHOD_RD | CLS_METHOD_WR, cls_version_inc, &h_version_inc_conds);
229 cls_register_cxx_method(h_class, "read", CLS_METHOD_RD, cls_version_read, &h_version_read);
230 cls_register_cxx_method(h_class, "check_conds", CLS_METHOD_RD, cls_version_check, &h_version_check_conds);
231
232 return;
233 }
234