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());
213 static int cls_log_trim(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
215 bufferlist::iterator in_iter
= in
->begin();
219 ::decode(op
, in_iter
);
220 } catch (buffer::error
& err
) {
221 CLS_LOG(0, "ERROR: cls_log_list_op(): failed to decode entry");
225 map
<string
, bufferlist
> keys
;
230 if (op
.from_marker
.empty()) {
231 get_index_time_prefix(op
.from_time
, from_index
);
233 from_index
= op
.from_marker
;
235 if (op
.to_marker
.empty()) {
236 get_index_time_prefix(op
.to_time
, to_index
);
238 to_index
= op
.to_marker
;
241 #define MAX_TRIM_ENTRIES 1000
242 size_t max_entries
= MAX_TRIM_ENTRIES
;
245 int rc
= cls_cxx_map_get_vals(hctx
, from_index
, log_index_prefix
, max_entries
, &keys
, &more
);
249 map
<string
, bufferlist
>::iterator iter
= keys
.begin();
251 bool removed
= false;
252 for (; iter
!= keys
.end(); ++iter
) {
253 const string
& index
= iter
->first
;
255 CLS_LOG(20, "index=%s to_index=%s", index
.c_str(), to_index
.c_str());
257 if (index
.compare(0, to_index
.size(), to_index
) > 0)
260 CLS_LOG(20, "removing key: index=%s", index
.c_str());
262 int rc
= cls_cxx_map_remove_key(hctx
, index
);
264 CLS_LOG(1, "ERROR: cls_cxx_map_remove_key failed rc=%d", rc
);
276 static int cls_log_info(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
278 bufferlist::iterator in_iter
= in
->begin();
282 ::decode(op
, in_iter
);
283 } catch (buffer::error
& err
) {
284 CLS_LOG(1, "ERROR: cls_log_add_op(): failed to decode op");
288 cls_log_info_ret ret
;
290 int rc
= read_header(hctx
, ret
.header
);
301 CLS_LOG(1, "Loaded log class!");
303 cls_handle_t h_class
;
304 cls_method_handle_t h_log_add
;
305 cls_method_handle_t h_log_list
;
306 cls_method_handle_t h_log_trim
;
307 cls_method_handle_t h_log_info
;
309 cls_register("log", &h_class
);
312 cls_register_cxx_method(h_class
, "add", CLS_METHOD_RD
| CLS_METHOD_WR
, cls_log_add
, &h_log_add
);
313 cls_register_cxx_method(h_class
, "list", CLS_METHOD_RD
, cls_log_list
, &h_log_list
);
314 cls_register_cxx_method(h_class
, "trim", CLS_METHOD_RD
| CLS_METHOD_WR
, cls_log_trim
, &h_log_trim
);
315 cls_register_cxx_method(h_class
, "info", CLS_METHOD_RD
, cls_log_info
, &h_log_info
);