// File: /workspace/github_c_makefile_star2_O1/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, %r12
cmpq $-0x1, %rsi
sete %al
cmpq $-0x1, %rdx
sete %cl
orb %al, %cl
je 0x5fe5
movq %r8, %r15
movq %rdx, %r13
movq %rsi, %r14
movq %rdi, %rbp
movl $0x58, %edi
callq 0x22a0
testq %rax, %rax
je 0x5c65
movq %rax, %rbx
movq %rbp, 0x18(%rax)
leaq 0x20(%rsp), %rdx
movq %rax, (%rdx)
movq $0x0, 0x10(%rdx)
leaq 0x547(%rip), %rsi       # 0x6025
movq %rbp, %rdi
callq 0x1111b
testl %eax, %eax
je 0x5b00
callq 0x20a0
cmpl $0x0, (%rax)
je 0x5b3d
movq %rax, %r14
leaq 0xed8d(%rip), %rdi      # 0x1488b
jmp 0x5b2a
leaq 0x34(%rsp), %rbp
movq %rbp, %rdi
callq 0xb8b5
orl -0x4(%rbp), %eax
je 0x5b49
callq 0x20a0
cmpl $0x0, (%rax)
je 0x5c1b
movq %rax, %r14
leaq 0xed80(%rip), %rdi      # 0x148aa
xorl %eax, %eax
callq 0x10048
movl $0x0, (%r14)
jmp 0x5c5d
leaq 0xed47(%rip), %rdi      # 0x1488b
jmp 0x5c22
movq %r13, %rax
andq %r14, %rax
cmpq $-0x1, %rax
movl $0x8000000, %eax        # imm = 0x8000000
cmovneq %r13, %rax
cmpq $-0x1, %rax
je 0x5b84
xorl %edx, %edx
divq (%rbx)
movq %rax, %r14
addq $-0x40000001, %rax      # imm = 0xBFFFFFFF
cmpq $-0x3ffffc02, %rax      # imm = 0xC00003FE
ja 0x5b84
leaq 0xe56c(%rip), %rdi      # 0x140eb
jmp 0x5c4b
movq %r14, 0x8(%rbx)
cmpq $-0x1, (%r12)
jne 0x5bb9
movq (%rbx), %rax
cmpq $0x800, %rax            # imm = 0x800
movl $0x80, %ecx
movl $0xff, %edx
cmovbq %rcx, %rdx
cmpq $0x400, %rax            # imm = 0x400
movl $0x40, %eax
cmovaeq %rdx, %rax
movq %rax, (%r12)
cmpq $-0x1, (%r15)
jne 0x5be8
movq (%rbx), %rax
cmpq $0x800, %rax            # imm = 0x800
movl $0xc0, %ecx
movl $0xff, %edx
cmovbq %rcx, %rdx
cmpq $0x400, %rax            # imm = 0x400
movl $0x60, %eax
cmovaeq %rdx, %rax
movq %rax, (%r15)
movq (%r12), %rsi
movq (%r15), %r8
movq (%rbx), %rcx
movabsq $-0x5555555555555555, %rdi # imm = 0xAAAAAAAAAAAAAAAB
movq %rcx, %rax
mulq %rdi
leaq (%rsi,%r8), %rax
addq $0x2, %rax
shrq %rdx
cmpq %rdx, %rax
jbe 0x5c2b
leaq 0xecac(%rip), %rdi      # 0x148c5
jmp 0x5c4b
leaq 0xec88(%rip), %rdi      # 0x148aa
xorl %eax, %eax
callq 0x10167
jmp 0x5c5d
addq %rcx, %rcx
movq %rcx, %rax
mulq %rdi
leaq (%rsi,%rsi,2), %rax
addq $0x5d, %rax
shrq %rdx
cmpq %rdx, %rax
jbe 0x5c79
leaq 0xeca7(%rip), %rdi      # 0x148f2
xorl %eax, %eax
callq 0x10167
callq 0x20a0
movl $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
movl $0x30, %esi
movq %r14, %rdi
callq 0x106ec
movq %rax, 0x30(%rbx)
testq %rax, %rax
je 0x5c5d
xorps %xmm0, %xmm0
movups %xmm0, 0x20(%rbx)
movq 0x28(%rsp), %r14
cmpq 0x10(%rbx), %r14
jae 0x5d2d
leaq 0x394(%rip), %r15       # 0x6040
leaq 0x14(%rsp), %r12
movq %r14, %rdi
movq $-0x1, %rsi
movl $0xffffffff, %edx       # imm = 0xFFFFFFFF
callq 0xac7c
movq %rax, 0x28(%rbx)
testq %rax, %rax
je 0x5e37
movq %rax, 0x20(%rbx)
movl $0x0, 0x14(%rsp)
movq %rbx, %rdi
movq %rax, %rsi
movq %r15, %rdx
movq %r12, %rcx
callq 0x8dde
testl %eax, %eax
jne 0x5e62
movq %r12, %rdi
callq 0xb8b5
testl %eax, %eax
jne 0x5e8d
movq 0x28(%rbx), %rsi
movb 0x1c(%rsi), %al
andb $0x12, %al
cmpb $0x10, %al
je 0x5d2d
movq %rbx, %rdi
callq 0x8de9
movq $0x0, 0x28(%rbx)
decq %r14
cmpq 0x10(%rbx), %r14
jb 0x5cb1
movq 0x28(%rbx), %rdi
testq %rdi, %rdi
je 0x5d51
callq 0xa703
movq 0x28(%rbx), %rsi
movl %eax, 0x18(%rsi)
testb $0x3, 0x1c(%rsi)
je 0x5d7a
movq (%rsi), %rax
movq %rax, 0x8(%rsi)
jmp 0x5db0
cmpq $0x0, 0x10(%rbx)
je 0x5eaa
leaq 0xebfa(%rip), %rdi      # 0x1495d
xorl %eax, %eax
callq 0x10167
callq 0x20a0
movl $0x0, (%rax)
jmp 0x5fb2
movq 0x8(%rsi), %rcx
movq 0x38(%rsi), %rax
leaq 0x1(%rax), %rdx
cmpq $0x1, %rdx
adcq $0x1, %rax
xorl %edx, %edx
movq 0x48(%rsi), %rdi
movq (%rdi,%rdx,8), %rdi
movq 0x8(%rdi), %rdi
cmpq %rcx, %rdi
jae 0x5da8
movq %rdi, 0x8(%rsi)
movq %rdi, %rcx
incq %rdx
cmpq %rdx, %rax
jne 0x5d90
movq 0x8(%rsi), %rax
movq %rax, 0x10(%rsi)
movq 0x10(%rbx), %rcx
subq %rax, %rcx
movq %rcx, 0x50(%rbx)
movq %rsi, 0x20(%rbx)
movq %rbx, %rdi
callq 0x6049
leaq 0x2a1(%rip), %rdi       # 0x6077
leaq 0xec53(%rip), %rdx      # 0x14a30
movq %rbx, %rsi
callq 0xc738
movq %rax, 0x38(%rbx)
testq %rax, %rax
je 0x5e2a
movq %rbx, %rdi
movsd 0x18(%rsp), %xmm0
callq 0x6ef4
movq %rax, 0x40(%rbx)
testq %rax, %rax
jne 0x5c67
callq 0x20a0
cmpl $0x0, (%rax)
jne 0x6004
leaq 0xeb92(%rip), %rdi      # 0x149b0
xorl %eax, %eax
callq 0x10167
jmp 0x601b
movq %rbx, %rdi
callq 0x60d6
jmp 0x5c65
callq 0x20a0
cmpl $0x0, (%rax)
je 0x5f30
movq %rax, %r14
leaq 0xeac6(%rip), %rdi      # 0x14915
xorl %eax, %eax
callq 0x10048
movl $0x0, (%r14)
jmp 0x5fb2
callq 0x20a0
cmpl $0x0, (%rax)
je 0x5f40
movq %rax, %r14
leaq 0xeab3(%rip), %rdi      # 0x1492d
xorl %eax, %eax
callq 0x10048
movl $0x0, (%r14)
jmp 0x5f4e
callq 0x20a0
cmpl $0x0, (%rax)
je 0x5f59
movq %rax, %r14
leaq 0xeaa0(%rip), %rdi      # 0x14945
jmp 0x5b2a
movq $0x0, (%rsp)
movq %rbx, %rdi
movl $0x1, %esi
xorl %edx, %edx
xorl %ecx, %ecx
xorl %r8d, %r8d
xorl %r9d, %r9d
callq 0x8ac8
movq %rax, 0x28(%rbx)
testq %rax, %rax
je 0x5fb2
orb $0x10, 0x1c(%rax)
movq 0x28(%rbx), %rsi
movq %rbx, %rdi
callq 0x6049
movq $0x1, 0x48(%rbx)
leaq 0x10(%rsp), %rdx
movl $0x0, (%rdx)
leaq 0x16e(%rip), %rsi       # 0x606e
movq %rbx, %rdi
callq 0x78c0
testl %eax, %eax
je 0x5f65
callq 0x20a0
cmpl $0x0, (%rax)
je 0x5f8c
movq %rax, %r14
leaq 0xea5d(%rip), %rdi      # 0x1497d
xorl %eax, %eax
callq 0x10048
movl $0x0, (%r14)
jmp 0x5f9a
leaq 0xe9de(%rip), %rdi      # 0x14915
xorl %eax, %eax
callq 0x10167
jmp 0x5fb2
leaq 0xe9e6(%rip), %rdi      # 0x1492d
xorl %eax, %eax
callq 0x10167
movq 0x28(%rbx), %rdi
callq 0xace6
jmp 0x5fb2
leaq 0xe9e5(%rip), %rdi      # 0x14945
jmp 0x5c22
leaq 0x10(%rsp), %rdi
callq 0xb8b5
testl %eax, %eax
je 0x5fc0
callq 0x20a0
cmpl $0x0, (%rax)
je 0x5fd9
movq %rax, %r14
leaq 0xea11(%rip), %rdi      # 0x14998
jmp 0x5b2a
leaq 0xe9ea(%rip), %rdi      # 0x1497d
xorl %eax, %eax
callq 0x10167
movq 0x28(%rbx), %rsi
movq %rbx, %rdi
callq 0x61b8
movq 0x28(%rbx), %rsi
movq %rbx, %rdi
callq 0x8de9
movq 0x30(%rbx), %rdi
callq 0x10853
jmp 0x5c5d
cmpq $0x1, 0x10(%rbx)
je 0x5dcf
xorps %xmm0, %xmm0
movsd %xmm0, 0x18(%rsp)
jmp 0x5dcf
leaq 0xe9b8(%rip), %rdi      # 0x14998
jmp 0x5c22
leaq 0xe7f1(%rip), %rdi      # 0x147dd
leaq 0xe827(%rip), %rsi      # 0x1481a
leaq 0xe828(%rip), %rcx      # 0x14822
movl $0xa3, %edx
callq 0x21c0
movq %rax, %rbx
leaq 0xe9a2(%rip), %rdi      # 0x149b0
xorl %eax, %eax
callq 0x10048
movl $0x0, (%rbx)
movl $0x1, %edi
callq 0x2370