Merge branch 'master' of tsn:public_html/git/elliptics
[elliptics.git] / example / smack_backend.c
blobd29cdac5dedfe8a2a775a160156b1ae44672a37a
1 /*
2 * 2012+ Copyright (c) Evgeniy Polyakov <zbr@ioremap.net>
3 * All rights reserved.
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>
17 #include <sys/stat.h>
18 #include <sys/socket.h>
19 #include <sys/mman.h>
20 #include <sys/wait.h>
22 #include <errno.h>
23 #include <ctype.h>
24 #include <dirent.h>
25 #include <fcntl.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
31 #include "elliptics/packet.h"
32 #include "elliptics/interface.h"
34 #include "backends.h"
35 #include "common.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"
41 #endif
43 #ifndef __unused
44 #define __unused __attribute__ ((unused))
45 #endif
47 struct smack_backend
49 int sync;
51 struct eblob_log log;
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);
61 idx->data_size = 0;
64 static int smack_backend_lookup_raw(struct smack_backend *s, struct index *idx, void *state, struct dnet_cmd *cmd)
66 int err, fd;
67 char *path;
69 err = smack_lookup(s->smack, idx, &path);
70 if (err < 0)
71 goto err_out_exit;
73 fd = open(path, O_RDONLY | O_CLOEXEC);
74 if (fd < 0) {
75 err = -errno;
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,
79 strerror(-err), err);
80 goto err_out_free;
83 err = dnet_send_file_info(state, cmd, fd, 0, idx->data_size);
84 if (err)
85 goto err_out_close;
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);
90 err_out_close:
91 close(fd);
92 err_out_free:
93 free(path);
94 err_out_exit:
95 return err;
98 static int smack_backend_lookup(struct smack_backend *s, void *state, struct dnet_cmd *cmd)
100 struct index idx;
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);
109 int err;
110 struct index idx;
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);
123 if (err < 0)
124 goto err_out_exit;
125 #if 0
126 err = smack_backend_lookup_raw(s, &idx, state, cmd);
127 if (err)
128 goto err_out_exit;
129 #else
130 a = malloc(sizeof(struct dnet_addr_attr) + sizeof(struct dnet_file_info));
131 if (!a) {
132 err = -ENOMEM;
133 goto err_out_exit;
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);
144 #endif
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);
148 err_out_exit:
149 return err;
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;
155 char *data;
156 struct index idx;
157 int err;
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);
165 if (err < 0)
166 goto err_out_exit;
168 io->size = idx.data_size;
169 err = dnet_send_read_data(state, cmd, io, data, -1, io->offset, 0);
170 if (err)
171 goto err_out_free;
173 err_out_free:
174 free(data);
175 err_out_exit:
176 return err;
179 static int smack_backend_remove(struct smack_backend *s, void *state __unused, struct dnet_cmd *cmd, void *data __unused)
181 struct index idx;
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)
189 int err = -1, ret;
190 struct dnet_io_attr *io = data;
191 struct dnet_io_attr *ios = io+1;
192 uint64_t count = 0;
193 uint64_t i;
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]);
200 if (!ret)
201 err = 0;
202 else if (err == -1)
203 err = ret;
206 return err;
208 static int smack_backend_command_handler(void *state, void *priv, struct dnet_cmd *cmd, void *data)
210 int err;
211 struct smack_backend *s = priv;
213 switch (cmd->cmd) {
214 case DNET_CMD_LOOKUP:
215 err = smack_backend_lookup(s, state, cmd);
216 break;
217 case DNET_CMD_WRITE:
218 err = smack_backend_write(s, state, cmd, data);
219 break;
220 case DNET_CMD_READ:
221 err = smack_backend_read(s, state, cmd, data);
222 break;
223 case DNET_CMD_STAT:
224 err = backend_stat(state, s->ictl.path, cmd);
225 break;
226 case DNET_CMD_DEL:
227 err = smack_backend_remove(s, state, cmd, data);
228 break;
229 case DNET_CMD_BULK_READ:
230 err = smack_backend_bulk_read(s, state, cmd, data);
231 break;
232 case DNET_CMD_READ_RANGE:
233 err = -ENOTSUP;
234 break;
235 default:
236 err = -EINVAL;
237 break;
240 return err;
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);
248 return 0;
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);
256 return 0;
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);
264 return 0;
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);
272 return 0;
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);
280 return 0;
283 static int dnet_smack_set_type(struct dnet_config_backend *b, char *key __unused, char *value)
285 struct smack_backend *s = b->data;
287 if (s->ictl.type)
288 free(s->ictl.type);
290 s->ictl.type = strdup(value);
291 return 0;
294 static int dnet_smack_set_log(struct dnet_config_backend *b, char *key __unused, char *value)
296 struct smack_backend *s = b->data;
297 char *tmp;
299 tmp = strdup(value);
300 if (!tmp)
301 return -ENOMEM;
303 if (s->ictl.log)
304 free(s->ictl.log);
305 s->ictl.log = tmp;
306 return 0;
309 static int dnet_smack_set_root(struct dnet_config_backend *b, char *key __unused, char *root)
311 struct smack_backend *s = b->data;
312 int err;
314 err = backend_storage_size(b, root);
315 if (err)
316 goto err_out_exit;
318 s->ictl.path = strdup(root);
319 if (!s->ictl.path) {
320 err = -ENOMEM;
321 goto err_out_exit;
324 return 0;
326 err_out_exit:
327 return err;
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;
334 struct index idx;
335 char *result = NULL;
336 char *data;
337 int err;
339 smack_setup_idx(&idx, id->id);
340 err = smack_read(s->smack, &idx, &data);
341 if (err)
342 goto err_out_exit;
344 struct dnet_io_control ctl;
346 memset(&ctl, 0, sizeof(ctl));
348 ctl.fd = -1;
350 ctl.data = data;
352 memcpy(&ctl.id, id, sizeof(struct dnet_id));
354 ctl.io.offset = 0;
355 ctl.io.size = idx.data_size;
356 ctl.io.type = 0;
357 ctl.io.flags = 0;
359 err = dnet_write_data_wait(n, &ctl, (void **)&result);
360 if (err < 0)
361 goto err_out_free;
362 free(result);
363 err = 0;
365 err_out_free:
366 free(data);
367 err_out_exit:
368 return err;
371 int smack_backend_storage_stat(void *priv, struct dnet_stat *st)
373 int err;
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);
379 if (err)
380 return err;
382 return 0;
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;
394 int err = 0;
396 snprintf(meta_path, sizeof(meta_path), "%s/meta", path);
398 memset(&ecfg, 0, sizeof(ecfg));
399 ecfg.file = meta_path;
400 ecfg.sync = 300;
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);
407 if (!s->meta) {
408 err = -EINVAL;
409 dnet_backend_log(DNET_LOG_ERROR, "Failed to initialize metadata eblob\n");
412 return err;
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);
421 free(s->ictl.path);
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;
458 int err;
460 c->cb = &b->cb;
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");
481 if (err)
482 goto err_out_exit;
484 s->ictl.log_level = c->log->log_level;
485 s->smack = smack_init(&s->ictl, &err);
486 if (!s->smack)
487 goto err_out_cleanup;
489 return 0;
491 err_out_cleanup:
492 dnet_smack_db_cleanup(s);
493 err_out_exit:
494 return err;
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 = {
516 .name = "smack",
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 */