1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
6 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 only,
10 * as published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License version 2 for more details (a copy is included
16 * in the LICENSE file that accompanied this code).
18 * You should have received a copy of the GNU General Public License
19 * version 2 along with this program; If not, see
20 * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
22 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23 * CA 95054 USA or visit www.sun.com if you need additional information or
29 * Copyright 2008 Sun Microsystems, Inc. All rights reserved
30 * Use is subject to license terms.
33 * This file is part of Lustre, http://www.lustre.org/
34 * Lustre is a trademark of Sun Microsystems, Inc.
36 * lustre/tests/write_append_truncate.c
38 * Each loop does 3 things:
39 * - truncate file to zero (not via ftruncate though, to test O_APPEND)
40 * - append a "chunk" of data (should be at file offset 0 after truncate)
41 * - on each of two threads either append or truncate-up the file
43 * If the truncate happened first, we should have a hole in the file.
44 * If the append happened first, we should have truncated the file down.
46 * We pick the CHUNK_SIZE_MAX and APPEND_SIZE_MAX so that we cross a stripe.
48 * compile: mpicc -g -Wall -o write_append_truncate write_append_truncate.c
49 * run: mpirun -np 2 -machlist <hostlist file> write_append_truncate <file>
50 * or: pdsh -w <two hosts> write_append_truncate <file>
51 * or: prun -n 2 [-N 2] write_append_truncate <file>
57 #include <sys/types.h>
65 #define DEFAULT_ITER 50000
67 #define CHUNK_SIZE_MAX 123456
68 #define CHUNK_CHAR 'C'
70 #define APPEND_SIZE_MAX 123456
71 #define APPEND_CHAR 'A'
73 #define TRUNC_SIZE_MAX (CHUNK_SIZE_MAX+APPEND_SIZE_MAX)
75 #define HOSTNAME_SIZE 50
77 void usage(char *prog)
79 printf("usage: %s <filename> [nloops]\n", prog);
80 printf("%s must be run with at least 2 processes\n", prog);
86 /* Print process rank, loop count, message, and exit (i.e. a fatal error) */
87 void rprintf(int rank, int loop, const char *fmt, ...)
91 printf("rank %d, loop %d: ", rank, loop);
97 MPI_Abort(MPI_COMM_WORLD, -1);
100 int main(int argc, char *argv[])
102 int n, nloops = 0, fd;
104 int chunk_size, append_size, trunc_offset;
105 char append_buf[APPEND_SIZE_MAX];
106 char chunk_buf[CHUNK_SIZE_MAX];
107 char read_buf[TRUNC_SIZE_MAX+APPEND_SIZE_MAX];
108 char trunc_buf[TRUNC_SIZE_MAX];
111 char hostname[HOSTNAME_SIZE];
114 error = MPI_Init(&argc, &argv);
115 if (error != MPI_SUCCESS)
116 rprintf(-1, -1, "MPI_Init failed: %d\n", error);
118 prog = strrchr(argv[0], '/');
124 if (argc < 2 || argc > 3)
127 error = MPI_Comm_rank(MPI_COMM_WORLD, &rank);
128 if (error != MPI_SUCCESS)
129 rprintf(-1, -1, "MPI_Comm_rank failed: %d\n", error);
131 error = MPI_Comm_size(MPI_COMM_WORLD, &size);
132 if (error != MPI_SUCCESS)
133 rprintf(rank, -1, "MPI_Comm_size failed: %d\n", error);
136 rprintf(rank, -1, "%s: must run with at least 2 processes\n",
139 memset(append_buf, APPEND_CHAR, APPEND_SIZE_MAX);
140 memset(chunk_buf, CHUNK_CHAR, CHUNK_SIZE_MAX);
141 memset(trunc_buf, 0, TRUNC_SIZE_MAX);
143 if (gethostname(hostname, HOSTNAME_SIZE) < 0)
144 rprintf(rank, -1, "gethostname failed: %s\n", strerror(errno));
149 nloops = strtoul(argv[2], NULL, 0);
151 nloops = DEFAULT_ITER;
154 fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666);
156 rprintf(0, -1, "create %s failed: %s\n", fname,
158 printf("using %s\n", fname);
160 error = MPI_Barrier(MPI_COMM_WORLD);
161 if (error != MPI_SUCCESS)
162 rprintf(rank, -1, "prep MPI_Barrier failed: %d\n", error);
164 fd = open(fname, O_RDWR | O_APPEND);
166 rprintf(rank, -1, "open %s failed: %s\n",fname,strerror(errno));
168 for (n = 0; n < nloops; n++) {
169 /* reset the environment */
170 chunk_size = (rand()%(CHUNK_SIZE_MAX-1))+1;
171 append_size = (rand()%(APPEND_SIZE_MAX-1))+1;
172 trunc_offset = chunk_size + rand()%append_size;
175 printf("loop %5d: chunk %6d/%#07x, "
176 "append %6d/%#07x, trunc @ %6d/%#07x\n",
177 n, chunk_size, chunk_size, append_size,
178 append_size, trunc_offset, trunc_offset);
180 ret = truncate(fname, (off_t)0);
182 rprintf(0, n, "truncate @ 0: %s\n",
186 ret = write(fd, chunk_buf+done,chunk_size-done);
188 rprintf(0, n, "chunk @ %d: %s\n",
189 done, strerror(errno));
193 } while (done != chunk_size);
196 error = MPI_Barrier(MPI_COMM_WORLD);
197 if (error != MPI_SUCCESS)
198 rprintf(rank, n, "start MPI_Barrier: %d\n",error);
201 if (rank == n % size) {
205 ret = write(fd, append_buf + done,
209 "loop %d: append @ %u: %s\n",
210 done, strerror(errno));
214 } while (done != append_size);
215 } else if (rank == (n + 1) % size) {
216 ret = truncate(fname, (off_t)trunc_offset);
218 rprintf(rank, n, "truncate @ %u: %s\n",
219 trunc_offset, strerror(errno) );
222 error = MPI_Barrier(MPI_COMM_WORLD);
223 if (error != MPI_SUCCESS)
224 rprintf(rank, n, "end MPI_Barrier: %d\n", error);
228 /* Check the result */
231 if (stat(fname, &st) < 0)
232 rprintf(0, n, "loop %d: stat %s: %s\n",
233 fname, strerror(errno));
235 if (lseek(fd, (off_t)0, SEEK_SET) != 0)
236 rprintf(0, n, "lseek fname 0: %s\n", fname,
241 ret = read(fd, read_buf+done, st.st_size-done);
243 rprintf(0, n, "read @ %u: %s\n",
244 done, strerror(errno));
247 } while (done != st.st_size);
249 if (memcmp(read_buf, chunk_buf, chunk_size)) {
250 printf("loop %d: base chunk bad"
251 " [0-%d]/[0-%#x] != %c\n", n,
252 chunk_size - 1, chunk_size - 1,
257 if (st.st_size == trunc_offset) {
258 /* Check case 1: first append then truncate */
259 error = memcmp(read_buf+chunk_size, append_buf,
260 trunc_offset - chunk_size);
262 printf("loop %d: trunc-after-append bad"
263 " [%d-%d]/[%#x-%#x] != %c\n",
264 n, chunk_size, trunc_offset - 1,
265 chunk_size, trunc_offset - 1,
269 /* Check case 2: first truncate then append */
270 if (memcmp(read_buf+chunk_size, trunc_buf,
271 trunc_offset-chunk_size)) {
272 printf("loop %d: append-after-TRUNC bad"
273 " [%d-%d]/[%#x-%#x] != 0\n",
274 n, chunk_size, trunc_offset - 1,
275 chunk_size, trunc_offset - 1);
277 } else if (memcmp(read_buf+trunc_offset,
278 append_buf, append_size)) {
279 printf("loop %d: APPEND-after-trunc bad"
280 " [%d-%d]/[%#x-%#x] != %c\n",
281 n, trunc_offset, append_size - 1,
282 trunc_offset, append_size - 1,
288 ret = MPI_Bcast(&error, 1, MPI_INT, 0, MPI_COMM_WORLD);
289 if (ret != MPI_SUCCESS)
290 rprintf(rank, n, "MPI_Bcast: %d\n");
296 printf("loop %5d: chunk %6d/%#07x, "
297 "append %6d/%#07x, trunc @ %6d/%#07x\n",
298 n, chunk_size, chunk_size, append_size,
299 append_size, trunc_offset, trunc_offset);
301 sprintf(command, "od -Ax -a %s", fname);
304 rprintf(rank, n, "on machine %s with pid %d\n",
305 hostname, (int)getpid());
309 printf("rank %d, loop %d: finished\n", rank, n);
313 error = unlink(fname);
315 rprintf(0, n, "unlink %s failed: %s\n",
316 fname, strerror(errno));