1 // -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "include/types.h"
5 #include "include/utime.h"
6 #include "objclass/objclass.h"
8 #include "cls_log_types.h"
9 #include "cls_log_ops.h"
11 #include "global/global_context.h"
12 #include "include/compat.h"
17 static string log_index_prefix = "1_";
20 static int write_log_entry(cls_method_context_t hctx, string& index, cls_log_entry& entry)
25 int ret = cls_cxx_map_set_val(hctx, index, &bl);
32 static void get_index_time_prefix(utime_t& ts, string& index)
35 snprintf(buf, sizeof(buf), "%010ld.%06ld_", (long)ts.sec(), (long)ts.usec());
37 index = log_index_prefix + buf;
40 static int read_header(cls_method_context_t hctx, cls_log_header& header)
44 int ret = cls_cxx_map_read_header(hctx, &header_bl);
48 if (header_bl.length() == 0) {
49 header = cls_log_header();
53 bufferlist::iterator iter = header_bl.begin();
55 ::decode(header, iter);
56 } catch (buffer::error& err) {
57 CLS_LOG(0, "ERROR: read_header(): failed to decode header");
63 static int write_header(cls_method_context_t hctx, cls_log_header& header)
66 ::encode(header, header_bl);
68 int ret = cls_cxx_map_write_header(hctx, &header_bl);
75 static void get_index(cls_method_context_t hctx, utime_t& ts, string& index)
77 get_index_time_prefix(ts, index);
81 cls_cxx_subop_version(hctx, &unique_id);
83 index.append(unique_id);
86 static int cls_log_add(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
88 bufferlist::iterator in_iter = in->begin();
92 ::decode(op, in_iter);
93 } catch (buffer::error& err) {
94 CLS_LOG(1, "ERROR: cls_log_add_op(): failed to decode op");
98 cls_log_header header;
100 int ret = read_header(hctx, header);
104 for (list<cls_log_entry>::iterator iter = op.entries.begin();
105 iter != op.entries.end(); ++iter) {
106 cls_log_entry& entry = *iter;
110 utime_t timestamp = entry.timestamp;
111 if (op.monotonic_inc && timestamp < header.max_time)
112 timestamp = header.max_time;
113 else if (timestamp > header.max_time)
114 header.max_time = timestamp;
116 if (entry.id.empty()) {
117 get_index(hctx, timestamp, index);
123 CLS_LOG(20, "storing entry at %s", index.c_str());
126 if (index > header.max_marker)
127 header.max_marker = index;
129 ret = write_log_entry(hctx, index, entry);
134 ret = write_header(hctx, header);
141 static int cls_log_list(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
143 bufferlist::iterator in_iter = in->begin();
147 ::decode(op, in_iter);
148 } catch (buffer::error& err) {
149 CLS_LOG(1, "ERROR: cls_log_list_op(): failed to decode op");
153 map<string, bufferlist> keys;
158 if (op.marker.empty()) {
159 get_index_time_prefix(op.from_time, from_index);
161 from_index = op.marker;
163 bool use_time_boundary = (!op.from_time.is_zero() && (op.to_time >= op.from_time));
165 if (use_time_boundary)
166 get_index_time_prefix(op.to_time, to_index);
168 #define MAX_ENTRIES 1000
169 size_t max_entries = op.max_entries;
170 if (!max_entries || max_entries > MAX_ENTRIES)
171 max_entries = MAX_ENTRIES;
173 cls_log_list_ret ret;
175 int rc = cls_cxx_map_get_vals(hctx, from_index, log_index_prefix, max_entries, &keys, &ret.truncated);
179 list<cls_log_entry>& entries = ret.entries;
180 map<string, bufferlist>::iterator iter = keys.begin();
184 for (; iter != keys.end(); ++iter) {
185 const string& index = iter->first;
187 if (use_time_boundary && index.compare(0, to_index.size(), to_index) >= 0) {
188 ret.truncated = false;
192 bufferlist& bl = iter->second;
193 bufferlist::iterator biter = bl.begin();
197 entries.push_back(e);
198 } catch (buffer::error& err) {
199 CLS_LOG(0, "ERROR: cls_log_list: could not decode entry, index=%s", index.c_str());
211 static int cls_log_trim(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
213 bufferlist::iterator in_iter = in->begin();
217 ::decode(op, in_iter);
218 } catch (buffer::error& err) {
219 CLS_LOG(0, "ERROR: cls_log_list_op(): failed to decode entry");
223 map<string, bufferlist> keys;
228 if (op.from_marker.empty()) {
229 get_index_time_prefix(op.from_time, from_index);
231 from_index = op.from_marker;
233 if (op.to_marker.empty()) {
234 get_index_time_prefix(op.to_time, to_index);
236 to_index = op.to_marker;
239 #define MAX_TRIM_ENTRIES 1000
240 size_t max_entries = MAX_TRIM_ENTRIES;
243 int rc = cls_cxx_map_get_vals(hctx, from_index, log_index_prefix, max_entries, &keys, &more);
247 map<string, bufferlist>::iterator iter = keys.begin();
249 bool removed = false;
250 for (; iter != keys.end(); ++iter) {
251 const string& index = iter->first;
253 CLS_LOG(20, "index=%s to_index=%s", index.c_str(), to_index.c_str());
255 if (index.compare(0, to_index.size(), to_index) > 0)
258 CLS_LOG(20, "removing key: index=%s", index.c_str());
260 int rc = cls_cxx_map_remove_key(hctx, index);
262 CLS_LOG(1, "ERROR: cls_cxx_map_remove_key failed rc=%d", rc);
274 static int cls_log_info(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
276 bufferlist::iterator in_iter = in->begin();
280 ::decode(op, in_iter);
281 } catch (buffer::error& err) {
282 CLS_LOG(1, "ERROR: cls_log_add_op(): failed to decode op");
286 cls_log_info_ret ret;
288 int rc = read_header(hctx, ret.header);
299 CLS_LOG(1, "Loaded log class!");
301 cls_handle_t h_class;
302 cls_method_handle_t h_log_add;
303 cls_method_handle_t h_log_list;
304 cls_method_handle_t h_log_trim;
305 cls_method_handle_t h_log_info;
307 cls_register("log", &h_class);
310 cls_register_cxx_method(h_class, "add", CLS_METHOD_RD | CLS_METHOD_WR, cls_log_add, &h_log_add);
311 cls_register_cxx_method(h_class, "list", CLS_METHOD_RD, cls_log_list, &h_log_list);
312 cls_register_cxx_method(h_class, "trim", CLS_METHOD_RD | CLS_METHOD_WR, cls_log_trim, &h_log_trim);
313 cls_register_cxx_method(h_class, "info", CLS_METHOD_RD, cls_log_info, &h_log_info);