xref: /netbsd-src/external/ibm-public/postfix/dist/src/fsstone/fsstone.c (revision 41fbaed053f8fbfdf9d2a4ee0a7386a3c83f8505)
1 /*	$NetBSD: fsstone.c,v 1.1.1.1 2009/06/23 10:08:44 tron Exp $	*/
2 
3 /*++
4 /* NAME
5 /*	fsstone 1
6 /* SUMMARY
7 /*	measure directory operation overhead
8 /* SYNOPSIS
9 /* .fi
10 /*	\fBfsstone\fR [\fB-cr\fR] [\fB-s \fIsize\fR]
11 /*		\fImsg_count files_per_dir\fR
12 /* DESCRIPTION
13 /*	The \fBfsstone\fR command measures the cost of creating, renaming
14 /*	and deleting queue files versus appending messages to existing
15 /*	files and truncating them after use.
16 /*
17 /*	The program simulates the arrival of \fImsg_count\fR short messages,
18 /*	and arranges for at most \fIfiles_per_dir\fR simultaneous files
19 /*	in the same directory.
20 /*
21 /*	Options:
22 /* .IP \fB-c\fR
23 /*	Create and delete files.
24 /* .IP \fB-r\fR
25 /*	Rename files twice (requires \fB-c\fR).
26 /* .IP \fB-s \fIsize\fR
27 /*	Specify the file size in kbytes.
28 /* DIAGNOSTICS
29 /*	Problems are reported to the standard error stream.
30 /* BUGS
31 /*	The \fB-r\fR option renames files within the same directory.
32 /*	For a more realistic simulation, the program should rename files
33 /*	<i>between</i> directories, and should also have an option to use
34 /*	<i>hashed</i> directories as implemented with, for example, the
35 /*	\fBdir_forest\fR(3) module.
36 /* LICENSE
37 /* .ad
38 /* .fi
39 /*	The Secure Mailer license must be distributed with this software.
40 /* AUTHOR(S)
41 /*	Wietse Venema
42 /*	IBM T.J. Watson Research
43 /*	P.O. Box 704
44 /*	Yorktown Heights, NY 10598, USA
45 /*--*/
46 
47 /* System library. */
48 
49 #include <sys_defs.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <unistd.h>
53 #include <string.h>
54 #include <sys/time.h>
55 
56 /* Utility library. */
57 
58 #include <msg.h>
59 #include <msg_vstream.h>
60 
61 /* Global directory. */
62 
63 #include <mail_version.h>
64 
65 /* rename_file - rename a file */
66 
rename_file(int old,int new)67 static void rename_file(int old, int new)
68 {
69     char    new_path[BUFSIZ];
70     char    old_path[BUFSIZ];
71 
72     sprintf(new_path, "%06d", new);
73     sprintf(old_path, "%06d", old);
74     if (rename(old_path, new_path))
75 	msg_fatal("rename %s to %s: %m", old_path, new_path);
76 }
77 
78 /* make_file - create a little file and use it */
79 
make_file(int seqno,int size)80 static void make_file(int seqno, int size)
81 {
82     char    path[BUFSIZ];
83     char    buf[1024];
84     FILE   *fp;
85     int     i;
86 
87     sprintf(path, "%06d", seqno);
88     if ((fp = fopen(path, "w")) == 0)
89 	msg_fatal("open %s: %m", path);
90     memset(buf, 'x', sizeof(buf));
91     for (i = 0; i < size; i++)
92 	if (fwrite(buf, 1, sizeof(buf), fp) != sizeof(buf))
93 	    msg_fatal("fwrite: %m");
94     if (fsync(fileno(fp)))
95 	msg_fatal("fsync: %m");
96     if (fclose(fp))
97 	msg_fatal("fclose: %m");
98     if ((fp = fopen(path, "r")) == 0)
99 	msg_fatal("open %s: %m", path);
100     while (fgets(path, sizeof(path), fp))
101 	 /* void */ ;
102     if (fclose(fp))
103 	msg_fatal("fclose: %m");
104 }
105 
106 /* use_file - use existing file */
107 
use_file(int seqno)108 static void use_file(int seqno)
109 {
110     char    path[BUFSIZ];
111     FILE   *fp;
112     int     i;
113 
114     sprintf(path, "%06d", seqno);
115     if ((fp = fopen(path, "w")) == 0)
116 	msg_fatal("open %s: %m", path);
117     for (i = 0; i < 400; i++)
118 	fprintf(fp, "hello");
119     if (fsync(fileno(fp)))
120 	msg_fatal("fsync: %m");
121     if (fclose(fp))
122 	msg_fatal("fclose: %m");
123     if ((fp = fopen(path, "r+")) == 0)
124 	msg_fatal("open %s: %m", path);
125     while (fgets(path, sizeof(path), fp))
126 	 /* void */ ;
127     if (ftruncate(fileno(fp), (off_t) 0))
128 	msg_fatal("ftruncate: %m");;
129     if (fclose(fp))
130 	msg_fatal("fclose: %m");
131 }
132 
133 /* remove_file - delete specified file */
134 
remove_file(int seq)135 static void remove_file(int seq)
136 {
137     char    path[BUFSIZ];
138 
139     sprintf(path, "%06d", seq);
140     if (remove(path))
141 	msg_fatal("remove %s: %m", path);
142 }
143 
144 /* remove_silent - delete specified file, silently */
145 
remove_silent(int seq)146 static void remove_silent(int seq)
147 {
148     char    path[BUFSIZ];
149 
150     sprintf(path, "%06d", seq);
151     (void) remove(path);
152 }
153 
154 /* usage - explain */
155 
usage(char * myname)156 static void usage(char *myname)
157 {
158     msg_fatal("usage: %s [-cr] [-s size] messages directory_entries", myname);
159 }
160 
161 MAIL_VERSION_STAMP_DECLARE;
162 
main(int argc,char ** argv)163 int     main(int argc, char **argv)
164 {
165     int     op_count;
166     int     max_file;
167     struct timeval start, end;
168     int     do_rename = 0;
169     int     do_create = 0;
170     int     seq;
171     int     ch;
172     int     size = 2;
173 
174     /*
175      * Fingerprint executables and core dumps.
176      */
177     MAIL_VERSION_STAMP_ALLOCATE;
178 
179     msg_vstream_init(argv[0], VSTREAM_ERR);
180     while ((ch = GETOPT(argc, argv, "crs:")) != EOF) {
181 	switch (ch) {
182 	case 'c':
183 	    do_create++;
184 	    break;
185 	case 'r':
186 	    do_rename++;
187 	    break;
188 	case 's':
189 	    if ((size = atoi(optarg)) <= 0)
190 		usage(argv[0]);
191 	    break;
192 	default:
193 	    usage(argv[0]);
194 	}
195     }
196 
197     if (argc - optind != 2 || (do_rename && !do_create))
198 	usage(argv[0]);
199     if ((op_count = atoi(argv[optind])) <= 0)
200 	usage(argv[0]);
201     if ((max_file = atoi(argv[optind + 1])) <= 0)
202 	usage(argv[0]);
203 
204     /*
205      * Populate the directory with little files.
206      */
207     for (seq = 0; seq < max_file; seq++)
208 	make_file(seq, size);
209 
210     /*
211      * Simulate arrival and delivery of mail messages.
212      */
213     GETTIMEOFDAY(&start);
214     while (op_count > 0) {
215 	seq %= max_file;
216 	if (do_create) {
217 	    remove_file(seq);
218 	    make_file(seq, size);
219 	    if (do_rename) {
220 		rename_file(seq, seq + max_file);
221 		rename_file(seq + max_file, seq);
222 	    }
223 	} else {
224 	    use_file(seq);
225 	}
226 	seq++;
227 	op_count--;
228     }
229     GETTIMEOFDAY(&end);
230     if (end.tv_usec < start.tv_usec) {
231 	end.tv_sec--;
232 	end.tv_usec += 1000000;
233     }
234     printf("elapsed time: %ld.%06ld\n",
235 	   (long) (end.tv_sec - start.tv_sec),
236 	   (long) (end.tv_usec - start.tv_usec));
237 
238     /*
239      * Clean up directory fillers.
240      */
241     for (seq = 0; seq < max_file; seq++)
242 	remove_silent(seq);
243     return (0);
244 }
245