Do not double-close python init file
[elliptics.git] / example / smack_backend.c
blobb850c1829bbcbc52cfa77c9f7351bc7607a96822
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 "config.h"
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <sys/socket.h>
21 #include <sys/mman.h>
22 #include <sys/wait.h>
24 #include <errno.h>
25 #include <ctype.h>
26 #include <dirent.h>
27 #include <fcntl.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <unistd.h>
33 #include "elliptics/packet.h"
34 #include "elliptics/interface.h"
36 #include "backends.h"
37 #include "common.h"
39 #include <smack/smack.h>
41 #if SMACK_KEY_SIZE != DNET_ID_SIZE
42 #error "SMACK_KEY_SIZE does not match DNET_ID_SIZE"
43 #endif
45 #ifndef __unused
46 #define __unused __attribute__ ((unused))
47 #endif
49 struct smack_backend
51 int sync;
53 struct eblob_log log;
54 struct eblob_backend *meta;
56 struct smack_init_ctl ictl;
57 struct smack_ctl *smack;
60 static inline void smack_setup_idx(struct index *idx, unsigned char *id)
62 memcpy(idx->id, id, SMACK_KEY_SIZE);
63 idx->data_offset = 0;
64 idx->data_size = 0;
67 static int smack_backend_lookup_raw(struct smack_backend *s, struct index *idx, void *state, struct dnet_cmd *cmd,
68 struct dnet_attr *attr)
70 int err, fd;
71 char *path;
73 err = smack_lookup(s->smack, idx, &path);
74 if (err < 0)
75 goto err_out_exit;
77 fd = open(path, O_RDONLY | O_CLOEXEC);
78 if (fd < 0) {
79 err = -errno;
80 dnet_backend_log(DNET_LOG_ERROR, "%s: SMACK: %s: lookup-open: offset: %llu, size: %llu: %s %d.\n",
81 dnet_dump_id_str(idx->id), path,
82 (unsigned long long)idx->data_offset, (unsigned long long)idx->data_size,
83 strerror(-err), err);
84 goto err_out_free;
87 attr->flags |= DNET_ATTR_NOCSUM;
88 err = dnet_send_file_info(state, cmd, attr, fd, idx->data_offset, idx->data_size);
89 if (err)
90 goto err_out_close;
92 dnet_backend_log(DNET_LOG_INFO, "%s: SMACK: %s: lookup: offset: %llu, size: %llu.\n",
93 dnet_dump_id(&cmd->id), path,
94 (unsigned long long)idx->data_offset, (unsigned long long)idx->data_size);
96 err_out_close:
97 close(fd);
98 err_out_free:
99 free(path);
100 err_out_exit:
101 return err;
104 static int smack_backend_lookup(struct smack_backend *s, void *state, struct dnet_cmd *cmd, struct dnet_attr *attr)
106 struct index idx;
108 smack_setup_idx(&idx, cmd->id.id);
109 return smack_backend_lookup_raw(s, &idx, state, cmd, attr);
112 static int smack_backend_write(struct smack_backend *s, void *state, struct dnet_cmd *cmd,
113 struct dnet_attr *attr, void *data)
115 int err;
116 struct index idx;
117 struct dnet_io_attr *io = data;
119 dnet_convert_io_attr(io);
121 data += sizeof(struct dnet_io_attr);
123 smack_setup_idx(&idx, io->id);
124 idx.data_offset = io->offset;
125 idx.data_size = io->size;
127 err = smack_write(s->smack, &idx, data);
128 if (err < 0)
129 goto err_out_exit;
130 #if 0
131 err = smack_backend_lookup_raw(s, &idx, state, cmd, attr);
132 if (err)
133 goto err_out_exit;
134 #else
135 if (!(cmd->flags & DNET_FLAGS_NEED_ACK)) {
136 char reply[1024];
137 char id_str[DNET_ID_SIZE * 2 + 1];
139 snprintf(reply, sizeof(reply), "<elliptics id=\"%s\" offset=%lld size=%lld />",
140 dnet_dump_id_len_raw(cmd->id.id, DNET_ID_SIZE, id_str),
141 (unsigned long long)io->offset, (unsigned long long)io->size);
143 err = dnet_send_reply(state, cmd, attr, reply, 256, 0);
145 #endif
146 dnet_backend_log(DNET_LOG_INFO, "%s: SMACK: : WRITE: Ok: offset: %llu, size: %llu.\n",
147 dnet_dump_id(&cmd->id), (unsigned long long)io->offset, (unsigned long long)io->size);
149 err_out_exit:
150 return err;
153 static int smack_backend_read(struct smack_backend *s, void *state, struct dnet_cmd *cmd,
154 struct dnet_attr *attr __unused, void *iodata)
156 struct dnet_io_attr *io = iodata;
157 char *data;
158 struct index idx;
159 int err;
161 dnet_convert_io_attr(io);
163 smack_setup_idx(&idx, io->id);
164 idx.data_offset = io->offset;
165 idx.data_size = io->size;
167 err = smack_read(s->smack, &idx, &data);
168 if (err < 0)
169 goto err_out_exit;
171 io->size = idx.data_size;
172 err = dnet_send_read_data(state, cmd, io, data, -1, io->offset, 1);
173 if (err)
174 goto err_out_free;
176 err_out_free:
177 free(data);
178 err_out_exit:
179 return err;
182 static int smack_backend_remove(struct smack_backend *s, void *state __unused, struct dnet_cmd *cmd,
183 struct dnet_attr *attr __unused, void *data __unused)
185 struct index idx;
187 smack_setup_idx(&idx, cmd->id.id);
188 return smack_remove(s->smack, &idx);
191 static int smack_backend_bulk_read(struct smack_backend *s, void *state, struct dnet_cmd *cmd,
192 struct dnet_attr *attr, void *data)
194 int err = -1, ret;
195 struct dnet_io_attr *io = data;
196 struct dnet_io_attr *ios = io+1;
197 uint64_t count = 0;
198 uint64_t i;
200 dnet_convert_io_attr(io);
201 count = io->size / sizeof(struct dnet_io_attr);
203 for (i = 0; i < count; i++) {
204 ret = smack_backend_read(s, state, cmd, attr, &ios[i]);
205 if (!ret)
206 err = 0;
207 else if (err == -1)
208 err = ret;
211 return err;
213 static int smack_backend_command_handler(void *state, void *priv,
214 struct dnet_cmd *cmd, struct dnet_attr *attr, void *data)
216 int err;
217 struct smack_backend *s = priv;
219 switch (attr->cmd) {
220 case DNET_CMD_LOOKUP:
221 err = smack_backend_lookup(s, state, cmd, attr);
222 break;
223 case DNET_CMD_WRITE:
224 err = smack_backend_write(s, state, cmd, attr, data);
225 break;
226 case DNET_CMD_READ:
227 err = smack_backend_read(s, state, cmd, attr, data);
228 break;
229 case DNET_CMD_STAT:
230 err = backend_stat(state, s->ictl.path, cmd, attr);
231 break;
232 case DNET_CMD_DEL:
233 err = smack_backend_remove(s, state, cmd, attr, data);
234 break;
235 case DNET_CMD_BULK_READ:
236 err = smack_backend_bulk_read(s, state, cmd, attr, data);
237 break;
238 case DNET_CMD_READ_RANGE:
239 err = -ENOTSUP;
240 break;
241 default:
242 err = -EINVAL;
243 break;
246 return err;
249 static int dnet_smack_set_cache_size(struct dnet_config_backend *b, char *key __unused, char *value)
251 struct smack_backend *s = b->data;
253 s->ictl.max_cache_size = atoi(value);
254 return 0;
257 static int dnet_smack_set_bloom_size(struct dnet_config_backend *b, char *key __unused, char *value)
259 struct smack_backend *s = b->data;
261 s->ictl.bloom_size = atoi(value);
262 return 0;
265 static int dnet_smack_set_blob_num(struct dnet_config_backend *b, char *key __unused, char *value)
267 struct smack_backend *s = b->data;
269 s->ictl.max_blob_num = atoi(value);
270 return 0;
273 static int dnet_smack_set_cache_thread_num(struct dnet_config_backend *b, char *key __unused, char *value)
275 struct smack_backend *s = b->data;
277 s->ictl.cache_thread_num = atoi(value);
278 return 0;
281 static int dnet_smack_set_sync(struct dnet_config_backend *b, char *key __unused, char *value)
283 struct smack_backend *s = b->data;
285 s->sync = atoi(value);
286 return 0;
289 static int dnet_smack_set_type(struct dnet_config_backend *b, char *key __unused, char *value)
291 struct smack_backend *s = b->data;
293 if (!strcmp(value, "zlib"))
294 s->ictl.type = SMACK_STORAGE_ZLIB;
295 else if (!strcmp(value, "mmap"))
296 s->ictl.type = SMACK_STORAGE_MMAP;
297 else if (!strcmp(value, "file"))
298 s->ictl.type = SMACK_STORAGE_FILE;
299 else
300 return -ENOTSUP;
301 return 0;
304 static int dnet_smack_set_log(struct dnet_config_backend *b, char *key __unused, char *value)
306 struct smack_backend *s = b->data;
307 char *tmp;
309 tmp = strdup(value);
310 if (!tmp)
311 return -ENOMEM;
313 if (s->ictl.log)
314 free(s->ictl.log);
315 s->ictl.log = tmp;
316 return 0;
319 static int dnet_smack_set_root(struct dnet_config_backend *b, char *key __unused, char *root)
321 struct smack_backend *s = b->data;
322 int err;
324 err = backend_storage_size(b, root);
325 if (err)
326 goto err_out_exit;
328 s->ictl.path = strdup(root);
329 if (!s->ictl.path) {
330 err = -ENOMEM;
331 goto err_out_exit;
334 return 0;
336 err_out_exit:
337 return err;
340 static int smack_backend_send(void *state, void *priv, struct dnet_id *id)
342 struct dnet_node *n = dnet_get_node_from_state(state);
343 struct smack_backend *s = priv;
344 struct index idx;
345 char *data;
346 int err;
348 smack_setup_idx(&idx, id->id);
349 err = smack_read(s->smack, &idx, &data);
350 if (err)
351 goto err_out_exit;
353 struct dnet_io_control ctl;
355 memset(&ctl, 0, sizeof(ctl));
357 ctl.fd = -1;
359 ctl.data = data;
361 memcpy(&ctl.id, id, sizeof(struct dnet_id));
363 ctl.io.offset = 0;
364 ctl.io.size = idx.data_size;
365 ctl.io.type = 0;
366 ctl.io.flags = 0;
368 err = dnet_write_data_wait(n, &ctl);
369 if (err < 0)
370 goto err_out_free;
371 err = 0;
373 err_out_free:
374 free(data);
375 err_out_exit:
376 return err;
379 int smack_backend_storage_stat(void *priv, struct dnet_stat *st)
381 int err;
382 struct smack_backend *s = priv;
384 memset(st, 0, sizeof(struct dnet_stat));
386 err = backend_stat_low_level(s->ictl.path ? s->ictl.path : ".", st);
387 if (err)
388 return err;
390 return 0;
393 static void dnet_smack_db_cleanup(struct smack_backend *s)
395 eblob_cleanup(s->meta);
398 static int dnet_smack_db_init(struct smack_backend *s, struct dnet_config *c, const char *path)
400 static char meta_path[300];
401 struct eblob_config ecfg;
402 int err = 0;
404 snprintf(meta_path, sizeof(meta_path), "%s/meta", path);
406 memset(&ecfg, 0, sizeof(ecfg));
407 ecfg.file = meta_path;
408 ecfg.sync = 300;
409 ecfg.blob_flags = EBLOB_RESERVE_10_PERCENTS | EBLOB_TRY_OVERWRITE | EBLOB_NO_FOOTER;
410 ecfg.defrag_percentage = 25;
411 ecfg.defrag_timeout = 3600;
412 ecfg.log = (struct eblob_log *)c->log;
414 s->meta = eblob_init(&ecfg);
415 if (!s->meta) {
416 err = -EINVAL;
417 dnet_backend_log(DNET_LOG_ERROR, "Failed to initialize metadata eblob\n");
420 return err;
423 static void smack_backend_cleanup(void *priv)
425 struct smack_backend *s = priv;
427 smack_cleanup(s->smack);
428 dnet_smack_db_cleanup(s);
429 free(s->ictl.path);
432 static ssize_t dnet_smack_db_read(void *priv, struct dnet_raw_id *id, void **datap)
434 struct smack_backend *s = priv;
435 return dnet_db_read_raw(s->meta, id, datap);
438 static int dnet_smack_db_write(void *priv, struct dnet_raw_id *id, void *data, size_t size)
440 struct smack_backend *s = priv;
441 return dnet_db_write_raw(s->meta, id, data, size);
444 static int dnet_smack_db_remove(void *priv, struct dnet_raw_id *id, int real_del)
446 struct smack_backend *s = priv;
447 return dnet_db_remove_raw(s->meta, id, real_del);
450 static long long dnet_smack_db_total_elements(void *priv)
452 struct smack_backend *s = priv;
453 return eblob_total_elements(s->meta);
456 static int dnet_smack_db_iterate(struct dnet_iterate_ctl *ctl)
458 struct smack_backend *s = ctl->iterate_private;
459 return dnet_db_iterate(s->meta, ctl);
462 static int dnet_smack_config_init(struct dnet_config_backend *b, struct dnet_config *c)
464 struct smack_backend *s = b->data;
465 int err;
467 c->cb = &b->cb;
469 b->cb.command_private = s;
471 b->cb.command_handler = smack_backend_command_handler;
472 b->cb.send = smack_backend_send;
474 c->storage_size = b->storage_size;
475 c->storage_free = b->storage_free;
477 b->cb.storage_stat = smack_backend_storage_stat;
478 b->cb.backend_cleanup = smack_backend_cleanup;
480 b->cb.meta_read = dnet_smack_db_read;
481 b->cb.meta_write = dnet_smack_db_write;
482 b->cb.meta_remove = dnet_smack_db_remove;
483 b->cb.meta_total_elements = dnet_smack_db_total_elements;
484 b->cb.meta_iterate = dnet_smack_db_iterate;
486 mkdir("history", 0755);
487 err = dnet_smack_db_init(s, c, "history");
488 if (err)
489 goto err_out_exit;
491 s->ictl.log_mask = c->log->log_mask;
492 s->smack = smack_init(&s->ictl, &err);
493 if (!s->smack)
494 goto err_out_cleanup;
496 return 0;
498 err_out_cleanup:
499 dnet_smack_db_cleanup(s);
500 err_out_exit:
501 return err;
504 static void dnet_smack_config_cleanup(struct dnet_config_backend *b)
506 struct smack_backend *s = b->data;
508 smack_backend_cleanup(s);
511 static struct dnet_config_entry dnet_cfg_entries_smacksystem[] = {
512 {"type", dnet_smack_set_type},
513 {"log", dnet_smack_set_log},
514 {"sync", dnet_smack_set_sync},
515 {"root", dnet_smack_set_root},
516 {"cache_size", dnet_smack_set_cache_size},
517 {"bloom_size", dnet_smack_set_bloom_size},
518 {"blob_num", dnet_smack_set_blob_num},
519 {"cache_thread_num", dnet_smack_set_cache_thread_num},
522 static struct dnet_config_backend dnet_smack_backend = {
523 .name = "smack",
524 .ent = dnet_cfg_entries_smacksystem,
525 .num = ARRAY_SIZE(dnet_cfg_entries_smacksystem),
526 .size = sizeof(struct smack_backend),
527 .init = dnet_smack_config_init,
528 .cleanup = dnet_smack_config_cleanup,
531 int dnet_smack_backend_init(void)
533 return dnet_backend_register(&dnet_smack_backend);
536 void dnet_smack_backend_exit(void)
538 /* cleanup routing will be called explicitly through backend->cleanup() callback */