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