]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: new user objclass
authorYehuda Sadeh <yehuda@inktank.com>
Fri, 6 Dec 2013 15:32:08 +0000 (07:32 -0800)
committerYehuda Sadeh <yehuda@inktank.com>
Fri, 24 Jan 2014 18:28:41 +0000 (10:28 -0800)
Signed-off-by: Yehuda Sadeh <yehuda@inktank.com>
src/cls/Makefile.am
src/cls/user/cls_user.cc [new file with mode: 0644]
src/cls/user/cls_user_client.cc [new file with mode: 0644]
src/cls/user/cls_user_client.h [new file with mode: 0644]
src/cls/user/cls_user_ops.h [new file with mode: 0644]
src/cls/user/cls_user_types.h [new file with mode: 0644]

index 2d3d43cb1e364aaa94252b24e875076889ac2888..b88b5cc33621c0e2f10c5da29fd8be9d9cf526df 100644 (file)
@@ -43,6 +43,11 @@ libcls_replica_log_la_LIBADD = $(PTHREAD_LIBS) $(EXTRALIBS)
 libcls_replica_log_la_LDFLAGS = ${AM_LDFLAGS} -version-info 1:0:0 -export-symbols-regex '.*__cls_.*'
 radoslib_LTLIBRARIES += libcls_replica_log.la
 
+libcls_user_la_SOURCES = cls/user/cls_user.cc
+libcls_user_la_LIBADD = $(PTHREAD_LIBS) $(EXTRALIBS)
+libcls_user_la_LDFLAGS = ${AM_LDFLAGS} -version-info 1:0:0 -export-symbols-regex '.*__cls_.*'
+radoslib_LTLIBRARIES += libcls_user.la
+
 libcls_rgw_la_SOURCES = \
        cls/rgw/cls_rgw.cc \
        cls/rgw/cls_rgw_ops.cc \
@@ -95,6 +100,8 @@ DENCODER_DEPS += libcls_rgw_client.la
 libcls_rbd_client_la_SOURCES = cls/rbd/cls_rbd_client.cc
 noinst_LTLIBRARIES += libcls_rbd_client.la
 
+libcls_user_client_a_SOURCES = cls/user/cls_user_client.cc
+noinst_LIBRARIES += libcls_user_client.a
 
 noinst_HEADERS += \
        cls/lock/cls_lock_types.h \
@@ -118,5 +125,8 @@ noinst_HEADERS += \
        cls/replica_log/cls_replica_log_client.h \
        cls/rgw/cls_rgw_client.h \
        cls/rgw/cls_rgw_ops.h \
-       cls/rgw/cls_rgw_types.h
+       cls/rgw/cls_rgw_types.h \
+       cls/user/cls_user_client.h \
+       cls/user/cls_user_ops.h \
+       cls/user/cls_user_types.h
 
diff --git a/src/cls/user/cls_user.cc b/src/cls/user/cls_user.cc
new file mode 100644 (file)
index 0000000..4f9446c
--- /dev/null
@@ -0,0 +1,211 @@
+// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include <iostream>
+
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "include/types.h"
+#include "include/utime.h"
+#include "objclass/objclass.h"
+
+#include "cls_user_types.h"
+#include "cls_user_ops.h"
+
+CLS_VER(1,0)
+CLS_NAME(user)
+
+cls_handle_t h_class;
+cls_method_handle_t h_user_set_buckets_info;
+cls_method_handle_t h_user_remove_bucket;
+cls_method_handle_t h_user_list_buckets;
+
+static int write_entry(cls_method_context_t hctx, const string& key, const cls_user_bucket_entry& entry)
+{
+  bufferlist bl;
+  ::encode(entry, bl);
+
+  int ret = cls_cxx_map_set_val(hctx, key, &bl);
+  if (ret < 0)
+    return ret;
+
+  return 0;
+}
+
+static int remove_entry(cls_method_context_t hctx, const string& key)
+{
+  int ret = cls_cxx_map_remove_key(hctx, key);
+  if (ret < 0)
+    return ret;
+
+  return 0;
+}
+
+static void get_key_by_bucket_name(const string& bucket_name, string *key)
+{
+  *key = bucket_name;
+}
+
+static int get_existing_bucket_entry(cls_method_context_t hctx, const string& bucket_name,
+                                     cls_user_bucket_entry& entry)
+{
+  if (bucket_name.empty()) {
+    return -EINVAL;
+  }
+
+  string key;
+  get_key_by_bucket_name(bucket_name, &key);
+
+  bufferlist bl;
+  int rc = cls_cxx_map_get_val(hctx, key, &bl);
+  if (rc < 0) {
+    CLS_LOG(10, "could not read entry %s", key.c_str());
+    return rc;
+  }
+  try {
+    bufferlist::iterator iter = bl.begin();
+    ::decode(entry, iter);
+  } catch (buffer::error& err) {
+    CLS_LOG(0, "ERROR: failed to decode entry %s", key.c_str());
+    return -EIO;
+  }
+
+  return 0;
+}
+
+static int cls_user_set_buckets_info(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
+{
+  bufferlist::iterator in_iter = in->begin();
+
+  cls_user_set_buckets_op op;
+  try {
+    ::decode(op, in_iter);
+  } catch (buffer::error& err) {
+    CLS_LOG(1, "ERROR: cls_user_add_op(): failed to decode op");
+    return -EINVAL;
+  }
+
+  for (list<cls_user_bucket_entry>::iterator iter = op.entries.begin();
+       iter != op.entries.end(); ++iter) {
+    cls_user_bucket_entry& entry = *iter;
+
+    string key;
+
+    get_key_by_bucket_name(entry.bucket.name, &key);
+
+    CLS_LOG(0, "storing entry by client/op at %s", key.c_str());
+
+    int ret = write_entry(hctx, key, entry);
+    if (ret < 0)
+      return ret;
+  }
+  
+  return 0;
+}
+
+static int cls_user_remove_bucket(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
+{
+  bufferlist::iterator in_iter = in->begin();
+
+  cls_user_remove_bucket_op op;
+  try {
+    ::decode(op, in_iter);
+  } catch (buffer::error& err) {
+    CLS_LOG(1, "ERROR: cls_user_add_op(): failed to decode op");
+    return -EINVAL;
+  }
+
+  string key;
+
+  get_key_by_bucket_name(op.bucket.name, &key);
+
+  CLS_LOG(20, "removing entry at %s", key.c_str());
+
+  int ret = remove_entry(hctx, key);
+  if (ret < 0)
+    return ret;
+  
+  return 0;
+}
+
+static int cls_user_list_buckets(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
+{
+  bufferlist::iterator in_iter = in->begin();
+
+  cls_user_list_buckets_op op;
+  try {
+    ::decode(op, in_iter);
+  } catch (buffer::error& err) {
+    CLS_LOG(1, "ERROR: cls_user_list_op(): failed to decode op");
+    return -EINVAL;
+  }
+
+  map<string, bufferlist> keys;
+
+  string from_index = op.marker;
+
+#define MAX_ENTRIES 1000
+  size_t max_entries = op.max_entries;
+  if (!max_entries || max_entries > MAX_ENTRIES)
+    max_entries = MAX_ENTRIES;
+
+  string match_prefix;
+
+  int rc = cls_cxx_map_get_vals(hctx, from_index, match_prefix, max_entries + 1, &keys);
+  if (rc < 0)
+    return rc;
+
+  CLS_LOG(20, "from_index=%s match_prefix=%s", from_index.c_str(), match_prefix.c_str());
+  cls_user_list_buckets_ret ret;
+
+  list<cls_user_bucket_entry>& entries = ret.entries;
+  map<string, bufferlist>::iterator iter = keys.begin();
+
+  bool done = false;
+  string marker;
+
+  size_t i;
+  for (i = 0; i < max_entries && iter != keys.end(); ++i, ++iter) {
+    const string& index = iter->first;
+    marker = index;
+
+    bufferlist& bl = iter->second;
+    bufferlist::iterator biter = bl.begin();
+    try {
+      cls_user_bucket_entry e;
+      ::decode(e, biter);
+      entries.push_back(e);
+    } catch (buffer::error& err) {
+      CLS_LOG(0, "ERROR: cls_user_list: could not decode entry, index=%s", index.c_str());
+    }
+  }
+
+  if (iter == keys.end())
+    done = true;
+  else
+    ret.marker = marker;
+
+  ret.truncated = !done;
+
+  ::encode(ret, *out);
+
+  return 0;
+}
+
+void __cls_init()
+{
+  CLS_LOG(1, "Loaded user class!");
+
+  cls_register("user", &h_class);
+
+  /* log */
+  cls_register_cxx_method(h_class, "set_buckets_info", CLS_METHOD_RD | CLS_METHOD_WR,
+                          cls_user_set_buckets_info, &h_user_set_buckets_info);
+  cls_register_cxx_method(h_class, "remove_bucket", CLS_METHOD_RD | CLS_METHOD_WR, cls_user_remove_bucket, &h_user_remove_bucket);
+  cls_register_cxx_method(h_class, "list_buckets", CLS_METHOD_RD, cls_user_list_buckets, &h_user_list_buckets);
+
+  return;
+}
+
diff --git a/src/cls/user/cls_user_client.cc b/src/cls/user/cls_user_client.cc
new file mode 100644 (file)
index 0000000..2b1c134
--- /dev/null
@@ -0,0 +1,72 @@
+// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include <errno.h>
+
+#include "include/types.h"
+#include "cls/user/cls_user_ops.h"
+#include "include/rados/librados.hpp"
+
+
+using namespace librados;
+
+
+void cls_user_set_buckets(librados::ObjectWriteOperation& op, list<cls_user_bucket_entry>& entries)
+{
+  bufferlist in;
+  cls_user_set_buckets_op call;
+  call.entries = entries;
+  ::encode(call, in);
+  op.exec("user", "set_buckets_info", in);
+}
+
+void cls_user_remove_bucket(librados::ObjectWriteOperation& op, const cls_user_bucket& bucket)
+{
+  bufferlist in;
+  cls_user_remove_bucket_op call;
+  call.bucket = bucket;
+  ::encode(call, in);
+  op.exec("user", "remove_bucket", in);
+}
+
+class ClsUserListCtx : public ObjectOperationCompletion {
+  list<cls_user_bucket_entry> *entries;
+  string *marker;
+  bool *truncated;
+public:
+  ClsUserListCtx(list<cls_user_bucket_entry> *_entries, string *_marker, bool *_truncated) :
+                                      entries(_entries), marker(_marker), truncated(_truncated) {}
+  void handle_completion(int r, bufferlist& outbl) {
+    if (r >= 0) {
+      cls_user_list_buckets_ret ret;
+      try {
+        bufferlist::iterator iter = outbl.begin();
+        ::decode(ret, iter);
+        if (entries)
+         *entries = ret.entries;
+        if (truncated)
+          *truncated = ret.truncated;
+        if (marker)
+          *marker = ret.marker;
+      } catch (buffer::error& err) {
+        // nothing we can do about it atm
+      }
+    }
+  }
+};
+
+void cls_user_bucket_list(librados::ObjectReadOperation& op,
+                       const string& in_marker, int max_entries, list<cls_user_bucket_entry>& entries,
+                       string *out_marker, bool *truncated)
+{
+  bufferlist inbl;
+  cls_user_list_buckets_op call;
+  call.marker = in_marker;
+  call.max_entries = max_entries;
+
+  ::encode(call, inbl);
+
+  op.exec("user", "list_buckets", inbl, new ClsUserListCtx(&entries, out_marker, truncated));
+}
+
+
diff --git a/src/cls/user/cls_user_client.h b/src/cls/user/cls_user_client.h
new file mode 100644 (file)
index 0000000..0f65875
--- /dev/null
@@ -0,0 +1,22 @@
+// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef CEPH_CLS_USER_CLIENT_H
+#define CEPH_CLS_USER_CLIENT_H
+
+#include "include/types.h"
+#include "include/rados/librados.hpp"
+#include "cls_user_types.h"
+
+/*
+ * user objclass
+ */
+
+void cls_user_set_buckets(librados::ObjectWriteOperation& op, list<cls_user_bucket_entry>& entries);
+void cls_user_remove_bucket(librados::ObjectWriteOperation& op,  const cls_user_bucket& bucket);
+void cls_user_bucket_list(librados::ObjectReadOperation& op,
+                       const string& in_marker, int max_entries,
+                       list<cls_user_bucket_entry>& entries,
+                       string *out_marker, bool *truncated);
+
+#endif
diff --git a/src/cls/user/cls_user_ops.h b/src/cls/user/cls_user_ops.h
new file mode 100644 (file)
index 0000000..a142d4d
--- /dev/null
@@ -0,0 +1,97 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef CEPH_CLS_USER_OPS_H
+#define CEPH_CLS_USER_OPS_H
+
+#include "include/types.h"
+#include "cls_user_types.h"
+
+struct cls_user_set_buckets_op {
+  list<cls_user_bucket_entry> entries;
+
+  cls_user_set_buckets_op() {}
+
+  void encode(bufferlist& bl) const {
+    ENCODE_START(1, 1, bl);
+    ::encode(entries, bl);
+    ENCODE_FINISH(bl);
+  }
+
+  void decode(bufferlist::iterator& bl) {
+    DECODE_START(1, bl);
+    ::decode(entries, bl);
+    DECODE_FINISH(bl);
+  }
+};
+WRITE_CLASS_ENCODER(cls_user_set_buckets_op)
+
+struct cls_user_remove_bucket_op {
+  cls_user_bucket bucket;
+
+  cls_user_remove_bucket_op() {}
+
+  void encode(bufferlist& bl) const {
+    ENCODE_START(1, 1, bl);
+    ::encode(bucket, bl);
+    ENCODE_FINISH(bl);
+  }
+
+  void decode(bufferlist::iterator& bl) {
+    DECODE_START(1, bl);
+    ::decode(bucket, bl);
+    DECODE_FINISH(bl);
+  }
+};
+WRITE_CLASS_ENCODER(cls_user_remove_bucket_op)
+
+struct cls_user_list_buckets_op {
+  string marker;
+  int max_entries; /* upperbound to returned num of entries
+                      might return less than that and still be truncated */
+
+  cls_user_list_buckets_op() {}
+
+  void encode(bufferlist& bl) const {
+    ENCODE_START(1, 1, bl);
+    ::encode(marker, bl);
+    ::encode(max_entries, bl);
+    ENCODE_FINISH(bl);
+  }
+
+  void decode(bufferlist::iterator& bl) {
+    DECODE_START(1, bl);
+    ::decode(marker, bl);
+    ::decode(max_entries, bl);
+    DECODE_FINISH(bl);
+  }
+};
+WRITE_CLASS_ENCODER(cls_user_list_buckets_op)
+
+struct cls_user_list_buckets_ret {
+  list<cls_user_bucket_entry> entries;
+  string marker;
+  bool truncated;
+
+  cls_user_list_buckets_ret() : truncated(false) {}
+
+  void encode(bufferlist& bl) const {
+    ENCODE_START(1, 1, bl);
+    ::encode(entries, bl);
+    ::encode(marker, bl);
+    ::encode(truncated, bl);
+    ENCODE_FINISH(bl);
+  }
+
+  void decode(bufferlist::iterator& bl) {
+    DECODE_START(1, bl);
+    ::decode(entries, bl);
+    ::decode(marker, bl);
+    ::decode(truncated, bl);
+    DECODE_FINISH(bl);
+  }
+};
+WRITE_CLASS_ENCODER(cls_user_list_buckets_ret)
+
+
+#endif
diff --git a/src/cls/user/cls_user_types.h b/src/cls/user/cls_user_types.h
new file mode 100644 (file)
index 0000000..f4f0c14
--- /dev/null
@@ -0,0 +1,111 @@
+// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef CEPH_CLS_USER_TYPES_H
+#define CEPH_CLS_USER_TYPES_H
+
+#include "include/encoding.h"
+#include "include/types.h"
+#include "include/utime.h"
+
+/*
+ * this needs to be compatible with with rgw_bucket, as it replaces it
+ */
+struct cls_user_bucket {
+  std::string name;
+  std::string data_pool;
+  std::string index_pool;
+  std::string marker;
+  std::string bucket_id;
+
+  void encode(bufferlist& bl) const {
+     ENCODE_START(6, 3, bl);
+    ::encode(name, bl);
+    ::encode(data_pool, bl);
+    ::encode(marker, bl);
+    ::encode(bucket_id, bl);
+    ::encode(index_pool, bl);
+    ENCODE_FINISH(bl);
+  }
+  void decode(bufferlist::iterator& bl) {
+    DECODE_START_LEGACY_COMPAT_LEN(6, 3, 3, bl);
+    ::decode(name, bl);
+    ::decode(data_pool, bl);
+    if (struct_v >= 2) {
+      ::decode(marker, bl);
+      if (struct_v <= 3) {
+        uint64_t id;
+        ::decode(id, bl);
+        char buf[16];
+        snprintf(buf, sizeof(buf), "%llu", (long long)id);
+        bucket_id = buf;
+      } else {
+        ::decode(bucket_id, bl);
+      }
+    }
+    if (struct_v >= 5) {
+      ::decode(index_pool, bl);
+    } else {
+      index_pool = data_pool;
+    }
+    DECODE_FINISH(bl);
+  }
+
+  bool operator<(const cls_user_bucket& b) const {
+    return name.compare(b.name) < 0;
+  }
+};
+WRITE_CLASS_ENCODER(cls_user_bucket)
+
+/*
+ * this structure overrides RGWBucketEnt
+ */
+struct cls_user_bucket_entry {
+  cls_user_bucket bucket;
+  size_t size;
+  size_t size_rounded;
+  time_t creation_time;
+  uint64_t count;
+
+  cls_user_bucket_entry() : size(0), size_rounded(0), creation_time(0), count(0) {}
+
+  void encode(bufferlist& bl) const {
+    ENCODE_START(5, 5, bl);
+    uint64_t s = size;
+    __u32 mt = creation_time;
+    string empty_str;  // originally had the bucket name here, but we encode bucket later
+    ::encode(empty_str, bl);
+    ::encode(s, bl);
+    ::encode(mt, bl);
+    ::encode(count, bl);
+    ::encode(bucket, bl);
+    s = size_rounded;
+    ::encode(s, bl);
+    ENCODE_FINISH(bl);
+  }
+  void decode(bufferlist::iterator& bl) {
+    DECODE_START_LEGACY_COMPAT_LEN(5, 5, 5, bl);
+    __u32 mt;
+    uint64_t s;
+    string empty_str;  // backward compatibility
+    ::decode(empty_str, bl);
+    ::decode(s, bl);
+    ::decode(mt, bl);
+    size = s;
+    creation_time = mt;
+    if (struct_v >= 2)
+      ::decode(count, bl);
+    if (struct_v >= 3)
+      ::decode(bucket, bl);
+    if (struct_v >= 4)
+      ::decode(s, bl);
+    size_rounded = s;
+    DECODE_FINISH(bl);
+  }
+};
+WRITE_CLASS_ENCODER(cls_user_bucket_entry)
+
+
+#endif
+
+