// File: /workspace/github_c_makefile_star2_O1/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 $0x228, %rsp            # imm = 0x228
movl %r9d, %r15d
movq %r8, %r12
movl %ecx, %ebp
movq %rdx, 0x10(%rsp)
movq %rsi, 0x18(%rsp)
movq %rdi, %r14
leaq 0x10155(%rip), %rax     # 0x19430
cmpl $0x0, (%rax)
jne 0x92ea
movl $0x6, %edi
callq 0x987b
movslq %ebp, %rdi
shlq $0x3, %rdi
callq 0x22e0
testq %rax, %rax
je 0x9438
movq %rax, %rbx
movq %r12, 0x20(%rsp)
movl %r15d, 0x4(%rsp)
testl %ebp, %ebp
movl %ebp, 0x8(%rsp)
movl %ebp, %r13d
jle 0x93a1
leaq 0x158(%r14), %r12
movq 0x10(%rsp), %rbp
xorl %r15d, %r15d
movq %r14, %rdi
movq 0x18(%rsp), %rsi
movq %rbp, %rdx
movl $0x1, %ecx
callq 0x7f33
movq %rax, (%rbx,%r15,8)
testq %rax, %rax
jne 0x938a
leaq 0xdf79(%rip), %rax      # 0x172c8
cmpl $0x0, (%rax)
js 0x936e
leaq 0xdf75(%rip), %rax      # 0x172d0
movq (%rax), %rcx
xorl %edi, %edi
leaq 0x7b02(%rip), %rsi      # 0x10e69
movl %r15d, %edx
xorl %eax, %eax
callq *%rcx
movq %r12, %rdi
callq 0x23b0
movq %r14, %rdi
callq 0x7eb1
movq %rax, (%rbx,%r15,8)
movq %r12, %rdi
callq 0x2190
cmpq $0x0, (%rbx,%r15,8)
je 0x946a
incq %r15
addq $0x14, %rbp
cmpq %r15, %r13
jne 0x932a
movq 0x278(%rsp), %rax
movq 0x270(%rsp), %rcx
movb 0x268(%rsp), %sil
movb 0x260(%rsp), %dl
movl 0x8(%rsp), %r11d
testl %r11d, %r11d
jle 0x94a3
xorl %edi, %edi
xorl %r12d, %r12d
movl 0x4(%rsp), %ebp
testl %r12d, %r12d
movl $0x0, %r8d
jle 0x940b
movl %r12d, %r9d
movq (%rbx,%rdi,8), %r10
xorl %r8d, %r8d
cmpq %r10, 0x120(%rsp,%r8,8)
je 0x9403
incq %r8
cmpq %r8, %r9
jne 0x93ec
movl %r9d, %r8d
jmp 0x940b
incl 0xa0(%rsp,%r8,4)
cmpl %r12d, %r8d
jne 0x942e
movq (%rbx,%rdi,8), %r8
movslq %r12d, %r9
movq %r8, 0x120(%rsp,%r9,8)
movl $0x1, 0xa0(%rsp,%r9,4)
incl %r12d
incq %rdi
cmpq %r13, %rdi
jne 0x93d7
jmp 0x94aa
leaq 0xde89(%rip), %rax      # 0x172c8
movl $0xffffffff, %r14d      # imm = 0xFFFFFFFF
cmpl $0x0, (%rax)
js 0x960b
leaq 0xde7b(%rip), %rax      # 0x172d0
movq (%rax), %rcx
leaq 0x79f8(%rip), %rsi      # 0x10e57
xorl %edi, %edi
xorl %eax, %eax
callq *%rcx
jmp 0x960b
leaq 0xde57(%rip), %rax      # 0x172c8
cmpl $0x0, (%rax)
js 0x9490
leaq 0xde53(%rip), %rax      # 0x172d0
movq (%rax), %rcx
leaq 0x7a0d(%rip), %rsi      # 0x10e94
xorl %edi, %edi
movl %r15d, %edx
xorl %eax, %eax
callq *%rcx
movq %rbx, %rdi
callq 0x22c0
movl $0xffffffff, %r14d      # imm = 0xFFFFFFFF
jmp 0x960b
xorl %r12d, %r12d
movl 0x4(%rsp), %ebp
movq %r14, 0x28(%rsp)
xorb $0x1, %sil
movzbl %sil, %esi
shll $0x5, %esi
incl %esi
movl %esi, 0x30(%rsp)
movl $0x0, 0x34(%rsp)
movq 0x18(%rsp), %rsi
movq %rsi, 0x38(%rsp)
movq 0x10(%rsp), %rsi
movq %rsi, 0x40(%rsp)
movq %rbx, 0x48(%rsp)
movl %r11d, 0x50(%rsp)
movb %dl, 0x54(%rsp)
movq 0x20(%rsp), %rdx
movq %rdx, 0x58(%rsp)
movl $0x1, 0x60(%rsp)
movq $0x0, 0x68(%rsp)
movl %ebp, 0x70(%rsp)
movq %rcx, 0x78(%rsp)
movq %rax, 0x80(%rsp)
movl $0x4, %edi
movl $0x1, %esi
callq 0xcd6c
movq %rax, 0x88(%rsp)
testl %r12d, %r12d
jle 0x9578
movl %r12d, %r15d
xorl %ebp, %ebp
leaq 0x28(%rsp), %r14
movq 0x120(%rsp,%rbp,8), %rax
movq %rax, 0x90(%rsp)
movl 0xa0(%rsp,%rbp,4), %eax
movl %eax, 0x98(%rsp)
movl %ebp, 0x9c(%rsp)
movq 0xfed0(%rip), %rdi      # 0x19438
movq %r14, %rsi
callq 0xcf8b
incq %rbp
cmpq %rbp, %r15
jne 0x953c
testl %r12d, %r12d
jle 0x95d8
leaq 0xc(%rsp), %r15
xorl %ebp, %ebp
xorl %r14d, %r14d
movq 0x88(%rsp), %rdi
movq %r15, %rsi
movl $0xffffffff, %edx       # imm = 0xFFFFFFFF
callq 0xd0df
movl 0xc(%rsp), %ecx
testl %ecx, %ecx
je 0x95cf
leaq 0xdd1d(%rip), %rax      # 0x172c8
cmpl $0x0, (%rax)
js 0x95ca
leaq 0xdd19(%rip), %rax      # 0x172d0
movq (%rax), %r8
xorl %edi, %edi
leaq 0x78ee(%rip), %rsi      # 0x10eb1
movl %ebp, %edx
xorl %eax, %eax
callq *%r8
movl 0xc(%rsp), %r14d
incl %ebp
cmpl %ebp, %r12d
jne 0x9587
jmp 0x95db
xorl %r14d, %r14d
movq 0x88(%rsp), %rdi
callq 0xcdfe
cmpl $0x0, 0x8(%rsp)
jle 0x9603
movq %rbx, %r15
movq (%r15), %rdi
callq 0x8426
addq $0x8, %r15
decq %r13
jne 0x95f2
movq %rbx, %rdi
callq 0x22c0
movl %r14d, %eax
addq $0x228, %rsp            # imm = 0x228
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq