Fixed pool growing policy
[elliptics.git] / example / check.c
blob7f4c349f07068e4bc9d0380ec5e84561150fa1c5
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;
187 memset(&cfg, 0, sizeof(struct dnet_config));
189 cfg.sock_type = SOCK_STREAM;
190 cfg.proto = IPPROTO_TCP;
191 cfg.wait_timeout = 60*60;
192 check_logger.log_level = DNET_LOG_INFO;
193 cfg.check_timeout = 60;
195 memcpy(&rem, &cfg, sizeof(struct dnet_config));
196 memset(&tm, 0, sizeof(tm));
198 memset(&r, 0, sizeof(r));
200 while ((ch = getopt(argc, argv, "b:B:DN:f:n:t:u:U:MRm:w:l:dr:g:h")) != -1) {
201 switch (ch) {
202 case 'b':
203 r.blob_start = atoi(optarg);
204 break;
205 case 'B':
206 r.blob_num = atoi(optarg);
207 break;
208 case 'N':
209 cfg.ns = optarg;
210 cfg.nsize = strlen(optarg);
211 break;
212 case 'f':
213 file = optarg;
214 break;
215 case 'n':
216 r.thread_num = atoi(optarg);
217 break;
218 case 't':
219 if (!strptime(optarg, "%F %T", &tm)) {
220 fprintf(stderr, "Invalid timestamp string in -t\n");
221 check_usage(argv[0]);
222 return -EINVAL;
224 r.timestamp = mktime(&tm);
225 break;
226 case 'u':
227 if (!strptime(optarg, "%F %T", &tm)) {
228 fprintf(stderr, "Invalid timestamp string in -u\n");
229 check_usage(argv[0]);
230 return -EINVAL;
232 r.updatestamp_start = mktime(&tm);
233 break;
234 case 'U':
235 if (!strptime(optarg, "%F %T", &tm)) {
236 fprintf(stderr, "Invalid timestamp string in -U\n");
237 check_usage(argv[0]);
238 return -EINVAL;
240 r.updatestamp_stop = mktime(&tm);
241 break;
242 case 'D':
243 r.flags |= DNET_CHECK_DRY_RUN;
244 break;
245 case 'M':
246 r.flags |= DNET_CHECK_MERGE;
247 break;
248 // case 'F':
249 // r.flags |= DNET_CHECK_FULL;
250 // break;
251 case 'R':
252 r.flags |= DNET_CHECK_DELETE;
253 break;
254 case 'm':
255 check_logger.log_level = strtoul(optarg, NULL, 0);
256 break;
257 case 'w':
258 cfg.check_timeout = cfg.wait_timeout = atoi(optarg);
259 break;
260 case 'l':
261 logfile = optarg;
262 break;
263 case 'd':
264 daemonize = 1;
265 break;
266 case 'r':
267 err = dnet_parse_addr(optarg, &rem);
268 if (err)
269 return err;
270 have_remote = 1;
271 break;
272 case 'g':
273 group_num = dnet_parse_groups(optarg, &groups);
274 if (group_num <= 0)
275 return -1;
276 break;
277 case 'h':
278 default:
279 check_usage(argv[0]);
280 return -1;
284 if (!have_remote) {
285 fprintf(stderr, "No remote node specified to route requests.\n");
286 return -ENOENT;
289 log = fopen(logfile, "a");
290 if (!log) {
291 err = -errno;
292 fprintf(stderr, "Failed to open log file %s: %s.\n", logfile, strerror(errno));
293 return err;
296 if (daemonize) {
297 if (logfile == default_log) {
298 fprintf(stderr, "You should specify log file for daemon mode\n");
299 } else {
300 dnet_background();
304 check_logger.log_private = log;
305 check_logger.log = dnet_common_log;
306 cfg.log = &check_logger;
308 n = dnet_node_create(&cfg);
309 if (!n)
310 return -1;
312 rem.flags = DNET_CFG_NO_ROUTE_LIST;
313 err = dnet_add_state(n, &rem);
314 if (err)
315 return err;
317 req = &r;
318 if (file) {
319 req = dnet_check_gen_request(n, &r, file);
320 if (!req)
321 return -EINVAL;
324 if (group_num > 0) {
325 req2 = malloc(sizeof(struct dnet_check_request) + req->obj_num * sizeof(struct dnet_id) + group_num * sizeof(int));
326 if (!req2)
327 return -ENOMEM;
329 memcpy(req2, req, sizeof(struct dnet_check_request) + req->obj_num * sizeof(struct dnet_id));
330 memcpy((char *)req2 + sizeof(struct dnet_check_request) + req->obj_num * sizeof(struct dnet_id), groups, group_num * sizeof(int));
331 req2->group_num = group_num;
333 req = req2;
336 return dnet_request_check(n, req);