Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / 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