Elliptics version update: 2.19.2.7
[elliptics.git] / example / smack_backend.c
blob3df87c9d43acabd7ded042ee77e0ff5b4b9c35db
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 struct dnet_session *sess = dnet_session_create(n);
360 dnet_session_set_groups(sess, (int *)&id->group_id, 1);
362 err = dnet_write_data_wait(sess, &ctl, (void **)&result);
363 if (err < 0)
364 goto err_out_free;
365 free(result);
366 err = 0;
368 err_out_free:
369 free(data);
370 err_out_exit:
371 return err;
374 int smack_backend_storage_stat(void *priv, struct dnet_stat *st)
376 int err;
377 struct smack_backend *s = priv;
379 memset(st, 0, sizeof(struct dnet_stat));
381 err = backend_stat_low_level(s->ictl.path ? s->ictl.path : ".", st);
382 if (err)
383 return err;
385 return 0;
388 static void dnet_smack_db_cleanup(struct smack_backend *s)
390 eblob_cleanup(s->meta);
393 static int dnet_smack_db_init(struct smack_backend *s, struct dnet_config *c, const char *path)
395 static char meta_path[300];
396 struct eblob_config ecfg;
397 int err = 0;
399 snprintf(meta_path, sizeof(meta_path), "%s/meta", path);
401 memset(&ecfg, 0, sizeof(ecfg));
402 ecfg.file = meta_path;
403 ecfg.sync = 300;
404 ecfg.blob_flags = EBLOB_RESERVE_10_PERCENTS | EBLOB_TRY_OVERWRITE | EBLOB_NO_FOOTER;
405 ecfg.defrag_percentage = 25;
406 ecfg.defrag_timeout = 3600;
407 ecfg.log = (struct eblob_log *)c->log;
409 s->meta = eblob_init(&ecfg);
410 if (!s->meta) {
411 err = -EINVAL;
412 dnet_backend_log(DNET_LOG_ERROR, "Failed to initialize metadata eblob\n");
415 return err;
418 static void smack_backend_cleanup(void *priv)
420 struct smack_backend *s = priv;
422 smack_cleanup(s->smack);
423 dnet_smack_db_cleanup(s);
424 free(s->ictl.path);
427 static ssize_t dnet_smack_db_read(void *priv, struct dnet_raw_id *id, void **datap)
429 struct smack_backend *s = priv;
430 return dnet_db_read_raw(s->meta, id, datap);
433 static int dnet_smack_db_write(void *priv, struct dnet_raw_id *id, void *data, size_t size)
435 struct smack_backend *s = priv;
436 return dnet_db_write_raw(s->meta, id, data, size);
439 static int dnet_smack_db_remove(void *priv, struct dnet_raw_id *id, int real_del)
441 struct smack_backend *s = priv;
442 return dnet_db_remove_raw(s->meta, id, real_del);
445 static int dnet_smack_db_iterate(struct dnet_iterate_ctl *ctl)
447 struct smack_backend *s = ctl->iterate_private;
448 return dnet_db_iterate(s->meta, ctl);
451 static long long smack_total_elements(void *priv)
453 struct smack_backend *s = priv;
455 return smack_total_num(s->smack);
458 static int dnet_smack_config_init(struct dnet_config_backend *b, struct dnet_config *c)
460 struct smack_backend *s = b->data;
461 int err;
463 c->cb = &b->cb;
465 b->cb.command_private = s;
467 b->cb.command_handler = smack_backend_command_handler;
468 b->cb.send = smack_backend_send;
470 c->storage_size = b->storage_size;
471 c->storage_free = b->storage_free;
473 b->cb.storage_stat = smack_backend_storage_stat;
474 b->cb.backend_cleanup = smack_backend_cleanup;
476 b->cb.meta_read = dnet_smack_db_read;
477 b->cb.meta_write = dnet_smack_db_write;
478 b->cb.meta_remove = dnet_smack_db_remove;
479 b->cb.meta_total_elements = smack_total_elements;
480 b->cb.meta_iterate = dnet_smack_db_iterate;
482 mkdir("history", 0755);
483 err = dnet_smack_db_init(s, c, "history");
484 if (err)
485 goto err_out_exit;
487 s->ictl.log_level = c->log->log_level;
488 s->smack = smack_init(&s->ictl, &err);
489 if (!s->smack)
490 goto err_out_cleanup;
492 return 0;
494 err_out_cleanup:
495 dnet_smack_db_cleanup(s);
496 err_out_exit:
497 return err;
500 static void dnet_smack_config_cleanup(struct dnet_config_backend *b)
502 struct smack_backend *s = b->data;
504 smack_backend_cleanup(s);
507 static struct dnet_config_entry dnet_cfg_entries_smacksystem[] = {
508 {"type", dnet_smack_set_type},
509 {"log", dnet_smack_set_log},
510 {"sync", dnet_smack_set_sync},
511 {"root", dnet_smack_set_root},
512 {"cache_size", dnet_smack_set_cache_size},
513 {"bloom_size", dnet_smack_set_bloom_size},
514 {"blob_num", dnet_smack_set_blob_num},
515 {"cache_thread_num", dnet_smack_set_cache_thread_num},
518 static struct dnet_config_backend dnet_smack_backend = {
519 .name = "smack",
520 .ent = dnet_cfg_entries_smacksystem,
521 .num = ARRAY_SIZE(dnet_cfg_entries_smacksystem),
522 .size = sizeof(struct smack_backend),
523 .init = dnet_smack_config_init,
524 .cleanup = dnet_smack_config_cleanup,
527 int dnet_smack_backend_init(void)
529 return dnet_backend_register(&dnet_smack_backend);
532 void dnet_smack_backend_exit(void)
534 /* cleanup routing will be called explicitly through backend->cleanup() callback */