ref: 11f9df0ac2980f77023e3a59e581faccf83d69ba
dir: /test/freplay.c/
#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <thread.h>
#include <9p.h>
File* ctlfile;
File* datfile;
char* mountpt = "/n/replay";
char* logfile;
char* replayfile;
char* membuf;
vlong membufsz;
vlong replaycount = -1;
int logfd = -1;
vlong nwrites;
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)
{
char buf[128];
if(r->fid->file == datfile){
readbuf(r, membuf, membufsz);
respond(r, nil);
}else if(r->fid->file == ctlfile){
snprint(buf, sizeof(buf), "writes %lld\n", nwrites);
readstr(r, buf);
respond(r, nil);
}else
abort();
}
void
fswrite(Req *r)
{
if(r->fid->file == datfile){
if(logfile == nil)
respond(r, "read-only replay file: no log defined");
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);
nwrites++;
}else if(r->fid->file == ctlfile){
if(strncmp(r->ifcall.data, "exit", 4) == 0){
print("exiting...\n");
r->ofcall.count = r->ifcall.count;
respond(r, nil);
exits(nil);
}
respond(r, "unknown ctl message");
}else
abort();
}
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;
Dir *d;
int i;
ARGBEGIN{
case 'd':
chatty9p++;
break;
case 'l':
logfile = EARGF(usage());
break;
case 'r':
replayfile = EARGF(usage());
break;
case 'W':
case 'c':
replaycount = atoi(EARGF(usage()));
break;
case 'm':
mountpt = EARGF(usage());
break;
default:
usage();
}ARGEND;
if(argc != 1)
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 = sbrk(d->length)) == nil)
sysfatal("failed to allocate buffer: %r");
memset(membuf, 0, d->length);
for(off = 0; off < d->length; off += n)
if((n = read(fd, membuf+off, 8192)) <= 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;
print("replayed %d ops\n", i);
close(replayfd);
}
if(logfile != nil){
if((logfd = create(logfile, OWRITE, 0666)) == -1)
sysfatal("failed to open log file: %r");
}
uid = getuser();
fs.tree = alloctree(uid, uid, DMDIR|0555, nil);
ctlfile = createfile(fs.tree->root, "ctl", uid, 0666, nil);
datfile = createfile(fs.tree->root, "data", uid, 0666, nil);
datfile->length = membufsz;
postmountsrv(&fs, nil, mountpt, 0);
exits(nil);
}