plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

clump.c (5316B)


      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 }