]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
cls_log: a class to handle info sorted by timestamp
authorYehuda Sadeh <yehuda@inktank.com>
Fri, 8 Mar 2013 23:30:31 +0000 (15:30 -0800)
committerYehuda Sadeh <yehuda@inktank.com>
Wed, 8 May 2013 17:55:50 +0000 (10:55 -0700)
Signed-off-by: Yehuda Sadeh <yehuda@inktank.com>
src/Makefile.am
src/cls/log/cls_log.cc [new file with mode: 0644]
src/cls/log/cls_log_client.cc [new file with mode: 0644]
src/cls/log/cls_log_client.h [new file with mode: 0644]
src/cls/log/cls_log_ops.h [new file with mode: 0644]
src/cls/log/cls_log_types.h [new file with mode: 0644]

index 250433fc81f8f7eec364e322290391d760558345..1c3dd7f5fdf27b1e5c2d554114506fa18d598e43 100644 (file)
@@ -555,6 +555,15 @@ libcls_version_la_LDFLAGS = ${AM_LDFLAGS} -version-info 1:0:0 -export-symbols-re
 
 radoslib_LTLIBRARIES += libcls_version.la
 
+# log class
+libcls_log_la_SOURCES = cls/log/cls_log.cc
+libcls_log_la_CFLAGS = ${AM_CFLAGS}
+libcls_log_la_CXXFLAGS= ${AM_CXXFLAGS}
+libcls_log_la_LIBADD = $(PTHREAD_LIBS) $(EXTRALIBS)
+libcls_log_la_LDFLAGS = ${AM_LDFLAGS} -version-info 1:0:0 -export-symbols-regex '.*__cls_.*'
+
+radoslib_LTLIBRARIES += libcls_log.la
+
 
 if WITH_RADOSGW
 # rgw: rados gateway
@@ -582,6 +591,10 @@ libcls_version_client_a_SOURCES =  \
        cls/version/cls_version_types.cc
 noinst_LIBRARIES += libcls_version_client.a
 
+libcls_log_client_a_SOURCES =  \
+       cls/log/cls_log_client.cc
+noinst_LIBRARIES += libcls_log_client.a
+
 libcls_rgw_client_a_SOURCES =  \
        cls/rgw/cls_rgw_client.cc \
        cls/rgw/cls_rgw_types.cc \
@@ -1602,6 +1615,8 @@ noinst_HEADERS = \
        cls/version/cls_version_types.h\
        cls/version/cls_version_ops.h\
        cls/version/cls_version_client.h\
+       cls/log/cls_log_types.h\
+       cls/log/cls_log_ops.h\
        cls/rgw/cls_rgw_client.h\
        cls/rgw/cls_rgw_ops.h\
        cls/rgw/cls_rgw_types.h\
diff --git a/src/cls/log/cls_log.cc b/src/cls/log/cls_log.cc
new file mode 100644 (file)
index 0000000..fad61eb
--- /dev/null
@@ -0,0 +1,192 @@
+// -*- 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_log_types.h"
+#include "cls_log_ops.h"
+
+#include "global/global_context.h"
+
+CLS_VER(1,0)
+CLS_NAME(log)
+
+cls_handle_t h_class;
+cls_method_handle_t h_log_add;
+cls_method_handle_t h_log_list;
+cls_method_handle_t h_log_trim;
+
+static string log_index_prefix = "1_";
+
+
+static int write_log_entry(cls_method_context_t hctx, string& index, cls_log_entry& entry)
+{
+  bufferlist bl;
+  ::encode(entry, bl);
+
+  int ret = cls_cxx_map_set_val(hctx, index, &bl);
+  if (ret < 0)
+    return ret;
+
+  return 0;
+}
+
+static void get_index_time_prefix(utime_t& ts, string& index)
+{
+  char buf[32];
+  snprintf(buf, sizeof(buf), "%10ld.%10ld_", (long)ts.sec(), (long)ts.usec());
+
+  index = log_index_prefix + buf;
+}
+
+static void get_index(utime_t& ts, string& section, string& name, string& index)
+{
+  get_index_time_prefix(ts, index);
+
+  index += section + ":" + name;
+}
+
+static int cls_log_add(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
+{
+  bufferlist::iterator in_iter = in->begin();
+
+  cls_log_add_op op;
+  try {
+    ::decode(op, in_iter);
+  } catch (buffer::error& err) {
+    CLS_LOG(1, "ERROR: cls_log_add_op(): failed to decode entry\n");
+    return -EINVAL;
+  }
+
+  cls_log_entry& entry = op.entry;
+
+  string index;
+
+  get_index(entry.timestamp, entry.section, entry.name, index);
+
+  int ret = write_log_entry(hctx, index, entry);
+  if (ret < 0)
+    return ret;
+  
+  return 0;
+}
+
+static int cls_log_list(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
+{
+  bufferlist::iterator in_iter = in->begin();
+
+  cls_log_list_op op;
+  try {
+    ::decode(op, in_iter);
+  } catch (buffer::error& err) {
+    CLS_LOG(1, "ERROR: cls_log_list_op(): failed to decode entry\n");
+    return -EINVAL;
+  }
+
+  map<string, bufferlist> keys;
+
+  string index;
+
+  get_index_time_prefix(op.from_time, index);
+
+#define MAX_ENTRIES 1000
+  size_t max_entries = min(MAX_ENTRIES, op.num_entries);
+
+  int rc = cls_cxx_map_get_vals(hctx, index, log_index_prefix, max_entries + 1, &keys);
+  if (rc < 0)
+    return rc;
+
+  cls_log_list_ret ret;
+
+  list<cls_log_entry>& entries = ret.entries;
+  map<string, bufferlist>::iterator iter = keys.begin();
+
+  size_t i;
+  for (i = 0; i < max_entries && iter != keys.end(); ++i, ++iter) {
+    bufferlist& bl = iter->second;
+    bufferlist::iterator biter = bl.begin();
+    try {
+      cls_log_entry e;
+      ::decode(e, biter);
+      entries.push_back(e);
+    } catch (buffer::error& err) {
+      CLS_LOG(0, "ERROR: cls_log_list: could not decode entry, index=%s\n", index.c_str());
+    }
+  }
+
+  ret.truncated = (i < keys.size());
+
+  ::encode(ret, *out);
+
+  return 0;
+}
+
+
+static int cls_log_trim(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
+{
+  bufferlist::iterator in_iter = in->begin();
+
+  cls_log_trim_op op;
+  try {
+    ::decode(op, in_iter);
+  } catch (buffer::error& err) {
+    CLS_LOG(1, "ERROR: cls_log_list_op(): failed to decode entry\n");
+    return -EINVAL;
+  }
+
+  map<string, bufferlist> keys;
+
+  string from_index;
+  string to_index;
+
+  get_index_time_prefix(op.from_time, from_index);
+  get_index_time_prefix(op.from_time, to_index);
+
+#define MAX_TRIM_ENTRIES 1000
+  size_t max_entries = MAX_TRIM_ENTRIES;
+
+  int rc = cls_cxx_map_get_vals(hctx, index, log_index_prefix, max_entries, &keys);
+  if (rc < 0)
+    return rc;
+
+  map<string, bufferlist>::iterator iter = keys.begin();
+
+  size_t i;
+  for (i = 0; i < max_entries && iter != keys.end(); ++i, ++iter) {
+    const string& index = iter->first;
+
+    if (index >= to_index)
+      break;
+
+    int rc = cls_cxx_map_remove_key(hctx, index);
+    if (rc < 0) {
+      CLS_LOG(1, "ERROR: cls_log_trim_op(): failed to decode entry\n");
+      return -EINVAL;
+    }
+  }
+
+  return 0;
+}
+
+void __cls_init()
+{
+  CLS_LOG(1, "Loaded log class!");
+
+  cls_register("log", &h_class);
+
+  /* log */
+  cls_register_cxx_method(h_class, "log_add", CLS_METHOD_RD | CLS_METHOD_WR, cls_log_add, &h_log_add);
+  cls_register_cxx_method(h_class, "log_list", CLS_METHOD_RD, cls_log_list, &h_log_list);
+  cls_register_cxx_method(h_class, "log_trim", CLS_METHOD_RD | CLS_METHOD_WR, cls_log_trim, &h_log_trim);
+
+  return;
+}
+
diff --git a/src/cls/log/cls_log_client.cc b/src/cls/log/cls_log_client.cc
new file mode 100644 (file)
index 0000000..0f1854f
--- /dev/null
@@ -0,0 +1,62 @@
+#include <errno.h>
+
+#include "include/types.h"
+#include "cls/log/cls_log_ops.h"
+#include "include/rados/librados.hpp"
+
+
+using namespace librados;
+
+
+
+
+void cls_log_add(librados::ObjectWriteOperation& op, cls_log_entry& entry)
+{
+  bufferlist in;
+  cls_log_add_op call;
+  call.entry = entry;
+  ::encode(call, in);
+  op.exec("log", "add", in);
+}
+
+void cls_log_trim(librados::ObjectWriteOperation& op, utime_t& from, utime_t& to)
+{
+  bufferlist in;
+  cls_log_trim_op call;
+  call.from_time = from;
+  call.to_time = to;
+  ::encode(call, in);
+  op.exec("log", "trim", in);
+}
+
+class LogListCtx : public ObjectOperationCompletion {
+  list<cls_log_entry> *entries;
+  bool *truncated;
+public:
+  LogListCtx(list<cls_log_entry> *_entries, bool *_truncated) :
+                                      entries(_entries), truncated(_truncated) {}
+  void handle_completion(int r, bufferlist& outbl) {
+    if (r >= 0) {
+      cls_log_list_ret ret;
+      try {
+        bufferlist::iterator iter = outbl.begin();
+        ::decode(ret, iter);
+       *entries = ret.entries;
+        *truncated = ret.truncated;
+      } catch (buffer::error& err) {
+        // nothing we can do about it atm
+      }
+    }
+  }
+};
+
+void cls_log_list(librados::ObjectReadOperation& op, utime_t& from, int max,
+                  list<cls_log_entry>& entries, bool *truncated)
+{
+  bufferlist inbl;
+  cls_log_list_op call;
+  call.from_time = from;
+  call.num_entries = max;
+  op.exec("log", "list", inbl, new LogListCtx(&entries, truncated));
+}
+
diff --git a/src/cls/log/cls_log_client.h b/src/cls/log/cls_log_client.h
new file mode 100644 (file)
index 0000000..b2543c0
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef CEPH_CLS_LOG_CLIENT_H
+#define CEPH_CLS_LOG_CLIENT_H
+
+#include "include/types.h"
+#include "include/rados/librados.hpp"
+
+/*
+ * log objclass
+ */
+
+void cls_log_add(librados::ObjectWriteOperation& op, cls_log_entry& entry);
+
+void cls_log_list(librados::ObjectReadOperation& op, utime_t& from, int max, list<cls_log_entry>& entries);
+
+void cls_log_trim(librados::ObjectWriteOperation& op, utime_t& from, utime_t& to);
+
+#endif
diff --git a/src/cls/log/cls_log_ops.h b/src/cls/log/cls_log_ops.h
new file mode 100644 (file)
index 0000000..28a7dc8
--- /dev/null
@@ -0,0 +1,95 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#ifndef CEPH_CLS_LOG_OPS_H
+#define CEPH_CLS_LOG_OPS_H
+
+#include "include/types.h"
+#include "cls_log_types.h"
+
+struct cls_log_add_op {
+  cls_log_entry entry;
+
+  cls_log_add_op() {}
+
+  void encode(bufferlist& bl) const {
+    ENCODE_START(1, 1, bl);
+    ::encode(entry, bl);
+    ENCODE_FINISH(bl);
+  }
+
+  void decode(bufferlist::iterator& bl) {
+    DECODE_START(1, bl);
+    ::decode(entry, bl);
+    DECODE_FINISH(bl);
+  }
+};
+WRITE_CLASS_ENCODER(cls_log_add_op)
+
+struct cls_log_list_op {
+  utime_t from_time;
+  int num_entries;
+
+  cls_log_list_op() {}
+
+  void encode(bufferlist& bl) const {
+    ENCODE_START(1, 1, bl);
+    ::encode(from_time, bl);
+    ::encode(num_entries, bl);
+    ENCODE_FINISH(bl);
+  }
+
+  void decode(bufferlist::iterator& bl) {
+    DECODE_START(1, bl);
+    ::decode(from_time, bl);
+    ::decode(num_entries, bl);
+    DECODE_FINISH(bl);
+  }
+};
+WRITE_CLASS_ENCODER(cls_log_list_op)
+
+struct cls_log_list_ret {
+  list<cls_log_entry> entries;
+  bool truncated;
+
+  cls_log_list_ret() : truncated(false) {}
+
+  void encode(bufferlist& bl) const {
+    ENCODE_START(1, 1, bl);
+    ::encode(entries, bl);
+    ::encode(truncated, bl);
+    ENCODE_FINISH(bl);
+  }
+
+  void decode(bufferlist::iterator& bl) {
+    DECODE_START(1, bl);
+    ::decode(entries, bl);
+    ::decode(truncated, bl);
+    DECODE_FINISH(bl);
+  }
+};
+WRITE_CLASS_ENCODER(cls_log_list_ret)
+
+struct cls_log_trim_op {
+  utime_t from_time;
+  utime_t to_time;
+
+  cls_log_trim_op() {}
+
+  void encode(bufferlist& bl) const {
+    ENCODE_START(1, 1, bl);
+    ::encode(from_time, bl);
+    ::encode(to_time, bl);
+    ENCODE_FINISH(bl);
+  }
+
+  void decode(bufferlist::iterator& bl) {
+    DECODE_START(1, bl);
+    ::decode(from_time, bl);
+    ::decode(to_time, bl);
+    DECODE_FINISH(bl);
+  }
+};
+WRITE_CLASS_ENCODER(cls_log_trim_op)
+
+#endif
diff --git a/src/cls/log/cls_log_types.h b/src/cls/log/cls_log_types.h
new file mode 100644 (file)
index 0000000..06684d9
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef CEPH_CLS_LOG_TYPES_H
+#define CEPH_CLS_LOG_TYPES_H
+
+#include "include/encoding.h"
+#include "include/types.h"
+
+#include "include/utime.h"
+
+class JSONObj;
+
+
+struct cls_log_entry {
+  string section;
+  string name;
+  utime_t timestamp;
+  bufferlist data;
+
+  cls_log_entry() {}
+
+  void encode(bufferlist& bl) const {
+    ENCODE_START(1, 1, bl);
+    ::encode(section, bl);
+    ::encode(name, bl);
+    ::encode(timestamp, bl);
+    ::encode(data, bl);
+    ENCODE_FINISH(bl);
+  }
+
+  void decode(bufferlist::iterator& bl) {
+    DECODE_START(1, bl);
+    ::decode(section, bl);
+    ::decode(name, bl);
+    ::decode(timestamp, bl);
+    ::decode(data, bl);
+    DECODE_FINISH(bl);
+  }
+
+  void dump(Formatter *f) const;
+  void decode_json(JSONObj *obj);
+};
+WRITE_CLASS_ENCODER(cls_log_entry)
+
+
+#endif
+
+