// File: /workspace/github_c_makefile_star2_O0/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:
subq $0x288, %rsp            # imm = 0x288
movl %ecx, 0xc(%rsp)
movq %rdx, %rax
movl 0xc(%rsp), %edx
movq %rax, 0x10(%rsp)
movq %rsi, %rax
movq 0x10(%rsp), %rsi
movq %rax, 0x18(%rsp)
movq %rdi, %r10
movq 0x18(%rsp), %rdi
movq 0x2a8(%rsp), %rax
movq 0x2a0(%rsp), %rax
movb 0x298(%rsp), %al
movb 0x290(%rsp), %cl
movq %r10, 0x278(%rsp)
movq %rdi, 0x270(%rsp)
movq %rsi, 0x268(%rsp)
movl %edx, 0x264(%rsp)
movq %r8, 0x258(%rsp)
movl %r9d, 0x254(%rsp)
andb $0x1, %cl
movb %cl, 0x253(%rsp)
andb $0x1, %al
movb %al, 0x252(%rsp)
leaq 0x127bd(%rip), %rax     # 0x20440
movl (%rax), %eax
cmpl $0x0, %eax
jne 0xdc94
movl $0x6, %edi
callq 0xe560
movslq 0x264(%rsp), %rdi
shlq $0x3, %rdi
callq 0x2310
movq %rax, 0x248(%rsp)
cmpq $0x0, 0x248(%rsp)
jne 0xdcee
leaq 0x10619(%rip), %rax     # 0x1e2d8
movl (%rax), %ecx
xorl %eax, %eax
cmpl %ecx, %eax
jg 0xdcde
leaq 0x10612(%rip), %rax     # 0x1e2e0
movq (%rax), %rcx
xorl %edi, %edi
leaq 0xb1d1(%rip), %rsi      # 0x18eab
movb $0x0, %al
callq *%rcx
movl $0xffffffff, 0x284(%rsp) # imm = 0xFFFFFFFF
jmp 0xe17f
movl $0x0, 0x244(%rsp)
movl 0x244(%rsp), %eax
cmpl 0x264(%rsp), %eax
jge 0xde5e
movq 0x278(%rsp), %rdi
movq 0x270(%rsp), %rsi
movq 0x268(%rsp), %rdx
movslq 0x244(%rsp), %rax
imulq $0x14, %rax, %rax
addq %rax, %rdx
movl $0x1, %ecx
callq 0xb760
movq %rax, %rdx
movq 0x248(%rsp), %rax
movslq 0x244(%rsp), %rcx
movq %rdx, (%rax,%rcx,8)
movq 0x248(%rsp), %rax
movslq 0x244(%rsp), %rcx
cmpq $0x0, (%rax,%rcx,8)
jne 0xdde5
leaq 0x10565(%rip), %rax     # 0x1e2d8
movl (%rax), %ecx
xorl %eax, %eax
cmpl %ecx, %eax
jg 0xdd99
leaq 0x1055e(%rip), %rax     # 0x1e2e0
movq (%rax), %rcx
movl 0x244(%rsp), %edx
xorl %edi, %edi
leaq 0xb128(%rip), %rsi      # 0x18ebd
movb $0x0, %al
callq *%rcx
movq 0x278(%rsp), %rdi
addq $0x158, %rdi            # imm = 0x158
callq 0x23e0
movq 0x278(%rsp), %rdi
callq 0xb660
movq %rax, %rdx
movq 0x248(%rsp), %rax
movslq 0x244(%rsp), %rcx
movq %rdx, (%rax,%rcx,8)
movq 0x278(%rsp), %rdi
addq $0x158, %rdi            # imm = 0x158
callq 0x21c0
movq 0x248(%rsp), %rax
movslq 0x244(%rsp), %rcx
cmpq $0x0, (%rax,%rcx,8)
jne 0xde46
leaq 0x104d5(%rip), %rax     # 0x1e2d8
movl (%rax), %ecx
xorl %eax, %eax
cmpl %ecx, %eax
jg 0xde29
leaq 0x104ce(%rip), %rax     # 0x1e2e0
movq (%rax), %rcx
movl 0x244(%rsp), %edx
xorl %edi, %edi
leaq 0xb0c3(%rip), %rsi      # 0x18ee8
movb $0x0, %al
callq *%rcx
movq 0x248(%rsp), %rdi
callq 0x22e0
movl $0xffffffff, 0x284(%rsp) # imm = 0xFFFFFFFF
jmp 0xe17f
jmp 0xde48
movl 0x244(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x244(%rsp)
jmp 0xdcf9
movl $0x0, 0xbc(%rsp)
movl $0x0, 0xb8(%rsp)
movl 0xb8(%rsp), %eax
cmpl 0x264(%rsp), %eax
jge 0xdf69
movl $0x0, 0xb4(%rsp)
movl 0xb4(%rsp), %eax
cmpl 0xbc(%rsp), %eax
jge 0xdef9
movslq 0xb4(%rsp), %rax
movq 0x140(%rsp,%rax,8), %rax
movq 0x248(%rsp), %rcx
movslq 0xb8(%rsp), %rdx
cmpq (%rcx,%rdx,8), %rax
jne 0xdee4
movslq 0xb4(%rsp), %rax
movl 0xc0(%rsp,%rax,4), %ecx
addl $0x1, %ecx
movl %ecx, 0xc0(%rsp,%rax,4)
jmp 0xdef9
jmp 0xdee6
movl 0xb4(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xb4(%rsp)
jmp 0xde93
movl 0xb4(%rsp), %eax
cmpl 0xbc(%rsp), %eax
jne 0xdf51
movq 0x248(%rsp), %rax
movslq 0xb8(%rsp), %rcx
movq (%rax,%rcx,8), %rcx
movslq 0xbc(%rsp), %rax
movq %rcx, 0x140(%rsp,%rax,8)
movslq 0xbc(%rsp), %rax
movl $0x1, 0xc0(%rsp,%rax,4)
movl 0xbc(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xbc(%rsp)
jmp 0xdf53
movl 0xb8(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xb8(%rsp)
jmp 0xde74
movq 0x278(%rsp), %rax
movq %rax, 0x38(%rsp)
movb 0x252(%rsp), %dl
movl $0x20, %eax
xorl %ecx, %ecx
testb $0x1, %dl
cmovnel %ecx, %eax
orl $0x1, %eax
movl %eax, 0x40(%rsp)
movl $0x0, 0x44(%rsp)
movq 0x270(%rsp), %rax
movq %rax, 0x48(%rsp)
movq 0x268(%rsp), %rax
movq %rax, 0x50(%rsp)
movq 0x248(%rsp), %rax
movq %rax, 0x58(%rsp)
movl 0x264(%rsp), %eax
movl %eax, 0x60(%rsp)
movb 0x253(%rsp), %al
andb $0x1, %al
movb %al, 0x64(%rsp)
movq 0x258(%rsp), %rax
movq %rax, 0x68(%rsp)
movl $0x1, 0x70(%rsp)
movq $0x0, 0x78(%rsp)
movl 0x254(%rsp), %eax
movl %eax, 0x80(%rsp)
movq 0x2a0(%rsp), %rax
movq %rax, 0x88(%rsp)
movq 0x2a8(%rsp), %rax
movq %rax, 0x90(%rsp)
movl $0x4, %edi
movl $0x1, %esi
callq 0x13e70
movq %rax, 0x98(%rsp)
movl $0x0, 0x34(%rsp)
movl 0x34(%rsp), %eax
cmpl 0xbc(%rsp), %eax
jge 0xe0a1
movslq 0x34(%rsp), %rax
movq 0x140(%rsp,%rax,8), %rax
movq %rax, 0xa0(%rsp)
movslq 0x34(%rsp), %rax
movl 0xc0(%rsp,%rax,4), %eax
movl %eax, 0xa8(%rsp)
movl 0x34(%rsp), %eax
movl %eax, 0xac(%rsp)
movq 0x123be(%rip), %rdi     # 0x20448
leaq 0x38(%rsp), %rsi
callq 0x14300
movl 0x34(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x34(%rsp)
jmp 0xe043
movl $0x0, 0x30(%rsp)
movl $0x0, 0x2c(%rsp)
movl 0x2c(%rsp), %eax
cmpl 0xbc(%rsp), %eax
jge 0xe122
movq 0x98(%rsp), %rdi
leaq 0x28(%rsp), %rsi
movl $0xffffffff, %edx       # imm = 0xFFFFFFFF
callq 0x14590
cmpl $0x0, 0x28(%rsp)
je 0xe113
leaq 0x101f5(%rip), %rax     # 0x1e2d8
movl (%rax), %ecx
xorl %eax, %eax
cmpl %ecx, %eax
jg 0xe10b
leaq 0x101ee(%rip), %rax     # 0x1e2e0
movq (%rax), %r8
movl 0x2c(%rsp), %edx
movl 0x28(%rsp), %ecx
xorl %edi, %edi
leaq 0xadff(%rip), %rsi      # 0x18f05
movb $0x0, %al
callq *%r8
movl 0x28(%rsp), %eax
movl %eax, 0x30(%rsp)
jmp 0xe115
movl 0x2c(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x2c(%rsp)
jmp 0xe0b1
movq 0x98(%rsp), %rdi
callq 0x13ff0
movl $0x0, 0x24(%rsp)
movl 0x24(%rsp), %eax
cmpl 0x264(%rsp), %eax
jge 0xe167
movq 0x248(%rsp), %rax
movslq 0x24(%rsp), %rcx
movq (%rax,%rcx,8), %rdi
callq 0xbe40
movl 0x24(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x24(%rsp)
jmp 0xe137
movq 0x248(%rsp), %rdi
callq 0x22e0
movl 0x30(%rsp), %eax
movl %eax, 0x284(%rsp)
movl 0x284(%rsp), %eax
addq $0x288, %rsp            # imm = 0x288
retq
nop