ref: ecf4557d007dcd4a34433b489e382842ccf37029
parent: c7bc6cca77498f87fa9230d9628b82c46c12dba5
author: Ori Bernstein <ori@eigenstate.org>
date: Sat May 27 17:31:56 EDT 2023
freplay: add test program to replay writes to files
--- /dev/null
+++ b/test/freplay.c
@@ -1,0 +1,142 @@
+#include <u.h>
+#include <libc.h>
+#include <fcall.h>
+#include <thread.h>
+#include <9p.h>
+
+char* mountpt = "/n/replay";
+char* logfile;
+char* replayfile;
+char* membuf;
+vlong membufsz;
+vlong replaycount = -1;
+int logfd;
+
+void
+log1(int fd, void *buf, vlong off, vlong sz)
+{
+ char *p, hdr[12];
+
+ p = hdr;
+ PBIT64(p, off); p += 8;
+ PBIT32(p, sz);
+ if(write(fd, hdr, sizeof(hdr)) == -1)
+ sysfatal("write header: %r");
+ if(write(fd, buf, sz) == -1)
+ sysfatal("write data: %r\n");
+}
+
+int
+replay1(int fd)
+{
+ uchar *p, hdr[12];
+ vlong o;
+ int n, r;
+
+ r = readn(fd, hdr, 12);
+ if(r == 0)
+ return 0;
+ if(r != 12)
+ sysfatal("failed to read operation header: %r");
+
+ p = hdr;
+ o = GBIT64(p); p += 8;
+ n = GBIT32(p);
+ if(o + n > membufsz)
+ sysfatal("operation exceeds buffer size");
+ if(readn(fd, membuf + o, n) != n)
+ sysfatal("read op: %r");
+ return 1;
+}
+
+void
+fsread(Req *r)
+{
+ readbuf(r, membuf, membufsz);
+ respond(r, nil);
+}
+
+void
+fswrite(Req *r)
+{
+ if(r->ifcall.offset + r->ifcall.count >= membufsz)
+ respond(r, "operation exceeds file size");
+ log1(logfd, r->ifcall.data, r->ifcall.offset, r->ifcall.count);
+ memcpy(membuf + r->ifcall.offset, r->ifcall.data, r->ifcall.count);
+ r->ofcall.count = r->ifcall.count;
+ respond(r, nil);
+}
+
+void
+usage(void)
+{
+ fprint(2, "usage: %s -l log [-r replay] [-c count] file\n", argv0);
+ exits("usage");
+}
+
+static Srv fs = {
+ .read = fsread,
+ .write = fswrite,
+};
+void
+main(int argc, char *argv[])
+{
+ int fd, replayfd;
+ vlong n, off;
+ char *uid;
+ File *f;
+ Dir *d;
+ int i;
+
+ ARGBEGIN{
+ case 'd':
+ chatty9p++;
+ break;
+ case 'l':
+ logfile = EARGF(usage());
+ break;
+ case 'r':
+ replayfile = EARGF(usage());
+ break;
+ case 'c':
+ replaycount = atoi(EARGF(usage()));
+ break;
+ case 'm':
+ mountpt = EARGF(usage());
+ break;
+ default:
+ usage();
+ }ARGEND;
+
+ if(argc != 1 || logfile == nil)
+ usage();
+
+ if((fd = open(argv[0], OREAD)) == -1)
+ sysfatal("open %s: %r", argv[0]);
+ if((d = dirfstat(fd)) == nil)
+ sysfatal("failed to stat file: %r");
+ if((membuf = mallocz(d->length, 1)) == nil)
+ sysfatal("failed to allocate buffer: %r");
+ for(off = 0; off < d->length; off += n)
+ if((n = read(fd, membuf+off, d->length - off)) <= 0)
+ sysfatal("read %s: short read", argv[0]);
+ membufsz = d->length;
+ free(d);
+ if(replayfile != nil){
+ if((replayfd = open(replayfile, OREAD)) == -1)
+ sysfatal("failed to open replay file: %r");
+ for(i = 0; i < replaycount || replaycount == -1; i++)
+ if(replay1(replayfd) == 0)
+ break;
+ close(replayfd);
+ }
+
+ if((logfd = create(logfile, OWRITE, 0666)) == -1)
+ sysfatal("failed to open log file: %r");
+ uid = getuser();
+ fs.tree = alloctree(uid, uid, DMDIR|0555, nil);
+ f = createfile(fs.tree->root, "data", uid, 0666, nil);
+ f->length = membufsz;
+ postmountsrv(&fs, nil, mountpt, 0);
+ exits(nil);
+}