// File: /workspace/github_c_makefile_star2_O3/sharpyfox[P]citrusleaf-client/src/cl_batch.c
// Function: do_get_exists_many_digest
static cl_rv
do_get_exists_many_digest(cl_cluster *asc, char *ns, const cf_digest *digests, int n_digests, cl_bin *bins, int n_bins, bool get_key, bool get_bin_data, citrusleaf_get_many_cb cb, void *udata)
{
	// TODO FAST PATH
	// fast path: if there's only one node, or the number of digests is super short, just dispatch to the server directly

	// Use lazy instantiation for batch threads.
	// The user can override the number of threads by calling citrusleaf_batch_init() directly
	// before making batch calls.
	if (cf_atomic32_get(batch_initialized) == 0) {
		citrusleaf_batch_init(MAX_BATCH_THREADS);
	}

	//
	// allocate the digest-node array, and populate it
	// 
	cl_cluster_node **nodes = malloc( sizeof(cl_cluster_node *)  * n_digests);
	if (!nodes) {
		cf_error("allocation failed");
		return(-1);
	}
	
	// loop through all digests and determine a node
	for (int i=0;i<n_digests;i++) {
		
		nodes[i] = cl_cluster_node_get(asc, ns, &digests[i], true/*write, but that's Ok*/);
		
		// not sure if this is required - it looks like cluster_node_get automatically calls random?
		// it's certainly safer though
		if (nodes[i] == 0) {
			cf_error("index %d: no specific node, getting random", i);
			pthread_mutex_lock(&asc->LOCK);
			nodes[i] = cl_cluster_node_get_random(asc);
			pthread_mutex_unlock(&asc->LOCK);
		}
		if (nodes[i] == 0) {
			cf_error("index %d: can't get any node", i);
			free(nodes);
			return(-1);
		}
			
	}

	// find unique set
	cl_cluster_node *unique_nodes[MAX_NODES];
	int				unique_nodes_count[MAX_NODES];
	int 			n_nodes = 0;
	for (int i=0;i<n_digests;i++) {
		// look to see if nodes[i] is in the unique list
		int j;
		for (j=0;j<n_nodes;j++) {
			if (unique_nodes[j] == nodes[i]) {
				unique_nodes_count[j]++;
				break;
			}
		}
		// not found, insert in nodes list
		if (j == n_nodes) {
			unique_nodes[n_nodes] = nodes[i];
			unique_nodes_count[n_nodes] = 1;
			n_nodes++;
		}
	}
	
	// 
	// Note:  The digest exists case does not retrieve bin data.
	//
	digest_work work;
	work.asc = asc;
	work.info1 = CL_MSG_INFO1_READ | (get_bin_data ? 0 : CL_MSG_INFO1_NOBINDATA);
	work.info2 = 0;
	work.ns = ns;
	work.digests = (cf_digest *) digests; // discarding const to make compiler happy
	work.nodes = nodes;
	work.n_digests = n_digests;
	work.get_key = get_key;
	work.bins = bins;
	work.operator = CL_OP_READ;
	work.operations = 0;
	work.n_ops = n_bins;
	work.cb = cb;
	work.udata = udata;
	
	work.complete_q = cf_queue_create(sizeof(int),true);
	//
	// dispatch work to the worker queue to allow the transactions in parallel
	//
	for (int i=0;i<n_nodes;i++) {
		
		// fill in per-request specifics
		work.my_node = unique_nodes[i];
		work.my_node_digest_count = unique_nodes_count[i];
		work.index = i;
		
		// dispatch - copies data
		cf_queue_push(g_batch_q, &work);
	}
	
	// wait for the work to complete
	int retval = 0;
	for (int i=0;i<n_nodes;i++) {
		int z;
		cf_queue_pop(work.complete_q, &z, CF_QUEUE_FOREVER);
		if (z != 0) {
			cf_error("Node %d retcode error: %d", i, z);
			retval = z;
		}
	}
	
	// free and return what needs freeing and putting
	cf_queue_destroy(work.complete_q);
	for (int i=0;i<n_digests;i++) {
		cl_cluster_node_put(nodes[i]);	
	}
	free(nodes);
	return retval;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x238, %rsp            # imm = 0x238
leaq 0xf3d2(%rip), %rax      # 0x18430
movq %rsi, 0x10(%rsp)
movq %rdi, 0x8(%rsp)
movl %r9d, %r14d
movq %r8, %r15
movl %ecx, %r12d
movq %rdx, %rbp
cmpl $0x0, (%rax)
jne 0x9083
movl $0x6, %edi
callq 0x9645
movslq %r12d, %rdi
shlq $0x3, %rdi
callq 0x22e0
testq %rax, %rax
je 0x91d2
movq %rax, %r13
testl %r12d, %r12d
movl %r12d, %ebx
movq %rax, 0x20(%rsp)
movl %r12d, (%rsp)
movq %rbp, 0x30(%rsp)
jle 0x9204
movq 0x8(%rsp), %rax
movl %r14d, 0x1c(%rsp)
movq 0x10(%rsp), %r14
movq %r15, 0x28(%rsp)
xorl %r15d, %r15d
leaq 0x158(%rax), %r12
movq 0x8(%rsp), %rdi
movq %r14, %rsi
movq %rbp, %rdx
movl $0x1, %ecx
callq 0x7daf
testq %rax, %rax
movq %rax, (%r13,%r15,8)
jne 0x914f
leaq 0xd1cf(%rip), %rax      # 0x162c8
cmpl $0x0, (%rax)
js 0x9118
leaq 0xd1cb(%rip), %rax      # 0x162d0
xorl %edi, %edi
leaq 0x6d7b(%rip), %rsi      # 0xfe89
movl %r15d, %edx
movq (%rax), %rcx
xorl %eax, %eax
callq *%rcx
movq %r12, %rdi
callq 0x23b0
movq 0x8(%rsp), %rdi
callq 0x7d2d
movq 0x20(%rsp), %r14
movq %r12, %rdi
movq %rax, %r13
movq %rax, (%r14,%r15,8)
callq 0x2190
testq %r13, %r13
movq %r14, %r13
movq 0x10(%rsp), %r14
je 0x93b2
incq %r15
addq $0x14, %rbp
cmpq %r15, %rbx
jne 0x90d3
movl (%rsp), %r12d
movl 0x1c(%rsp), %r14d
movq 0x28(%rsp), %r15
testl %r12d, %r12d
jle 0x9204
xorl %eax, %eax
xorl %ebp, %ebp
testl %ebp, %ebp
movl $0x0, %ecx
jle 0x91a7
movq (%r13,%rax,8), %rdx
movl %ebp, %esi
xorl %ecx, %ecx
cmpq %rdx, 0x130(%rsp,%rcx,8)
je 0x91a0
incq %rcx
cmpq %rcx, %rsi
jne 0x918c
jmp 0x91ab
incl 0xb0(%rsp,%rcx,4)
cmpl %ebp, %ecx
jne 0x91c8
movq (%r13,%rax,8), %rcx
movslq %ebp, %rdx
incl %ebp
movl $0x1, 0xb0(%rsp,%rdx,4)
movq %rcx, 0x130(%rsp,%rdx,8)
incq %rax
cmpq %rbx, %rax
jne 0x917a
jmp 0x9206
leaq 0xd0ef(%rip), %rax      # 0x162c8
movl $0xffffffff, %r14d      # imm = 0xFFFFFFFF
cmpl $0x0, (%rax)
js 0x939d
leaq 0xd0e1(%rip), %rax      # 0x162d0
leaq 0x6c81(%rip), %rsi      # 0xfe77
xorl %edi, %edi
movq (%rax), %rcx
xorl %eax, %eax
callq *%rcx
jmp 0x939d
xorl %ebp, %ebp
movb 0x278(%rsp), %dl
movq 0x8(%rsp), %rdi
movb 0x270(%rsp), %sil
movq 0x10(%rsp), %r8
movq 0x288(%rsp), %rax
movq 0x280(%rsp), %rcx
xorb $0x1, %dl
movq %rdi, 0x38(%rsp)
movq 0x30(%rsp), %rdi
movzbl %dl, %edx
shll $0x5, %edx
incl %edx
movl %edx, 0x40(%rsp)
movl $0x0, 0x44(%rsp)
movq %r8, 0x48(%rsp)
movq %rdi, 0x50(%rsp)
movq %r13, 0x58(%rsp)
movl %r12d, 0x60(%rsp)
movb %sil, 0x64(%rsp)
movl $0x4, %edi
movl $0x1, %esi
movq %r15, 0x68(%rsp)
movl $0x1, 0x70(%rsp)
movq $0x0, 0x78(%rsp)
movl %r14d, 0x80(%rsp)
movq %rcx, 0x88(%rsp)
movq %rax, 0x90(%rsp)
callq 0xc964
testl %ebp, %ebp
movq %rax, 0x98(%rsp)
jle 0x9366
movl %ebp, %r13d
xorl %r15d, %r15d
leaq 0x38(%rsp), %r14
movq 0x130(%rsp,%r15,8), %rax
movq 0xf168(%rip), %rdi      # 0x18438
movq %r14, %rsi
movq %rax, 0xa0(%rsp)
movl 0xb0(%rsp,%r15,4), %eax
movl %eax, 0xa8(%rsp)
movl %r15d, 0xac(%rsp)
callq 0xcb7c
incq %r15
cmpq %r15, %r13
jne 0x92c1
testl %r13d, %r13d
jle 0x9366
leaq 0xcfbd(%rip), %r12      # 0x162c8
leaq 0x4(%rsp), %r15
xorl %ebp, %ebp
xorl %r14d, %r14d
movq 0x98(%rsp), %rdi
movq %r15, %rsi
movl $0xffffffff, %edx       # imm = 0xFFFFFFFF
callq 0xccdc
movl 0x4(%rsp), %ecx
testl %ecx, %ecx
je 0x935d
cmpl $0x0, (%r12)
js 0x935a
leaq 0xcf90(%rip), %rax      # 0x162d0
xorl %edi, %edi
leaq 0x6b88(%rip), %rsi      # 0xfed1
movl %ebp, %edx
movq (%rax), %r8
xorl %eax, %eax
callq *%r8
movl 0x4(%rsp), %r14d
jmp 0x935d
movl %ecx, %r14d
incl %ebp
cmpl %ebp, %r13d
jne 0x9315
jmp 0x9369
xorl %r14d, %r14d
movq 0x98(%rsp), %rdi
callq 0xc9f6
cmpl $0x0, (%rsp)
movq 0x20(%rsp), %r12
jle 0x9395
movq %r12, %r15
movq (%r15), %rdi
callq 0x8227
addq $0x8, %r15
decq %rbx
jne 0x9384
movq %r12, %rdi
callq 0x22c0
movl %r14d, %eax
addq $0x238, %rsp            # imm = 0x238
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0xcf0f(%rip), %rax      # 0x162c8
cmpl $0x0, (%rax)
js 0x93d8
leaq 0xcf0b(%rip), %rax      # 0x162d0
leaq 0x6ae8(%rip), %rsi      # 0xfeb4
xorl %edi, %edi
movl %r15d, %edx
movq (%rax), %rcx
xorl %eax, %eax
callq *%rcx
movq %r13, %rdi
callq 0x22c0
movl $0xffffffff, %r14d      # imm = 0xFFFFFFFF
jmp 0x939d