// File: /workspace/github_c_makefile_star2_O3/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 0x5ff8
movq %r8, %r12
movq %rdx, %r13
movq %rsi, %r14
movq %rdi, %rbp
movl $0x58, %edi
callq 0x22a0
testq %rax, %rax
je 0x5c5e
movq %rax, %rbx
movq %rbp, 0x18(%rax)
leaq 0x20(%rsp), %rdx
movq %rax, (%rdx)
movq $0x0, 0x10(%rdx)
leaq 0x55e(%rip), %rsi       # 0x6038
movq %rbp, %rdi
callq 0x110c7
testl %eax, %eax
je 0x5afc
callq 0x20a0
cmpl $0x0, (%rax)
je 0x5b39
movq %rax, %r14
leaq 0xed61(%rip), %rdi      # 0x1485b
jmp 0x5b26
leaq 0x34(%rsp), %rbp
movq %rbp, %rdi
callq 0xb761
orl -0x4(%rbp), %eax
je 0x5b45
callq 0x20a0
cmpl $0x0, (%rax)
je 0x5c14
movq %rax, %r14
leaq 0xed54(%rip), %rdi      # 0x1487a
xorl %eax, %eax
callq 0xffd0
movl $0x0, (%r14)
jmp 0x5c56
leaq 0xed1b(%rip), %rdi      # 0x1485b
jmp 0x5c1b
movq %r13, %rax
andq %r14, %rax
cmpq $-0x1, %rax
movl $0x8000000, %eax        # imm = 0x8000000
cmovneq %r13, %rax
movq (%rbx), %rcx
cmpq $-0x1, %rax
je 0x5b83
xorl %edx, %edx
divq %rcx
movq %rax, %r14
addq $-0x40000001, %rax      # imm = 0xBFFFFFFF
cmpq $-0x3ffffc02, %rax      # imm = 0xC00003FE
ja 0x5b83
leaq 0xe56d(%rip), %rdi      # 0x140eb
jmp 0x5c44
movq %r14, 0x8(%rbx)
cmpq $-0x1, (%r15)
jne 0x5bb5
cmpq $0x800, %rcx            # imm = 0x800
movl $0x80, %eax
movl $0xff, %edx
cmovbq %rax, %rdx
cmpq $0x400, %rcx            # imm = 0x400
movl $0x40, %eax
cmovaeq %rdx, %rax
movq %rax, (%r15)
movq (%r12), %rdi
cmpq $-0x1, %rdi
jne 0x5be8
cmpq $0x800, %rcx            # imm = 0x800
movl $0xc0, %eax
movl $0xff, %edx
cmovbq %rax, %rdx
cmpq $0x400, %rcx            # imm = 0x400
movl $0x60, %edi
cmovaeq %rdx, %rdi
movq %rdi, (%r12)
movq (%r15), %rsi
movabsq $-0x5555555555555555, %r8 # imm = 0xAAAAAAAAAAAAAAAB
movq %rcx, %rax
mulq %r8
leaq (%rsi,%rdi), %rax
addq $0x2, %rax
shrq %rdx
cmpq %rdx, %rax
jbe 0x5c24
leaq 0xec83(%rip), %rdi      # 0x14895
jmp 0x5c44
leaq 0xec5f(%rip), %rdi      # 0x1487a
xorl %eax, %eax
callq 0x100ef
jmp 0x5c56
addq %rcx, %rcx
movq %rcx, %rax
mulq %r8
leaq (%rsi,%rsi,2), %rax
addq $0x5d, %rax
shrq %rdx
cmpq %rdx, %rax
jbe 0x5c72
leaq 0xec7e(%rip), %rdi      # 0x148c2
xorl %eax, %eax
callq 0x100ef
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 0x1065c
movq %rax, 0x30(%rbx)
testq %rax, %rax
je 0x5c56
xorps %xmm0, %xmm0
movups %xmm0, 0x20(%rbx)
movq 0x28(%rsp), %r14
movq 0x10(%rbx), %rax
cmpq %rax, %r14
jae 0x5d34
leaq 0x3ab(%rip), %r15       # 0x6053
leaq 0x14(%rsp), %r12
movq %r14, %rdi
movq $-0x1, %rsi
movl $0xffffffff, %edx       # imm = 0xFFFFFFFF
callq 0xab58
movq %rax, 0x28(%rbx)
testq %rax, %rax
je 0x5de8
movq %rax, 0x20(%rbx)
movl $0x0, 0x14(%rsp)
movq %rbx, %rdi
movq %rax, %rsi
movq %r15, %rdx
movq %r12, %rcx
callq 0x8d57
testl %eax, %eax
jne 0x5e13
movq %r12, %rdi
callq 0xb761
testl %eax, %eax
jne 0x5e3e
movq 0x28(%rbx), %rsi
movb 0x1c(%rsi), %al
andb $0x12, %al
cmpb $0x10, %al
je 0x5e5b
movq %rbx, %rdi
callq 0x8d62
movq $0x0, 0x28(%rbx)
decq %r14
movq 0x10(%rbx), %rax
cmpq %rax, %r14
jb 0x5cad
testq %rax, %rax
je 0x5d57
leaq 0xebed(%rip), %rdi      # 0x1492d
xorl %eax, %eax
callq 0x100ef
callq 0x20a0
movl $0x0, (%rax)
jmp 0x5fc5
movq $0x0, (%rsp)
movq %rbx, %rdi
movl $0x1, %esi
xorl %edx, %edx
xorl %ecx, %ecx
xorl %r8d, %r8d
xorl %r9d, %r9d
callq 0x8a48
movq %rax, 0x28(%rbx)
testq %rax, %rax
je 0x5fc5
orb $0x10, 0x1c(%rax)
movq 0x28(%rbx), %rsi
movq %rbx, %rdi
callq 0x605c
movq $0x1, 0x48(%rbx)
leaq 0x10(%rsp), %rdx
movl $0x0, (%rdx)
leaq 0x2d4(%rip), %rsi       # 0x6081
movq %rbx, %rdi
callq 0x7868
testl %eax, %eax
je 0x5e7c
callq 0x20a0
cmpl $0x0, (%rax)
je 0x5f9f
movq %rax, %r14
leaq 0xeb78(%rip), %rdi      # 0x1494d
xorl %eax, %eax
callq 0xffd0
movl $0x0, (%r14)
jmp 0x5fad
callq 0x20a0
cmpl $0x0, (%rax)
je 0x5eab
movq %rax, %r14
leaq 0xeae5(%rip), %rdi      # 0x148e5
xorl %eax, %eax
callq 0xffd0
movl $0x0, (%r14)
jmp 0x5fc5
callq 0x20a0
cmpl $0x0, (%rax)
je 0x5ebe
movq %rax, %r14
leaq 0xead2(%rip), %rdi      # 0x148fd
xorl %eax, %eax
callq 0xffd0
movl $0x0, (%r14)
jmp 0x5ecc
callq 0x20a0
cmpl $0x0, (%rax)
je 0x5eda
movq %rax, %r14
leaq 0xeabf(%rip), %rdi      # 0x14915
jmp 0x5b26
movq %rsi, %rdi
callq 0xa5e7
movq 0x28(%rbx), %rsi
movl %eax, 0x18(%rsi)
testb $0x3, 0x1c(%rsi)
je 0x5ee6
movq (%rsi), %rax
movq %rax, 0x8(%rsi)
jmp 0x5f1c
leaq 0x10(%rsp), %rdi
callq 0xb761
testl %eax, %eax
je 0x5fd3
callq 0x20a0
cmpl $0x0, (%rax)
je 0x5fec
movq %rax, %r14
leaq 0xeac2(%rip), %rdi      # 0x14968
jmp 0x5b26
leaq 0xea33(%rip), %rdi      # 0x148e5
xorl %eax, %eax
callq 0x100ef
jmp 0x5fc5
leaq 0xea38(%rip), %rdi      # 0x148fd
xorl %eax, %eax
callq 0x100ef
movq 0x28(%rbx), %rdi
callq 0xab9b
jmp 0x5fc5
leaq 0xea34(%rip), %rdi      # 0x14915
jmp 0x5c1b
movq 0x8(%rsi), %rax
movq 0x38(%rsi), %rcx
leaq 0x1(%rcx), %rdx
cmpq $0x1, %rdx
adcq $0x1, %rcx
movq 0x48(%rsi), %rdx
xorl %edi, %edi
movq (%rdx,%rdi,8), %r8
movq 0x8(%r8), %r8
cmpq %rax, %r8
jae 0x5f14
movq %r8, 0x8(%rsi)
movq %r8, %rax
incq %rdi
cmpq %rdi, %rcx
jne 0x5f00
movq %rax, 0x10(%rsi)
movq 0x10(%rbx), %rcx
subq %rax, %rcx
movq %rcx, 0x50(%rbx)
movq %rsi, 0x20(%rbx)
movq %rbx, %rdi
callq 0x605c
leaq 0x14c(%rip), %rdi       # 0x608a
leaq 0xeabb(%rip), %rdx      # 0x14a00
movq %rbx, %rsi
callq 0xc618
movq %rax, 0x38(%rbx)
testq %rax, %rax
je 0x5f92
movq %rbx, %rdi
movsd 0x18(%rsp), %xmm0
callq 0x6ea0
movq %rax, 0x40(%rbx)
testq %rax, %rax
jne 0x5c60
callq 0x20a0
cmpl $0x0, (%rax)
jne 0x6017
leaq 0xe9fa(%rip), %rdi      # 0x14980
xorl %eax, %eax
callq 0x100ef
jmp 0x602e
movq %rbx, %rdi
callq 0x60e9
jmp 0x5c5e
leaq 0xe9a7(%rip), %rdi      # 0x1494d
xorl %eax, %eax
callq 0x100ef
movq 0x28(%rbx), %rsi
movq %rbx, %rdi
callq 0x61cb
movq 0x28(%rbx), %rsi
movq %rbx, %rdi
callq 0x8d62
movq 0x30(%rbx), %rdi
callq 0x107b8
jmp 0x5c56
cmpq $0x1, 0x10(%rbx)
je 0x5f37
xorps %xmm0, %xmm0
movsd %xmm0, 0x18(%rsp)
jmp 0x5f37
leaq 0xe975(%rip), %rdi      # 0x14968
jmp 0x5c1b
leaq 0xe7ae(%rip), %rdi      # 0x147ad
leaq 0xe7e4(%rip), %rsi      # 0x147ea
leaq 0xe7e5(%rip), %rcx      # 0x147f2
movl $0xa3, %edx
callq 0x21c0
movq %rax, %rbx
leaq 0xe95f(%rip), %rdi      # 0x14980
xorl %eax, %eax
callq 0xffd0
movl $0x0, (%rbx)
movl $0x1, %edi
callq 0x2370