X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fceph%2Fsrc%2Fcls%2Fversion%2Fcls_version.cc;fp=src%2Fceph%2Fsrc%2Fcls%2Fversion%2Fcls_version.cc;h=c68f8c4e1ceaab2e2afd78a96658d216eafbd61d;hb=812ff6ca9fcd3e629e49d4328905f33eee8ca3f5;hp=0000000000000000000000000000000000000000;hpb=15280273faafb77777eab341909a3f495cf248d9;p=stor4nfv.git diff --git a/src/ceph/src/cls/version/cls_version.cc b/src/ceph/src/cls/version/cls_version.cc new file mode 100644 index 0000000..c68f8c4 --- /dev/null +++ b/src/ceph/src/cls/version/cls_version.cc @@ -0,0 +1,234 @@ +// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include + +#include "objclass/objclass.h" + +#include "cls/version/cls_version_ops.h" + +#include "include/compat.h" + +CLS_VER(1,0) +CLS_NAME(version) + + +#define VERSION_ATTR "ceph.objclass.version" + +static int set_version(cls_method_context_t hctx, struct obj_version *objv) +{ + bufferlist bl; + + ::encode(*objv, bl); + + CLS_LOG(20, "cls_version: set_version %s:%d", objv->tag.c_str(), (int)objv->ver); + + int ret = cls_cxx_setxattr(hctx, VERSION_ATTR, &bl); + if (ret < 0) + return ret; + + return 0; +} + +static int init_version(cls_method_context_t hctx, struct obj_version *objv) +{ +#define TAG_LEN 24 + char buf[TAG_LEN + 1]; + + int ret = cls_gen_rand_base64(buf, sizeof(buf)); + if (ret < 0) + return ret; + + objv->ver = 1; + objv->tag = buf; + + CLS_LOG(20, "cls_version: init_version %s:%d", objv->tag.c_str(), (int)objv->ver); + + return set_version(hctx, objv); +} + +/* implicit create should be true only if called from a write operation (set, inc), never from a read operation (read, check) */ +static int read_version(cls_method_context_t hctx, obj_version *objv, bool implicit_create) +{ + bufferlist bl; + int ret = cls_cxx_getxattr(hctx, VERSION_ATTR, &bl); + if (ret == -ENOENT || ret == -ENODATA) { + objv->ver = 0; + + if (implicit_create) { + return init_version(hctx, objv); + } + return 0; + } + if (ret < 0) + return ret; + + try { + bufferlist::iterator iter = bl.begin(); + ::decode(*objv, iter); + } catch (buffer::error& err) { + CLS_LOG(0, "ERROR: read_version(): failed to decode version entry\n"); + return -EIO; + } + + return 0; +} + +static int cls_version_set(cls_method_context_t hctx, bufferlist *in, bufferlist *out) +{ + bufferlist::iterator in_iter = in->begin(); + + cls_version_set_op op; + try { + ::decode(op, in_iter); + } catch (buffer::error& err) { + CLS_LOG(1, "ERROR: cls_version_get(): failed to decode entry\n"); + return -EINVAL; + } + + int ret = set_version(hctx, &op.objv); + if (ret < 0) + return ret; + + return 0; +} + +static bool check_conds(list& conds, obj_version& objv) +{ + if (conds.empty()) + return true; + + for (list::iterator iter = conds.begin(); iter != conds.end(); ++iter) { + obj_version_cond& cond = *iter; + obj_version& v = cond.ver; + CLS_LOG(20, "cls_version: check_version %s:%d (cond=%d)", v.tag.c_str(), (int)v.ver, (int)cond.cond); + + switch (cond.cond) { + case VER_COND_NONE: + break; + case VER_COND_EQ: + if (!objv.compare(&v)) + return false; + break; + case VER_COND_GT: + if (!(objv.ver > v.ver)) + return false; + break; + case VER_COND_GE: + if (!(objv.ver >= v.ver)) + return false; + break; + case VER_COND_LT: + if (!(objv.ver < v.ver)) + return false; + break; + case VER_COND_LE: + if (!(objv.ver <= v.ver)) + return false; + break; + case VER_COND_TAG_EQ: + if (objv.tag.compare(v.tag) != 0) + return false; + break; + case VER_COND_TAG_NE: + if (objv.tag.compare(v.tag) == 0) + return false; + break; + } + } + + return true; +} + +static int cls_version_inc(cls_method_context_t hctx, bufferlist *in, bufferlist *out) +{ + bufferlist::iterator in_iter = in->begin(); + + cls_version_inc_op op; + try { + ::decode(op, in_iter); + } catch (buffer::error& err) { + CLS_LOG(1, "ERROR: cls_version_get(): failed to decode entry\n"); + return -EINVAL; + } + + obj_version objv; + int ret = read_version(hctx, &objv, true); + if (ret < 0) + return ret; + + if (!check_conds(op.conds, objv)) { + return -ECANCELED; + } + objv.inc(); + + ret = set_version(hctx, &objv); + if (ret < 0) + return ret; + + return 0; +} + +static int cls_version_check(cls_method_context_t hctx, bufferlist *in, bufferlist *out) +{ + bufferlist::iterator in_iter = in->begin(); + + cls_version_check_op op; + try { + ::decode(op, in_iter); + } catch (buffer::error& err) { + CLS_LOG(1, "ERROR: cls_version_get(): failed to decode entry\n"); + return -EINVAL; + } + + obj_version objv; + int ret = read_version(hctx, &objv, false); + if (ret < 0) + return ret; + CLS_LOG(20, "cls_version: read_version %s:%d", objv.tag.c_str(), (int)objv.ver); + + if (!check_conds(op.conds, objv)) { + CLS_LOG(20, "cls_version: failed condition check"); + return -ECANCELED; + } + + return 0; +} + +static int cls_version_read(cls_method_context_t hctx, bufferlist *in, bufferlist *out) +{ + obj_version objv; + + cls_version_read_ret read_ret; + int ret = read_version(hctx, &read_ret.objv, false); + if (ret < 0) + return ret; + + ::encode(read_ret, *out); + + return 0; +} + +CLS_INIT(version) +{ + CLS_LOG(1, "Loaded version class!"); + + cls_handle_t h_class; + cls_method_handle_t h_version_set; + cls_method_handle_t h_version_inc; + cls_method_handle_t h_version_inc_conds; + cls_method_handle_t h_version_read; + cls_method_handle_t h_version_check_conds; + + cls_register("version", &h_class); + + /* version */ + cls_register_cxx_method(h_class, "set", CLS_METHOD_RD | CLS_METHOD_WR, cls_version_set, &h_version_set); + cls_register_cxx_method(h_class, "inc", CLS_METHOD_RD | CLS_METHOD_WR, cls_version_inc, &h_version_inc); + cls_register_cxx_method(h_class, "inc_conds", CLS_METHOD_RD | CLS_METHOD_WR, cls_version_inc, &h_version_inc_conds); + cls_register_cxx_method(h_class, "read", CLS_METHOD_RD, cls_version_read, &h_version_read); + cls_register_cxx_method(h_class, "check_conds", CLS_METHOD_RD, cls_version_check, &h_version_check_conds); + + return; +} +