2 * 2012+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
16 #include <sys/types.h>
18 #include <sys/socket.h>
31 #include "elliptics/packet.h"
32 #include "elliptics/interface.h"
37 #include <smack/smack.h>
39 #if SMACK_KEY_SIZE != DNET_ID_SIZE
40 #error "SMACK_KEY_SIZE does not match DNET_ID_SIZE"
44 #define __unused __attribute__ ((unused))
52 struct eblob_backend
*meta
;
54 struct smack_init_ctl ictl
;
55 struct smack_ctl
*smack
;
58 static inline void smack_setup_idx(struct index
*idx
, unsigned char *id
)
60 memcpy(idx
->id
, id
, SMACK_KEY_SIZE
);
64 static int smack_backend_lookup_raw(struct smack_backend
*s
, struct index
*idx
, void *state
, struct dnet_cmd
*cmd
)
69 err
= smack_lookup(s
->smack
, idx
, &path
);
73 fd
= open(path
, O_RDONLY
| O_CLOEXEC
);
76 dnet_backend_log(DNET_LOG_ERROR
, "%s: SMACK: %s: lookup-open: size: %llu: %s %d.\n",
77 dnet_dump_id_str(idx
->id
), path
,
78 (unsigned long long)idx
->data_size
,
83 err
= dnet_send_file_info(state
, cmd
, fd
, 0, idx
->data_size
);
87 dnet_backend_log(DNET_LOG_INFO
, "%s: SMACK: %s: lookup: size: %llu.\n",
88 dnet_dump_id(&cmd
->id
), path
, (unsigned long long)idx
->data_size
);
98 static int smack_backend_lookup(struct smack_backend
*s
, void *state
, struct dnet_cmd
*cmd
)
102 smack_setup_idx(&idx
, cmd
->id
.id
);
103 return smack_backend_lookup_raw(s
, &idx
, state
, cmd
);
106 static int smack_backend_write(struct smack_backend
*s
, void *state
, struct dnet_cmd
*cmd
, void *data
)
108 struct dnet_node
*n
= dnet_get_node_from_state(state
);
111 struct dnet_io_attr
*io
= data
;
112 struct dnet_file_info
*info
;
113 struct dnet_addr_attr
*a
;
115 dnet_convert_io_attr(io
);
117 data
+= sizeof(struct dnet_io_attr
);
119 smack_setup_idx(&idx
, io
->id
);
120 idx
.data_size
= io
->size
;
122 err
= smack_write(s
->smack
, &idx
, data
);
126 err
= smack_backend_lookup_raw(s
, &idx
, state
, cmd
);
130 a
= malloc(sizeof(struct dnet_addr_attr
) + sizeof(struct dnet_file_info
));
135 info
= (struct dnet_file_info
*)(a
+ 1);
137 dnet_fill_addr_attr(n
, a
);
138 dnet_convert_addr_attr(a
);
140 memset(info
, 0, sizeof(struct dnet_file_info
));
141 dnet_convert_file_info(info
);
143 err
= dnet_send_reply(state
, cmd
, a
, sizeof(struct dnet_addr_attr
) + sizeof(struct dnet_file_info
), 0);
145 dnet_backend_log(DNET_LOG_INFO
, "%s: SMACK: : WRITE: Ok: offset: %llu, size: %llu.\n",
146 dnet_dump_id(&cmd
->id
), (unsigned long long)io
->offset
, (unsigned long long)io
->size
);
152 static int smack_backend_read(struct smack_backend
*s
, void *state
, struct dnet_cmd
*cmd
, void *iodata
)
154 struct dnet_io_attr
*io
= iodata
;
159 dnet_convert_io_attr(io
);
161 smack_setup_idx(&idx
, io
->id
);
162 idx
.data_size
= io
->size
;
164 err
= smack_read(s
->smack
, &idx
, &data
);
168 io
->size
= idx
.data_size
;
169 err
= dnet_send_read_data(state
, cmd
, io
, data
, -1, io
->offset
, 0);
179 static int smack_backend_remove(struct smack_backend
*s
, void *state __unused
, struct dnet_cmd
*cmd
, void *data __unused
)
183 smack_setup_idx(&idx
, cmd
->id
.id
);
184 return smack_remove(s
->smack
, &idx
);
187 static int smack_backend_bulk_read(struct smack_backend
*s
, void *state
, struct dnet_cmd
*cmd
, void *data
)
190 struct dnet_io_attr
*io
= data
;
191 struct dnet_io_attr
*ios
= io
+1;
195 dnet_convert_io_attr(io
);
196 count
= io
->size
/ sizeof(struct dnet_io_attr
);
198 for (i
= 0; i
< count
; i
++) {
199 ret
= smack_backend_read(s
, state
, cmd
, &ios
[i
]);
208 static int smack_backend_command_handler(void *state
, void *priv
, struct dnet_cmd
*cmd
, void *data
)
211 struct smack_backend
*s
= priv
;
214 case DNET_CMD_LOOKUP
:
215 err
= smack_backend_lookup(s
, state
, cmd
);
218 err
= smack_backend_write(s
, state
, cmd
, data
);
221 err
= smack_backend_read(s
, state
, cmd
, data
);
224 err
= backend_stat(state
, s
->ictl
.path
, cmd
);
227 err
= smack_backend_remove(s
, state
, cmd
, data
);
229 case DNET_CMD_BULK_READ
:
230 err
= smack_backend_bulk_read(s
, state
, cmd
, data
);
232 case DNET_CMD_READ_RANGE
:
243 static int dnet_smack_set_cache_size(struct dnet_config_backend
*b
, char *key __unused
, char *value
)
245 struct smack_backend
*s
= b
->data
;
247 s
->ictl
.max_cache_size
= atoi(value
);
251 static int dnet_smack_set_bloom_size(struct dnet_config_backend
*b
, char *key __unused
, char *value
)
253 struct smack_backend
*s
= b
->data
;
255 s
->ictl
.bloom_size
= atoi(value
);
259 static int dnet_smack_set_blob_num(struct dnet_config_backend
*b
, char *key __unused
, char *value
)
261 struct smack_backend
*s
= b
->data
;
263 s
->ictl
.max_blob_num
= atoi(value
);
267 static int dnet_smack_set_cache_thread_num(struct dnet_config_backend
*b
, char *key __unused
, char *value
)
269 struct smack_backend
*s
= b
->data
;
271 s
->ictl
.cache_thread_num
= atoi(value
);
275 static int dnet_smack_set_sync(struct dnet_config_backend
*b
, char *key __unused
, char *value
)
277 struct smack_backend
*s
= b
->data
;
279 s
->sync
= atoi(value
);
283 static int dnet_smack_set_type(struct dnet_config_backend
*b
, char *key __unused
, char *value
)
285 struct smack_backend
*s
= b
->data
;
290 s
->ictl
.type
= strdup(value
);
294 static int dnet_smack_set_log(struct dnet_config_backend
*b
, char *key __unused
, char *value
)
296 struct smack_backend
*s
= b
->data
;
309 static int dnet_smack_set_root(struct dnet_config_backend
*b
, char *key __unused
, char *root
)
311 struct smack_backend
*s
= b
->data
;
314 err
= backend_storage_size(b
, root
);
318 s
->ictl
.path
= strdup(root
);
330 static int smack_backend_send(void *state
, void *priv
, struct dnet_id
*id
)
332 struct dnet_node
*n
= dnet_get_node_from_state(state
);
333 struct smack_backend
*s
= priv
;
339 smack_setup_idx(&idx
, id
->id
);
340 err
= smack_read(s
->smack
, &idx
, &data
);
344 struct dnet_io_control ctl
;
346 memset(&ctl
, 0, sizeof(ctl
));
352 memcpy(&ctl
.id
, id
, sizeof(struct dnet_id
));
355 ctl
.io
.size
= idx
.data_size
;
359 err
= dnet_write_data_wait(n
, &ctl
, (void **)&result
);
371 int smack_backend_storage_stat(void *priv
, struct dnet_stat
*st
)
374 struct smack_backend
*s
= priv
;
376 memset(st
, 0, sizeof(struct dnet_stat
));
378 err
= backend_stat_low_level(s
->ictl
.path
? s
->ictl
.path
: ".", st
);
385 static void dnet_smack_db_cleanup(struct smack_backend
*s
)
387 eblob_cleanup(s
->meta
);
390 static int dnet_smack_db_init(struct smack_backend
*s
, struct dnet_config
*c
, const char *path
)
392 static char meta_path
[300];
393 struct eblob_config ecfg
;
396 snprintf(meta_path
, sizeof(meta_path
), "%s/meta", path
);
398 memset(&ecfg
, 0, sizeof(ecfg
));
399 ecfg
.file
= meta_path
;
401 ecfg
.blob_flags
= EBLOB_RESERVE_10_PERCENTS
| EBLOB_TRY_OVERWRITE
| EBLOB_NO_FOOTER
;
402 ecfg
.defrag_percentage
= 25;
403 ecfg
.defrag_timeout
= 3600;
404 ecfg
.log
= (struct eblob_log
*)c
->log
;
406 s
->meta
= eblob_init(&ecfg
);
409 dnet_backend_log(DNET_LOG_ERROR
, "Failed to initialize metadata eblob\n");
415 static void smack_backend_cleanup(void *priv
)
417 struct smack_backend
*s
= priv
;
419 smack_cleanup(s
->smack
);
420 dnet_smack_db_cleanup(s
);
424 static ssize_t
dnet_smack_db_read(void *priv
, struct dnet_raw_id
*id
, void **datap
)
426 struct smack_backend
*s
= priv
;
427 return dnet_db_read_raw(s
->meta
, id
, datap
);
430 static int dnet_smack_db_write(void *priv
, struct dnet_raw_id
*id
, void *data
, size_t size
)
432 struct smack_backend
*s
= priv
;
433 return dnet_db_write_raw(s
->meta
, id
, data
, size
);
436 static int dnet_smack_db_remove(void *priv
, struct dnet_raw_id
*id
, int real_del
)
438 struct smack_backend
*s
= priv
;
439 return dnet_db_remove_raw(s
->meta
, id
, real_del
);
442 static int dnet_smack_db_iterate(struct dnet_iterate_ctl
*ctl
)
444 struct smack_backend
*s
= ctl
->iterate_private
;
445 return dnet_db_iterate(s
->meta
, ctl
);
448 static long long smack_total_elements(void *priv
)
450 struct smack_backend
*s
= priv
;
452 return smack_total_num(s
->smack
);
455 static int dnet_smack_config_init(struct dnet_config_backend
*b
, struct dnet_config
*c
)
457 struct smack_backend
*s
= b
->data
;
462 b
->cb
.command_private
= s
;
464 b
->cb
.command_handler
= smack_backend_command_handler
;
465 b
->cb
.send
= smack_backend_send
;
467 c
->storage_size
= b
->storage_size
;
468 c
->storage_free
= b
->storage_free
;
470 b
->cb
.storage_stat
= smack_backend_storage_stat
;
471 b
->cb
.backend_cleanup
= smack_backend_cleanup
;
473 b
->cb
.meta_read
= dnet_smack_db_read
;
474 b
->cb
.meta_write
= dnet_smack_db_write
;
475 b
->cb
.meta_remove
= dnet_smack_db_remove
;
476 b
->cb
.meta_total_elements
= smack_total_elements
;
477 b
->cb
.meta_iterate
= dnet_smack_db_iterate
;
479 mkdir("history", 0755);
480 err
= dnet_smack_db_init(s
, c
, "history");
484 s
->ictl
.log_level
= c
->log
->log_level
;
485 s
->smack
= smack_init(&s
->ictl
, &err
);
487 goto err_out_cleanup
;
492 dnet_smack_db_cleanup(s
);
497 static void dnet_smack_config_cleanup(struct dnet_config_backend
*b
)
499 struct smack_backend
*s
= b
->data
;
501 smack_backend_cleanup(s
);
504 static struct dnet_config_entry dnet_cfg_entries_smacksystem
[] = {
505 {"type", dnet_smack_set_type
},
506 {"log", dnet_smack_set_log
},
507 {"sync", dnet_smack_set_sync
},
508 {"root", dnet_smack_set_root
},
509 {"cache_size", dnet_smack_set_cache_size
},
510 {"bloom_size", dnet_smack_set_bloom_size
},
511 {"blob_num", dnet_smack_set_blob_num
},
512 {"cache_thread_num", dnet_smack_set_cache_thread_num
},
515 static struct dnet_config_backend dnet_smack_backend
= {
517 .ent
= dnet_cfg_entries_smacksystem
,
518 .num
= ARRAY_SIZE(dnet_cfg_entries_smacksystem
),
519 .size
= sizeof(struct smack_backend
),
520 .init
= dnet_smack_config_init
,
521 .cleanup
= dnet_smack_config_cleanup
,
524 int dnet_smack_backend_init(void)
526 return dnet_backend_register(&dnet_smack_backend
);
529 void dnet_smack_backend_exit(void)
531 /* cleanup routing will be called explicitly through backend->cleanup() callback */