2 * 2008+ 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.
16 #define _XOPEN_SOURCE 600
20 #include <sys/socket.h>
21 #include <sys/syscall.h>
23 #include <sys/types.h>
35 #include <netinet/in.h>
37 #include "elliptics/packet.h"
38 #include "elliptics/interface.h"
43 #define __unused __attribute__ ((unused))
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"
73 static int dnet_check_fill(struct dnet_node
*n
, struct dnet_check_request
*r
, char *data
, int num
)
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');
87 dnet_transform(n
, data
, cur
- data
, &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
));
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
;
104 int fd
, err
, num
= 0;
107 fd
= open(file
, O_RDONLY
);
110 dnet_log_raw(n
, DNET_LOG_ERROR
, "check: failed to open check file '%s': %s [%d]\n",
111 file
, strerror(errno
), errno
);
115 err
= fstat(fd
, &st
);
118 dnet_log_raw(n
, DNET_LOG_ERROR
, "check: failed to stat check file '%s': %s [%d]\n",
119 file
, strerror(errno
), errno
);
123 data
= mmap(NULL
, st
.st_size
, PROT_READ
, MAP_SHARED
, fd
, 0);
124 if (data
== MAP_FAILED
) {
126 dnet_log_raw(n
, DNET_LOG_ERROR
, "check: failed to map check file '%s': %s [%d]\n",
127 file
, strerror(errno
), errno
);
132 while (cur
&& *cur
) {
133 cur
= strchr(cur
, '\n');
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
));
152 memcpy(r
, base
, sizeof(*r
));
155 err
= dnet_check_fill(n
, r
, data
, num
);
159 munmap(data
, st
.st_size
);
167 munmap(data
, st
.st_size
);
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
;
182 struct dnet_check_request r
, *req
, *req2
;
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) {
204 r
.blob_start
= atoi(optarg
);
207 r
.blob_num
= atoi(optarg
);
211 cfg
.nsize
= strlen(optarg
);
217 r
.thread_num
= atoi(optarg
);
220 if (!strptime(optarg
, "%F %T", &tm
)) {
221 fprintf(stderr
, "Invalid timestamp string in -t\n");
222 check_usage(argv
[0]);
225 r
.timestamp
= mktime(&tm
);
228 if (!strptime(optarg
, "%F %T", &tm
)) {
229 fprintf(stderr
, "Invalid timestamp string in -u\n");
230 check_usage(argv
[0]);
233 r
.updatestamp_start
= mktime(&tm
);
236 if (!strptime(optarg
, "%F %T", &tm
)) {
237 fprintf(stderr
, "Invalid timestamp string in -U\n");
238 check_usage(argv
[0]);
241 r
.updatestamp_stop
= mktime(&tm
);
244 r
.flags
|= DNET_CHECK_DRY_RUN
;
247 r
.flags
|= DNET_CHECK_MERGE
;
250 // r.flags |= DNET_CHECK_FULL;
253 r
.flags
|= DNET_CHECK_DELETE
;
256 check_logger
.log_level
= strtoul(optarg
, NULL
, 0);
259 cfg
.check_timeout
= cfg
.wait_timeout
= atoi(optarg
);
268 err
= dnet_parse_addr(optarg
, &rem
);
274 group_num
= dnet_parse_groups(optarg
, &groups
);
280 check_usage(argv
[0]);
286 fprintf(stderr
, "No remote node specified to route requests.\n");
290 log
= fopen(logfile
, "a");
293 fprintf(stderr
, "Failed to open log file %s: %s.\n", logfile
, strerror(errno
));
298 if (logfile
== default_log
) {
299 fprintf(stderr
, "You should specify log file for daemon mode\n");
305 check_logger
.log_private
= log
;
306 check_logger
.log
= dnet_common_log
;
307 cfg
.log
= &check_logger
;
309 n
= dnet_node_create(&cfg
);
313 rem
.flags
= DNET_CFG_NO_ROUTE_LIST
;
314 err
= dnet_add_state(n
, &rem
);
320 req
= dnet_check_gen_request(n
, &r
, file
);
326 req2
= malloc(sizeof(struct dnet_check_request
) + req
->obj_num
* sizeof(struct dnet_id
) + group_num
* sizeof(int));
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
;
337 s
= dnet_session_create(n
);
341 return dnet_request_check(s
, req
);