| /* |
| * This file and its contents are supplied under the terms of the |
| * Common Development and Distribution License ("CDDL"), version 1.0. |
| * You may only use this file in accordance with the terms of version |
| * 1.0 of the CDDL. |
| * |
| * A full copy of the text of the CDDL should have accompanied this |
| * source. A copy of the CDDL is also available via the Internet at |
| * http://www.illumos.org/license/CDDL. |
| */ |
| |
| /* |
| * Copyright (c) 2017 by Delphix. All rights reserved. |
| */ |
| |
| /* |
| * The following is defined so the source can use |
| * lrand48() and srand48(). |
| */ |
| #define __EXTENSIONS__ |
| |
| #include <stdint.h> |
| #include <string.h> |
| #include "../file_common.h" |
| |
| /* |
| * The following sample was derived from real-world data |
| * of a production Oracle database. |
| */ |
| static uint64_t size_distribution[] = { |
| 0, |
| 1499018, |
| 352084, |
| 1503485, |
| 4206227, |
| 5626657, |
| 5387001, |
| 3733756, |
| 2233094, |
| 874652, |
| 238635, |
| 81434, |
| 33357, |
| 13106, |
| 2009, |
| 1, |
| 23660, |
| }; |
| |
| |
| static uint64_t distribution_n; |
| |
| static uint8_t randbuf[BLOCKSZ]; |
| |
| static void |
| rwc_pwrite(int fd, const void *buf, size_t nbytes, off_t offset) |
| { |
| size_t nleft = nbytes; |
| ssize_t nwrite = 0; |
| |
| nwrite = pwrite(fd, buf, nbytes, offset); |
| if (nwrite < 0) { |
| perror("pwrite"); |
| exit(EXIT_FAILURE); |
| } |
| |
| nleft -= nwrite; |
| if (nleft != 0) { |
| (void) fprintf(stderr, "warning: pwrite: " |
| "wrote %zu out of %zu bytes\n", |
| (nbytes - nleft), nbytes); |
| } |
| } |
| |
| static void |
| fillbuf(char *buf) |
| { |
| uint64_t rv = lrand48() % distribution_n; |
| uint64_t sum = 0; |
| |
| uint64_t i; |
| for (i = 0; |
| i < sizeof (size_distribution) / sizeof (size_distribution[0]); |
| i++) { |
| sum += size_distribution[i]; |
| if (rv < sum) |
| break; |
| } |
| |
| bcopy(randbuf, buf, BLOCKSZ); |
| if (i == 0) |
| bzero(buf, BLOCKSZ - 10); |
| else if (i < 16) |
| bzero(buf, BLOCKSZ - i * 512 + 256); |
| /*LINTED: E_BAD_PTR_CAST_ALIGN*/ |
| ((uint32_t *)buf)[0] = lrand48(); |
| } |
| |
| static void |
| exit_usage(void) |
| { |
| (void) printf("usage: "); |
| (void) printf("randwritecomp <file> [-s] [nwrites]\n"); |
| exit(EXIT_FAILURE); |
| } |
| |
| static void |
| sequential_writes(int fd, char *buf, uint64_t nblocks, int64_t n) |
| { |
| for (int64_t i = 0; n == -1 || i < n; i++) { |
| fillbuf(buf); |
| |
| static uint64_t j = 0; |
| if (j == 0) |
| j = lrand48() % nblocks; |
| rwc_pwrite(fd, buf, BLOCKSZ, j * BLOCKSZ); |
| j++; |
| if (j >= nblocks) |
| j = 0; |
| } |
| } |
| |
| static void |
| random_writes(int fd, char *buf, uint64_t nblocks, int64_t n) |
| { |
| for (int64_t i = 0; n == -1 || i < n; i++) { |
| fillbuf(buf); |
| rwc_pwrite(fd, buf, BLOCKSZ, (lrand48() % nblocks) * BLOCKSZ); |
| } |
| } |
| |
| int |
| main(int argc, char *argv[]) |
| { |
| int fd, err; |
| char *filename = NULL; |
| char buf[BLOCKSZ]; |
| struct stat ss; |
| uint64_t nblocks; |
| int64_t n = -1; |
| int sequential = 0; |
| |
| if (argc < 2) |
| exit_usage(); |
| |
| argv++; |
| if (strcmp("-s", argv[0]) == 0) { |
| sequential = 1; |
| argv++; |
| } |
| |
| if (argv[0] == NULL) |
| exit_usage(); |
| else |
| filename = argv[0]; |
| |
| argv++; |
| if (argv[0] != NULL) |
| n = strtoull(argv[0], NULL, 0); |
| |
| fd = open(filename, O_RDWR|O_CREAT, 0666); |
| err = fstat(fd, &ss); |
| if (err != 0) { |
| (void) fprintf(stderr, |
| "error: fstat returned error code %d\n", err); |
| exit(EXIT_FAILURE); |
| } |
| |
| nblocks = ss.st_size / BLOCKSZ; |
| if (nblocks == 0) { |
| (void) fprintf(stderr, "error: " |
| "file is too small (min allowed size is %d bytes)\n", |
| BLOCKSZ); |
| exit(EXIT_FAILURE); |
| } |
| |
| srand48(getpid()); |
| for (int i = 0; i < BLOCKSZ; i++) |
| randbuf[i] = lrand48(); |
| |
| distribution_n = 0; |
| for (uint64_t i = 0; |
| i < sizeof (size_distribution) / sizeof (size_distribution[0]); |
| i++) { |
| distribution_n += size_distribution[i]; |
| } |
| |
| if (sequential) |
| sequential_writes(fd, buf, nblocks, n); |
| else |
| random_writes(fd, buf, nblocks, n); |
| |
| return (0); |
| } |