// File: /workspace/github_c_makefile_star2_O2/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 0xeb46(%rip), %rax      # 0x17430
movq %rsi, 0x20(%rsp)
movq %rdi, 0x10(%rsp)
movl %r9d, %ebp
movq %r8, %r14
movl %ecx, %r15d
movq %rdx, %r13
cmpl $0x0, (%rax)
jne 0x890d
pushq $0x6
popq %rdi
callq 0x8e4e
movslq %r15d, %rdi
shlq $0x3, %rdi
callq 0x22e0
testq %rax, %rax
je 0x8ba1
movl %ebp, 0x1c(%rsp)
movq 0x10(%rsp), %rcx
testl %r15d, %r15d
movl $0x0, %ebp
movl %r15d, 0x18(%rsp)
movq %rax, %rbx
movq %r14, 0x30(%rsp)
movq %r13, 0x28(%rsp)
cmovgl %r15d, %ebp
movq 0x20(%rsp), %r15
xorl %r14d, %r14d
leaq 0x158(%rcx), %r12
cmpq %r14, %rbp
je 0x89d7
movq 0x10(%rsp), %rdi
movq %r15, %rsi
movq %r13, %rdx
pushq $0x1
popq %rcx
callq 0x7787
testq %rax, %rax
movq %rax, (%rbx,%r14,8)
jne 0x89ce
leaq 0xc948(%rip), %rax      # 0x152c8
cmpl $0x0, (%rax)
js 0x899f
leaq 0xc944(%rip), %rax      # 0x152d0
xorl %edi, %edi
leaq 0x6504(%rip), %rsi      # 0xee99
movl %r14d, %edx
movq (%rax), %rcx
xorl %eax, %eax
callq *%rcx
movq %r12, %rdi
callq 0x23b0
movq 0x10(%rsp), %rdi
callq 0x7711
movq %r12, %rdi
movq %rax, %r15
movq %rax, (%rbx,%r14,8)
callq 0x2190
testq %r15, %r15
movq 0x20(%rsp), %r15
je 0x8bca
incq %r14
addq $0x14, %r13
jmp 0x8958
movl 0x18(%rsp), %edi
movq 0x28(%rsp), %r8
xorl %eax, %eax
xorl %r12d, %r12d
cmpq %rbp, %rax
je 0x8a40
testl %r12d, %r12d
movl $0x0, %ecx
cmovgl %r12d, %ecx
xorl %edx, %edx
cmpq %rdx, %rcx
je 0x8a19
movq 0x130(%rsp,%rdx,8), %rsi
cmpq (%rbx,%rax,8), %rsi
je 0x8a10
incq %rdx
jmp 0x89f8
incl 0xb0(%rsp,%rdx,4)
movl %edx, %ecx
cmpl %r12d, %ecx
jne 0x8a3b
movq (%rbx,%rax,8), %rcx
movslq %r12d, %rdx
incl %r12d
movl $0x1, 0xb0(%rsp,%rdx,4)
movq %rcx, 0x130(%rsp,%rdx,8)
incq %rax
jmp 0x89e5
movq 0x10(%rsp), %rax
leaq 0x38(%rsp), %r14
movq 0x30(%rsp), %rcx
movl 0x1c(%rsp), %esi
movq 0x280(%rsp), %rdx
movq %rax, (%r14)
movb 0x278(%rsp), %al
xorb $0x1, %al
movzbl %al, %eax
shll $0x5, %eax
incl %eax
movl %eax, 0x8(%r14)
andl $0x0, 0xc(%r14)
movq %r15, 0x10(%r14)
movq %r8, 0x18(%r14)
movq %rbx, 0x20(%r14)
movl %edi, 0x28(%r14)
movb 0x270(%rsp), %dil
movb %dil, 0x2c(%r14)
movq %rcx, 0x30(%r14)
movq 0x288(%rsp), %rcx
movl $0x1, 0x38(%r14)
andq $0x0, 0x40(%r14)
movl %esi, 0x48(%r14)
movq %rdx, 0x50(%r14)
movq %rcx, 0x58(%r14)
pushq $0x4
popq %rdi
pushq $0x1
popq %rsi
callq 0xbe10
xorl %r15d, %r15d
testl %r12d, %r12d
movq %rax, 0x60(%r14)
cmovlel %r15d, %r12d
cmpq %r15, %r12
je 0x8b12
movq 0x130(%rsp,%r15,8), %rax
movq 0xe952(%rip), %rdi      # 0x17438
movq %r14, %rsi
movq %rax, 0xa0(%rsp)
movl 0xb0(%rsp,%r15,4), %eax
movl %eax, 0xa8(%rsp)
movl %r15d, 0xac(%rsp)
callq 0xc01b
incq %r15
jmp 0x8ad2
pushq $-0x1
popq %r14
xorl %r15d, %r15d
xorl %r13d, %r13d
cmpl %r13d, %r12d
je 0x8b74
movq 0x98(%rsp), %rdi
leaq 0xc(%rsp), %rsi
movl %r14d, %edx
callq 0xc163
movl 0xc(%rsp), %ecx
testl %ecx, %ecx
je 0x8b6f
leaq 0xc783(%rip), %rax      # 0x152c8
cmpl $0x0, (%rax)
js 0x8b6c
leaq 0xc77f(%rip), %rax      # 0x152d0
xorl %edi, %edi
leaq 0x6387(%rip), %rsi      # 0xeee1
movl %r13d, %edx
movq (%rax), %r8
xorl %eax, %eax
callq *%r8
movl 0xc(%rsp), %r15d
jmp 0x8b6f
movl %ecx, %r15d
incl %r13d
jmp 0x8b1c
movq 0x98(%rsp), %rdi
callq 0xbe9d
xorl %r14d, %r14d
cmpq %r14, %rbp
je 0x8b97
movq (%rbx,%r14,8), %rdi
callq 0x7b74
incq %r14
jmp 0x8b84
movq %rbx, %rdi
callq 0x22c0
jmp 0x8bfc
leaq 0xc720(%rip), %rax      # 0x152c8
pushq $-0x1
popq %r15
cmpl $0x0, (%rax)
js 0x8bfc
leaq 0xc718(%rip), %rax      # 0x152d0
leaq 0x62c8(%rip), %rsi      # 0xee87
xorl %edi, %edi
movq (%rax), %rcx
xorl %eax, %eax
callq *%rcx
jmp 0x8bfc
leaq 0xc6f7(%rip), %rax      # 0x152c8
cmpl $0x0, (%rax)
js 0x8bf0
leaq 0xc6f3(%rip), %rax      # 0x152d0
leaq 0x62e0(%rip), %rsi      # 0xeec4
xorl %edi, %edi
movl %r14d, %edx
movq (%rax), %rcx
xorl %eax, %eax
callq *%rcx
movq %rbx, %rdi
callq 0x22c0
pushq $-0x1
popq %r15
movl %r15d, %eax
addq $0x238, %rsp            # imm = 0x238
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq