// File: /workspace/github_c_makefile_star2_O2/Tarsnap[P]kivaloo/kvlds/btree.c
// Function: btree_init
struct btree *
btree_init(struct wire_requestqueue * Q_lbs, uint64_t npages,
    uint64_t npagebytes, uint64_t * keylen, uint64_t * vallen, double Scost)
{
	struct btree * T;
	struct node * C;
	struct params_cookie PC;
	struct getroot_cookie GC;
	struct sync_cookie SC;
	uint64_t rootblk;
	size_t i;

	/* Sanity check: at least one of {npages, npagebytes} must be unset. */
	assert((npages == (uint64_t)(-1)) || (npagebytes == (uint64_t)(-1)));

#if SIZE_MAX < UINT64_MAX
	/* Sanity check: must be able to fit npagebytes in memory. */
	assert((npagebytes == (uint64_t)(-1)) || (npagebytes <= SIZE_MAX));

	/* Sanity check: must be able to fit npages in memory. */
	assert((npages == (uint64_t)(-1)) || (npages <= SIZE_MAX));
#endif

	/* Allocate space for the B+Tree. */
	if ((T = malloc(sizeof(struct btree))) == NULL)
		goto err0;

	/* Attach LBS request queue to the tree. */
	T->LBS = Q_lbs;

	/* Issue a PARAMS2 request. */
	PC.T = T;
	PC.failed = PC.done = 0;
	if (proto_lbs_request_params2(T->LBS, callback_params, &PC)) {
		warnp("Failed to send PARAMS2 request");
		goto err1;
	}
	if (events_spin(&PC.done) || PC.failed) {
		warnp("LBS PARAMS2 request failed");
		goto err1;
	}

	/* If we have neither npages nor npagebytes, set a default. */
	if ((npages == (uint64_t)(-1)) && (npagebytes == (uint64_t)(-1))) {
#if 128 * 1024 * 1024 < SIZE_MAX
		/* Normal default is 128 MB. */
		npagebytes = 128 * 1024 * 1024;
#else
		/* Set a smaller default size for systems with a tiny size_t. */
		npagebytes = SIZE_MAX;
#endif
	}

	/* Figure out how many pages to use and sanity-check. */
	if (npagebytes != (uint64_t)(-1)) {
		npages = npagebytes / T->pagelen;
		if ((npages < 1024) || (npages > 1024 * 1024 * 1024)) {
			warn0("Cache size in pages must be in [2^10, 2^30]");
			goto err1;
		}
	}
	T->poolsz = (size_t)npages;

	/* Set default key/value lengths if necessary. */
	if (*keylen == (uint64_t)(-1)) {
		if (T->pagelen < 1024)
			*keylen = 64;
		else if (T->pagelen < 2048)
			*keylen = 128;
		else
			*keylen = 255;
	}
	if (*vallen == (uint64_t)(-1)) {
		if (T->pagelen < 1024)
			*vallen = 96;
		else if (T->pagelen < 2048)
			*vallen = 192;
		else
			*vallen = 255;
	}

	/* Sanity-check key and value lengths. */
	if (*keylen + *vallen + 2 > T->pagelen / 3) {
		warn0("Key or value lengths too large for page size");
		goto err1;
	}
	if (*keylen * 3 + 3 + SERIALIZE_PERCHILD * 4 + SERIALIZE_OVERHEAD >
	    T->pagelen * 2 / 3) {
		warn0("Key length too large for page size");
		goto err1;
	}

	/* Create a page pool. */
	if ((T->P = pool_init(T->poolsz,
	    offsetof(struct node, pool_cookie))) == NULL)
		goto err1;

	/* No root nodes yet. */
	T->root_shadow = T->root_dirty = NULL;

	/*
	 * Try to find a root node by scanning backwards from the last block
	 * the block store reports having present.
	 */
	for (rootblk = PC.lastblk; rootblk < T->nextblk; rootblk--) {
		/*
		 * Create a node.  If we keep this node, we will fill in the
		 * oldestleaf and pagesize values later.
		 */
		if ((T->root_dirty = node_alloc(rootblk, (uint64_t)(-1),
		    (uint32_t)(-1))) == NULL) {
			warnp("Failed to allocate node");
			goto err2;
		}
		T->root_shadow = T->root_dirty;

		/* Page in the node data. */
		GC.done = 0;
		if (btree_node_fetch_try(T, T->root_dirty,
		    callback_getroot, &GC)) {
			warnp("Failed to GET root page");
			goto err3;
		}

		/* Wait until we've finished fetching. */
		if (events_spin(&GC.done)) {
			warnp("Error reading root page");

			/*
			 * If events_spin failed, we don't know what state
			 * the root node is in, so we can't safely free it.
			 */
			goto err1;
		}

		/* Is this a root node? */
		if (node_present(T->root_dirty) && T->root_dirty->root)
			break;

		/* Not a root node; free this and try the next one. */
		btree_node_destroy(T, T->root_dirty);
		T->root_dirty = NULL;
	}

	/* If we have found a root node, finish up initialization. */
	if (T->root_dirty != NULL) {
		/* Record the size of the serialized node. */
		T->root_dirty->pagesize =
		    (uint32_t)serialize_size(T->root_dirty);

		/* Figure out the oldestleaf. */
		if (T->root_dirty->type == NODE_TYPE_PARENT) {
			for (i = 0; i <= T->root_dirty->nkeys; i++) {
				C = T->root_dirty->v.children[i];
				if (C->oldestleaf <
				    T->root_dirty->oldestleaf)
					T->root_dirty->oldestleaf =
					    C->oldestleaf;
			}
		} else {
			T->root_dirty->oldestleaf = T->root_dirty->pagenum;
		}

		/* The oldest not-being-cleaned leaf is the oldest leaf. */
		T->root_dirty->oldestncleaf = T->root_dirty->oldestleaf;

		/* Figure out how many pages we're using. */
		T->npages = T->nextblk - T->root_dirty->oldestleaf;

		/* This is also our shadow root. */
		T->root_shadow = T->root_dirty;
		btree_node_lock(T, T->root_shadow);

		/* We have a root! */
		goto gotroot;
	}

	/* If we had any pages, one of them should have been a root. */
	if (T->nextblk > 0) {
		warn0("Could not find root B+Tree node");
		goto err2;
	}

	/* Create a dirty leaf node. */
	if ((T->root_dirty = btree_node_mkleaf(T, 0, NULL)) == NULL)
		goto err2;

	/* Mark the node as a root. */
	T->root_dirty->root = 1;
	btree_node_lock(T, T->root_dirty);

	/* This tree contains 1 node. */
	T->nnodes = 1;

	/* Sync the (trivial) dirty tree out. */
	SC.done = 0;
	if (btree_sync(T, callback_sync, &SC)) {
		warnp("Failed to APPEND root page");
		goto err4;
	}

	/* Wait until we've finished writing. */
	if (events_spin(&SC.done)) {
		warnp("Error writing root page");

		/*
		 * If events_spin failed, we don't know what state
		 * the root nodes are in, so we can't free them.
		 */
		goto err1;
	}

	/*
	 * If the next writable block is not block #1, we're using a sparse
	 * block space and need to disable cleaning (see comment above).
	 */
	if (T->nextblk != 1)
		Scost = 0.0;

gotroot:
	/* Schedule a callback to invoke FREE. */
	if ((T->gc_timer =
	    events_timer_register(callback_gc, T, &free_time)) == NULL) {
		btree_free(T);
		goto err0;
	}

	/* Start background cleaning. */
	if ((T->cstate = btree_cleaning_start(T, Scost)) == NULL) {
		warnp("Cannot start background cleaning");
		exit(1);
	}

	/* Success! */
	return (T);

	/* Root-creation path. */
err4:
	btree_node_unlock(T, T->root_dirty);
	btree_node_destroy(T, T->root_dirty);
	goto err2;

	/* Root-fetching path. */
err3:
	node_free(T->root_dirty);

	/* Merged exit path. */
err2:
	pool_free(T->P);
err1:
	free(T);
err0:
	/* Failure! */
	return (NULL);
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x38, %rsp
movsd %xmm0, 0x18(%rsp)
movq %rcx, %r15
cmpq $-0x1, %rsi
sete %al
cmpq $-0x1, %rdx
sete %cl
orb %al, %cl
je 0x5299
movq %r8, %r12
movq %rdx, %r13
movq %rsi, %r14
movq %rdi, %rbp
pushq $0x58
popq %rdi
callq 0x22a0
testq %rax, %rax
je 0x4f36
movq %rax, %rbx
movq %rbp, 0x18(%rax)
leaq 0x20(%rsp), %rdx
movq %rax, (%rdx)
andq $0x0, 0x10(%rdx)
leaq 0x50f(%rip), %rsi       # 0x52d4
movq %rbp, %rdi
callq 0xf0b4
testl %eax, %eax
je 0x4de7
callq 0x20a0
cmpl $0x0, (%rax)
je 0x4e21
movq %rax, %r14
leaq 0xca8e(%rip), %rdi      # 0x11873
jmp 0x4e11
leaq 0x34(%rsp), %rbp
movq %rbp, %rdi
callq 0x9e9b
orl -0x4(%rbp), %eax
je 0x4e2d
callq 0x20a0
cmpl $0x0, (%rax)
je 0x4ef0
movq %rax, %r14
leaq 0xca81(%rip), %rdi      # 0x11892
xorl %eax, %eax
callq 0xdf55
andl $0x0, (%r14)
jmp 0x4f2e
leaq 0xca4b(%rip), %rdi      # 0x11873
jmp 0x4ef7
movq %r13, %rax
andq %r14, %rax
cmpq $-0x1, %rax
movl $0x8000000, %eax        # imm = 0x8000000
cmovneq %r13, %rax
movq (%rbx), %rcx
cmpq $-0x1, %rax
je 0x4e6b
xorl %edx, %edx
divq %rcx
movq %rax, %r14
addq $-0x40000001, %rax      # imm = 0xBFFFFFFF
cmpq $-0x3ffffc02, %rax      # imm = 0xC00003FE
ja 0x4e6b
leaq 0xc285(%rip), %rdi      # 0x110eb
jmp 0x4f1f
movq %r14, 0x8(%rbx)
cmpq $-0x1, (%r15)
jne 0x4e9b
cmpq $0x800, %rcx            # imm = 0x800
movl $0x80, %eax
movl $0xff, %edx
cmovbq %rax, %rdx
cmpq $0x400, %rcx            # imm = 0x400
pushq $0x40
popq %rax
cmovaeq %rdx, %rax
movq %rax, (%r15)
movq (%r12), %rax
cmpq $-0x1, %rax
jne 0x4ecc
cmpq $0x800, %rcx            # imm = 0x800
movl $0xc0, %eax
movl $0xff, %edx
cmovbq %rax, %rdx
cmpq $0x400, %rcx            # imm = 0x400
pushq $0x60
popq %rax
cmovaeq %rdx, %rax
movq %rax, (%r12)
movq (%r15), %rdi
leaq (%rdi,%rax), %r8
addq $0x2, %r8
pushq $0x3
popq %rsi
movq %rcx, %rax
xorl %edx, %edx
divq %rsi
cmpq %rax, %r8
jbe 0x4f00
leaq 0xc9bf(%rip), %rdi      # 0x118ad
jmp 0x4f1f
leaq 0xc99b(%rip), %rdi      # 0x11892
xorl %eax, %eax
callq 0xe0e4
jmp 0x4f2e
leaq (%rdi,%rdi,2), %rdi
addq $0x5d, %rdi
addq %rcx, %rcx
movq %rcx, %rax
xorl %edx, %edx
divq %rsi
cmpq %rax, %rdi
jbe 0x4f4a
leaq 0xc9bb(%rip), %rdi      # 0x118da
xorl %eax, %eax
callq 0xe0e4
callq 0x20a0
andl $0x0, (%rax)
movq %rbx, %rdi
callq 0x2040
xorl %ebx, %ebx
movq %rbx, %rax
addq $0x38, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
pushq $0x30
popq %rsi
movq %r14, %rdi
callq 0xe674
movq %rax, 0x30(%rbx)
testq %rax, %rax
je 0x4f2e
xorps %xmm0, %xmm0
movups %xmm0, 0x20(%rbx)
movq 0x28(%rsp), %r14
pushq $-0x1
popq %r15
pushq $-0x1
popq %rbp
leaq 0x377(%rip), %r12       # 0x52ef
leaq 0x14(%rsp), %r13
cmpq 0x10(%rbx), %r14
jae 0x4fee
movq %r14, %rdi
movq %r15, %rsi
movl %ebp, %edx
callq 0x934c
movq %rax, 0x28(%rbx)
testq %rax, %rax
je 0x5014
movq %rax, 0x20(%rbx)
andl $0x0, 0x14(%rsp)
movq %rbx, %rdi
movq %rax, %rsi
movq %r12, %rdx
movq %r13, %rcx
callq 0x7918
testl %eax, %eax
jne 0x503c
movq %r13, %rdi
callq 0x9e9b
testl %eax, %eax
jne 0x5064
movq 0x28(%rbx), %rsi
movb 0x1c(%rsi), %al
andb $0x12, %al
cmpb $0x10, %al
je 0x5081
movq %rbx, %rdi
callq 0x7921
andq $0x0, 0x28(%rbx)
decq %r14
jmp 0x4f7d
cmpq $0x0, 0x10(%rbx)
je 0x511b
leaq 0xc945(%rip), %rdi      # 0x11945
xorl %eax, %eax
callq 0xe0e4
callq 0x20a0
andl $0x0, (%rax)
jmp 0x51c8
callq 0x20a0
cmpl $0x0, (%rax)
je 0x51a1
movq %rax, %r14
leaq 0xc8d1(%rip), %rdi      # 0x118fd
xorl %eax, %eax
callq 0xdf55
andl $0x0, (%r14)
jmp 0x51c8
callq 0x20a0
cmpl $0x0, (%rax)
je 0x51b1
movq %rax, %r14
leaq 0xc8c1(%rip), %rdi      # 0x11915
xorl %eax, %eax
callq 0xdf55
andl $0x0, (%r14)
jmp 0x51bf
callq 0x20a0
cmpl $0x0, (%rax)
je 0x51e3
movq %rax, %r14
leaq 0xc8b1(%rip), %rdi      # 0x1192d
jmp 0x4e11
movq %rsi, %rdi
callq 0x8e4b
movq 0x28(%rbx), %rsi
movl %eax, 0x18(%rsi)
testb $0x3, 0x1c(%rsi)
je 0x51ef
movq (%rsi), %rax
movq %rax, 0x8(%rsi)
movq %rax, 0x10(%rsi)
movq 0x10(%rbx), %rcx
subq %rax, %rcx
movq %rcx, 0x50(%rbx)
movq %rsi, 0x20(%rbx)
movq %rbx, %rdi
callq 0x52f8
leaq 0x263(%rip), %rdi       # 0x5326
leaq 0xc94e(%rip), %rdx      # 0x11a18
movq %rbx, %rsi
callq 0xaa98
movq %rax, 0x38(%rbx)
testq %rax, %rax
je 0x51d6
movq %rbx, %rdi
movsd 0x18(%rsp), %xmm0
callq 0x5f00
movq %rax, 0x40(%rbx)
testq %rax, %rax
jne 0x4f38
callq 0x20a0
cmpl $0x0, (%rax)
jne 0x52b8
leaq 0xc889(%rip), %rdi      # 0x11998
xorl %eax, %eax
callq 0xe0e4
jmp 0x52cc
andq $0x0, (%rsp)
pushq $0x1
popq %rsi
movq %rbx, %rdi
xorl %edx, %edx
xorl %ecx, %ecx
xorl %r8d, %r8d
xorl %r9d, %r9d
callq 0x767c
movq %rax, 0x28(%rbx)
testq %rax, %rax
je 0x51c8
orb $0x10, 0x1c(%rax)
movq 0x28(%rbx), %rsi
movq %rbx, %rdi
callq 0x52f8
movq $0x1, 0x48(%rbx)
leaq 0x10(%rsp), %rdx
andl $0x0, (%rdx)
leaq 0x1b4(%rip), %rsi       # 0x531d
movq %rbx, %rdi
callq 0x67b4
testl %eax, %eax
je 0x5222
callq 0x20a0
cmpl $0x0, (%rax)
je 0x5249
movq %rax, %r14
leaq 0xc7d4(%rip), %rdi      # 0x11965
xorl %eax, %eax
callq 0xdf55
andl $0x0, (%r14)
jmp 0x5257
leaq 0xc755(%rip), %rdi      # 0x118fd
xorl %eax, %eax
callq 0xe0e4
jmp 0x51c8
leaq 0xc75d(%rip), %rdi      # 0x11915
xorl %eax, %eax
callq 0xe0e4
movq 0x28(%rbx), %rdi
callq 0x9388
movq 0x30(%rbx), %rdi
callq 0xe7bc
jmp 0x4f2e
movq %rbx, %rdi
callq 0x5380
jmp 0x4f36
leaq 0xc743(%rip), %rdi      # 0x1192d
jmp 0x4ef7
movq 0x8(%rsi), %rax
movq 0x38(%rsi), %rcx
incq %rcx
xorl %edx, %edx
cmpq %rdx, %rcx
je 0x50a1
movq 0x48(%rsi), %rdi
movq (%rdi,%rdx,8), %rdi
movq 0x8(%rdi), %rdi
cmpq %rax, %rdi
jae 0x521d
movq %rdi, 0x8(%rsi)
movq %rdi, %rax
incq %rdx
jmp 0x51fc
leaq 0x10(%rsp), %rdi
callq 0x9e9b
testl %eax, %eax
je 0x5274
callq 0x20a0
cmpl $0x0, (%rax)
je 0x528d
movq %rax, %r14
leaq 0xc73c(%rip), %rdi      # 0x11980
jmp 0x4e11
leaq 0xc715(%rip), %rdi      # 0x11965
xorl %eax, %eax
callq 0xe0e4
movq 0x28(%rbx), %rsi
movq %rbx, %rdi
callq 0x5403
movq 0x28(%rbx), %rsi
movq %rbx, %rdi
callq 0x7921
jmp 0x51c8
cmpq $0x1, 0x10(%rbx)
je 0x50bc
xorps %xmm0, %xmm0
movsd %xmm0, 0x18(%rsp)
jmp 0x50bc
leaq 0xc6ec(%rip), %rdi      # 0x11980
jmp 0x4ef7
leaq 0xc525(%rip), %rdi      # 0x117c5
leaq 0xc55b(%rip), %rsi      # 0x11802
leaq 0xc55c(%rip), %rcx      # 0x1180a
movl $0xa3, %edx
callq 0x21c0
movq %rax, %rbx
leaq 0xc6d6(%rip), %rdi      # 0x11998
xorl %eax, %eax
callq 0xdf55
andl $0x0, (%rbx)
pushq $0x1
popq %rdi
callq 0x2370