clump.c 5.6 KB

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