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 #include <stdint.h>
17 #include <string.h>
18 #include "file_common.h"
19
20 /*
21 * The following sample was derived from real-world data
22 * of a production Oracle database.
23 */
24 static const uint64_t size_distribution[] = {
25 0,
26 1499018,
27 352084,
28 1503485,
29 4206227,
30 5626657,
31 5387001,
32 3733756,
33 2233094,
34 874652,
35 238635,
36 81434,
37 33357,
38 13106,
39 2009,
40 1,
41 23660,
42 };
43
44
45 static uint64_t distribution_n;
46
47 static uint8_t randbuf[BLOCKSZ];
48
49 static void
rwc_pwrite(int fd,const void * buf,size_t nbytes,off_t offset)50 rwc_pwrite(int fd, const void *buf, size_t nbytes, off_t offset)
51 {
52 size_t nleft = nbytes;
53 ssize_t nwrite = 0;
54
55 nwrite = pwrite(fd, buf, nbytes, offset);
56 if (nwrite < 0) {
57 perror("pwrite");
58 exit(EXIT_FAILURE);
59 }
60
61 nleft -= nwrite;
62 if (nleft != 0) {
63 (void) fprintf(stderr, "warning: pwrite: "
64 "wrote %zu out of %zu bytes\n",
65 (nbytes - nleft), nbytes);
66 }
67 }
68
69 static void
fillbuf(char * buf)70 fillbuf(char *buf)
71 {
72 uint64_t rv = lrand48() % distribution_n;
73 uint64_t sum = 0;
74
75 uint64_t i;
76 for (i = 0;
77 i < sizeof (size_distribution) / sizeof (size_distribution[0]);
78 i++) {
79 sum += size_distribution[i];
80 if (rv < sum)
81 break;
82 }
83
84 memcpy(buf, randbuf, BLOCKSZ);
85 if (i == 0)
86 memset(buf, 0, BLOCKSZ - 10);
87 else if (i < 16)
88 memset(buf, 0, BLOCKSZ - i * 512 + 256);
89 /*LINTED: E_BAD_PTR_CAST_ALIGN*/
90 ((uint32_t *)buf)[0] = lrand48();
91 }
92
93 static void
exit_usage(void)94 exit_usage(void)
95 {
96 (void) puts("usage: randwritecomp [-s] file [nwrites]");
97 exit(EXIT_FAILURE);
98 }
99
100 static void
sequential_writes(int fd,char * buf,uint64_t nblocks,int64_t n)101 sequential_writes(int fd, char *buf, uint64_t nblocks, int64_t n)
102 {
103 for (int64_t i = 0; n == -1 || i < n; i++) {
104 fillbuf(buf);
105
106 static uint64_t j = 0;
107 if (j == 0)
108 j = lrand48() % nblocks;
109 rwc_pwrite(fd, buf, BLOCKSZ, j * BLOCKSZ);
110 j++;
111 if (j >= nblocks)
112 j = 0;
113 }
114 }
115
116 static void
random_writes(int fd,char * buf,uint64_t nblocks,int64_t n)117 random_writes(int fd, char *buf, uint64_t nblocks, int64_t n)
118 {
119 for (int64_t i = 0; n == -1 || i < n; i++) {
120 fillbuf(buf);
121 rwc_pwrite(fd, buf, BLOCKSZ, (lrand48() % nblocks) * BLOCKSZ);
122 }
123 }
124
125 int
main(int argc,char * argv[])126 main(int argc, char *argv[])
127 {
128 int fd, err;
129 char *filename = NULL;
130 char buf[BLOCKSZ];
131 struct stat ss;
132 uint64_t nblocks;
133 int64_t n = -1;
134 int sequential = 0;
135
136 if (argc < 2)
137 exit_usage();
138
139 argv++;
140 if (strcmp("-s", argv[0]) == 0) {
141 sequential = 1;
142 argv++;
143 }
144
145 if (argv[0] == NULL)
146 exit_usage();
147 else
148 filename = argv[0];
149
150 argv++;
151 if (argv[0] != NULL)
152 n = strtoull(argv[0], NULL, 0);
153
154 fd = open(filename, O_RDWR|O_CREAT, 0666);
155 if (fd == -1) {
156 (void) fprintf(stderr, "open(%s) failed: %s\n", filename,
157 strerror(errno));
158 exit(EXIT_FAILURE);
159 }
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