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
rwc_pwrite(int fd,const void * buf,size_t nbytes,off_t offset)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
fillbuf(char * buf)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
exit_usage(void)95 exit_usage(void)
96 {
97 (void) puts("usage: randwritecomp [-s] file [nwrites]");
98 exit(EXIT_FAILURE);
99 }
100
101 static void
sequential_writes(int fd,char * buf,uint64_t nblocks,int64_t n)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
random_writes(int fd,char * buf,uint64_t nblocks,int64_t n)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
main(int argc,char * argv[])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