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