Merge branch 'master' of http://toshik-nb-w7.ld.yandex.ru/gitweb/elliptics into toshik
[elliptics.git] / example / check.c
blob1d5b02513dc24571c29917716dd413c58fb01fef
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 #define _XOPEN_SOURCE 600
18 #include <sys/mman.h>
19 #include <sys/stat.h>
20 #include <sys/socket.h>
21 #include <sys/syscall.h>
22 #include <sys/time.h>
23 #include <sys/types.h>
25 #include <ctype.h>
26 #include <fcntl.h>
27 #include <errno.h>
28 #include <pthread.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <time.h>
33 #include <unistd.h>
35 #include <netinet/in.h>
37 #include "elliptics/packet.h"
38 #include "elliptics/interface.h"
40 #include "common.h"
42 #ifndef __unused
43 #define __unused __attribute__ ((unused))
44 #endif
46 static struct dnet_log check_logger;
47 static char *default_log = "/dev/stderr";
49 static void check_usage(char *p)
51 fprintf(stderr, "Usage: %s\n"
52 " -r addr:port:family - adds remote node\n"
53 " -l log - log file. Default: disabled\n"
54 " -d - work as daemon\n"
55 " -w timeout - wait timeout in seconds used to wait for content sync.\n"
56 " -m level - log events level\n"
57 " -M - do not check copies in other groups, run only merge check\n"
58 " -R - only delete objects marked as REMOVED\n"
59 " -D - dry run - do not perform any action, just update counters\n"
60 " -t timestamp - only check those objects, which were previously checked BEFORE this time\n"
61 " format: year-month-day hours:minutes:seconds like \"2011-01-13 23:15:00\"\n"
62 " -u timestamp - only check those objects, which were created after this time, format as above\n"
63 " -U timestamp - only check those objects, which were created before this time, format as above\n"
64 " -g group:group... - override groups with replicas\n"
65 " -n num - number of checking threads to start by the server\n"
66 " -f file - file with list of objects to check\n"
67 " -b num - start checking for data in blob number <num>\n"
68 " -B num - number of blobs to check objects in\n"
69 " -h - this help\n"
70 , p);
73 static int dnet_check_fill(struct dnet_node *n, struct dnet_check_request *r, char *data, int num)
75 int i;
76 char *cur;
77 struct dnet_id id;
78 struct dnet_id *rid = (struct dnet_id *)(r + 1);
79 char tmp_str[DNET_ID_SIZE*2+1];
81 for (i=0; i<num; ++i) {
82 cur = strchr(data, '\n');
84 if (!cur || !*cur)
85 break;
87 dnet_transform(n, data, cur - data, &id);
89 rid[i] = id;
90 dnet_convert_id(&rid[i]);
92 dnet_log_raw(n, DNET_LOG_NOTICE, "check: %s\n", dnet_dump_id_len_raw(id.id, DNET_ID_SIZE, tmp_str));
94 data = cur + 1;
97 return 0;
100 static struct dnet_check_request *dnet_check_gen_request(struct dnet_node *n, struct dnet_check_request *base, char *file)
102 struct dnet_check_request *r;
103 char *data, *cur;
104 int fd, err, num = 0;
105 struct stat st;
107 fd = open(file, O_RDONLY);
108 if (fd < 0) {
109 err = -errno;
110 dnet_log_raw(n, DNET_LOG_ERROR, "check: failed to open check file '%s': %s [%d]\n",
111 file, strerror(errno), errno);
112 goto err_out_exit;
115 err = fstat(fd, &st);
116 if (err < 0) {
117 err = -errno;
118 dnet_log_raw(n, DNET_LOG_ERROR, "check: failed to stat check file '%s': %s [%d]\n",
119 file, strerror(errno), errno);
120 goto err_out_close;
123 data = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
124 if (data == MAP_FAILED) {
125 err = -errno;
126 dnet_log_raw(n, DNET_LOG_ERROR, "check: failed to map check file '%s': %s [%d]\n",
127 file, strerror(errno), errno);
128 goto err_out_close;
131 cur = data;
132 while (cur && *cur) {
133 cur = strchr(cur, '\n');
134 if (!cur)
135 break;
137 num++;
138 cur++;
141 if (!num) {
142 dnet_log_raw(n, DNET_LOG_NOTICE, "check: check file '%s' is empty: %s [%d]\n",
143 file, strerror(errno), errno);
146 r = malloc(sizeof(*r) + num * sizeof(struct dnet_id));
147 if (!r) {
148 err = -ENOMEM;
149 goto err_out_unmap;
152 memcpy(r, base, sizeof(*r));
153 r->obj_num = num;
155 err = dnet_check_fill(n, r, data, num);
156 if (err)
157 goto err_out_free;
159 munmap(data, st.st_size);
160 close(fd);
162 return r;
164 err_out_free:
165 free(r);
166 err_out_unmap:
167 munmap(data, st.st_size);
168 err_out_close:
169 close(fd);
170 err_out_exit:
171 return NULL;
174 int main(int argc, char *argv[])
176 int ch, err, have_remote = 0;
177 struct dnet_node *n = NULL;
178 struct dnet_config cfg, rem;
179 char *logfile = default_log;
180 int daemonize = 0;
181 FILE *log = NULL;
182 struct dnet_check_request r, *req, *req2;
183 struct tm tm;
184 char *file = NULL;
185 int group_num = 0, *groups;
186 struct dnet_session *s;
188 memset(&cfg, 0, sizeof(struct dnet_config));
190 cfg.sock_type = SOCK_STREAM;
191 cfg.proto = IPPROTO_TCP;
192 cfg.wait_timeout = 60*60;
193 check_logger.log_level = DNET_LOG_INFO;
194 cfg.check_timeout = 60;
196 memcpy(&rem, &cfg, sizeof(struct dnet_config));
197 memset(&tm, 0, sizeof(tm));
199 memset(&r, 0, sizeof(r));
201 while ((ch = getopt(argc, argv, "b:B:DN:f:n:t:u:U:MRm:w:l:dr:g:h")) != -1) {
202 switch (ch) {
203 case 'b':
204 r.blob_start = atoi(optarg);
205 break;
206 case 'B':
207 r.blob_num = atoi(optarg);
208 break;
209 case 'N':
210 cfg.ns = optarg;
211 cfg.nsize = strlen(optarg);
212 break;
213 case 'f':
214 file = optarg;
215 break;
216 case 'n':
217 r.thread_num = atoi(optarg);
218 break;
219 case 't':
220 if (!strptime(optarg, "%F %T", &tm)) {
221 fprintf(stderr, "Invalid timestamp string in -t\n");
222 check_usage(argv[0]);
223 return -EINVAL;
225 r.timestamp = mktime(&tm);
226 break;
227 case 'u':
228 if (!strptime(optarg, "%F %T", &tm)) {
229 fprintf(stderr, "Invalid timestamp string in -u\n");
230 check_usage(argv[0]);
231 return -EINVAL;
233 r.updatestamp_start = mktime(&tm);
234 break;
235 case 'U':
236 if (!strptime(optarg, "%F %T", &tm)) {
237 fprintf(stderr, "Invalid timestamp string in -U\n");
238 check_usage(argv[0]);
239 return -EINVAL;
241 r.updatestamp_stop = mktime(&tm);
242 break;
243 case 'D':
244 r.flags |= DNET_CHECK_DRY_RUN;
245 break;
246 case 'M':
247 r.flags |= DNET_CHECK_MERGE;
248 break;
249 // case 'F':
250 // r.flags |= DNET_CHECK_FULL;
251 // break;
252 case 'R':
253 r.flags |= DNET_CHECK_DELETE;
254 break;
255 case 'm':
256 check_logger.log_level = strtoul(optarg, NULL, 0);
257 break;
258 case 'w':
259 cfg.check_timeout = cfg.wait_timeout = atoi(optarg);
260 break;
261 case 'l':
262 logfile = optarg;
263 break;
264 case 'd':
265 daemonize = 1;
266 break;
267 case 'r':
268 err = dnet_parse_addr(optarg, &rem);
269 if (err)
270 return err;
271 have_remote = 1;
272 break;
273 case 'g':
274 group_num = dnet_parse_groups(optarg, &groups);
275 if (group_num <= 0)
276 return -1;
277 break;
278 case 'h':
279 default:
280 check_usage(argv[0]);
281 return -1;
285 if (!have_remote) {
286 fprintf(stderr, "No remote node specified to route requests.\n");
287 return -ENOENT;
290 log = fopen(logfile, "a");
291 if (!log) {
292 err = -errno;
293 fprintf(stderr, "Failed to open log file %s: %s.\n", logfile, strerror(errno));
294 return err;
297 if (daemonize) {
298 if (logfile == default_log) {
299 fprintf(stderr, "You should specify log file for daemon mode\n");
300 } else {
301 dnet_background();
305 check_logger.log_private = log;
306 check_logger.log = dnet_common_log;
307 cfg.log = &check_logger;
309 n = dnet_node_create(&cfg);
310 if (!n)
311 return -1;
313 rem.flags = DNET_CFG_NO_ROUTE_LIST;
314 err = dnet_add_state(n, &rem);
315 if (err)
316 return err;
318 req = &r;
319 if (file) {
320 req = dnet_check_gen_request(n, &r, file);
321 if (!req)
322 return -EINVAL;
325 if (group_num > 0) {
326 req2 = malloc(sizeof(struct dnet_check_request) + req->obj_num * sizeof(struct dnet_id) + group_num * sizeof(int));
327 if (!req2)
328 return -ENOMEM;
330 memcpy(req2, req, sizeof(struct dnet_check_request) + req->obj_num * sizeof(struct dnet_id));
331 memcpy((char *)req2 + sizeof(struct dnet_check_request) + req->obj_num * sizeof(struct dnet_id), groups, group_num * sizeof(int));
332 req2->group_num = group_num;
334 req = req2;
337 s = dnet_session_create(n);
338 if (!s)
339 return -ENOMEM;
341 return dnet_request_check(s, req);