glusterfs  8.2
About: GlusterFS is a network/cluster filesystem. The storage server (or each in a cluster) runs glusterfsd and the clients use mount command or glusterfs client to mount the exported filesystem. Release series 8.x (latest version).
  Fossies Dox: glusterfs-8.2.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

rdd.c
Go to the documentation of this file.
1 /*
2  Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com>
3  This file is part of GlusterFS.
4 
5  This file is licensed to you under your choice of the GNU Lesser
6  General Public License, version 3 or any later version (LGPLv3 or
7  later), or the GNU General Public License, version 2 (GPLv2), in all
8  cases as published by the Free Software Foundation.
9 */
10 #include <stdio.h>
11 #include <sys/stat.h>
12 #include <sys/types.h>
13 #include <fcntl.h>
14 #include <unistd.h>
15 #include <pthread.h>
16 #include <stdlib.h>
17 #include <errno.h>
18 #include <string.h>
19 #include <argp.h>
20 
21 #define TWO_POWER(power) (2UL << (power))
22 
23 #define RDD_INTEGER_VALUE ((TWO_POWER((sizeof(int) * 8))) - 1)
24 
25 #ifndef UNIX_PATH_MAX
26 #define UNIX_PATH_MAX 108
27 #endif
28 
29 #define UNIT_KB 1024ULL
30 #define UNIT_MB UNIT_KB * 1024ULL
31 #define UNIT_GB UNIT_MB * 1024ULL
32 #define UNIT_TB UNIT_GB * 1024ULL
33 #define UNIT_PB UNIT_TB * 1024ULL
34 
35 #define UNIT_KB_STRING "KB"
36 #define UNIT_MB_STRING "MB"
37 #define UNIT_GB_STRING "GB"
38 #define UNIT_TB_STRING "TB"
39 #define UNIT_PB_STRING "PB"
40 
41 struct rdd_file {
43  struct stat st;
44  int fd;
45 };
46 
47 struct rdd_config {
48  long iters;
50  size_t max_bs;
51  size_t min_bs;
53  pthread_t *threads;
54  pthread_barrier_t barrier;
55  pthread_mutex_t lock;
56  struct rdd_file in_file;
57  struct rdd_file out_file;
58  ssize_t file_size;
59 };
60 static struct rdd_config rdd_config;
61 
62 enum rdd_keys {
65 };
66 
67 static error_t
68 rdd_parse_opts(int key, char *arg, struct argp_state *_state)
69 {
70  switch (key) {
71  case 'o': {
72  int len = 0;
73  len = strlen(arg);
74  if (len > UNIX_PATH_MAX) {
75  fprintf(stderr, "output file name too long (%s)\n", arg);
76  return -1;
77  }
78 
79  strncpy(rdd_config.out_file.path, arg, len);
80  } break;
81 
82  case 'i': {
83  int len = 0;
84  len = strlen(arg);
85  if (len > UNIX_PATH_MAX) {
86  fprintf(stderr, "input file name too long (%s)\n", arg);
87  return -1;
88  }
89 
90  strncpy(rdd_config.in_file.path, arg, len);
91  rdd_config.in_file.path[len] = '\0';
92  } break;
93 
94  case 'f': {
95  char *tmp = NULL;
96  unsigned long long fs = 0;
97  if (string2bytesize(arg, &fs) == -1) {
98  fprintf(stderr,
99  "invalid argument for file size "
100  "(%s)\n",
101  arg);
102  return -1;
103  }
104 
105  rdd_config.file_size = fs;
106  } break;
107 
108  case RDD_MIN_BS_KEY: {
109  char *tmp = NULL;
110  long bs = 0;
111  bs = strtol(arg, &tmp, 10);
112  if ((bs == LONG_MAX) || (bs == LONG_MIN) || (tmp && *tmp)) {
113  fprintf(stderr,
114  "invalid argument for minimum block"
115  "size (%s)\n",
116  arg);
117  return -1;
118  }
119 
120  rdd_config.min_bs = bs;
121  } break;
122 
123  case RDD_MAX_BS_KEY: {
124  char *tmp = NULL;
125  long bs = 0;
126  bs = strtol(arg, &tmp, 10);
127  if ((bs == LONG_MAX) || (bs == LONG_MIN) || (tmp && *tmp)) {
128  fprintf(stderr,
129  "invalid argument for maximum block"
130  "size (%s)\n",
131  arg);
132  return -1;
133  }
134 
135  rdd_config.max_bs = bs;
136  } break;
137 
138  case 'r': {
139  char *tmp = NULL;
140  long iters = 0;
141  iters = strtol(arg, &tmp, 10);
142  if ((iters == LONG_MAX) || (iters == LONG_MIN) || (tmp && *tmp)) {
143  fprintf(stderr,
144  "invalid argument for iterations"
145  "(%s)\n",
146  arg);
147  return -1;
148  }
149 
151  } break;
152 
153  case 'm': {
154  char *tmp = NULL;
155  long max_ops = 0;
156  max_ops = strtol(arg, &tmp, 10);
157  if ((max_ops == LONG_MAX) || (max_ops == LONG_MIN) ||
158  (tmp && *tmp)) {
159  fprintf(stderr,
160  "invalid argument for max-ops"
161  "(%s)\n",
162  arg);
163  return -1;
164  }
165 
166  rdd_config.max_ops_per_seq = max_ops;
167  } break;
168 
169  case 't': {
170  char *tmp = NULL;
171  long threads = 0;
172  threads = strtol(arg, &tmp, 10);
173  if ((threads == LONG_MAX) || (threads == LONG_MIN) ||
174  (tmp && *tmp)) {
175  fprintf(stderr,
176  "invalid argument for thread count"
177  "(%s)\n",
178  arg);
179  return -1;
180  }
181 
183  } break;
184 
185  case ARGP_KEY_NO_ARGS:
186  break;
187  case ARGP_KEY_ARG:
188  break;
189  case ARGP_KEY_END:
190  if (_state->argc == 1) {
191  argp_usage(_state);
192  }
193  }
194 
195  return 0;
196 }
197 
198 int
199 string2bytesize(const char *str, unsigned long long *n)
200 {
201  unsigned long long value = 0ULL;
202  char *tail = NULL;
203  int old_errno = 0;
204  const char *s = NULL;
205 
206  if (str == NULL || n == NULL) {
207  errno = EINVAL;
208  return -1;
209  }
210 
211  for (s = str; *s != '\0'; s++) {
212  if (isspace(*s)) {
213  continue;
214  }
215  if (*s == '-') {
216  return -1;
217  }
218  break;
219  }
220 
221  old_errno = errno;
222  errno = 0;
223  value = strtoull(str, &tail, 10);
224 
225  if (errno == ERANGE || errno == EINVAL) {
226  return -1;
227  }
228 
229  if (errno == 0) {
230  errno = old_errno;
231  }
232 
233  if (tail[0] != '\0') {
234  if (strcasecmp(tail, UNIT_KB_STRING) == 0) {
235  value *= UNIT_KB;
236  } else if (strcasecmp(tail, UNIT_MB_STRING) == 0) {
237  value *= UNIT_MB;
238  } else if (strcasecmp(tail, UNIT_GB_STRING) == 0) {
239  value *= UNIT_GB;
240  } else if (strcasecmp(tail, UNIT_TB_STRING) == 0) {
241  value *= UNIT_TB;
242  } else if (strcasecmp(tail, UNIT_PB_STRING) == 0) {
243  value *= UNIT_PB;
244  }
245 
246  else {
247  return -1;
248  }
249  }
250 
251  *n = value;
252 
253  return 0;
254 }
255 
256 static struct argp_option rdd_options[] = {
257  {"if", 'i', "INPUT_FILE", 0, "input-file"},
258  {"of", 'o', "OUTPUT_FILE", 0, "output-file"},
259  {"threads", 't', "COUNT", 0, "number of threads to spawn (defaults to 2)"},
260  {"min-bs", RDD_MIN_BS_KEY, "MIN_BLOCK_SIZE", 0,
261  "Minimum block size in bytes (defaults to 1024)"},
262  {"max-bs", RDD_MAX_BS_KEY, "MAX_BLOCK_SIZE", 0,
263  "Maximum block size in bytes (defaults to 4096)"},
264  {"iters", 'r', "ITERS", 0,
265  "Number of read-write sequences (defaults to 1000000)"},
266  {"max-ops", 'm', "MAXOPS", 0,
267  "maximum number of read-writes to be performed in a sequence (defaults to "
268  "1)"},
269  {"file-size", 'f', "FILESIZE", 0,
270  "the size of the file which will be created and upon it I/O will be done"
271  " (defaults to 100MB"},
272  {0, 0, 0, 0, 0}};
273 
274 static struct argp argp = {
276  "random dd - tool to do a sequence of random block-sized continuous"
277  "read writes starting at a random offset"};
278 
279 static void
281 {
282  char *tmp_path = "rdd.in";
283 
285  rdd_config.iters = 1000000;
286  rdd_config.max_bs = 4096;
287  rdd_config.min_bs = 1024;
290  strncpy(rdd_config.in_file.path, tmp_path, strlen(tmp_path));
291  rdd_config.file_size = 104857600;
292 
293  return;
294 }
295 
296 static char
298 {
299  char ret = 1;
300  int fd = -1;
301 
302  fd = open(rdd_config.in_file.path, O_RDONLY);
303  if (fd == -1 && (errno != ENOENT)) {
304  fprintf(stderr, "open: (%s)", strerror(errno));
305  ret = 0;
306  goto out;
307  }
308  close(fd);
309 
311  fprintf(stderr,
312  "minimum blocksize %ld is greater than the "
313  "maximum blocksize %ld",
315  ret = 0;
316  goto out;
317  }
318 
319  if (strlen(rdd_config.out_file.path) == 0) {
320  sprintf(rdd_config.out_file.path, "%s.rddout", rdd_config.in_file.path);
321  }
322 
323 out:
324  return ret;
325 }
326 
327 static void *
328 rdd_read_write(void *arg)
329 {
330  int i = 0, ret = 0;
331  size_t bs = 0;
332  off_t offset = 0;
333  long rand = 0;
334  long max_ops = 0;
335  char *buf = NULL;
336 
337  buf = calloc(1, rdd_config.max_bs);
338  if (!buf) {
339  fprintf(stderr, "calloc failed (%s)\n", strerror(errno));
340  ret = -1;
341  goto out;
342  }
343 
344  for (i = 0; i < rdd_config.iters; i++) {
345  pthread_mutex_lock(&rdd_config.lock);
346  {
347  int bytes = 0;
348  rand = random();
349 
351  bs = rdd_config.max_bs;
352  } else {
353  bs = rdd_config.min_bs +
354  (rand % (rdd_config.max_bs - rdd_config.min_bs));
355  }
356 
357  offset = rand % rdd_config.in_file.st.st_size;
358  max_ops = rand % rdd_config.max_ops_per_seq;
359  if (!max_ops) {
360  max_ops++;
361  }
362 
363  ret = lseek(rdd_config.in_file.fd, offset, SEEK_SET);
364  if (ret != offset) {
365  fprintf(stderr, "lseek failed (%s)\n", strerror(errno));
366  ret = -1;
367  goto unlock;
368  }
369 
370  ret = lseek(rdd_config.out_file.fd, offset, SEEK_SET);
371  if (ret != offset) {
372  fprintf(stderr, "lseek failed (%s)\n", strerror(errno));
373  ret = -1;
374  goto unlock;
375  }
376 
377  while (max_ops--) {
378  bytes = read(rdd_config.in_file.fd, buf, bs);
379  if (!bytes) {
380  break;
381  }
382 
383  if (bytes == -1) {
384  fprintf(stderr, "read failed (%s)\n", strerror(errno));
385  ret = -1;
386  goto unlock;
387  }
388 
389  if (write(rdd_config.out_file.fd, buf, bytes) != bytes) {
390  fprintf(stderr, "write failed (%s)\n", strerror(errno));
391  ret = -1;
392  goto unlock;
393  }
394  }
395  }
396  unlock:
397  pthread_mutex_unlock(&rdd_config.lock);
398  if (ret == -1) {
399  goto out;
400  }
401  ret = 0;
402  }
403 out:
404  free(buf);
405  pthread_barrier_wait(&rdd_config.barrier);
406 
407  return NULL;
408 }
409 
410 static void
411 cleanup(void)
412 {
413  close(rdd_config.in_file.fd);
414  close(rdd_config.out_file.fd);
416 }
417 
418 static int
420 {
421  int ret = -1;
422  char buf[4096] = {
423  0,
424  };
425  struct stat stbuf = {
426  0,
427  };
428  int fd[2] = {
429  -1,
430  };
431  size_t total_size = -1;
432 
433  total_size = rdd_config.file_size;
434 
435  ret = stat(rdd_config.in_file.path, &stbuf);
436  if (ret == -1 && (errno != ENOENT))
437  goto out;
438 
439  fd[1] = open(rdd_config.in_file.path, O_CREAT | O_WRONLY | O_TRUNC);
440  if (fd[1] == -1)
441  goto out;
442 
443  fd[0] = open("/dev/urandom", O_RDONLY);
444  if (fd[0] == -1)
445  goto out;
446 
447  while (total_size > 0) {
448  if (total_size >= 4096) {
449  ret = read(fd[0], buf, 4096);
450  if (ret == -1)
451  goto out;
452  ret = write(fd[1], buf, 4096);
453  if (ret == -1)
454  goto out;
455  total_size = total_size - 4096;
456  } else {
457  ret = read(fd[0], buf, total_size);
458  if (ret == -1)
459  goto out;
460  ret = write(fd[1], buf, total_size);
461  if (ret == -1)
462  goto out;
463  total_size = total_size - total_size;
464  }
465  }
466 
467  ret = 0;
468 
469 out:
470  if (fd[0] > 0)
471  close(fd[0]);
472  if (fd[1] > 0)
473  close(fd[1]);
474  return ret;
475 }
476 
477 static int
479 {
480  int i = 0, ret = -1, fd = -1;
481  char buf[4096];
482 
483  ret = check_and_create();
484  if (ret == -1)
485  goto out;
486 
487  fd = open(rdd_config.in_file.path, O_RDONLY);
488  if (fd < 0) {
489  fprintf(stderr, "cannot open %s (%s)\n", rdd_config.in_file.path,
490  strerror(errno));
491  ret = -1;
492  goto out;
493  }
494  ret = fstat(fd, &rdd_config.in_file.st);
495  if (ret != 0) {
496  close(fd);
497  fprintf(stderr, "cannot stat %s (%s)\n", rdd_config.in_file.path,
498  strerror(errno));
499  ret = -1;
500  goto out;
501  }
502  rdd_config.in_file.fd = fd;
503 
504  fd = open(rdd_config.out_file.path, O_WRONLY | O_CREAT | O_TRUNC,
505  S_IRWXU | S_IROTH);
506  if (fd < 0) {
507  close(rdd_config.in_file.fd);
508  rdd_config.in_file.fd = -1;
509  fprintf(stderr, "cannot open %s (%s)\n", rdd_config.out_file.path,
510  strerror(errno));
511  ret = -1;
512  goto out;
513  }
514  rdd_config.out_file.fd = fd;
515 
516  while ((ret = read(rdd_config.in_file.fd, buf, 4096)) > 0) {
517  if (write(rdd_config.out_file.fd, buf, ret) != ret) {
518  fprintf(stderr, "write failed (%s)\n", strerror(errno));
519  cleanup();
520  ret = -1;
521  goto out;
522  }
523  }
524 
525  rdd_config.threads = calloc(rdd_config.thread_count, sizeof(pthread_t));
526  if (rdd_config.threads == NULL) {
527  fprintf(stderr, "calloc() failed (%s)\n", strerror(errno));
528 
529  ret = -1;
530  cleanup();
531  goto out;
532  }
533 
534  ret = pthread_barrier_init(&rdd_config.barrier, NULL,
536  if (ret != 0) {
537  fprintf(stderr, "pthread_barrier_init() failed (%s)\n", strerror(ret));
538 
539  free(rdd_config.threads);
540  cleanup();
541  ret = -1;
542  goto out;
543  }
544 
545  ret = pthread_mutex_init(&rdd_config.lock, NULL);
546  if (ret != 0) {
547  fprintf(stderr, "pthread_mutex_init() failed (%s)\n", strerror(ret));
548 
549  free(rdd_config.threads);
550  pthread_barrier_destroy(&rdd_config.barrier);
551  cleanup();
552  ret = -1;
553  goto out;
554  }
555 
556  for (i = 0; i < rdd_config.thread_count; i++) {
557  ret = pthread_create(&rdd_config.threads[i], NULL, rdd_read_write,
558  NULL);
559  if (ret != 0) {
560  fprintf(stderr, "pthread_create failed (%s)\n", strerror(errno));
561  exit(1);
562  }
563  }
564 
565 out:
566  return ret;
567 }
568 
569 static void
571 {
572  pthread_barrier_wait(&rdd_config.barrier);
573 }
574 
575 int
576 main(int argc, char *argv[])
577 {
578  int ret = -1;
579 
581 
582  ret = argp_parse(&argp, argc, argv, 0, 0, NULL);
583  if (ret != 0) {
584  ret = -1;
585  fprintf(stderr, "%s: argp_parse() failed\n", argv[0]);
586  goto err;
587  }
588 
589  if (!rdd_valid_config()) {
590  ret = -1;
591  fprintf(stderr, "%s: configuration validation failed\n", argv[0]);
592  goto err;
593  }
594 
595  ret = rdd_spawn_threads();
596  if (ret != 0) {
597  fprintf(stderr, "%s: spawning threads failed\n", argv[0]);
598  goto err;
599  }
600 
602 
603 err:
604  return ret;
605 }
RDD_MAX_BS_KEY
@ RDD_MAX_BS_KEY
Definition: rdd.c:64
out
#define out(x...)
Definition: gcrawler.c:35
rdd_config::out_file
struct rdd_file out_file
Definition: rdd.c:57
UNIT_MB
#define UNIT_MB
Definition: rdd.c:30
string2bytesize
int string2bytesize(const char *str, unsigned long long *n)
Definition: rdd.c:199
rdd_file
Definition: rdd.c:41
check_and_create
static int check_and_create(void)
Definition: rdd.c:419
UNIT_TB_STRING
#define UNIT_TB_STRING
Definition: rdd.c:38
rdd_keys
rdd_keys
Definition: rdd.c:62
rdd_spawn_threads
static int rdd_spawn_threads(void)
Definition: rdd.c:478
rdd_config::min_bs
size_t min_bs
Definition: rdd.c:51
rdd_config::max_ops_per_seq
long max_ops_per_seq
Definition: rdd.c:49
UNIT_PB
#define UNIT_PB
Definition: rdd.c:33
rdd_config::barrier
pthread_barrier_t barrier
Definition: rdd.c:54
rdd_options
static struct argp_option rdd_options[]
Definition: rdd.c:256
rdd_read_write
static void * rdd_read_write(void *arg)
Definition: rdd.c:328
RDD_MIN_BS_KEY
@ RDD_MIN_BS_KEY
Definition: rdd.c:63
rdd_parse_opts
static error_t rdd_parse_opts(int key, char *arg, struct argp_state *_state)
Definition: rdd.c:68
rdd_config::threads
pthread_t * threads
Definition: rdd.c:53
rdd_file::st
struct stat st
Definition: rdd.c:43
rdd_config::in_file
struct rdd_file in_file
Definition: rdd.c:56
rdd_config::lock
pthread_mutex_t lock
Definition: rdd.c:55
UNIT_PB_STRING
#define UNIT_PB_STRING
Definition: rdd.c:39
rdd_config::iters
long iters
Definition: rdd.c:48
UNIT_TB
#define UNIT_TB
Definition: rdd.c:32
UNIT_GB
#define UNIT_GB
Definition: rdd.c:31
rdd_config::file_size
ssize_t file_size
Definition: rdd.c:58
rdd_config::thread_count
int thread_count
Definition: rdd.c:52
rdd_config::max_bs
size_t max_bs
Definition: rdd.c:50
cleanup
static void cleanup(void)
Definition: rdd.c:411
main
int main(int argc, char *argv[])
Definition: rdd.c:576
rdd_valid_config
static char rdd_valid_config(void)
Definition: rdd.c:297
rdd_file::path
char path[108]
Definition: rdd.c:42
rdd_wait_for_completion
static void rdd_wait_for_completion(void)
Definition: rdd.c:570
rdd_default_config
static void rdd_default_config(void)
Definition: rdd.c:280
UNIT_MB_STRING
#define UNIT_MB_STRING
Definition: rdd.c:36
UNIT_GB_STRING
#define UNIT_GB_STRING
Definition: rdd.c:37
rdd_config
Definition: rdd.c:47
UNIT_KB
#define UNIT_KB
Definition: rdd.c:29
UNIT_KB_STRING
#define UNIT_KB_STRING
Definition: rdd.c:35
rdd_file::fd
int fd
Definition: rdd.c:44
err
#define err(x...)
Definition: gcrawler.c:34
UNIX_PATH_MAX
#define UNIX_PATH_MAX
Definition: rdd.c:26
argp
static struct argp argp
Definition: rdd.c:274