Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include "stdinc.h"
2
#include "dat.h"
3
#include "fns.h"
4
#include "whack.h"
5
 
6
/*
7
 * Write a lump to disk.  Updates ia with an index address
8
 * for the newly-written lump.  Upon return, the lump will
9
 * have been placed in the disk cache but will likely not be on disk yet.
10
 */
11
int
12
storeclump(Index *ix, ZBlock *zb, u8int *sc, int type, u32int creator, IAddr *ia)
13
{
14
	ZBlock *cb;
15
	Clump cl;
16
	u64int a;
17
	u8int bh[VtScoreSize];
18
	int size, dsize;
19
 
20
	trace(TraceLump, "storeclump enter", sc, type);
21
	size = zb->len;
22
	if(size > VtMaxLumpSize){
23
		seterr(EStrange, "lump too large");
24
		return -1;
25
	}
26
	if(vttypevalid(type) < 0){
27
		seterr(EStrange, "invalid lump type");
28
		return -1;
29
	}
30
 
31
	if(0){
32
		scoremem(bh, zb->data, size);
33
		if(scorecmp(sc, bh) != 0){
34
			seterr(ECorrupt, "storing clump: corrupted; expected=%V got=%V, size=%d", sc, bh, size);
35
			return -1;
36
		}
37
	}
38
 
39
	cb = alloczblock(size + ClumpSize + U32Size, 0, 0);
40
	if(cb == nil)
41
		return -1;
42
 
43
	cl.info.type = type;
44
	cl.info.uncsize = size;
45
	cl.creator = creator;
46
	cl.time = now();
47
	scorecp(cl.info.score, sc);
48
 
49
	trace(TraceLump, "storeclump whackblock");
50
	dsize = whackblock(&cb->data[ClumpSize], zb->data, size);
51
	if(dsize > 0 && dsize < size){
52
		cl.encoding = ClumpECompress;
53
	}else{
54
		if(dsize > size){
55
			fprint(2, "whack error: dsize=%d size=%d\n", dsize, size);
56
			abort();
57
		}
58
		cl.encoding = ClumpENone;
59
		dsize = size;
60
		memmove(&cb->data[ClumpSize], zb->data, size);
61
	}
62
	memset(cb->data+ClumpSize+dsize, 0, 4);
63
	cl.info.size = dsize;
64
 
65
	a = writeiclump(ix, &cl, cb->data);
66
	trace(TraceLump, "storeclump exit %lld", a);
67
	freezblock(cb);
68
	if(a == TWID64)
69
		return -1;
70
 
71
	ia->addr = a;
72
	ia->type = type;
73
	ia->size = size;
74
	ia->blocks = (dsize + ClumpSize + (1 << ABlockLog) - 1) >> ABlockLog;
75
 
76
/*
77
	qlock(&stats.lock);
78
	stats.clumpwrites++;
79
	stats.clumpbwrites += size;
80
	stats.clumpbcomp += dsize;
81
	qunlock(&stats.lock);
82
*/
83
 
84
	return 0;
85
}
86
 
87
u32int
88
clumpmagic(Arena *arena, u64int aa)
89
{
90
	u8int buf[U32Size];
91
 
92
	if(readarena(arena, aa, buf, U32Size) == TWID32)
93
		return TWID32;
94
	return unpackmagic(buf);
95
}
96
 
97
/*
98
 * fetch a block based at addr.
99
 * score is filled in with the block's score.
100
 * blocks is roughly the length of the clump on disk;
101
 * if zero, the length is unknown.
102
 */
103
ZBlock*
104
loadclump(Arena *arena, u64int aa, int blocks, Clump *cl, u8int *score, int verify)
105
{
106
	Unwhack uw;
107
	ZBlock *zb, *cb;
108
	u8int bh[VtScoreSize], *buf;
109
	u32int n;
110
	int nunc;
111
 
112
/*
113
	qlock(&stats.lock);
114
	stats.clumpreads++;
115
	qunlock(&stats.lock);
116
*/
117
 
118
	if(blocks <= 0)
119
		blocks = 1;
120
 
121
	trace(TraceLump, "loadclump enter");
122
 
123
	cb = alloczblock(blocks << ABlockLog, 0, 0);
124
	if(cb == nil)
125
		return nil;
126
	n = readarena(arena, aa, cb->data, blocks << ABlockLog);
127
	if(n < ClumpSize){
128
		if(n != 0)
129
			seterr(ECorrupt, "loadclump read less than a header");
130
		freezblock(cb);
131
		return nil;
132
	}
133
	trace(TraceLump, "loadclump unpack");
134
	if(unpackclump(cl, cb->data, arena->clumpmagic) < 0){
135
		seterr(ECorrupt, "loadclump %s %llud: %r", arena->name, aa);
136
		freezblock(cb);
137
		return nil;
138
	}
139
	if(cl->info.type == VtCorruptType){
140
		seterr(EOk, "clump is marked corrupt");
141
		freezblock(cb);
142
		return nil;
143
	}
144
	n -= ClumpSize;
145
	if(n < cl->info.size){
146
		freezblock(cb);
147
		n = cl->info.size;
148
		cb = alloczblock(n, 0, 0);
149
		if(cb == nil)
150
			return nil;
151
		if(readarena(arena, aa + ClumpSize, cb->data, n) != n){
152
			seterr(ECorrupt, "loadclump read too little data");
153
			freezblock(cb);
154
			return nil;
155
		}
156
		buf = cb->data;
157
	}else
158
		buf = cb->data + ClumpSize;
159
 
160
	scorecp(score, cl->info.score);
161
 
162
	zb = alloczblock(cl->info.uncsize, 0, 0);
163
	if(zb == nil){
164
		freezblock(cb);
165
		return nil;
166
	}
167
	switch(cl->encoding){
168
	case ClumpECompress:
169
		trace(TraceLump, "loadclump decompress");
170
		unwhackinit(&uw);
171
		nunc = unwhack(&uw, zb->data, cl->info.uncsize, buf, cl->info.size);
172
		if(nunc != cl->info.uncsize){
173
			if(nunc < 0)
174
				seterr(ECorrupt, "decompression of %llud failed: %s", aa, uw.err);
175
			else
176
				seterr(ECorrupt, "decompression of %llud gave partial block: %d/%d\n", aa, nunc, cl->info.uncsize);
177
			freezblock(cb);
178
			freezblock(zb);
179
			return nil;
180
		}
181
		break;
182
	case ClumpENone:
183
		if(cl->info.size != cl->info.uncsize){
184
			seterr(ECorrupt, "loading clump: bad uncompressed size for uncompressed block %llud", aa);
185
			freezblock(cb);
186
			freezblock(zb);
187
			return nil;
188
		}
189
		scoremem(bh, buf, cl->info.uncsize);
190
		if(scorecmp(cl->info.score, bh) != 0)
191
			seterr(ECorrupt, "pre-copy sha1 wrong at %s %llud: expected=%V got=%V", arena->name, aa, cl->info.score, bh);
192
		memmove(zb->data, buf, cl->info.uncsize);
193
		break;
194
	default:
195
		seterr(ECorrupt, "unknown encoding in loadlump %llud", aa);
196
		freezblock(cb);
197
		freezblock(zb);
198
		return nil;
199
	}
200
	freezblock(cb);
201
 
202
	if(verify){
203
		trace(TraceLump, "loadclump verify");
204
		scoremem(bh, zb->data, cl->info.uncsize);
205
		if(scorecmp(cl->info.score, bh) != 0){
206
			seterr(ECorrupt, "loading clump: corrupted at %s %llud; expected=%V got=%V", arena->name, aa, cl->info.score, bh);
207
			freezblock(zb);
208
			return nil;
209
		}
210
		if(vttypevalid(cl->info.type) < 0){
211
			seterr(ECorrupt, "loading lump at %s %llud: invalid lump type %d", arena->name, aa, cl->info.type);
212
			freezblock(zb);
213
			return nil;
214
		}
215
	}
216
 
217
	trace(TraceLump, "loadclump exit");
218
/*
219
	qlock(&stats.lock);
220
	stats.clumpbreads += cl->info.size;
221
	stats.clumpbuncomp += cl->info.uncsize;
222
	qunlock(&stats.lock);
223
*/
224
	return zb;
225
}