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.
18 #include <sys/types.h>
20 #include <sys/socket.h>
33 #include "elliptics/packet.h"
34 #include "elliptics/interface.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"
46 #define __unused __attribute__ ((unused))
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
);
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
)
73 err
= smack_lookup(s
->smack
, idx
, &path
);
77 fd
= open(path
, O_RDONLY
| O_CLOEXEC
);
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
,
87 attr
->flags
|= DNET_ATTR_NOCSUM
;
88 err
= dnet_send_file_info(state
, cmd
, attr
, fd
, idx
->data_offset
, idx
->data_size
);
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
);
104 static int smack_backend_lookup(struct smack_backend
*s
, void *state
, struct dnet_cmd
*cmd
, struct dnet_attr
*attr
)
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
)
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
);
131 err
= smack_backend_lookup_raw(s
, &idx
, state
, cmd
, attr
);
135 if (!(cmd
->flags
& DNET_FLAGS_NEED_ACK
)) {
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);
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
);
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
;
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
);
171 io
->size
= idx
.data_size
;
172 err
= dnet_send_read_data(state
, cmd
, io
, data
, -1, io
->offset
, 1);
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
)
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
)
195 struct dnet_io_attr
*io
= data
;
196 struct dnet_io_attr
*ios
= io
+1;
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
]);
213 static int smack_backend_command_handler(void *state
, void *priv
,
214 struct dnet_cmd
*cmd
, struct dnet_attr
*attr
, void *data
)
217 struct smack_backend
*s
= priv
;
220 case DNET_CMD_LOOKUP
:
221 err
= smack_backend_lookup(s
, state
, cmd
, attr
);
224 err
= smack_backend_write(s
, state
, cmd
, attr
, data
);
227 err
= smack_backend_read(s
, state
, cmd
, attr
, data
);
230 err
= backend_stat(state
, s
->ictl
.path
, cmd
, attr
);
233 err
= smack_backend_remove(s
, state
, cmd
, attr
, data
);
235 case DNET_CMD_BULK_READ
:
236 err
= smack_backend_bulk_read(s
, state
, cmd
, attr
, data
);
238 case DNET_CMD_READ_RANGE
:
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
);
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
);
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
);
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
);
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
);
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
;
304 static int dnet_smack_set_log(struct dnet_config_backend
*b
, char *key __unused
, char *value
)
306 struct smack_backend
*s
= b
->data
;
319 static int dnet_smack_set_root(struct dnet_config_backend
*b
, char *key __unused
, char *root
)
321 struct smack_backend
*s
= b
->data
;
324 err
= backend_storage_size(b
, root
);
328 s
->ictl
.path
= strdup(root
);
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
;
348 smack_setup_idx(&idx
, id
->id
);
349 err
= smack_read(s
->smack
, &idx
, &data
);
353 struct dnet_io_control ctl
;
355 memset(&ctl
, 0, sizeof(ctl
));
361 memcpy(&ctl
.id
, id
, sizeof(struct dnet_id
));
364 ctl
.io
.size
= idx
.data_size
;
368 err
= dnet_write_data_wait(n
, &ctl
);
379 int smack_backend_storage_stat(void *priv
, struct dnet_stat
*st
)
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
);
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
;
404 snprintf(meta_path
, sizeof(meta_path
), "%s/meta", path
);
406 memset(&ecfg
, 0, sizeof(ecfg
));
407 ecfg
.file
= meta_path
;
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
);
417 dnet_backend_log(DNET_LOG_ERROR
, "Failed to initialize metadata eblob\n");
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
);
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
;
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");
491 s
->ictl
.log_mask
= c
->log
->log_mask
;
492 s
->smack
= smack_init(&s
->ictl
, &err
);
494 goto err_out_cleanup
;
499 dnet_smack_db_cleanup(s
);
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
= {
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 */