1 // SPDX-License-Identifier: CDDL-1.0 2 /* 3 * This file and its contents are supplied under the terms of the 4 * Common Development and Distribution License ("CDDL"), version 1.0. 5 * You may only use this file in accordance with the terms of version 6 * 1.0 of the CDDL. 7 * 8 * A full copy of the text of the CDDL should have accompanied this 9 * source. A copy of the CDDL is also available via the Internet at 10 * http://www.illumos.org/license/CDDL. 11 */ 12 13 /* 14 * Copyright (c) 2017 by Delphix. All rights reserved. 15 */ 16 17 #include <stdint.h> 18 #include <string.h> 19 #include "file_common.h" 20 21 /* 22 * The following sample was derived from real-world data 23 * of a production Oracle database. 24 */ 25 static const uint64_t size_distribution[] = { 26 0, 27 1499018, 28 352084, 29 1503485, 30 4206227, 31 5626657, 32 5387001, 33 3733756, 34 2233094, 35 874652, 36 238635, 37 81434, 38 33357, 39 13106, 40 2009, 41 1, 42 23660, 43 }; 44 45 46 static uint64_t distribution_n; 47 48 static uint8_t randbuf[BLOCKSZ]; 49 50 static void 51 rwc_pwrite(int fd, const void *buf, size_t nbytes, off_t offset) 52 { 53 size_t nleft = nbytes; 54 ssize_t nwrite = 0; 55 56 nwrite = pwrite(fd, buf, nbytes, offset); 57 if (nwrite < 0) { 58 perror("pwrite"); 59 exit(EXIT_FAILURE); 60 } 61 62 nleft -= nwrite; 63 if (nleft != 0) { 64 (void) fprintf(stderr, "warning: pwrite: " 65 "wrote %zu out of %zu bytes\n", 66 (nbytes - nleft), nbytes); 67 } 68 } 69 70 static void 71 fillbuf(char *buf) 72 { 73 uint64_t rv = lrand48() % distribution_n; 74 uint64_t sum = 0; 75 76 uint64_t i; 77 for (i = 0; 78 i < sizeof (size_distribution) / sizeof (size_distribution[0]); 79 i++) { 80 sum += size_distribution[i]; 81 if (rv < sum) 82 break; 83 } 84 85 memcpy(buf, randbuf, BLOCKSZ); 86 if (i == 0) 87 memset(buf, 0, BLOCKSZ - 10); 88 else if (i < 16) 89 memset(buf, 0, BLOCKSZ - i * 512 + 256); 90 /*LINTED: E_BAD_PTR_CAST_ALIGN*/ 91 ((uint32_t *)buf)[0] = lrand48(); 92 } 93 94 static void 95 exit_usage(void) 96 { 97 (void) puts("usage: randwritecomp [-s] file [nwrites]"); 98 exit(EXIT_FAILURE); 99 } 100 101 static void 102 sequential_writes(int fd, char *buf, uint64_t nblocks, int64_t n) 103 { 104 for (int64_t i = 0; n == -1 || i < n; i++) { 105 fillbuf(buf); 106 107 static uint64_t j = 0; 108 if (j == 0) 109 j = lrand48() % nblocks; 110 rwc_pwrite(fd, buf, BLOCKSZ, j * BLOCKSZ); 111 j++; 112 if (j >= nblocks) 113 j = 0; 114 } 115 } 116 117 static void 118 random_writes(int fd, char *buf, uint64_t nblocks, int64_t n) 119 { 120 for (int64_t i = 0; n == -1 || i < n; i++) { 121 fillbuf(buf); 122 rwc_pwrite(fd, buf, BLOCKSZ, (lrand48() % nblocks) * BLOCKSZ); 123 } 124 } 125 126 int 127 main(int argc, char *argv[]) 128 { 129 int fd, err; 130 char *filename = NULL; 131 char buf[BLOCKSZ]; 132 struct stat ss; 133 uint64_t nblocks; 134 int64_t n = -1; 135 int sequential = 0; 136 137 if (argc < 2) 138 exit_usage(); 139 140 argv++; 141 if (strcmp("-s", argv[0]) == 0) { 142 sequential = 1; 143 argv++; 144 } 145 146 if (argv[0] == NULL) 147 exit_usage(); 148 else 149 filename = argv[0]; 150 151 argv++; 152 if (argv[0] != NULL) 153 n = strtoull(argv[0], NULL, 0); 154 155 fd = open(filename, O_RDWR|O_CREAT, 0666); 156 if (fd == -1) { 157 (void) fprintf(stderr, "open(%s) failed: %s\n", filename, 158 strerror(errno)); 159 exit(EXIT_FAILURE); 160 } 161 err = fstat(fd, &ss); 162 if (err != 0) { 163 (void) fprintf(stderr, 164 "error: fstat returned error code %d\n", err); 165 exit(EXIT_FAILURE); 166 } 167 168 nblocks = ss.st_size / BLOCKSZ; 169 if (nblocks == 0) { 170 (void) fprintf(stderr, "error: " 171 "file is too small (min allowed size is %d bytes)\n", 172 BLOCKSZ); 173 exit(EXIT_FAILURE); 174 } 175 176 srand48(getpid()); 177 for (int i = 0; i < BLOCKSZ; i++) 178 randbuf[i] = lrand48(); 179 180 distribution_n = 0; 181 for (uint64_t i = 0; 182 i < sizeof (size_distribution) / sizeof (size_distribution[0]); 183 i++) { 184 distribution_n += size_distribution[i]; 185 } 186 187 if (sequential) 188 sequential_writes(fd, buf, nblocks, n); 189 else 190 random_writes(fd, buf, nblocks, n); 191 192 return (0); 193 } 194