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