1 // -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
6 #include "objclass/objclass.h"
8 #include "cls_statelog_ops.h"
14 static string statelog_index_by_client_prefix
= "1_";
15 static string statelog_index_by_object_prefix
= "2_";
18 static int write_statelog_entry(cls_method_context_t hctx
, const string
& index
, const cls_statelog_entry
& entry
)
23 int ret
= cls_cxx_map_set_val(hctx
, index
, &bl
);
30 static void get_index_by_client(const string
& client_id
, const string
& op_id
, string
& index
)
32 index
= statelog_index_by_client_prefix
;
33 index
.append(client_id
+ "_" + op_id
);
36 static void get_index_by_client(cls_statelog_entry
& entry
, string
& index
)
38 get_index_by_client(entry
.client_id
, entry
.op_id
, index
);
41 static void get_index_by_object(const string
& object
, const string
& op_id
, string
& index
)
44 snprintf(buf
, sizeof(buf
), "%d_", (int)object
.size());
46 index
= statelog_index_by_object_prefix
+ buf
; /* append object length to ensure uniqueness */
47 index
.append(object
+ "_" + op_id
);
50 static void get_index_by_object(cls_statelog_entry
& entry
, string
& index
)
52 get_index_by_object(entry
.object
, entry
.op_id
, index
);
55 static int get_existing_entry(cls_method_context_t hctx
, const string
& client_id
,
56 const string
& op_id
, const string
& object
,
57 cls_statelog_entry
& entry
)
59 if ((object
.empty() && client_id
.empty()) || op_id
.empty()) {
64 if (!object
.empty()) {
65 get_index_by_object(object
, op_id
, obj_index
);
67 get_index_by_client(client_id
, op_id
, obj_index
);
71 int rc
= cls_cxx_map_get_val(hctx
, obj_index
, &bl
);
73 CLS_LOG(0, "could not find entry %s", obj_index
.c_str());
77 bufferlist::iterator iter
= bl
.begin();
78 ::decode(entry
, iter
);
79 } catch (buffer::error
& err
) {
80 CLS_LOG(0, "ERROR: failed to decode entry %s", obj_index
.c_str());
84 if ((!object
.empty() && entry
.object
!= object
) ||
85 (!client_id
.empty() && entry
.client_id
!= client_id
)){
86 /* ouch, we were passed inconsistent client_id / object */
87 CLS_LOG(0, "data mismatch: object=%s client_id=%s entry: object=%s client_id=%s",
88 object
.c_str(), client_id
.c_str(), entry
.object
.c_str(), entry
.client_id
.c_str());
95 static int cls_statelog_add(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
97 bufferlist::iterator in_iter
= in
->begin();
99 cls_statelog_add_op op
;
101 ::decode(op
, in_iter
);
102 } catch (buffer::error
& err
) {
103 CLS_LOG(1, "ERROR: cls_statelog_add_op(): failed to decode op");
107 for (list
<cls_statelog_entry
>::iterator iter
= op
.entries
.begin();
108 iter
!= op
.entries
.end(); ++iter
) {
109 cls_statelog_entry
& entry
= *iter
;
111 string index_by_client
;
113 get_index_by_client(entry
, index_by_client
);
115 CLS_LOG(0, "storing entry by client/op at %s", index_by_client
.c_str());
117 int ret
= write_statelog_entry(hctx
, index_by_client
, entry
);
123 get_index_by_object(entry
, index_by_obj
);
125 CLS_LOG(0, "storing entry by object at %s", index_by_obj
.c_str());
126 ret
= write_statelog_entry(hctx
, index_by_obj
, entry
);
135 static int cls_statelog_list(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
137 bufferlist::iterator in_iter
= in
->begin();
139 cls_statelog_list_op op
;
141 ::decode(op
, in_iter
);
142 } catch (buffer::error
& err
) {
143 CLS_LOG(1, "ERROR: cls_statelog_list_op(): failed to decode op");
147 map
<string
, bufferlist
> keys
;
152 if (!op
.client_id
.empty()) {
153 get_index_by_client(op
.client_id
, op
.op_id
, match_prefix
);
154 } else if (!op
.object
.empty()) {
155 get_index_by_object(op
.object
, op
.op_id
, match_prefix
);
157 match_prefix
= statelog_index_by_object_prefix
;
160 if (op
.marker
.empty()) {
161 from_index
= match_prefix
;
163 from_index
= op
.marker
;
166 #define MAX_ENTRIES 1000
167 size_t max_entries
= op
.max_entries
;
168 if (!max_entries
|| max_entries
> MAX_ENTRIES
)
169 max_entries
= MAX_ENTRIES
;
171 cls_statelog_list_ret ret
;
173 int rc
= cls_cxx_map_get_vals(hctx
, from_index
, match_prefix
, max_entries
, &keys
, &ret
.truncated
);
177 CLS_LOG(20, "from_index=%s match_prefix=%s", from_index
.c_str(), match_prefix
.c_str());
179 list
<cls_statelog_entry
>& entries
= ret
.entries
;
180 map
<string
, bufferlist
>::iterator iter
= keys
.begin();
184 for (; iter
!= keys
.end(); ++iter
) {
185 const string
& index
= iter
->first
;
188 bufferlist
& bl
= iter
->second
;
189 bufferlist::iterator biter
= bl
.begin();
191 cls_statelog_entry e
;
193 entries
.push_back(e
);
194 } catch (buffer::error
& err
) {
195 CLS_LOG(0, "ERROR: cls_statelog_list: could not decode entry, index=%s", index
.c_str());
208 static int cls_statelog_remove(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
210 bufferlist::iterator in_iter
= in
->begin();
212 cls_statelog_remove_op op
;
214 ::decode(op
, in_iter
);
215 } catch (buffer::error
& err
) {
216 CLS_LOG(1, "ERROR: cls_statelog_remove_op(): failed to decode op");
220 cls_statelog_entry entry
;
222 int rc
= get_existing_entry(hctx
, op
.client_id
, op
.op_id
, op
.object
, entry
);
227 get_index_by_object(entry
.object
, entry
.op_id
, obj_index
);
229 rc
= cls_cxx_map_remove_key(hctx
, obj_index
);
231 CLS_LOG(0, "ERROR: failed to remove key");
236 get_index_by_client(entry
.client_id
, entry
.op_id
, client_index
);
238 rc
= cls_cxx_map_remove_key(hctx
, client_index
);
240 CLS_LOG(0, "ERROR: failed to remove key");
247 static int cls_statelog_check_state(cls_method_context_t hctx
, bufferlist
*in
, bufferlist
*out
)
249 bufferlist::iterator in_iter
= in
->begin();
251 cls_statelog_check_state_op op
;
253 ::decode(op
, in_iter
);
254 } catch (buffer::error
& err
) {
255 CLS_LOG(1, "ERROR: cls_statelog_check_state_op(): failed to decode op");
259 if (op
.object
.empty() || op
.op_id
.empty()) {
260 CLS_LOG(0, "object name or op id not specified");
265 cls_statelog_entry entry
;
267 int rc
= get_existing_entry(hctx
, op
.client_id
, op
.op_id
, op
.object
, entry
);
271 if (entry
.state
!= op
.state
)
279 CLS_LOG(1, "Loaded log class!");
281 cls_handle_t h_class
;
282 cls_method_handle_t h_statelog_add
;
283 cls_method_handle_t h_statelog_list
;
284 cls_method_handle_t h_statelog_remove
;
285 cls_method_handle_t h_statelog_check_state
;
287 cls_register("statelog", &h_class
);
290 cls_register_cxx_method(h_class
, "add", CLS_METHOD_RD
| CLS_METHOD_WR
, cls_statelog_add
, &h_statelog_add
);
291 cls_register_cxx_method(h_class
, "list", CLS_METHOD_RD
, cls_statelog_list
, &h_statelog_list
);
292 cls_register_cxx_method(h_class
, "remove", CLS_METHOD_RD
| CLS_METHOD_WR
, cls_statelog_remove
, &h_statelog_remove
);
293 cls_register_cxx_method(h_class
, "check_state", CLS_METHOD_RD
, cls_statelog_check_state
, &h_statelog_check_state
);