index.c (19202B)
1 /* 2 * Index, mapping scores to log positions. 3 * 4 * The index is made up of some number of index sections, each of 5 * which is typically stored on a different disk. The blocks in all the 6 * index sections are logically numbered, with each index section 7 * responsible for a range of blocks. Blocks are typically 8kB. 8 * 9 * The N index blocks are treated as a giant hash table. The top 32 bits 10 * of score are used as the key for a lookup. Each index block holds 11 * one hash bucket, which is responsible for ceil(2^32 / N) of the key space. 12 * 13 * The index is sized so that a particular bucket is extraordinarily 14 * unlikely to overflow: assuming compressed data blocks are 4kB 15 * on disk, and assuming each block has a 40 byte index entry, 16 * the index data will be 1% of the total data. Since scores are essentially 17 * random, all buckets should be about the same fullness. 18 * A factor of 5 gives us a wide comfort boundary to account for 19 * random variation. So the index disk space should be 5% of the arena disk space. 20 */ 21 22 #include "stdinc.h" 23 #include "dat.h" 24 #include "fns.h" 25 26 static int initindex1(Index*); 27 static ISect *initisect1(ISect *is); 28 29 #define KEY(k,d) ((d) ? (k)>>(32-(d)) : 0) 30 31 static char IndexMagic[] = "venti index configuration"; 32 33 Index* 34 initindex(char *name, ISect **sects, int n) 35 { 36 IFile f; 37 Index *ix; 38 ISect *is; 39 u32int last, blocksize, tabsize; 40 int i; 41 42 if(n <= 0){ 43 fprint(2, "bad n\n"); 44 seterr(EOk, "no index sections to initialize index"); 45 return nil; 46 } 47 ix = MKZ(Index); 48 if(ix == nil){ 49 fprint(2, "no mem\n"); 50 seterr(EOk, "can't initialize index: out of memory"); 51 freeindex(ix); 52 return nil; 53 } 54 55 tabsize = sects[0]->tabsize; 56 if(partifile(&f, sects[0]->part, sects[0]->tabbase, tabsize) < 0) 57 return nil; 58 if(parseindex(&f, ix) < 0){ 59 freeifile(&f); 60 freeindex(ix); 61 return nil; 62 } 63 freeifile(&f); 64 if(namecmp(ix->name, name) != 0){ 65 seterr(ECorrupt, "mismatched index name: found %s expected %s", ix->name, name); 66 return nil; 67 } 68 if(ix->nsects != n){ 69 seterr(ECorrupt, "mismatched number index sections: found %d expected %d", n, ix->nsects); 70 freeindex(ix); 71 return nil; 72 } 73 ix->sects = sects; 74 last = 0; 75 blocksize = ix->blocksize; 76 for(i = 0; i < ix->nsects; i++){ 77 is = sects[i]; 78 if(namecmp(is->index, ix->name) != 0) { 79 seterr(ECorrupt, "%s: index name is %s, not %s", 80 sects[i]->part->name, is->index, ix->name); 81 bad: 82 freeindex(ix); 83 return nil; 84 } 85 if(is->blocksize != blocksize) { 86 seterr(ECorrupt, "%s: blocksize is %d, not %d", 87 sects[i]->part->name, (int)is->blocksize, (int)blocksize); 88 goto bad; 89 } 90 if(is->tabsize != tabsize) { 91 seterr(ECorrupt, "%s: tabsize is %d, not %d", 92 sects[i]->part->name, (int)is->tabsize, (int)tabsize); 93 goto bad; 94 } 95 if(namecmp(is->name, ix->smap[i].name) != 0) { 96 seterr(ECorrupt, "%s: name is %s, not %s", 97 sects[i]->part->name, is->name, ix->smap[i].name); 98 goto bad; 99 } 100 if(is->start != ix->smap[i].start || is->stop != ix->smap[i].stop) { 101 seterr(ECorrupt, "%s: range is %lld,%lld, not %lld,%lld", 102 sects[i]->part->name, is->start, is->stop, 103 ix->smap[i].start, ix->smap[i].stop); 104 goto bad; 105 } 106 if(is->start > is->stop) { 107 seterr(ECorrupt, "%s: invalid range %lld,%lld", 108 sects[i]->part->name, is->start, is->stop); 109 goto bad; 110 } 111 if(is->start != last || is->start > is->stop) { 112 seterr(ECorrupt, "%s: range %lld-%lld, but last section ended at %lld", 113 sects[i]->part->name, is->start, is->stop, last); 114 goto bad; 115 } 116 last = is->stop; 117 } 118 ix->tabsize = tabsize; 119 ix->buckets = last; 120 121 if(initindex1(ix) < 0){ 122 freeindex(ix); 123 return nil; 124 } 125 126 ix->arenas = MKNZ(Arena*, ix->narenas); 127 if(maparenas(ix->amap, ix->arenas, ix->narenas, ix->name) < 0){ 128 freeindex(ix); 129 return nil; 130 } 131 132 return ix; 133 } 134 135 static int 136 initindex1(Index *ix) 137 { 138 u32int buckets; 139 140 ix->div = (((u64int)1 << 32) + ix->buckets - 1) / ix->buckets; 141 buckets = (((u64int)1 << 32) - 1) / ix->div + 1; 142 if(buckets != ix->buckets){ 143 seterr(ECorrupt, "inconsistent math for divisor and buckets in %s", ix->name); 144 return -1; 145 } 146 147 return 0; 148 } 149 150 int 151 wbindex(Index *ix) 152 { 153 Fmt f; 154 ZBlock *b; 155 int i; 156 157 if(ix->nsects == 0){ 158 seterr(EOk, "no sections in index %s", ix->name); 159 return -1; 160 } 161 b = alloczblock(ix->tabsize, 1, ix->blocksize); 162 if(b == nil){ 163 seterr(EOk, "can't write index configuration: out of memory"); 164 return -1; 165 } 166 fmtzbinit(&f, b); 167 if(outputindex(&f, ix) < 0){ 168 seterr(EOk, "can't make index configuration: table storage too small %d", ix->tabsize); 169 freezblock(b); 170 return -1; 171 } 172 for(i = 0; i < ix->nsects; i++){ 173 if(writepart(ix->sects[i]->part, ix->sects[i]->tabbase, b->data, ix->tabsize) < 0 174 || flushpart(ix->sects[i]->part) < 0){ 175 seterr(EOk, "can't write index: %r"); 176 freezblock(b); 177 return -1; 178 } 179 } 180 freezblock(b); 181 182 for(i = 0; i < ix->nsects; i++) 183 if(wbisect(ix->sects[i]) < 0) 184 return -1; 185 186 return 0; 187 } 188 189 /* 190 * index: IndexMagic '\n' version '\n' name '\n' blocksize '\n' [V2: bitblocks '\n'] sections arenas 191 * version, blocksize: u32int 192 * name: max. ANameSize string 193 * sections, arenas: AMap 194 */ 195 int 196 outputindex(Fmt *f, Index *ix) 197 { 198 if(fmtprint(f, "%s\n%ud\n%s\n%ud\n", IndexMagic, ix->version, ix->name, ix->blocksize) < 0 199 || outputamap(f, ix->smap, ix->nsects) < 0 200 || outputamap(f, ix->amap, ix->narenas) < 0) 201 return -1; 202 return 0; 203 } 204 205 int 206 parseindex(IFile *f, Index *ix) 207 { 208 AMapN amn; 209 u32int v; 210 char *s; 211 212 /* 213 * magic 214 */ 215 s = ifileline(f); 216 if(s == nil || strcmp(s, IndexMagic) != 0){ 217 seterr(ECorrupt, "bad index magic for %s", f->name); 218 return -1; 219 } 220 221 /* 222 * version 223 */ 224 if(ifileu32int(f, &v) < 0){ 225 seterr(ECorrupt, "syntax error: bad version number in %s", f->name); 226 return -1; 227 } 228 ix->version = v; 229 if(ix->version != IndexVersion){ 230 seterr(ECorrupt, "bad version number in %s", f->name); 231 return -1; 232 } 233 234 /* 235 * name 236 */ 237 if(ifilename(f, ix->name) < 0){ 238 seterr(ECorrupt, "syntax error: bad index name in %s", f->name); 239 return -1; 240 } 241 242 /* 243 * block size 244 */ 245 if(ifileu32int(f, &v) < 0){ 246 seterr(ECorrupt, "syntax error: bad block size number in %s", f->name); 247 return -1; 248 } 249 ix->blocksize = v; 250 251 if(parseamap(f, &amn) < 0) 252 return -1; 253 ix->nsects = amn.n; 254 ix->smap = amn.map; 255 256 if(parseamap(f, &amn) < 0) 257 return -1; 258 ix->narenas = amn.n; 259 ix->amap = amn.map; 260 261 return 0; 262 } 263 264 /* 265 * initialize an entirely new index 266 */ 267 Index * 268 newindex(char *name, ISect **sects, int n) 269 { 270 Index *ix; 271 AMap *smap; 272 u64int nb; 273 u32int div, ub, xb, start, stop, blocksize, tabsize; 274 int i, j; 275 276 if(n < 1){ 277 seterr(EOk, "creating index with no index sections"); 278 return nil; 279 } 280 281 /* 282 * compute the total buckets available in the index, 283 * and the total buckets which are used. 284 */ 285 nb = 0; 286 blocksize = sects[0]->blocksize; 287 tabsize = sects[0]->tabsize; 288 for(i = 0; i < n; i++){ 289 /* 290 * allow index, start, and stop to be set if index is correct 291 * and start and stop are what we would have picked. 292 * this allows calling fmtindex to reformat the index after 293 * replacing a bad index section with a freshly formatted one. 294 * start and stop are checked below. 295 */ 296 if(sects[i]->index[0] != '\0' && strcmp(sects[i]->index, name) != 0){ 297 seterr(EOk, "creating new index using non-empty section %s", sects[i]->name); 298 return nil; 299 } 300 if(blocksize != sects[i]->blocksize){ 301 seterr(EOk, "%s has block size %d, but %s has %d", 302 sects[0]->part->name, (int)blocksize, 303 sects[i]->part->name, (int)sects[i]->blocksize); 304 return nil; 305 } 306 if(tabsize != sects[i]->tabsize){ 307 seterr(EOk, "%s has table size %d, but %s has %d", 308 sects[0]->part->name, (int)tabsize, 309 sects[i]->part->name, (int)sects[i]->tabsize); 310 return nil; 311 } 312 nb += sects[i]->blocks; 313 } 314 315 /* 316 * check for duplicate names 317 */ 318 for(i = 0; i < n; i++){ 319 for(j = i + 1; j < n; j++){ 320 if(namecmp(sects[i]->name, sects[j]->name) == 0){ 321 seterr(EOk, "%s and %s both have section name %s", 322 sects[i]->part->name, 323 sects[j]->part->name, 324 sects[i]->name); 325 return nil; 326 } 327 } 328 } 329 330 if(nb >= ((u64int)1 << 32)){ 331 fprint(2, "%s: index is 2^32 blocks or more; ignoring some of it\n", 332 argv0); 333 nb = ((u64int)1 << 32) - 1; 334 } 335 336 div = (((u64int)1 << 32) + nb - 1) / nb; 337 if(div < 100){ 338 fprint(2, "%s: index divisor %d too coarse; " 339 "index larger than needed, ignoring some of it\n", 340 argv0, div); 341 div = 100; 342 nb = (((u64int)1 << 32) - 1) / (100 - 1); 343 } 344 ub = (((u64int)1 << 32) - 1) / div + 1; 345 if(ub > nb){ 346 seterr(EBug, "index initialization math wrong"); 347 return nil; 348 } 349 xb = nb - ub; 350 351 /* 352 * initialize each of the index sections 353 * and the section map table 354 */ 355 smap = MKNZ(AMap, n); 356 if(smap == nil){ 357 seterr(EOk, "can't create new index: out of memory"); 358 return nil; 359 } 360 start = 0; 361 for(i = 0; i < n; i++){ 362 stop = start + sects[i]->blocks - xb / n; 363 if(i == n - 1) 364 stop = ub; 365 366 if(sects[i]->start != 0 || sects[i]->stop != 0) 367 if(sects[i]->start != start || sects[i]->stop != stop){ 368 seterr(EOk, "creating new index using non-empty section %s", sects[i]->name); 369 return nil; 370 } 371 372 sects[i]->start = start; 373 sects[i]->stop = stop; 374 namecp(sects[i]->index, name); 375 376 smap[i].start = start; 377 smap[i].stop = stop; 378 namecp(smap[i].name, sects[i]->name); 379 start = stop; 380 } 381 382 /* 383 * initialize the index itself 384 */ 385 ix = MKZ(Index); 386 if(ix == nil){ 387 seterr(EOk, "can't create new index: out of memory"); 388 free(smap); 389 return nil; 390 } 391 ix->version = IndexVersion; 392 namecp(ix->name, name); 393 ix->sects = sects; 394 ix->smap = smap; 395 ix->nsects = n; 396 ix->blocksize = blocksize; 397 ix->buckets = ub; 398 ix->tabsize = tabsize; 399 ix->div = div; 400 401 if(initindex1(ix) < 0){ 402 free(smap); 403 return nil; 404 } 405 406 return ix; 407 } 408 409 ISect* 410 initisect(Part *part) 411 { 412 ISect *is; 413 ZBlock *b; 414 int ok; 415 416 b = alloczblock(HeadSize, 0, 0); 417 if(b == nil || readpart(part, PartBlank, b->data, HeadSize) < 0){ 418 seterr(EAdmin, "can't read index section header: %r"); 419 return nil; 420 } 421 422 is = MKZ(ISect); 423 if(is == nil){ 424 freezblock(b); 425 return nil; 426 } 427 is->part = part; 428 ok = unpackisect(is, b->data); 429 freezblock(b); 430 if(ok < 0){ 431 seterr(ECorrupt, "corrupted index section header: %r"); 432 freeisect(is); 433 return nil; 434 } 435 436 if(is->version != ISectVersion1 && is->version != ISectVersion2){ 437 seterr(EAdmin, "unknown index section version %d", is->version); 438 freeisect(is); 439 return nil; 440 } 441 442 return initisect1(is); 443 } 444 445 ISect* 446 newisect(Part *part, u32int vers, char *name, u32int blocksize, u32int tabsize) 447 { 448 ISect *is; 449 u32int tabbase; 450 451 is = MKZ(ISect); 452 if(is == nil) 453 return nil; 454 455 namecp(is->name, name); 456 is->version = vers; 457 is->part = part; 458 is->blocksize = blocksize; 459 is->start = 0; 460 is->stop = 0; 461 tabbase = (PartBlank + HeadSize + blocksize - 1) & ~(blocksize - 1); 462 is->blockbase = (tabbase + tabsize + blocksize - 1) & ~(blocksize - 1); 463 is->blocks = is->part->size / blocksize - is->blockbase / blocksize; 464 is->bucketmagic = 0; 465 if(is->version == ISectVersion2){ 466 do{ 467 is->bucketmagic = fastrand(); 468 }while(is->bucketmagic==0); 469 } 470 is = initisect1(is); 471 if(is == nil) 472 return nil; 473 474 return is; 475 } 476 477 /* 478 * initialize the computed parameters for an index 479 */ 480 static ISect* 481 initisect1(ISect *is) 482 { 483 u64int v; 484 485 is->buckmax = (is->blocksize - IBucketSize) / IEntrySize; 486 is->blocklog = u64log2(is->blocksize); 487 if(is->blocksize != (1 << is->blocklog)){ 488 seterr(ECorrupt, "illegal non-power-of-2 bucket size %d\n", is->blocksize); 489 freeisect(is); 490 return nil; 491 } 492 partblocksize(is->part, is->blocksize); 493 is->tabbase = (PartBlank + HeadSize + is->blocksize - 1) & ~(is->blocksize - 1); 494 if(is->tabbase >= is->blockbase){ 495 seterr(ECorrupt, "index section config table overlaps bucket storage"); 496 freeisect(is); 497 return nil; 498 } 499 is->tabsize = is->blockbase - is->tabbase; 500 v = is->part->size & ~(u64int)(is->blocksize - 1); 501 if(is->blockbase + (u64int)is->blocks * is->blocksize != v){ 502 seterr(ECorrupt, "invalid blocks in index section %s", is->name); 503 /* ZZZ what to do? 504 freeisect(is); 505 return nil; 506 */ 507 } 508 509 if(is->stop - is->start > is->blocks){ 510 seterr(ECorrupt, "index section overflows available space"); 511 freeisect(is); 512 return nil; 513 } 514 if(is->start > is->stop){ 515 seterr(ECorrupt, "invalid index section range"); 516 freeisect(is); 517 return nil; 518 } 519 520 return is; 521 } 522 523 int 524 wbisect(ISect *is) 525 { 526 ZBlock *b; 527 528 b = alloczblock(HeadSize, 1, 0); 529 if(b == nil){ 530 /* ZZZ set error? */ 531 return -1; 532 } 533 534 if(packisect(is, b->data) < 0){ 535 seterr(ECorrupt, "can't make index section header: %r"); 536 freezblock(b); 537 return -1; 538 } 539 if(writepart(is->part, PartBlank, b->data, HeadSize) < 0 || flushpart(is->part) < 0){ 540 seterr(EAdmin, "can't write index section header: %r"); 541 freezblock(b); 542 return -1; 543 } 544 freezblock(b); 545 546 return 0; 547 } 548 549 void 550 freeisect(ISect *is) 551 { 552 if(is == nil) 553 return; 554 free(is); 555 } 556 557 void 558 freeindex(Index *ix) 559 { 560 int i; 561 562 if(ix == nil) 563 return; 564 free(ix->amap); 565 free(ix->arenas); 566 if(ix->sects) 567 for(i = 0; i < ix->nsects; i++) 568 freeisect(ix->sects[i]); 569 free(ix->sects); 570 free(ix->smap); 571 free(ix); 572 } 573 574 /* 575 * write a clump to an available arena in the index 576 * and return the address of the clump within the index. 577 ZZZ question: should this distinguish between an arena 578 filling up and real errors writing the clump? 579 */ 580 u64int 581 writeiclump(Index *ix, Clump *c, u8int *clbuf) 582 { 583 u64int a; 584 int i; 585 IAddr ia; 586 AState as; 587 588 trace(TraceLump, "writeiclump enter"); 589 qlock(&ix->writing); 590 for(i = ix->mapalloc; i < ix->narenas; i++){ 591 a = writeaclump(ix->arenas[i], c, clbuf); 592 if(a != TWID64){ 593 ix->mapalloc = i; 594 ia.addr = ix->amap[i].start + a; 595 ia.type = c->info.type; 596 ia.size = c->info.uncsize; 597 ia.blocks = (c->info.size + ClumpSize + (1<<ABlockLog) - 1) >> ABlockLog; 598 as.arena = ix->arenas[i]; 599 as.aa = ia.addr; 600 as.stats = as.arena->memstats; 601 insertscore(c->info.score, &ia, IEDirty, &as); 602 qunlock(&ix->writing); 603 trace(TraceLump, "writeiclump exit"); 604 return ia.addr; 605 } 606 } 607 qunlock(&ix->writing); 608 609 seterr(EAdmin, "no space left in arenas"); 610 trace(TraceLump, "writeiclump failed"); 611 return TWID64; 612 } 613 614 /* 615 * convert an arena index to an relative arena address 616 */ 617 Arena* 618 amapitoa(Index *ix, u64int a, u64int *aa) 619 { 620 int i, r, l, m; 621 622 l = 1; 623 r = ix->narenas - 1; 624 while(l <= r){ 625 m = (r + l) / 2; 626 if(ix->amap[m].start <= a) 627 l = m + 1; 628 else 629 r = m - 1; 630 } 631 l--; 632 633 if(a > ix->amap[l].stop){ 634 for(i=0; i<ix->narenas; i++) 635 print("arena %d: %llux - %llux\n", i, ix->amap[i].start, ix->amap[i].stop); 636 print("want arena %d for %llux\n", l, a); 637 seterr(ECrash, "unmapped address passed to amapitoa"); 638 return nil; 639 } 640 641 if(ix->arenas[l] == nil){ 642 seterr(ECrash, "unmapped arena selected in amapitoa"); 643 return nil; 644 } 645 *aa = a - ix->amap[l].start; 646 return ix->arenas[l]; 647 } 648 649 /* 650 * convert an arena index to the bounds of the containing arena group. 651 */ 652 Arena* 653 amapitoag(Index *ix, u64int a, u64int *gstart, u64int *glimit, int *g) 654 { 655 u64int aa; 656 Arena *arena; 657 658 arena = amapitoa(ix, a, &aa); 659 if(arena == nil) 660 return nil; 661 if(arenatog(arena, aa, gstart, glimit, g) < 0) 662 return nil; 663 *gstart += a - aa; 664 *glimit += a - aa; 665 return arena; 666 } 667 668 int 669 iaddrcmp(IAddr *ia1, IAddr *ia2) 670 { 671 return ia1->type != ia2->type 672 || ia1->size != ia2->size 673 || ia1->blocks != ia2->blocks 674 || ia1->addr != ia2->addr; 675 } 676 677 /* 678 * lookup the score in the partition 679 * 680 * nothing needs to be explicitly locked: 681 * only static parts of ix are used, and 682 * the bucket is locked by the DBlock lock. 683 */ 684 int 685 loadientry(Index *ix, u8int *score, int type, IEntry *ie) 686 { 687 ISect *is; 688 DBlock *b; 689 IBucket ib; 690 u32int buck; 691 int h, ok; 692 693 ok = -1; 694 695 trace(TraceLump, "loadientry enter"); 696 697 /* 698 qlock(&stats.lock); 699 stats.indexreads++; 700 qunlock(&stats.lock); 701 */ 702 703 if(!inbloomfilter(mainindex->bloom, score)){ 704 trace(TraceLump, "loadientry bloomhit"); 705 return -1; 706 } 707 708 trace(TraceLump, "loadientry loadibucket"); 709 b = loadibucket(ix, score, &is, &buck, &ib); 710 trace(TraceLump, "loadientry loadedibucket"); 711 if(b == nil) 712 return -1; 713 714 if(okibucket(&ib, is) < 0){ 715 trace(TraceLump, "loadientry badbucket"); 716 goto out; 717 } 718 719 h = bucklook(score, type, ib.data, ib.n); 720 if(h & 1){ 721 h ^= 1; 722 trace(TraceLump, "loadientry found"); 723 unpackientry(ie, &ib.data[h]); 724 ok = 0; 725 goto out; 726 } 727 trace(TraceLump, "loadientry notfound"); 728 addstat(StatBloomFalseMiss, 1); 729 out: 730 putdblock(b); 731 trace(TraceLump, "loadientry exit"); 732 return ok; 733 } 734 735 int 736 okibucket(IBucket *ib, ISect *is) 737 { 738 if(ib->n <= is->buckmax) 739 return 0; 740 741 seterr(EICorrupt, "corrupted disk index bucket: n=%ud max=%ud, range=[%lud,%lud)", 742 ib->n, is->buckmax, is->start, is->stop); 743 return -1; 744 } 745 746 /* 747 * look for score within data; 748 * return 1 | byte index of matching index, 749 * or 0 | index of least element > score 750 */ 751 int 752 bucklook(u8int *score, int otype, u8int *data, int n) 753 { 754 int i, r, l, m, h, c, cc, type; 755 756 if(otype == -1) 757 type = -1; 758 else 759 type = vttodisktype(otype); 760 l = 0; 761 r = n - 1; 762 while(l <= r){ 763 m = (r + l) >> 1; 764 h = m * IEntrySize; 765 for(i = 0; i < VtScoreSize; i++){ 766 c = score[i]; 767 cc = data[h + i]; 768 if(c != cc){ 769 if(c > cc) 770 l = m + 1; 771 else 772 r = m - 1; 773 goto cont; 774 } 775 } 776 cc = data[h + IEntryTypeOff]; 777 if(type != cc && type != -1){ 778 if(type > cc) 779 l = m + 1; 780 else 781 r = m - 1; 782 goto cont; 783 } 784 return h | 1; 785 cont:; 786 } 787 788 return l * IEntrySize; 789 } 790 791 /* 792 * compare two IEntries; consistent with bucklook 793 */ 794 int 795 ientrycmp(const void *vie1, const void *vie2) 796 { 797 u8int *ie1, *ie2; 798 int i, v1, v2; 799 800 ie1 = (u8int*)vie1; 801 ie2 = (u8int*)vie2; 802 for(i = 0; i < VtScoreSize; i++){ 803 v1 = ie1[i]; 804 v2 = ie2[i]; 805 if(v1 != v2){ 806 if(v1 < v2) 807 return -1; 808 return 1; 809 } 810 } 811 v1 = ie1[IEntryTypeOff]; 812 v2 = ie2[IEntryTypeOff]; 813 if(v1 != v2){ 814 if(v1 < v2) 815 return -1; 816 return 1; 817 } 818 return 0; 819 } 820 821 /* 822 * find the number of the index section holding bucket #buck 823 */ 824 int 825 indexsect0(Index *ix, u32int buck) 826 { 827 int r, l, m; 828 829 l = 1; 830 r = ix->nsects - 1; 831 while(l <= r){ 832 m = (r + l) >> 1; 833 if(ix->sects[m]->start <= buck) 834 l = m + 1; 835 else 836 r = m - 1; 837 } 838 return l - 1; 839 } 840 841 /* 842 * load the index block at bucket #buck 843 */ 844 static DBlock* 845 loadibucket0(Index *ix, u32int buck, ISect **pis, u32int *pbuck, IBucket *ib, int mode) 846 { 847 ISect *is; 848 DBlock *b; 849 850 is = ix->sects[indexsect0(ix, buck)]; 851 if(buck < is->start || is->stop <= buck){ 852 seterr(EAdmin, "index lookup out of range: %ud not found in index\n", buck); 853 return nil; 854 } 855 856 buck -= is->start; 857 if((b = getdblock(is->part, is->blockbase + ((u64int)buck << is->blocklog), mode)) == nil) 858 return nil; 859 860 if(pis) 861 *pis = is; 862 if(pbuck) 863 *pbuck = buck; 864 if(ib) 865 unpackibucket(ib, b->data, is->bucketmagic); 866 return b; 867 } 868 869 /* 870 * find the number of the index section holding score 871 */ 872 int 873 indexsect1(Index *ix, u8int *score) 874 { 875 return indexsect0(ix, hashbits(score, 32) / ix->div); 876 } 877 878 /* 879 * load the index block responsible for score. 880 */ 881 static DBlock* 882 loadibucket1(Index *ix, u8int *score, ISect **pis, u32int *pbuck, IBucket *ib) 883 { 884 return loadibucket0(ix, hashbits(score, 32)/ix->div, pis, pbuck, ib, OREAD); 885 } 886 887 int 888 indexsect(Index *ix, u8int *score) 889 { 890 return indexsect1(ix, score); 891 } 892 893 DBlock* 894 loadibucket(Index *ix, u8int *score, ISect **pis, u32int *pbuck, IBucket *ib) 895 { 896 return loadibucket1(ix, score, pis, pbuck, ib); 897 }