clump.c 5.2 KB

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