Added possibility to start defragmentation on demand
[elliptics.git] / example / ioclient.c
bloba6a32395d0710be0ba91b0c654bb0435f230d4a8
1 /*
2 * 2008+ 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/time.h>
22 #include <sys/syscall.h>
24 #include <ctype.h>
25 #include <fcntl.h>
26 #include <errno.h>
27 #include <unistd.h>
28 #include <signal.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <time.h>
34 #include <netinet/in.h>
36 #include "elliptics/packet.h"
37 #include "elliptics/interface.h"
39 #include "backends.h"
40 #include "common.h"
42 #ifndef __unused
43 #define __unused __attribute__ ((unused))
44 #endif
46 static struct dnet_log ioclient_logger;
48 static void dnet_usage(char *p)
50 fprintf(stderr, "Usage: %s\n"
51 " -r addr:port:family - adds a route to the given node\n"
52 " -W file - write given file to the network storage\n"
53 " -s - request IO counter stats from node\n"
54 " -z - request VFS IO stats from node\n"
55 " -a - request stats from all connected nodes\n"
56 " -U status - update server status: 1 - elliptics exits, 2 - goes RO\n"
57 " -R file - read given file from the network into the local storage\n"
58 " -I id - transaction id (used to read data)\n"
59 " -g groups - group IDs to connect\n"
60 " -c cmd-event - execute command with given event on the remote node\n"
61 " -L file - lookup a storage which hosts given file\n"
62 " -l log - log file. Default: disabled\n"
63 " -w timeout - wait timeout in seconds used to wait for content sync.\n"
64 " ... - parameters can be repeated multiple times\n"
65 " each time they correspond to the last added node\n"
66 " -m mask - log events mask\n"
67 " -M mask - set new log mask\n"
68 " -F flags - change node flags (see @cfg->flags comments in include/elliptics/interface.h)\n"
69 " -O offset - read/write offset in the file\n"
70 " -S size - read/write transaction size\n"
71 " -u file - unlink file\n"
72 " -N namespace - use this namespace for operations\n"
73 " -D object - read latest data for given object, if -I id is specified, this field is unused\n"
74 " -C flags - command flags\n"
75 " -t column - column ID to read or write\n"
76 " -d - start defragmentation\n"
77 , p);
80 int main(int argc, char *argv[])
82 int ch, err, i, have_remote = 0;
83 int io_counter_stat = 0, vfs_stat = 0, single_node_stat = 1;
84 struct dnet_node_status node_status;
85 int update_status = 0;
86 struct dnet_node *n = NULL;
87 struct dnet_config cfg, rem, *remotes = NULL;
88 char *logfile = "/dev/stderr", *readf = NULL, *writef = NULL, *cmd = NULL, *lookup = NULL;
89 char *read_data = NULL;
90 char *removef = NULL;
91 unsigned char trans_id[DNET_ID_SIZE], *id = NULL;
92 FILE *log = NULL;
93 uint64_t offset, size;
94 int *groups = NULL, group_num = 0;
95 int type = EBLOB_TYPE_DATA;
96 uint64_t cflags = 0;
97 int defrag = 0;
98 sigset_t mask;
100 memset(&node_status, 0, sizeof(struct dnet_node_status));
101 memset(&cfg, 0, sizeof(struct dnet_config));
103 node_status.nflags = -1;
104 node_status.status_flags = -1;
105 node_status.log_mask = ~0U;
107 size = offset = 0;
109 cfg.sock_type = SOCK_STREAM;
110 cfg.proto = IPPROTO_TCP;
111 cfg.wait_timeout = 60;
112 ioclient_logger.log_mask = DNET_LOG_ERROR | DNET_LOG_DATA;
114 memcpy(&rem, &cfg, sizeof(struct dnet_config));
116 while ((ch = getopt(argc, argv, "dC:t:A:F:M:N:g:u:O:S:m:zsU:aL:w:l:c:I:r:W:R:D:h")) != -1) {
117 switch (ch) {
118 case 'd':
119 defrag = 1;
120 break;
121 case 'C':
122 cflags = strtoull(optarg, NULL, 0);
123 break;
124 case 't':
125 type = atoi(optarg);
126 break;
127 case 'F':
128 node_status.nflags = strtol(optarg, NULL, 0);
129 update_status = 1;
130 break;
131 case 'M':
132 node_status.log_mask = strtol(optarg, NULL, 0);
133 update_status = 1;
134 break;
135 case 'N':
136 cfg.ns = optarg;
137 cfg.nsize = strlen(optarg);
138 break;
139 case 'u':
140 removef = optarg;
141 break;
142 case 'O':
143 offset = strtoull(optarg, NULL, 0);
144 break;
145 case 'S':
146 size = strtoull(optarg, NULL, 0);
147 break;
148 case 'm':
149 ioclient_logger.log_mask = strtoul(optarg, NULL, 0);
150 break;
151 case 's':
152 io_counter_stat = 1;
153 break;
154 case 'U':
155 node_status.status_flags = strtol(optarg, NULL, 0);
156 update_status = 1;
157 break;
158 case 'z':
159 vfs_stat = 1;
160 break;
161 case 'a':
162 single_node_stat = 0;
163 break;
164 case 'L':
165 lookup = optarg;
166 break;
167 case 'w':
168 cfg.check_timeout = cfg.wait_timeout = atoi(optarg);
169 break;
170 case 'l':
171 logfile = optarg;
172 break;
173 case 'c':
174 cmd = optarg;
175 break;
176 case 'I':
177 err = dnet_parse_numeric_id(optarg, trans_id);
178 if (err)
179 return err;
180 id = trans_id;
181 break;
182 case 'g':
183 group_num = dnet_parse_groups(optarg, &groups);
184 if (group_num <= 0)
185 return -1;
186 break;
187 case 'r':
188 err = dnet_parse_addr(optarg, &rem);
189 if (err)
190 return err;
191 have_remote++;
192 remotes = realloc(remotes, sizeof(rem) * have_remote);
193 if (!remotes)
194 return -ENOMEM;
195 memcpy(&remotes[have_remote - 1], &rem, sizeof(rem));
196 break;
197 case 'W':
198 writef = optarg;
199 break;
200 case 'R':
201 readf = optarg;
202 break;
203 case 'D':
204 read_data = optarg;
205 break;
206 case 'h':
207 default:
208 dnet_usage(argv[0]);
209 return -1;
213 log = fopen(logfile, "a");
214 if (!log) {
215 err = -errno;
216 fprintf(stderr, "Failed to open log file %s: %s.\n", logfile, strerror(errno));
217 return err;
220 ioclient_logger.log_private = log;
221 ioclient_logger.log = dnet_common_log;
222 cfg.log = &ioclient_logger;
224 n = dnet_node_create(&cfg);
225 if (!n)
226 return -1;
228 sigemptyset(&mask);
229 sigaddset(&mask, SIGTERM);
230 sigaddset(&mask, SIGINT);
231 sigaddset(&mask, SIGHUP);
232 sigaddset(&mask, SIGCHLD);
233 pthread_sigmask(SIG_UNBLOCK, &mask, NULL);
234 sigprocmask(SIG_UNBLOCK, &mask, NULL);
236 dnet_node_set_groups(n, groups, group_num);
238 if (have_remote) {
239 int error = -ECONNRESET;
240 for (i=0; i<have_remote; ++i) {
241 if (single_node_stat && (vfs_stat || io_counter_stat))
242 remotes[i].flags = DNET_CFG_NO_ROUTE_LIST;
243 err = dnet_add_state(n, &remotes[i]);
244 if (!err)
245 error = 0;
248 if (error)
249 return error;
252 if (defrag)
253 return dnet_start_defrag(n, cflags);
255 if (writef) {
256 if (id) {
257 struct dnet_id raw;
259 dnet_setup_id(&raw, 0, id);
260 raw.type = type;
262 err = dnet_write_file_id(n, writef, &raw, offset, offset, size, cflags, 0);
263 } else {
264 err = dnet_write_file(n, writef, writef, strlen(writef), offset, offset, size, cflags, 0, type);
267 if (err)
268 return err;
271 if (readf) {
272 if (id) {
273 struct dnet_id raw;
275 dnet_setup_id(&raw, 0, id);
276 raw.type = type;
278 err = dnet_read_file_id(n, readf, &raw, offset, size);
279 } else {
280 err = dnet_read_file(n, readf, readf, strlen(readf), offset, size, type);
282 if (err)
283 return err;
286 if (read_data) {
287 void *data;
288 struct dnet_id raw;
289 struct dnet_io_attr io;
291 if (!id) {
292 dnet_transform(n, read_data, strlen(read_data), &raw);
293 } else {
294 memcpy(&raw.id, id, DNET_ID_SIZE);
296 raw.type = type;
297 raw.group_id = 0; /* unused */
299 memset(&io, 0, sizeof(io));
300 io.type = type;
301 memcpy(io.id, raw.id, DNET_ID_SIZE);
302 memcpy(io.parent, raw.id, DNET_ID_SIZE);
304 /* number of copies to check to find the latest data */
305 io.num = group_num;
307 err = dnet_read_latest(n, &raw, &io, cflags, &data);
308 if (err)
309 return err;
311 data += sizeof(struct dnet_io_attr);
312 io.size -= sizeof(struct dnet_io_attr);
314 while (io.size) {
315 err = write(1, data, io.size);
316 if (err <= 0) {
317 err = -errno;
318 dnet_log_raw(n, DNET_LOG_ERROR, "%s: can not write data to stdout: %d %s",
319 read_data, err, strerror(-err));
320 return err;
323 io.size -= err;
327 if (removef) {
328 if (id) {
329 struct dnet_id raw;
331 for (i=0; i<group_num; ++i) {
332 dnet_setup_id(&raw, groups[i], id);
333 raw.type = type;
334 dnet_remove_object_now(n, &raw, cflags);
337 return 0;
340 err = dnet_remove_file(n, removef, strlen(removef), NULL, cflags);
341 if (err)
342 return err;
345 if (cmd) {
346 struct dnet_id __did, *did = NULL;
347 struct sph *sph;
348 int len = strlen(cmd);
349 int event_size = len;
350 char *ret = NULL;
351 char *tmp;
353 tmp = strchr(cmd, ' ');
354 if (tmp) {
355 event_size = tmp - cmd;
358 if (id) {
359 did = &__did;
361 dnet_setup_id(did, 0, id);
362 did->type = type;
365 sph = malloc(sizeof(struct sph) + len + 1);
366 if (!sph)
367 return -ENOMEM;
369 memset(sph, 0, sizeof(struct sph));
371 sph->flags = DNET_SPH_FLAGS_SRC_BLOCK;
372 sph->key = -1;
373 sph->binary_size = 0;
374 sph->data_size = len - event_size;
375 sph->event_size = event_size;
377 sprintf(sph->data, "%s", cmd);
379 err = dnet_send_cmd(n, did, sph, (void **)&ret);
380 if (err < 0)
381 return err;
383 free(sph);
385 if (err > 0) {
386 char *old = ret;
388 ret = realloc(ret, err + 1);
389 if (!ret)
390 ret = old;
391 else
392 ret[err] = '\0';
394 printf("%s: '%s'", cmd, ret);
395 free(ret);
399 if (lookup) {
400 err = dnet_lookup(n, lookup);
401 if (err)
402 return err;
405 if (vfs_stat) {
406 err = dnet_request_stat(n, NULL, DNET_CMD_STAT, 0, NULL, NULL);
407 if (err < 0)
408 return err;
411 if (io_counter_stat) {
412 err = dnet_request_stat(n, NULL, DNET_CMD_STAT_COUNT, DNET_ATTR_CNTR_GLOBAL, NULL, NULL);
413 if (err < 0)
414 return err;
417 if (update_status) {
418 struct dnet_addr addr;
420 for (i=0; i<have_remote; ++i) {
421 memset(&addr, 0, sizeof(addr));
422 addr.addr_len = sizeof(addr.addr);
424 err = dnet_fill_addr(&addr, remotes[i].addr, remotes[i].port,
425 remotes[i].family, remotes[i].sock_type, remotes[i].proto);
426 if (err) {
427 dnet_log_raw(n, DNET_LOG_ERROR, "ioclient: dnet_fill_addr: %s:%s:%d, sock_type: %d, proto: %d: %s %d\n",
428 remotes[i].addr, remotes[i].port,
429 remotes[i].family, remotes[i].sock_type, remotes[i].proto,
430 strerror(-err), err);
433 err = dnet_update_status(n, &addr, NULL, &node_status);
434 if (err) {
435 dnet_log_raw(n, DNET_LOG_ERROR, "ioclient: dnet_update_status: %s:%s:%d, sock_type: %d, proto: %d: update: %d: "
436 "%s %d\n",
437 remotes[i].addr, remotes[i].port,
438 remotes[i].family, remotes[i].sock_type, remotes[i].proto, update_status,
439 strerror(-err), err);
445 dnet_node_destroy(n);
447 return 0;