ref: f2efe296f67cf1200dfcb30231ddae20dabd27da
parent: fcf497d84bd8740b57f0b20a3982122d292009b3
author: Ori Bernstein <[email protected]>
date: Thu Nov 23 14:58:45 EST 2023
fs: implement auto-snapshots
--- a/blk.c
+++ b/blk.c
@@ -1051,10 +1051,6 @@
Qent qe;
int i;
- if(waserror()){
- fprint(2, "failed to sync: %s\n", errmsg());
- nexterror();
- }
if(fs->rdonly)
return;
@@ -1061,8 +1057,12 @@
qlock(&fs->synclk);
if(!fs->snap.dirty){
qunlock(&fs->synclk);
- poperror();
return;
+ }
+ if(waserror()){
+ fprint(2, "failed to sync: %s\n", errmsg());
+ qunlock(&fs->synclk);
+ nexterror();
}
flushdlcache(0);
gen = aincv(&fs->qgen, 1);
--- a/cons.c
+++ b/cons.c
@@ -57,7 +57,7 @@
static void
listsnap(int fd)
{
- char *fnam, pfx[Snapsz];
+ char *fmut, *fauto, pfx[Snapsz];
Scan s;
uint flg;
int sz;
@@ -70,8 +70,9 @@
if(!btnext(&s, &s.kv))
break;
flg = UNPACK32(s.kv.v+1+8);
- fnam = (flg & Lmut) ? "mutable" : "";
- fprint(fd, "snap %.*s %s\n", s.kv.nk-1, s.kv.k+1, fnam);
+ fmut = (flg & Lmut) ? " mutable" : "";
+ fauto = (flg & Lauto) ? " auto" : "";
+ fprint(fd, "snap %.*s%s%s\n", s.kv.nk-1, s.kv.k+1, fmut, fauto);
}
btexit(&s);
}
@@ -89,7 +90,7 @@
a->fd = fd;
if(ap[0][0] == '-'){
switch(ap[0][1]){
- case 'm': a->mutable++; break;
+ case 'm': a->flag = Lmut; break;
case 'd': a->delete++; break;
case 'l':
listsnap(fd);
--- a/dat.h
+++ b/dat.h
@@ -118,6 +118,7 @@
enum {
Lmut = 1 << 0,
+ Lauto = 1 << 1,
};
enum {
@@ -384,8 +385,9 @@
struct { /* AOsnap */
char old[128];
char new[128];
- int mutable;
- int delete;
+ int flag;
+ char delete;
+
};
struct { /* AOsync */
int halt;
@@ -565,6 +567,8 @@
RWLock flushq[Nflushtab];
int flushop[Nflushtab];
+ char minutely[60][128];
+ char hourly[24][128];
Stats stats;
};
--- a/fs.c
+++ b/fs.c
@@ -54,7 +54,8 @@
}
}
if(t == nil && (t = opensnap(a->old, nil)) == nil){
- fprint(a->fd, "snap: open '%s': does not exist\n", a->old);
+ if(a->fd != -1)
+ fprint(a->fd, "snap: open '%s': does not exist\n", a->old);
unlock(&fs->mountlk);
poperror();
return;
@@ -61,8 +62,10 @@
}
if(a->delete){
if(mnt != nil) {
- fprint(a->fd, "snap: snap is mounted: '%s'\n", a->old);
+ if(a->fd != -1)
+ fprint(a->fd, "snap: snap is mounted: '%s'\n", a->old);
unlock(&fs->mountlk);
+ poperror();
return;
}
if(t->nlbl == 1 && t->nref <= 1 && t->succ == -1){
@@ -74,23 +77,26 @@
delsnap(t, t->succ, a->old);
}else{
if((s = opensnap(a->new, nil)) != nil){
- fprint(a->fd, "snap: already exists '%s'\n", a->new);
+ if(a->fd != -1)
+ fprint(a->fd, "snap: already exists '%s'\n", a->new);
closesnap(s);
unlock(&fs->mountlk);
+ poperror();
return;
}
- tagsnap(t, a->new, a->mutable);
+ tagsnap(t, a->new, a->flag);
}
closesnap(t);
unlock(&fs->mountlk);
poperror();
- /* we probably want explicit snapshots to get synced */
- if(a->delete)
- fprint(a->fd, "deleted: %s\n", a->old);
- else if(a->mutable)
- fprint(a->fd, "forked: %s from %s\n", a->new, a->old);
- else
- fprint(a->fd, "labeled: %s from %s\n", a->new, a->old);
+ if(a->fd != -1){
+ if(a->delete)
+ fprint(a->fd, "deleted: %s\n", a->old);
+ else if(a->flag & Lmut)
+ fprint(a->fd, "forked: %s from %s\n", a->new, a->old);
+ else
+ fprint(a->fd, "labeled: %s from %s\n", a->new, a->old);
+ }
}
static void
@@ -1407,6 +1413,7 @@
return;
}
lock(f);
+
if(waserror()){
rerror(m, errmsg());
goto Err;
@@ -1652,8 +1659,7 @@
wunlock(f->dent);
nexterror();
}
- if((*ao = malloc(sizeof(Amsg))) == nil)
- error(Enomem);
+ *ao = emalloc(sizeof(Amsg), 1);
aincl(&f->mnt->ref, 1);
(*ao)->op = AOclear;
(*ao)->mnt = f->mnt;
@@ -2231,6 +2237,7 @@
fprint(2, "taking snap: %s\n", errmsg());
ainc(&fs->rdonly);
}
+
qlock(&fs->mutlk);
if(waserror()){
qunlock(&fs->mutlk);
@@ -2242,6 +2249,7 @@
epochend(id);
poperror();
qunlock(&fs->mutlk);
+
if(pred != -1){
epochwait();
sweeptree(bp, pred);
@@ -2278,22 +2286,107 @@
}
}
+static void
+loadautos(void)
+{
+ char pfx[Snapsz];
+ int m, h, ns, nl;
+ uint flg;
+ Scan s;
+
+ m = 0;
+ h = 0;
+ pfx[0] = Klabel;
+ pfx[1] = '@';
+ btnewscan(&s, pfx, 2);
+ btenter(&fs->snap, &s);
+ while(1){
+ if(!btnext(&s, &s.kv))
+ break;
+ flg = UNPACK32(s.kv.v+1+8);
+ if(!(flg & Lauto))
+ continue;
+ nl = s.kv.nk-1;
+ ns = strlen("@minute.");
+ assert(nl+1 < sizeof(fs->minutely[0]));
+ if(nl > ns && strncmp(s.kv.k+1, "@minute.", ns) == 0){
+ memcpy(fs->minutely[m], s.kv.k+1, s.kv.nk-1);
+ fs->minutely[m][s.kv.nk-1] = 0;
+ m = (m+1)%60;
+ continue;
+ }
+ ns = strlen("@hour.");
+ if(nl > ns && strncmp(s.kv.k+1, "@hour.", ns) == 0){
+ memcpy(fs->hourly[h], s.kv.k+1, s.kv.nk-1);
+ fs->hourly[h][s.kv.nk-1] = 0;
+ h = (h+1)%24;
+ continue;
+ }
+ fprint(2, "unknown autosnap %.*s\n", s.kv.nk-1, s.kv.k+1);
+ }
+ btexit(&s);
+}
+
void
+snapmsg(char *old, char *new, int flg)
+{
+ Amsg *a;
+
+ a = emalloc(sizeof(Amsg), 1);
+ a->op = AOsnap;
+ a->fd = -1;
+ a->flag = flg;
+ strecpy(a->old, a->old+sizeof(a->old), old);
+ if(new == nil)
+ a->delete = 1;
+ else
+ strecpy(a->new, a->new+sizeof(a->new), new);
+ chsend(fs->admchan, a);
+}
+
+void
runtasks(int, void *)
{
+ char buf[128];
+ Tm now, then;
+ int m, h;
Amsg *a;
+ m = 0;
+ h = 0;
+ loadautos();
+ tmnow(&then, nil);
+ tmnow(&now, nil);
while(1){
+ if(waserror())
+ fprint(2, "task error: %s", errmsg());
sleep(5000);
- a = mallocz(sizeof(Amsg), 1);
- if(a == nil){
- fprint(2, "alloc sync msg: %r\n");
- free(a);
- return;
- }
+ a = emalloc(sizeof(Amsg), 1);
a->op = AOsync;
a->halt = 0;
a->fd = -1;
chsend(fs->admchan, a);
+
+ tmnow(&now, nil);
+ if(now.yday != then.yday){
+ snprint(buf, sizeof(buf), "@day.%τ", tmfmt(&now, "YYYY.MM.DD[_]hh:mm:ss"));
+ snapmsg("main", buf, Lauto);
+ }
+ if(now.hour != then.hour){
+ if(fs->hourly[h][0] != 0)
+ snapmsg(fs->hourly[h], nil, 0);
+ snprint(fs->hourly[h], sizeof(fs->hourly[h]), "@hour.%τ", tmfmt(&now, "YYYY.MM.DD[_]hh:mm:ss"));
+ snapmsg("main", fs->hourly[h], Lauto);
+ h = (h+1)%24;
+ }
+ if(now.min != then.min){
+ if(fs->minutely[m][0] != 0)
+ snapmsg(fs->minutely[m], nil, 0);
+ snprint(fs->minutely[m], sizeof(fs->minutely[m]), "@minute.%τ", tmfmt(&now, "YYYY.MM.DD[_]hh:mm:ss"));
+ snapmsg("main", fs->minutely[m], Lauto);
+ m = (m+1)%60;
+ }
+ then = now;
+ poperror();
}
}
--- a/main.c
+++ b/main.c
@@ -265,6 +265,7 @@
errctx = privalloc();
if((*errctx = mallocz(sizeof(Errctx), 1)) == nil)
sysfatal("malloc: %r");
+ tmfmtinstall();
fmtinstall('H', encodefmt);
fmtinstall('B', Bconv);
fmtinstall('M', Mconv);
--- a/snap.c
+++ b/snap.c
@@ -109,8 +109,8 @@
m.op = Oinsert;
dlist2kv(dl, &m, kvbuf, sizeof(kvbuf));
btupsert(&fs->snap, &m, 1);
- poperror();
Found:
+ poperror();
h = ihash(gen) ^ ihash(bgen);
p = &fs->dlcache[h % fs->dlcmax];
dl->chain = *p;
@@ -325,7 +325,7 @@
* will show up in the dump.
*/
void
-tagsnap(Tree *t, char *name, int mutable)
+tagsnap(Tree *t, char *name, int flg)
{
char buf[3][Kvmax];
Msg m[3];
@@ -343,7 +343,7 @@
free(n);
nexterror();
}
- if(mutable){
+ if(flg & Lmut){
n = emalloc(sizeof(Tree), 1);
n->memref = 1;
n->dirty = 0;
@@ -362,7 +362,7 @@
retag2kv(t->gen, t->succ, 0, 1, &m[i], buf[i], sizeof(buf[i]));
i++;
m[i].op = Oinsert;
- lbl2kv(name, n->gen, 1, &m[i], buf[i], sizeof(buf[i]));
+ lbl2kv(name, n->gen, flg, &m[i], buf[i], sizeof(buf[i]));
i++;
m[i].op = Oinsert;
tree2kv(n, &m[i], buf[i], sizeof(buf[i]));
@@ -376,7 +376,7 @@
m[i].op = Oinsert;
t->pred = t->gen;
t->nlbl++;
- lbl2kv(name, t->gen, 0, &m[i], buf[i], sizeof(buf[i]));
+ lbl2kv(name, t->gen, flg, &m[i], buf[i], sizeof(buf[i]));
i++;
}
btupsert(&fs->snap, m, i);
--- a/tree.c
+++ b/tree.c
@@ -1041,7 +1041,6 @@
enqueue(p->nl);
rp = p;
}else{
-
splitleaf(t, up, p, &mid);
enqueue(p->nl);
enqueue(p->nr);
@@ -1218,12 +1217,13 @@
npull = 0;
path = nil;
npath = 0;
+
+Again:
if(waserror()){
freepath(t, path, npath);
nexterror();
}
-Again:
b = getroot(t, &height);
if(b->type == Tpivot && !filledbuf(b, nmsg, sz)){
fastupsert(t, b, msg, nmsg);
@@ -1230,7 +1230,6 @@
poperror();
return;
}
-
/*
* The tree can grow in height by 1 when we
* split, so we allocate room for one extra
@@ -1279,7 +1278,6 @@
else
fatal("broken path change");
-
assert(rb->bp.addr != 0);
assert(rb->bp.addr != 0);
@@ -1288,11 +1286,13 @@
t->bp = rb->bp;
t->dirty = 1;
unlock(&t->lk);
+
npull += rp->npull;
freepath(t, path, npath);
+ poperror();
+
if(npull != nmsg)
goto Again;
- poperror();
}
Blk*