xref: /plan9/sys/src/cmd/venti/srv/clump.c (revision f9e1cf08d3be51592e03e639fc848a68dc31a55e)
1368c31abSDavid du Colombier #include "stdinc.h"
2368c31abSDavid du Colombier #include "dat.h"
3368c31abSDavid du Colombier #include "fns.h"
4368c31abSDavid du Colombier #include "whack.h"
5368c31abSDavid du Colombier 
6368c31abSDavid du Colombier /*
7368c31abSDavid du Colombier  * Write a lump to disk.  Updates ia with an index address
8368c31abSDavid du Colombier  * for the newly-written lump.  Upon return, the lump will
9368c31abSDavid du Colombier  * have been placed in the disk cache but will likely not be on disk yet.
10368c31abSDavid du Colombier  */
11368c31abSDavid du Colombier int
storeclump(Index * ix,ZBlock * zb,u8int * sc,int type,u32int creator,IAddr * ia)12368c31abSDavid du Colombier storeclump(Index *ix, ZBlock *zb, u8int *sc, int type, u32int creator, IAddr *ia)
13368c31abSDavid du Colombier {
14368c31abSDavid du Colombier 	ZBlock *cb;
15368c31abSDavid du Colombier 	Clump cl;
16368c31abSDavid du Colombier 	u64int a;
17368c31abSDavid du Colombier 	u8int bh[VtScoreSize];
18368c31abSDavid du Colombier 	int size, dsize;
19368c31abSDavid du Colombier 
20368c31abSDavid du Colombier 	trace(TraceLump, "storeclump enter", sc, type);
21368c31abSDavid du Colombier 	size = zb->len;
22368c31abSDavid du Colombier 	if(size > VtMaxLumpSize){
23368c31abSDavid du Colombier 		seterr(EStrange, "lump too large");
24368c31abSDavid du Colombier 		return -1;
25368c31abSDavid du Colombier 	}
26368c31abSDavid du Colombier 	if(vttypevalid(type) < 0){
27368c31abSDavid du Colombier 		seterr(EStrange, "invalid lump type");
28368c31abSDavid du Colombier 		return -1;
29368c31abSDavid du Colombier 	}
30368c31abSDavid du Colombier 
31368c31abSDavid du Colombier 	if(0){
32368c31abSDavid du Colombier 		scoremem(bh, zb->data, size);
33368c31abSDavid du Colombier 		if(scorecmp(sc, bh) != 0){
34368c31abSDavid du Colombier 			seterr(ECorrupt, "storing clump: corrupted; expected=%V got=%V, size=%d", sc, bh, size);
35368c31abSDavid du Colombier 			return -1;
36368c31abSDavid du Colombier 		}
37368c31abSDavid du Colombier 	}
38368c31abSDavid du Colombier 
39368c31abSDavid du Colombier 	cb = alloczblock(size + ClumpSize + U32Size, 0, 0);
40368c31abSDavid du Colombier 	if(cb == nil)
41368c31abSDavid du Colombier 		return -1;
42368c31abSDavid du Colombier 
43368c31abSDavid du Colombier 	cl.info.type = type;
44368c31abSDavid du Colombier 	cl.info.uncsize = size;
45368c31abSDavid du Colombier 	cl.creator = creator;
46368c31abSDavid du Colombier 	cl.time = now();
47368c31abSDavid du Colombier 	scorecp(cl.info.score, sc);
48368c31abSDavid du Colombier 
49368c31abSDavid du Colombier 	trace(TraceLump, "storeclump whackblock");
50368c31abSDavid du Colombier 	dsize = whackblock(&cb->data[ClumpSize], zb->data, size);
51368c31abSDavid du Colombier 	if(dsize > 0 && dsize < size){
52368c31abSDavid du Colombier 		cl.encoding = ClumpECompress;
53368c31abSDavid du Colombier 	}else{
54368c31abSDavid du Colombier 		if(dsize > size){
55368c31abSDavid du Colombier 			fprint(2, "whack error: dsize=%d size=%d\n", dsize, size);
56368c31abSDavid du Colombier 			abort();
57368c31abSDavid du Colombier 		}
58368c31abSDavid du Colombier 		cl.encoding = ClumpENone;
59368c31abSDavid du Colombier 		dsize = size;
60368c31abSDavid du Colombier 		memmove(&cb->data[ClumpSize], zb->data, size);
61368c31abSDavid du Colombier 	}
62368c31abSDavid du Colombier 	memset(cb->data+ClumpSize+dsize, 0, 4);
63368c31abSDavid du Colombier 	cl.info.size = dsize;
64368c31abSDavid du Colombier 
65*f9e1cf08SDavid du Colombier 	a = writeiclump(ix, &cl, cb->data);
66368c31abSDavid du Colombier 	trace(TraceLump, "storeclump exit %lld", a);
67368c31abSDavid du Colombier 	freezblock(cb);
68368c31abSDavid du Colombier 	if(a == TWID64)
69368c31abSDavid du Colombier 		return -1;
70368c31abSDavid du Colombier 
71*f9e1cf08SDavid du Colombier 	ia->addr = a;
72*f9e1cf08SDavid du Colombier 	ia->type = type;
73*f9e1cf08SDavid du Colombier 	ia->size = size;
74*f9e1cf08SDavid du Colombier 	ia->blocks = (dsize + ClumpSize + (1 << ABlockLog) - 1) >> ABlockLog;
75*f9e1cf08SDavid du Colombier 
76368c31abSDavid du Colombier /*
77368c31abSDavid du Colombier 	qlock(&stats.lock);
78368c31abSDavid du Colombier 	stats.clumpwrites++;
79368c31abSDavid du Colombier 	stats.clumpbwrites += size;
80368c31abSDavid du Colombier 	stats.clumpbcomp += dsize;
81368c31abSDavid du Colombier 	qunlock(&stats.lock);
82368c31abSDavid du Colombier */
83368c31abSDavid du Colombier 
84368c31abSDavid du Colombier 	return 0;
85368c31abSDavid du Colombier }
86368c31abSDavid du Colombier 
87368c31abSDavid du Colombier u32int
clumpmagic(Arena * arena,u64int aa)88368c31abSDavid du Colombier clumpmagic(Arena *arena, u64int aa)
89368c31abSDavid du Colombier {
90368c31abSDavid du Colombier 	u8int buf[U32Size];
91368c31abSDavid du Colombier 
92368c31abSDavid du Colombier 	if(readarena(arena, aa, buf, U32Size) == TWID32)
93368c31abSDavid du Colombier 		return TWID32;
94368c31abSDavid du Colombier 	return unpackmagic(buf);
95368c31abSDavid du Colombier }
96368c31abSDavid du Colombier 
97368c31abSDavid du Colombier /*
98368c31abSDavid du Colombier  * fetch a block based at addr.
99368c31abSDavid du Colombier  * score is filled in with the block's score.
100368c31abSDavid du Colombier  * blocks is roughly the length of the clump on disk;
101368c31abSDavid du Colombier  * if zero, the length is unknown.
102368c31abSDavid du Colombier  */
103368c31abSDavid du Colombier ZBlock*
loadclump(Arena * arena,u64int aa,int blocks,Clump * cl,u8int * score,int verify)104368c31abSDavid du Colombier loadclump(Arena *arena, u64int aa, int blocks, Clump *cl, u8int *score, int verify)
105368c31abSDavid du Colombier {
106368c31abSDavid du Colombier 	Unwhack uw;
107368c31abSDavid du Colombier 	ZBlock *zb, *cb;
108368c31abSDavid du Colombier 	u8int bh[VtScoreSize], *buf;
109368c31abSDavid du Colombier 	u32int n;
110368c31abSDavid du Colombier 	int nunc;
111368c31abSDavid du Colombier 
112368c31abSDavid du Colombier /*
113368c31abSDavid du Colombier 	qlock(&stats.lock);
114368c31abSDavid du Colombier 	stats.clumpreads++;
115368c31abSDavid du Colombier 	qunlock(&stats.lock);
116368c31abSDavid du Colombier */
117368c31abSDavid du Colombier 
118368c31abSDavid du Colombier 	if(blocks <= 0)
119368c31abSDavid du Colombier 		blocks = 1;
120368c31abSDavid du Colombier 
121368c31abSDavid du Colombier 	trace(TraceLump, "loadclump enter");
122368c31abSDavid du Colombier 
123368c31abSDavid du Colombier 	cb = alloczblock(blocks << ABlockLog, 0, 0);
124368c31abSDavid du Colombier 	if(cb == nil)
125368c31abSDavid du Colombier 		return nil;
126368c31abSDavid du Colombier 	n = readarena(arena, aa, cb->data, blocks << ABlockLog);
127368c31abSDavid du Colombier 	if(n < ClumpSize){
128368c31abSDavid du Colombier 		if(n != 0)
129368c31abSDavid du Colombier 			seterr(ECorrupt, "loadclump read less than a header");
130368c31abSDavid du Colombier 		freezblock(cb);
131368c31abSDavid du Colombier 		return nil;
132368c31abSDavid du Colombier 	}
133368c31abSDavid du Colombier 	trace(TraceLump, "loadclump unpack");
134368c31abSDavid du Colombier 	if(unpackclump(cl, cb->data, arena->clumpmagic) < 0){
135368c31abSDavid du Colombier 		seterr(ECorrupt, "loadclump %s %llud: %r", arena->name, aa);
136368c31abSDavid du Colombier 		freezblock(cb);
137368c31abSDavid du Colombier 		return nil;
138368c31abSDavid du Colombier 	}
139368c31abSDavid du Colombier 	if(cl->info.type == VtCorruptType){
140368c31abSDavid du Colombier 		seterr(EOk, "clump is marked corrupt");
141368c31abSDavid du Colombier 		freezblock(cb);
142368c31abSDavid du Colombier 		return nil;
143368c31abSDavid du Colombier 	}
144368c31abSDavid du Colombier 	n -= ClumpSize;
145368c31abSDavid du Colombier 	if(n < cl->info.size){
146368c31abSDavid du Colombier 		freezblock(cb);
147368c31abSDavid du Colombier 		n = cl->info.size;
148368c31abSDavid du Colombier 		cb = alloczblock(n, 0, 0);
149368c31abSDavid du Colombier 		if(cb == nil)
150368c31abSDavid du Colombier 			return nil;
151368c31abSDavid du Colombier 		if(readarena(arena, aa + ClumpSize, cb->data, n) != n){
152368c31abSDavid du Colombier 			seterr(ECorrupt, "loadclump read too little data");
153368c31abSDavid du Colombier 			freezblock(cb);
154368c31abSDavid du Colombier 			return nil;
155368c31abSDavid du Colombier 		}
156368c31abSDavid du Colombier 		buf = cb->data;
157368c31abSDavid du Colombier 	}else
158368c31abSDavid du Colombier 		buf = cb->data + ClumpSize;
159368c31abSDavid du Colombier 
160368c31abSDavid du Colombier 	scorecp(score, cl->info.score);
161368c31abSDavid du Colombier 
162368c31abSDavid du Colombier 	zb = alloczblock(cl->info.uncsize, 0, 0);
163368c31abSDavid du Colombier 	if(zb == nil){
164368c31abSDavid du Colombier 		freezblock(cb);
165368c31abSDavid du Colombier 		return nil;
166368c31abSDavid du Colombier 	}
167368c31abSDavid du Colombier 	switch(cl->encoding){
168368c31abSDavid du Colombier 	case ClumpECompress:
169368c31abSDavid du Colombier 		trace(TraceLump, "loadclump decompress");
170368c31abSDavid du Colombier 		unwhackinit(&uw);
171368c31abSDavid du Colombier 		nunc = unwhack(&uw, zb->data, cl->info.uncsize, buf, cl->info.size);
172368c31abSDavid du Colombier 		if(nunc != cl->info.uncsize){
173368c31abSDavid du Colombier 			if(nunc < 0)
174368c31abSDavid du Colombier 				seterr(ECorrupt, "decompression of %llud failed: %s", aa, uw.err);
175368c31abSDavid du Colombier 			else
176368c31abSDavid du Colombier 				seterr(ECorrupt, "decompression of %llud gave partial block: %d/%d\n", aa, nunc, cl->info.uncsize);
177368c31abSDavid du Colombier 			freezblock(cb);
178368c31abSDavid du Colombier 			freezblock(zb);
179368c31abSDavid du Colombier 			return nil;
180368c31abSDavid du Colombier 		}
181368c31abSDavid du Colombier 		break;
182368c31abSDavid du Colombier 	case ClumpENone:
183368c31abSDavid du Colombier 		if(cl->info.size != cl->info.uncsize){
184368c31abSDavid du Colombier 			seterr(ECorrupt, "loading clump: bad uncompressed size for uncompressed block %llud", aa);
185368c31abSDavid du Colombier 			freezblock(cb);
186368c31abSDavid du Colombier 			freezblock(zb);
187368c31abSDavid du Colombier 			return nil;
188368c31abSDavid du Colombier 		}
189368c31abSDavid du Colombier 		scoremem(bh, buf, cl->info.uncsize);
190368c31abSDavid du Colombier 		if(scorecmp(cl->info.score, bh) != 0)
191368c31abSDavid du Colombier 			seterr(ECorrupt, "pre-copy sha1 wrong at %s %llud: expected=%V got=%V", arena->name, aa, cl->info.score, bh);
192368c31abSDavid du Colombier 		memmove(zb->data, buf, cl->info.uncsize);
193368c31abSDavid du Colombier 		break;
194368c31abSDavid du Colombier 	default:
195368c31abSDavid du Colombier 		seterr(ECorrupt, "unknown encoding in loadlump %llud", aa);
196368c31abSDavid du Colombier 		freezblock(cb);
197368c31abSDavid du Colombier 		freezblock(zb);
198368c31abSDavid du Colombier 		return nil;
199368c31abSDavid du Colombier 	}
200368c31abSDavid du Colombier 	freezblock(cb);
201368c31abSDavid du Colombier 
202368c31abSDavid du Colombier 	if(verify){
203368c31abSDavid du Colombier 		trace(TraceLump, "loadclump verify");
204368c31abSDavid du Colombier 		scoremem(bh, zb->data, cl->info.uncsize);
205368c31abSDavid du Colombier 		if(scorecmp(cl->info.score, bh) != 0){
206368c31abSDavid du Colombier 			seterr(ECorrupt, "loading clump: corrupted at %s %llud; expected=%V got=%V", arena->name, aa, cl->info.score, bh);
207368c31abSDavid du Colombier 			freezblock(zb);
208368c31abSDavid du Colombier 			return nil;
209368c31abSDavid du Colombier 		}
210368c31abSDavid du Colombier 		if(vttypevalid(cl->info.type) < 0){
211368c31abSDavid du Colombier 			seterr(ECorrupt, "loading lump at %s %llud: invalid lump type %d", arena->name, aa, cl->info.type);
212368c31abSDavid du Colombier 			freezblock(zb);
213368c31abSDavid du Colombier 			return nil;
214368c31abSDavid du Colombier 		}
215368c31abSDavid du Colombier 	}
216368c31abSDavid du Colombier 
217368c31abSDavid du Colombier 	trace(TraceLump, "loadclump exit");
218368c31abSDavid du Colombier /*
219368c31abSDavid du Colombier 	qlock(&stats.lock);
220368c31abSDavid du Colombier 	stats.clumpbreads += cl->info.size;
221368c31abSDavid du Colombier 	stats.clumpbuncomp += cl->info.uncsize;
222368c31abSDavid du Colombier 	qunlock(&stats.lock);
223368c31abSDavid du Colombier */
224368c31abSDavid du Colombier 	return zb;
225368c31abSDavid du Colombier }
226