Blob


1 #include "stdinc.h"
2 #include "dat.h"
3 #include "fns.h"
5 /*
6 * disk structure conversion routines
7 */
8 #define U8GET(p) ((p)[0])
9 #define U16GET(p) (((p)[0]<<8)|(p)[1])
10 #define U32GET(p) ((u32int)(((p)[0]<<24)|((p)[1]<<16)|((p)[2]<<8)|(p)[3]))
11 #define U64GET(p) (((u64int)U32GET(p)<<32)|(u64int)U32GET((p)+4))
13 #define U8PUT(p,v) (p)[0]=(v)&0xFF
14 #define U16PUT(p,v) (p)[0]=((v)>>8)&0xFF;(p)[1]=(v)&0xFF
15 #define U32PUT(p,v) (p)[0]=((v)>>24)&0xFF;(p)[1]=((v)>>16)&0xFF;(p)[2]=((v)>>8)&0xFF;(p)[3]=(v)&0xFF
16 #define U64PUT(p,v,t32) t32=(v)>>32;U32PUT(p,t32);t32=(v);U32PUT((p)+4,t32)
18 int debugarena = -1; /* hack to improve error reporting */
20 static struct {
21 u32int m;
22 char *s;
23 } magics[] = {
24 ArenaPartMagic, "ArenaPartMagic",
25 ArenaHeadMagic, "ArenaHeadMagic",
26 ArenaMagic, "ArenaMagic",
27 ISectMagic, "ISectMagic",
28 BloomMagic, "BloomMagic",
29 };
31 static char*
32 fmtmagic(char *s, u32int m)
33 {
34 int i;
36 for(i=0; i<nelem(magics); i++)
37 if(magics[i].m == m)
38 return magics[i].s;
39 sprint(s, "%#08ux", m);
40 return s;
41 }
43 u32int
44 unpackmagic(u8int *buf)
45 {
46 return U32GET(buf);
47 }
49 void
50 packmagic(u32int magic, u8int *buf)
51 {
52 U32PUT(buf, magic);
53 }
55 int
56 unpackarenapart(ArenaPart *ap, u8int *buf)
57 {
58 u8int *p;
59 u32int m;
60 char fbuf[20];
62 p = buf;
64 m = U32GET(p);
65 if(m != ArenaPartMagic){
66 seterr(ECorrupt, "arena set has wrong magic number: %s expected ArenaPartMagic (%#lux)", fmtmagic(fbuf, m), ArenaPartMagic);
67 return -1;
68 }
69 p += U32Size;
70 ap->version = U32GET(p);
71 p += U32Size;
72 ap->blocksize = U32GET(p);
73 p += U32Size;
74 ap->arenabase = U32GET(p);
75 p += U32Size;
77 if(buf + ArenaPartSize != p)
78 sysfatal("unpackarenapart unpacked wrong amount");
80 return 0;
81 }
83 int
84 packarenapart(ArenaPart *ap, u8int *buf)
85 {
86 u8int *p;
88 p = buf;
90 U32PUT(p, ArenaPartMagic);
91 p += U32Size;
92 U32PUT(p, ap->version);
93 p += U32Size;
94 U32PUT(p, ap->blocksize);
95 p += U32Size;
96 U32PUT(p, ap->arenabase);
97 p += U32Size;
99 if(buf + ArenaPartSize != p)
100 sysfatal("packarenapart packed wrong amount");
102 return 0;
105 int
106 unpackarena(Arena *arena, u8int *buf)
108 int sz;
109 u8int *p;
110 u32int m;
111 char fbuf[20];
113 p = buf;
115 m = U32GET(p);
116 if(m != ArenaMagic){
117 seterr(ECorrupt, "arena %d has wrong magic number: %s "
118 "expected ArenaMagic (%#lux)", debugarena,
119 fmtmagic(fbuf, m), ArenaMagic);
120 return -1;
122 p += U32Size;
123 arena->version = U32GET(p);
124 p += U32Size;
125 namecp(arena->name, (char*)p);
126 p += ANameSize;
127 arena->diskstats.clumps = U32GET(p);
128 p += U32Size;
129 arena->diskstats.cclumps = U32GET(p);
130 p += U32Size;
131 arena->ctime = U32GET(p);
132 p += U32Size;
133 arena->wtime = U32GET(p);
134 p += U32Size;
135 if(arena->version == ArenaVersion5){
136 arena->clumpmagic = U32GET(p);
137 p += U32Size;
139 arena->diskstats.used = U64GET(p);
140 p += U64Size;
141 arena->diskstats.uncsize = U64GET(p);
142 p += U64Size;
143 arena->diskstats.sealed = U8GET(p);
144 p += U8Size;
145 switch(arena->version){
146 case ArenaVersion4:
147 sz = ArenaSize4;
148 arena->clumpmagic = _ClumpMagic;
149 break;
150 case ArenaVersion5:
151 sz = ArenaSize5;
152 break;
153 default:
154 seterr(ECorrupt, "arena has bad version number %d", arena->version);
155 return -1;
157 /*
158 * Additional fields for the memstats version of the stats.
159 * Diskstats reflects what is committed to the index.
160 * Memstats reflects what is in the arena. Originally intended
161 * this to be a version 5 extension, but might as well use for
162 * all the existing version 4 arenas too.
164 * To maintain backwards compatibility with existing venti
165 * installations using the older format, we define that if
166 * memstats == diskstats, then the extension fields are not
167 * included (see packarena below). That is, only partially
168 * indexed arenas have these fields. Fully indexed arenas
169 * (in particular, sealed arenas) do not.
170 */
171 if(U8GET(p) == 1){
172 sz += ArenaSize5a-ArenaSize5;
173 p += U8Size;
174 arena->memstats.clumps = U32GET(p);
175 p += U32Size;
176 arena->memstats.cclumps = U32GET(p);
177 p += U32Size;
178 arena->memstats.used = U64GET(p);
179 p += U64Size;
180 arena->memstats.uncsize = U64GET(p);
181 p += U64Size;
182 arena->memstats.sealed = U8GET(p);
183 p += U8Size;
185 /*
186 * 2008/4/2
187 * Packarena (below) used to have a bug in which it would
188 * not zero out any existing extension fields when writing
189 * the arena metadata. This would manifest itself as arenas
190 * with arena->diskstats.sealed == 1 but arena->memstats.sealed == 0
191 * after a server restart. Because arena->memstats.sealed wouldn't
192 * be set, the server might try to fit another block into the arena
193 * (and succeed), violating the append-only structure of the log
194 * and invalidating any already-computed seal on the arena.
196 * It might end up that other fields in arena->memstats end up
197 * behind arena->diskstats too, but that would be considerably
198 * more rare, and the bug is fixed now. The case we need to
199 * handle is just the sealed mismatch.
201 * If we encounter such a bogus arena, fix the sealed field.
202 */
203 if(arena->diskstats.sealed)
204 arena->memstats.sealed = 1;
205 }else
206 arena->memstats = arena->diskstats;
207 if(buf + sz != p)
208 sysfatal("unpackarena unpacked wrong amount");
210 return 0;
213 int
214 packarena(Arena *arena, u8int *buf)
216 return _packarena(arena, buf, 0);
219 int
220 _packarena(Arena *arena, u8int *buf, int forceext)
222 int sz;
223 u8int *p;
224 u32int t32;
226 switch(arena->version){
227 case ArenaVersion4:
228 sz = ArenaSize4;
229 if(arena->clumpmagic != _ClumpMagic)
230 fprint(2, "warning: writing old arena tail loses clump magic 0x%lux != 0x%lux\n",
231 (ulong)arena->clumpmagic, (ulong)_ClumpMagic);
232 break;
233 case ArenaVersion5:
234 sz = ArenaSize5;
235 break;
236 default:
237 sysfatal("packarena unknown version %d", arena->version);
238 return -1;
241 p = buf;
243 U32PUT(p, ArenaMagic);
244 p += U32Size;
245 U32PUT(p, arena->version);
246 p += U32Size;
247 namecp((char*)p, arena->name);
248 p += ANameSize;
249 U32PUT(p, arena->diskstats.clumps);
250 p += U32Size;
251 U32PUT(p, arena->diskstats.cclumps);
252 p += U32Size;
253 U32PUT(p, arena->ctime);
254 p += U32Size;
255 U32PUT(p, arena->wtime);
256 p += U32Size;
257 if(arena->version == ArenaVersion5){
258 U32PUT(p, arena->clumpmagic);
259 p += U32Size;
261 U64PUT(p, arena->diskstats.used, t32);
262 p += U64Size;
263 U64PUT(p, arena->diskstats.uncsize, t32);
264 p += U64Size;
265 U8PUT(p, arena->diskstats.sealed);
266 p += U8Size;
268 /*
269 * Extension fields; see above.
270 */
271 if(forceext
272 || arena->memstats.clumps != arena->diskstats.clumps
273 || arena->memstats.cclumps != arena->diskstats.cclumps
274 || arena->memstats.used != arena->diskstats.used
275 || arena->memstats.uncsize != arena->diskstats.uncsize
276 || arena->memstats.sealed != arena->diskstats.sealed){
277 sz += ArenaSize5a - ArenaSize5;
278 U8PUT(p, 1);
279 p += U8Size;
280 U32PUT(p, arena->memstats.clumps);
281 p += U32Size;
282 U32PUT(p, arena->memstats.cclumps);
283 p += U32Size;
284 U64PUT(p, arena->memstats.used, t32);
285 p += U64Size;
286 U64PUT(p, arena->memstats.uncsize, t32);
287 p += U64Size;
288 U8PUT(p, arena->memstats.sealed);
289 p += U8Size;
290 }else{
291 /* Clear any extension fields already on disk. */
292 memset(p, 0, ArenaSize5a - ArenaSize5);
293 p += ArenaSize5a - ArenaSize5;
294 sz += ArenaSize5a - ArenaSize5;
297 if(buf + sz != p)
298 sysfatal("packarena packed wrong amount");
300 return 0;
303 int
304 unpackarenahead(ArenaHead *head, u8int *buf)
306 u8int *p;
307 u32int m;
308 int sz;
309 char fbuf[20];
311 p = buf;
313 m = U32GET(p);
314 if(m != ArenaHeadMagic){
315 seterr(ECorrupt, "arena %d head has wrong magic number: %s "
316 "expected ArenaHeadMagic (%#lux)", debugarena,
317 fmtmagic(fbuf, m), ArenaHeadMagic);
318 return -1;
321 p += U32Size;
322 head->version = U32GET(p);
323 p += U32Size;
324 namecp(head->name, (char*)p);
325 p += ANameSize;
326 head->blocksize = U32GET(p);
327 p += U32Size;
328 head->size = U64GET(p);
329 p += U64Size;
330 if(head->version == ArenaVersion5){
331 head->clumpmagic = U32GET(p);
332 p += U32Size;
335 switch(head->version){
336 case ArenaVersion4:
337 sz = ArenaHeadSize4;
338 head->clumpmagic = _ClumpMagic;
339 break;
340 case ArenaVersion5:
341 sz = ArenaHeadSize5;
342 break;
343 default:
344 seterr(ECorrupt, "arena head has unexpected version %d", head->version);
345 return -1;
348 if(buf + sz != p)
349 sysfatal("unpackarenahead unpacked wrong amount");
351 return 0;
354 int
355 packarenahead(ArenaHead *head, u8int *buf)
357 u8int *p;
358 int sz;
359 u32int t32;
361 switch(head->version){
362 case ArenaVersion4:
363 sz = ArenaHeadSize4;
364 if(head->clumpmagic != _ClumpMagic)
365 fprint(2, "warning: writing old arena header loses clump magic 0x%lux != 0x%lux\n",
366 (ulong)head->clumpmagic, (ulong)_ClumpMagic);
367 break;
368 case ArenaVersion5:
369 sz = ArenaHeadSize5;
370 break;
371 default:
372 sysfatal("packarenahead unknown version %d", head->version);
373 return -1;
376 p = buf;
378 U32PUT(p, ArenaHeadMagic);
379 p += U32Size;
380 U32PUT(p, head->version);
381 p += U32Size;
382 namecp((char*)p, head->name);
383 p += ANameSize;
384 U32PUT(p, head->blocksize);
385 p += U32Size;
386 U64PUT(p, head->size, t32);
387 p += U64Size;
388 if(head->version == ArenaVersion5){
389 U32PUT(p, head->clumpmagic);
390 p += U32Size;
392 if(buf + sz != p)
393 sysfatal("packarenahead packed wrong amount");
395 return 0;
398 static int
399 checkclump(Clump *w)
401 if(w->encoding == ClumpENone){
402 if(w->info.size != w->info.uncsize){
403 seterr(ECorrupt, "uncompressed wad size mismatch");
404 return -1;
406 }else if(w->encoding == ClumpECompress){
407 if(w->info.size >= w->info.uncsize){
408 seterr(ECorrupt, "compressed lump has inconsistent block sizes %d %d", w->info.size, w->info.uncsize);
409 return -1;
411 }else{
412 seterr(ECorrupt, "clump has illegal encoding");
413 return -1;
416 return 0;
419 int
420 unpackclump(Clump *c, u8int *buf, u32int cmagic)
422 u8int *p;
423 u32int magic;
425 p = buf;
426 magic = U32GET(p);
427 if(magic != cmagic){
428 seterr(ECorrupt, "clump has bad magic number=%#8.8ux != %#8.8ux", magic, cmagic);
429 return -1;
431 p += U32Size;
433 c->info.type = vtfromdisktype(U8GET(p));
434 p += U8Size;
435 c->info.size = U16GET(p);
436 p += U16Size;
437 c->info.uncsize = U16GET(p);
438 p += U16Size;
439 scorecp(c->info.score, p);
440 p += VtScoreSize;
442 c->encoding = U8GET(p);
443 p += U8Size;
444 c->creator = U32GET(p);
445 p += U32Size;
446 c->time = U32GET(p);
447 p += U32Size;
449 if(buf + ClumpSize != p)
450 sysfatal("unpackclump unpacked wrong amount");
452 return checkclump(c);
455 int
456 packclump(Clump *c, u8int *buf, u32int magic)
458 u8int *p;
460 p = buf;
461 U32PUT(p, magic);
462 p += U32Size;
464 U8PUT(p, vttodisktype(c->info.type));
465 p += U8Size;
466 U16PUT(p, c->info.size);
467 p += U16Size;
468 U16PUT(p, c->info.uncsize);
469 p += U16Size;
470 scorecp(p, c->info.score);
471 p += VtScoreSize;
473 U8PUT(p, c->encoding);
474 p += U8Size;
475 U32PUT(p, c->creator);
476 p += U32Size;
477 U32PUT(p, c->time);
478 p += U32Size;
480 if(buf + ClumpSize != p)
481 sysfatal("packclump packed wrong amount");
483 return checkclump(c);
486 void
487 unpackclumpinfo(ClumpInfo *ci, u8int *buf)
489 u8int *p;
491 p = buf;
492 ci->type = vtfromdisktype(U8GET(p));
493 p += U8Size;
494 ci->size = U16GET(p);
495 p += U16Size;
496 ci->uncsize = U16GET(p);
497 p += U16Size;
498 scorecp(ci->score, p);
499 p += VtScoreSize;
501 if(buf + ClumpInfoSize != p)
502 sysfatal("unpackclumpinfo unpacked wrong amount");
505 void
506 packclumpinfo(ClumpInfo *ci, u8int *buf)
508 u8int *p;
510 p = buf;
511 U8PUT(p, vttodisktype(ci->type));
512 p += U8Size;
513 U16PUT(p, ci->size);
514 p += U16Size;
515 U16PUT(p, ci->uncsize);
516 p += U16Size;
517 scorecp(p, ci->score);
518 p += VtScoreSize;
520 if(buf + ClumpInfoSize != p)
521 sysfatal("packclumpinfo packed wrong amount");
524 int
525 unpackisect(ISect *is, u8int *buf)
527 u8int *p;
528 u32int m;
529 char fbuf[20];
531 p = buf;
534 m = U32GET(p);
535 if(m != ISectMagic){
536 seterr(ECorrupt, "index section has wrong magic number: %s expected ISectMagic (%#lux)",
537 fmtmagic(fbuf, m), ISectMagic);
538 return -1;
540 p += U32Size;
541 is->version = U32GET(p);
542 p += U32Size;
543 namecp(is->name, (char*)p);
544 p += ANameSize;
545 namecp(is->index, (char*)p);
546 p += ANameSize;
547 is->blocksize = U32GET(p);
548 p += U32Size;
549 is->blockbase = U32GET(p);
550 p += U32Size;
551 is->blocks = U32GET(p);
552 p += U32Size;
553 is->start = U32GET(p);
554 p += U32Size;
555 is->stop = U32GET(p);
556 p += U32Size;
557 if(buf + ISectSize1 != p)
558 sysfatal("unpackisect unpacked wrong amount");
559 is->bucketmagic = 0;
560 if(is->version == ISectVersion2){
561 is->bucketmagic = U32GET(p);
562 p += U32Size;
563 if(buf + ISectSize2 != p)
564 sysfatal("unpackisect unpacked wrong amount");
567 return 0;
570 int
571 packisect(ISect *is, u8int *buf)
573 u8int *p;
575 p = buf;
577 U32PUT(p, ISectMagic);
578 p += U32Size;
579 U32PUT(p, is->version);
580 p += U32Size;
581 namecp((char*)p, is->name);
582 p += ANameSize;
583 namecp((char*)p, is->index);
584 p += ANameSize;
585 U32PUT(p, is->blocksize);
586 p += U32Size;
587 U32PUT(p, is->blockbase);
588 p += U32Size;
589 U32PUT(p, is->blocks);
590 p += U32Size;
591 U32PUT(p, is->start);
592 p += U32Size;
593 U32PUT(p, is->stop);
594 p += U32Size;
595 if(buf + ISectSize1 != p)
596 sysfatal("packisect packed wrong amount");
597 if(is->version == ISectVersion2){
598 U32PUT(p, is->bucketmagic);
599 p += U32Size;
600 if(buf + ISectSize2 != p)
601 sysfatal("packisect packed wrong amount");
604 return 0;
607 void
608 unpackientry(IEntry *ie, u8int *buf)
610 u8int *p;
612 p = buf;
614 scorecp(ie->score, p);
615 p += VtScoreSize;
616 /* ie->wtime = U32GET(p); */
617 p += U32Size;
618 /* ie->train = U16GET(p); */
619 p += U16Size;
620 if(p - buf != IEntryAddrOff)
621 sysfatal("unpackentry bad IEntryAddrOff amount");
622 ie->ia.addr = U64GET(p);
623 if(ie->ia.addr>>56) print("%.8H => %llux\n", p, ie->ia.addr);
624 p += U64Size;
625 ie->ia.size = U16GET(p);
626 p += U16Size;
627 if(p - buf != IEntryTypeOff)
628 sysfatal("unpackientry bad IEntryTypeOff amount");
629 ie->ia.type = vtfromdisktype(U8GET(p));
630 p += U8Size;
631 ie->ia.blocks = U8GET(p);
632 p += U8Size;
634 if(p - buf != IEntrySize)
635 sysfatal("unpackientry unpacked wrong amount");
638 void
639 packientry(IEntry *ie, u8int *buf)
641 u32int t32;
642 u8int *p;
644 p = buf;
646 scorecp(p, ie->score);
647 p += VtScoreSize;
648 U32PUT(p, 0); /* wtime */
649 p += U32Size;
650 U16PUT(p, 0); /* train */
651 p += U16Size;
652 U64PUT(p, ie->ia.addr, t32);
653 p += U64Size;
654 U16PUT(p, ie->ia.size);
655 p += U16Size;
656 U8PUT(p, vttodisktype(ie->ia.type));
657 p += U8Size;
658 U8PUT(p, ie->ia.blocks);
659 p += U8Size;
661 if(p - buf != IEntrySize)
662 sysfatal("packientry packed wrong amount");
665 void
666 unpackibucket(IBucket *b, u8int *buf, u32int magic)
668 b->n = U16GET(buf);
669 b->data = buf + IBucketSize;
670 if(magic && magic != U32GET(buf+U16Size))
671 b->n = 0;
674 void
675 packibucket(IBucket *b, u8int *buf, u32int magic)
677 U16PUT(buf, b->n);
678 U32PUT(buf+U16Size, magic);
681 void
682 packbloomhead(Bloom *b, u8int *buf)
684 u8int *p;
686 p = buf;
687 U32PUT(p, BloomMagic);
688 U32PUT(p+4, BloomVersion);
689 U32PUT(p+8, b->nhash);
690 U32PUT(p+12, b->size);
693 int
694 unpackbloomhead(Bloom *b, u8int *buf)
696 u8int *p;
697 u32int m;
698 char fbuf[20];
700 p = buf;
702 m = U32GET(p);
703 if(m != BloomMagic){
704 seterr(ECorrupt, "bloom filter has wrong magic number: %s expected BloomMagic (%#lux)", fmtmagic(fbuf, m), (ulong)BloomMagic);
705 return -1;
707 p += U32Size;
709 m = U32GET(p);
710 if(m != BloomVersion){
711 seterr(ECorrupt, "bloom filter has wrong version %ud expected %ud", (uint)m, (uint)BloomVersion);
712 return -1;
714 p += U32Size;
716 b->nhash = U32GET(p);
717 p += U32Size;
719 b->size = U32GET(p);
720 p += U32Size;
721 if(b->size < BloomHeadSize || b->size > MaxBloomSize || (b->size&(b->size-1))){
722 seterr(ECorrupt, "bloom filter has invalid size %#lux", b->size);
723 return -1;
726 if(buf + BloomHeadSize != p)
727 sysfatal("unpackarena unpacked wrong amount");
729 return 0;