xref: /plan9/sys/src/cmd/venti/srv/syncarena.c (revision f9e1cf08d3be51592e03e639fc848a68dc31a55e)
1 #include "stdinc.h"
2 #include "dat.h"
3 #include "fns.h"
4 
5 static int	writeclumphead(Arena *arena, u64int aa, Clump *cl);
6 static int	writeclumpmagic(Arena *arena, u64int aa, u32int magic);
7 
8 int
clumpinfocmp(ClumpInfo * c,ClumpInfo * d)9 clumpinfocmp(ClumpInfo *c, ClumpInfo *d)
10 {
11 	return c->type != d->type
12 		|| c->size != d->size
13 		|| c->uncsize != d->uncsize
14 		|| scorecmp(c->score, d->score)!=0;
15 }
16 
17 /*
18  * synchronize the clump info directory with
19  * with the clumps actually stored in the arena.
20  * the directory should be at least as up to date
21  * as the arena's trailer.
22  *
23  * checks/updates at most n clumps.
24  *
25  * returns 0 if ok, flags if error occurred
26  */
27 int
syncarena(Arena * arena,u32int n,int zok,int fix)28 syncarena(Arena *arena, u32int n, int zok, int fix)
29 {
30 	ZBlock *lump;
31 	Clump cl;
32 	ClumpInfo ci;
33 	static ClumpInfo zci = { .type = -1 };
34 	u8int score[VtScoreSize];
35 	u64int uncsize, used, aa;
36 	u32int clump, clumps, cclumps, magic;
37 	int err, flush, broken;
38 
39 	used = arena->memstats.used;
40 	clumps = arena->memstats.clumps;
41 	cclumps = arena->memstats.cclumps;
42 	uncsize = arena->memstats.uncsize;
43 	trace(TraceProc, "syncarena start");
44 	flush = 0;
45 	err = 0;
46 	for(; n; n--){
47 		aa = arena->memstats.used;
48 		clump = arena->memstats.clumps;
49 		magic = clumpmagic(arena, aa);
50 		if(magic == ClumpFreeMagic)
51 			break;
52 		if(magic != arena->clumpmagic){
53 			fprint(2, "%s: illegal clump magic number=%#8.8ux at clump=%d\n", arena->name, magic, clump);
54 			/* err |= SyncDataErr; */
55 			if(fix && writeclumpmagic(arena, aa, ClumpFreeMagic) < 0){
56 				fprint(2, "%s: can't write corrected clump free magic: %r", arena->name);
57 				err |= SyncFixErr;
58 			}
59 			break;
60 		}
61 
62 		broken = 0;
63 		lump = loadclump(arena, aa, 0, &cl, score, 0);
64 		if(lump == nil){
65 			fprint(2, "%s: clump=%d failed to read correctly: %r\n", arena->name, clump);
66 			break;
67 		}else if(cl.info.type != VtCorruptType){
68 			scoremem(score, lump->data, cl.info.uncsize);
69 			if(scorecmp(cl.info.score, score) != 0){
70 				/* ignore partially written block */
71 				if(cl.encoding == ClumpENone)
72 					break;
73 				fprint(2, "%s: clump=%d has mismatched score\n", arena->name, clump);
74 				err |= SyncDataErr;
75 				broken = 1;
76 			}else if(vttypevalid(cl.info.type) < 0){
77 				fprint(2, "%s: clump=%d has invalid type %d", arena->name, clump, cl.info.type);
78 				err |= SyncDataErr;
79 				broken = 1;
80 			}
81 			if(broken && fix){
82 				cl.info.type = VtCorruptType;
83 				if(writeclumphead(arena, aa, &cl) < 0){
84 					fprint(2, "%s: can't write corrected clump header: %r", arena->name);
85 					err |= SyncFixErr;
86 				}
87 			}
88 		}
89 		freezblock(lump);
90 		arena->memstats.used += ClumpSize + cl.info.size;
91 
92 		arena->memstats.clumps++;
93 		if(!broken && readclumpinfo(arena, clump, &ci)<0){
94 			fprint(2, "%s: arena directory read failed\n", arena->name);
95 			broken = 1;
96 		}else if(!broken && clumpinfocmp(&ci, &cl.info)!=0){
97 			if(clumpinfocmp(&ci, &zci) == 0){
98 				err |= SyncCIZero;
99 				if(!zok)
100 					fprint(2, "%s: unwritten clump info for clump=%d\n", arena->name, clump);
101 			}else{
102 				err |= SyncCIErr;
103 				fprint(2, "%s: bad clump info for clump=%d\n", arena->name, clump);
104 				fprint(2, "\texpected score=%V type=%d size=%d uncsize=%d\n",
105 					cl.info.score, cl.info.type, cl.info.size, cl.info.uncsize);
106 				fprint(2, "\tfound score=%V type=%d size=%d uncsize=%d\n",
107 					ci.score, ci.type, ci.size, ci.uncsize);
108 			}
109 			broken = 1;
110 		}
111 		if(broken && fix){
112 			flush = 1;
113 			ci = cl.info;
114 			if(writeclumpinfo(arena, clump, &ci) < 0){
115 				fprint(2, "%s: can't write correct clump directory: %r\n", arena->name);
116 				err |= SyncFixErr;
117 			}
118 		}
119 		trace(TraceProc, "syncarena unindexed clump %V %d", cl.info.score, arena->memstats.clumps);
120 
121 		arena->memstats.uncsize += cl.info.uncsize;
122 		if(cl.info.size < cl.info.uncsize)
123 			arena->memstats.cclumps++;
124 	}
125 
126 	if(flush){
127 		trace(TraceProc, "syncarena flush");
128 		arena->wtime = now();
129 		if(arena->ctime == 0 && arena->memstats.clumps)
130 			arena->ctime = arena->wtime;
131 		flushdcache();
132 	}
133 
134 	if(used != arena->memstats.used
135 	|| clumps != arena->memstats.clumps
136 	|| cclumps != arena->memstats.cclumps
137 	|| uncsize != arena->memstats.uncsize){
138 		err |= SyncHeader;
139 		fprint(2, "arena %s: fix=%d flush=%d %lld->%lld %ud->%ud %ud->%ud %lld->%lld\n",
140 			arena->name,
141 			fix,
142 			flush,
143 			used, arena->memstats.used,
144 			clumps, arena->memstats.clumps,
145 			cclumps, arena->memstats.cclumps,
146 			uncsize, arena->memstats.uncsize);
147 	}
148 
149 	return err;
150 }
151 
152 static int
writeclumphead(Arena * arena,u64int aa,Clump * cl)153 writeclumphead(Arena *arena, u64int aa, Clump *cl)
154 {
155 	ZBlock *zb;
156 	int bad;
157 
158 	zb = alloczblock(ClumpSize, 0, arena->blocksize);
159 	if(zb == nil)
160 		return -1;
161 	bad = packclump(cl, zb->data, arena->clumpmagic)<0
162 		|| writearena(arena, aa, zb->data, ClumpSize) != ClumpSize;
163 	freezblock(zb);
164 	return bad ? -1 : 0;
165 }
166 
167 static int
writeclumpmagic(Arena * arena,u64int aa,u32int magic)168 writeclumpmagic(Arena *arena, u64int aa, u32int magic)
169 {
170 	u8int buf[U32Size];
171 
172 	packmagic(magic, buf);
173 	return writearena(arena, aa, buf, U32Size) == U32Size;
174 }
175