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 }