static void *ileaf_resize(struct btree *btree, tuxkey_t inum, vleaf *base, unsigned newsize) { assert(ileaf_sniff(btree, base)); struct ileaf *leaf = base; assert(inum >= ibase(leaf)); be_u16 *dict = base + btree->sb->blocksize; unsigned at = inum - ibase(leaf); if (at >= btree->entries_per_leaf) return NULL; unsigned extend_empty = at < icount(leaf) ? 0 : at - icount(leaf) + 1; unsigned offset = at && icount(leaf) ? from_be_u16(*(dict - (at < icount(leaf) ? at : icount(leaf)))) : 0; unsigned size = at < icount(leaf) ? from_be_u16(*(dict - at - 1)) - offset : 0; int more = newsize - size; if (more > 0 && sizeof(*dict) * extend_empty + more > ileaf_free(btree, leaf)) return NULL; for (; extend_empty--; leaf->count = to_be_u16(from_be_u16(leaf->count) + 1)) *(dict - icount(leaf) - 1) = to_be_u16(atdict(dict, icount(leaf))); assert(icount(leaf)); unsigned itop = from_be_u16(*(dict - icount(leaf))); void *attrs = leaf->table + offset; printf("resize inum 0x%Lx at 0x%x from %x to %x\n", (L)inum, offset, size, newsize); assert(itop >= offset + size); memmove(attrs + newsize, attrs + size, itop - offset - size); for (int i = at + 1; i <= icount(leaf); i++) add_idict(dict - i, more); return attrs; }
Move pb_probe(Pos *pos) { Move m1 = 0; if (!enabled) return m1; if (!check_do_search(pos)) return m1; if (book_depth_count >= max_book_depth) return m1; Key key = polyglot_key(pos); int n = find_first_key(key); if (n < 1) { search_counter++; if (search_counter > 4) { // Stop searching after 4 times not in the book till position changes // according to check_do_search() do_search = false; search_counter = 0; book_depth_count = 0; } return m1; } book_depth_count++; ssize_t idx1 = use_best_book_move ? index_best : index_rand; m1 = pg_move_to_sf_move(pos, from_be_u16(polyhash[idx1].move)); if (!is_draw(pos)) return m1; // 64 if (n == 1) return m1; // Special case draw position and 2 moves available if (!check_draw(pos, m1)) return m1; ssize_t idx2 = index_first; if (idx1 == idx2) idx2++; Move m2 = pg_move_to_sf_move(pos, from_be_u16(polyhash[idx2].move)); if (!check_draw(pos, m2)) return m2; return 0; }
/* userland only */ void ileaf_merge(struct btree *btree, struct ileaf *leaf, struct ileaf *from) { if (!icount(from)) return; be_u16 *dict = (void *)leaf + btree->sb->blocksize; be_u16 *fromdict = (void *)from + btree->sb->blocksize; unsigned at = icount(leaf), free = atdict(dict, at), size = atdict(fromdict, icount(from)); printf("copy in %i bytes\n", size); memcpy(leaf->table + free, from->table, size); leaf->count = to_be_u16(from_be_u16(leaf->count) + icount(from)); veccopy(dict - icount(leaf), fromdict - icount(from), icount(from)); for (int i = at + 1; at && i <= at + icount(from); i++) add_idict(dict - i, from_be_u16(*(dict - at))); }
static void ileaf_dump(struct btree *btree, vleaf *vleaf) { struct sb *sb = btree->sb; struct ileaf *leaf = vleaf; inum_t inum = ibase(leaf); be_u16 *dict = vleaf + sb->blocksize; unsigned offset = 0; printf("inode table block 0x%Lx/%i (%x bytes free)\n", (L)ibase(leaf), icount(leaf), ileaf_free(btree, leaf)); //hexdump(dict - icount(leaf), icount(leaf) * 2); for (int i = -1; -i <= icount(leaf); i--, inum++) { int limit = from_be_u16(dict[i]), size = limit - offset; if (!size) continue; printf(" 0x%Lx: ", (L)inum); //printf("[%x] ", offset); if (size < 0) printf("<corrupt>\n"); else if (!size) printf("<empty>\n"); else { /* FIXME: this doesn't work in kernel */ struct inode inode = { .i_sb = vfs_sb(btree->sb) }; unsigned xsize = decode_xsize(&inode, leaf->table + offset, size); tux_inode(&inode)->xcache = xsize ? new_xcache(xsize) : NULL; decode_attrs(&inode, leaf->table + offset, size); dump_attrs(&inode); xcache_dump(&inode); free(tux_inode(&inode)->xcache); } offset = limit; } } void *ileaf_lookup(struct btree *btree, inum_t inum, struct ileaf *leaf, unsigned *result) { assert(inum >= ibase(leaf)); assert(inum < ibase(leaf) + btree->entries_per_leaf); unsigned at = inum - ibase(leaf), size = 0; void *attrs = NULL; printf("lookup inode 0x%Lx, %Lx + %x\n", (L)inum, (L)ibase(leaf), at); if (at < icount(leaf)) { be_u16 *dict = (void *)leaf + btree->sb->blocksize; unsigned offset = atdict(dict, at); if ((size = from_be_u16(*(dict - at - 1)) - offset)) attrs = leaf->table + offset; } *result = size; return attrs; }
inum_t find_empty_inode(struct btree *btree, struct ileaf *leaf, inum_t goal) { assert(goal >= ibase(leaf)); goal -= ibase(leaf); //printf("find empty inode starting at %Lx, base %Lx\n", (L)goal, (L)ibase(leaf)); be_u16 *dict = (void *)leaf + btree->sb->blocksize; unsigned i, offset = goal && goal < icount(leaf) ? from_be_u16(*(dict - goal)) : 0; for (i = goal; i < icount(leaf); i++) { unsigned limit = from_be_u16(*(dict - i - 1)); if (offset == limit) break; offset = limit; } return i + ibase(leaf); }
static void ileaf_trim(struct btree *btree, struct ileaf *leaf) { be_u16 *dict = (void *)leaf + btree->sb->blocksize; while (icount(leaf) > 1 && *(dict - icount(leaf)) == *(dict - icount(leaf) + 1)) leaf->count = to_be_u16(from_be_u16(leaf->count) - 1); if (icount(leaf) == 1 && !*(dict - 1)) leaf->count = 0; }
static int isinorder(struct btree *btree, struct ileaf *leaf) { be_u16 *dict = (void *)leaf + btree->sb->blocksize; for (int i = 0, offset = 0, limit; --i >= -icount(leaf); offset = limit) if ((limit = from_be_u16(dict[i])) < offset) return 0; return 1; }
int ileaf_purge(struct btree *btree, inum_t inum, struct ileaf *leaf) { if (inum < ibase(leaf) || inum - ibase(leaf) >= btree->entries_per_leaf) return -EINVAL; be_u16 *dict = (void *)leaf + btree->sb->blocksize; unsigned at = inum - ibase(leaf); unsigned offset = atdict(dict, at); unsigned size = from_be_u16(*(dict - at - 1)) - offset; printf("delete inode %Lx from %p[%x/%x]\n", (L)inum, leaf, at, size); if (!size) return -ENOENT; unsigned free = from_be_u16(*(dict - icount(leaf))), tail = free - offset - size; assert(offset + size + tail <= free); memmove(leaf->table + offset, leaf->table + offset + size, tail); for (int i = at + 1; i <= icount(leaf); i++) add_idict(dict - i, -size); ileaf_trim(btree, leaf); return 0; }
static tuxkey_t ileaf_split(struct btree *btree, tuxkey_t inum, vleaf *from, vleaf *into) { assert(ileaf_sniff(btree, from)); struct ileaf *leaf = from, *dest = into; be_u16 *dict = from + btree->sb->blocksize, *destdict = into + btree->sb->blocksize; #ifdef SPLIT_AT_INUM printf("split at inum 0x%Lx\n", (L)inum); assert(inum >= ibase(leaf)); unsigned at = inum - ibase(leaf) < icount(leaf) ? inum - ibase(leaf) : icount(leaf); #else /* binsearch inum starting nearest middle of block */ unsigned at = 1, hi = icount(leaf); while (at < hi) { int mid = (at + hi) / 2; if (*(dict - mid) < (btree->sb->blocksize / 2)) at = mid + 1; else hi = mid; } #endif /* should trim leading empty inodes on copy */ unsigned split = atdict(dict, at), free = from_be_u16(*(dict - icount(leaf))); printf("split at %x of %x\n", at, icount(leaf)); printf("copy out %x bytes at %x\n", free - split, split); assert(free >= split); memcpy(dest->table, leaf->table + split, free - split); dest->count = to_be_u16(icount(leaf) - at); veccopy(destdict - icount(dest), dict - icount(leaf), icount(dest)); for (int i = 1; i <= icount(dest); i++) add_idict(destdict - i, -split); #ifdef SPLIT_AT_INUM /* round down to multiple of 64 above ibase */ inum_t round = inum & ~(inum_t)(btree->entries_per_leaf - 1); dest->ibase = to_be_u64(round > ibase(leaf) + icount(leaf) ? round : inum); #else dest->ibase = to_be_u64(ibase(leaf) + at); #endif leaf->count = to_be_u16(at); memset(leaf->table + split, 0, (char *)(dict - icount(leaf)) - (leaf->table + split)); ileaf_trim(btree, leaf); return ibase(dest); }
static int get_key_data(void) { int best_weight = from_be_u16(polyhash[index_first].weight); index_weight_count = best_weight; uint64_t key = polyhash[index_first].key; index_count = 1; index_best = index_first; for (ssize_t i = index_first + 1; i < keycount; i++) { if (polyhash[i].key != key) break; index_count++; index_weight_count += from_be_u16(polyhash[i].weight); if (from_be_u16(polyhash[i].weight) > best_weight) { best_weight = from_be_u16(polyhash[i].weight); index_best = i; } } int rand_pos = prng_rand(&sr) % index_weight_count; int weight_count = 0; index_rand = index_best; for (ssize_t i = index_first; i < index_first + index_count; i++) { if ( rand_pos >= weight_count && rand_pos < weight_count + from_be_u16(polyhash[i].weight)) { index_rand = i; break; } weight_count += from_be_u16(polyhash[i].weight); } return index_count; }
static inline unsigned icount(struct ileaf *leaf) { return from_be_u16(leaf->count); }
static inline void add_idict(be_u16 *dict, int n) { *dict = to_be_u16(from_be_u16(*dict) + n); }
static inline unsigned atdict(be_u16 *dict, unsigned at) { return at ? from_be_u16(*(dict - at)) : 0; }