/* * 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 "../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 [-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); }