#include #include #include #include "block.h" #include "log.h" static int checksuper(Log *l) { if(l->super.magic != LogMagic){ werrstr("bad magic %08uX", l->super.magic); return -1; } if(l->super.start < 1 || l->super.start > l->blocks){ werrstr("bad log start block %llud", l->super.start); return -1; } if(l->super.end < 1 || l->super.end > l->blocks){ werrstr("bad log end block %llud", l->super.end); return -1; } return 0; } int logreadsuper(Log *l) { uchar *p, buf[LogBlockSize]; memset(buf, 0, sizeof buf); if(blockread(l->fd, buf, sizeof buf, 1, 0) != 1) return -1; p = buf; l->super.magic = GBIT32(p); l->super.start = GBIT64(p+4); l->super.end = GBIT64(p+12); return 0; } int logwritesuper(Log *l) { uchar *p, buf[LogBlockSize]; memset(buf, 0, sizeof buf); p = buf; PBIT32(p, l->super.magic); PBIT64(p+4, l->super.start); PBIT64(p+12, l->super.end); if(blockwrite(l->fd, buf, sizeof buf, 1, 0) != 1) return -1; return 0; } static u64int logbuffered(Log *l) { u64int s, e; s = l->super.start; e = l->super.end; if(e >= s) return e - s; else return l->blocks - 1 - (s - e); } static u64int logavailable(Log *l) { u64int a; a = (l->blocks - 1) - logbuffered(l); //if(a < 0) // a = 0; return a; } Log* logopen(char *logfile) { vlong sz; Dir *d; Log *l; l = mallocz(sizeof(*l), 1); if(l == nil) return nil; l->fd = open(logfile, ORDWR); if(l->fd < 0){ free(l); return nil; } d = dirfstat(l->fd); if(d == nil) goto fail; sz = d->length; free(d); if(sz < 100){ werrstr("log is too short"); goto fail; } l->blocks = (sz - (sz % LogBlockSize)) / LogBlockSize; if(logreadsuper(l) < 0) goto fail; if(checksuper(l) < 0) goto fail; print("%llud log entries free, %llud total log entries\n", logavailable(l), l->blocks - 1); return l; fail: close(l->fd); free(l); return nil; } void logclose(Log *l) { close(l->fd); free(l); } static u64int tid = 0; long logwrite(Log *l, vlong off, void *data, int ndata) { u64int blocks, n, m; uchar *p; LogEntry e; assert(ndata != 0 && ndata % LogBlockSize == 0); memset(&e, 0, sizeof(e)); blocks = ((ndata + LogBlockSize - 1) & ~(LogBlockSize - 1)) / LogBlockSize; print("write off %lld blocks %llud\n", off, blocks); /* check for enough log space for this transaction */ if(blocks + 2 > logavailable(l)){ werrstr("log out of room"); return -1; } e.hdr.type = LBEGIN; e.hdr.tid = tid; e.hdr.off = off; if(blockwrite(l->fd, &e, LogBlockSize, 1, l->super.end) != 1) return -1; l->super.end = (l->super.end + 1) % l->blocks; p = data; n = blocks; while(n > 0){ if(blockwrite(l->fd, p, LogBlockSize, 1, l->super.end) != 1) return -1; p += LogBlockSize; l->super.end = (l->super.end + 1) % l->blocks; n--; } e.hdr.type = LEND; e.hdr.tid = tid++; e.hdr.off = off; if(blockwrite(l->fd, &e, LogBlockSize, 1, l->super.end) != 1) return -1; l->super.end = (l->super.end + 1) % l->blocks; return ndata; } long logsync(Log *l) { while(l->super.start != l->super.end){ } return 0; }