summaryrefslogtreecommitdiffstats
path: root/src/fsstone/fsstone.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/fsstone/fsstone.c')
-rw-r--r--src/fsstone/fsstone.c242
1 files changed, 242 insertions, 0 deletions
diff --git a/src/fsstone/fsstone.c b/src/fsstone/fsstone.c
new file mode 100644
index 0000000..217cb04
--- /dev/null
+++ b/src/fsstone/fsstone.c
@@ -0,0 +1,242 @@
+/*++
+/* NAME
+/* fsstone 1
+/* SUMMARY
+/* measure directory operation overhead
+/* SYNOPSIS
+/* .fi
+/* \fBfsstone\fR [\fB-cr\fR] [\fB-s \fIsize\fR]
+/* \fImsg_count files_per_dir\fR
+/* DESCRIPTION
+/* The \fBfsstone\fR command measures the cost of creating, renaming
+/* and deleting queue files versus appending messages to existing
+/* files and truncating them after use.
+/*
+/* The program simulates the arrival of \fImsg_count\fR short messages,
+/* and arranges for at most \fIfiles_per_dir\fR simultaneous files
+/* in the same directory.
+/*
+/* Options:
+/* .IP \fB-c\fR
+/* Create and delete files.
+/* .IP \fB-r\fR
+/* Rename files twice (requires \fB-c\fR).
+/* .IP \fB-s \fIsize\fR
+/* Specify the file size in kbytes.
+/* DIAGNOSTICS
+/* Problems are reported to the standard error stream.
+/* BUGS
+/* The \fB-r\fR option renames files within the same directory.
+/* For a more realistic simulation, the program should rename files
+/* <i>between</i> directories, and should also have an option to use
+/* <i>hashed</i> directories as implemented with, for example, the
+/* \fBdir_forest\fR(3) module.
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/time.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <msg_vstream.h>
+
+/* Global directory. */
+
+#include <mail_version.h>
+
+/* rename_file - rename a file */
+
+static void rename_file(int old, int new)
+{
+ char new_path[BUFSIZ];
+ char old_path[BUFSIZ];
+
+ sprintf(new_path, "%06d", new);
+ sprintf(old_path, "%06d", old);
+ if (rename(old_path, new_path))
+ msg_fatal("rename %s to %s: %m", old_path, new_path);
+}
+
+/* make_file - create a little file and use it */
+
+static void make_file(int seqno, int size)
+{
+ char path[BUFSIZ];
+ char buf[1024];
+ FILE *fp;
+ int i;
+
+ sprintf(path, "%06d", seqno);
+ if ((fp = fopen(path, "w")) == 0)
+ msg_fatal("open %s: %m", path);
+ memset(buf, 'x', sizeof(buf));
+ for (i = 0; i < size; i++)
+ if (fwrite(buf, 1, sizeof(buf), fp) != sizeof(buf))
+ msg_fatal("fwrite: %m");
+ if (fsync(fileno(fp)))
+ msg_fatal("fsync: %m");
+ if (fclose(fp))
+ msg_fatal("fclose: %m");
+ if ((fp = fopen(path, "r")) == 0)
+ msg_fatal("open %s: %m", path);
+ while (fgets(path, sizeof(path), fp))
+ /* void */ ;
+ if (fclose(fp))
+ msg_fatal("fclose: %m");
+}
+
+/* use_file - use existing file */
+
+static void use_file(int seqno)
+{
+ char path[BUFSIZ];
+ FILE *fp;
+ int i;
+
+ sprintf(path, "%06d", seqno);
+ if ((fp = fopen(path, "w")) == 0)
+ msg_fatal("open %s: %m", path);
+ for (i = 0; i < 400; i++)
+ fprintf(fp, "hello");
+ if (fsync(fileno(fp)))
+ msg_fatal("fsync: %m");
+ if (fclose(fp))
+ msg_fatal("fclose: %m");
+ if ((fp = fopen(path, "r+")) == 0)
+ msg_fatal("open %s: %m", path);
+ while (fgets(path, sizeof(path), fp))
+ /* void */ ;
+ if (ftruncate(fileno(fp), (off_t) 0))
+ msg_fatal("ftruncate: %m");;
+ if (fclose(fp))
+ msg_fatal("fclose: %m");
+}
+
+/* remove_file - delete specified file */
+
+static void remove_file(int seq)
+{
+ char path[BUFSIZ];
+
+ sprintf(path, "%06d", seq);
+ if (remove(path))
+ msg_fatal("remove %s: %m", path);
+}
+
+/* remove_silent - delete specified file, silently */
+
+static void remove_silent(int seq)
+{
+ char path[BUFSIZ];
+
+ sprintf(path, "%06d", seq);
+ (void) remove(path);
+}
+
+/* usage - explain */
+
+static void usage(char *myname)
+{
+ msg_fatal("usage: %s [-cr] [-s size] messages directory_entries", myname);
+}
+
+MAIL_VERSION_STAMP_DECLARE;
+
+int main(int argc, char **argv)
+{
+ int op_count;
+ int max_file;
+ struct timeval start, end;
+ int do_rename = 0;
+ int do_create = 0;
+ int seq;
+ int ch;
+ int size = 2;
+
+ /*
+ * Fingerprint executables and core dumps.
+ */
+ MAIL_VERSION_STAMP_ALLOCATE;
+
+ msg_vstream_init(argv[0], VSTREAM_ERR);
+ while ((ch = GETOPT(argc, argv, "crs:")) != EOF) {
+ switch (ch) {
+ case 'c':
+ do_create++;
+ break;
+ case 'r':
+ do_rename++;
+ break;
+ case 's':
+ if ((size = atoi(optarg)) <= 0)
+ usage(argv[0]);
+ break;
+ default:
+ usage(argv[0]);
+ }
+ }
+
+ if (argc - optind != 2 || (do_rename && !do_create))
+ usage(argv[0]);
+ if ((op_count = atoi(argv[optind])) <= 0)
+ usage(argv[0]);
+ if ((max_file = atoi(argv[optind + 1])) <= 0)
+ usage(argv[0]);
+
+ /*
+ * Populate the directory with little files.
+ */
+ for (seq = 0; seq < max_file; seq++)
+ make_file(seq, size);
+
+ /*
+ * Simulate arrival and delivery of mail messages.
+ */
+ GETTIMEOFDAY(&start);
+ while (op_count > 0) {
+ seq %= max_file;
+ if (do_create) {
+ remove_file(seq);
+ make_file(seq, size);
+ if (do_rename) {
+ rename_file(seq, seq + max_file);
+ rename_file(seq + max_file, seq);
+ }
+ } else {
+ use_file(seq);
+ }
+ seq++;
+ op_count--;
+ }
+ GETTIMEOFDAY(&end);
+ if (end.tv_usec < start.tv_usec) {
+ end.tv_sec--;
+ end.tv_usec += 1000000;
+ }
+ printf("elapsed time: %ld.%06ld\n",
+ (long) (end.tv_sec - start.tv_sec),
+ (long) (end.tv_usec - start.tv_usec));
+
+ /*
+ * Clean up directory fillers.
+ */
+ for (seq = 0; seq < max_file; seq++)
+ remove_silent(seq);
+ return (0);
+}