// File: /workspace/github_c_makefile_star2_O2/sharpyfox[P]citrusleaf-client/src/cl_async.c
// Function: cl_do_async_monte
int
cl_do_async_monte(cl_cluster *asc, int info1, int info2, const char *ns, const char *set, const cl_object *key,
			const cf_digest *digest, cl_bin **values, cl_operator operator, cl_operation **operations, 
			int *n_values, uint32_t *cl_gen, const cl_write_parameters *cl_w_p, uint64_t *trid, void *udata)

{
	cl_async_work	*workitem = NULL;

	uint8_t		wr_stack_buf[STACK_BUF_SZ];
	uint8_t		*wr_buf = wr_stack_buf;
	size_t		wr_buf_sz = sizeof(wr_stack_buf);
	int        	progress_timeout_ms;
	uint64_t 	deadline_ms;
	uint64_t	starttime, endtime;
	bool 		network_error;
	int 		fd = -1;
	int		rv = CITRUSLEAF_FAIL_CLIENT;	//Assume that this is a failure;

	as_msg 		msg;
	cf_digest	d_ret;
	cl_cluster_node	*node = 0;

#if ONEASYNCFD
	if (shash_get_size(g_cl_async_hashtab) >= g_async_h_szlimit) {
		//cf_error("Async hashtab is full. Cannot insert any more elements");
		return CITRUSLEAF_FAIL_ASYNCQ_FULL;
	}
#else
	//If the async buffer is at the max limit, do not entertain more requests.
	if (cf_queue_sz(g_cl_async_q) >= cf_atomic32_get(g_async_q_szlimit)) {
		//cf_error("Async buffer is full. Cannot insert any more elements");
		return CITRUSLEAF_FAIL_ASYNCQ_FULL;
	}
#endif

	//Allocate memory for work item that will be added to the async work list

	if (cf_queue_sz(g_cl_workitems_freepool_q) > 0) {
		cf_queue_pop(g_cl_workitems_freepool_q, &workitem, CF_QUEUE_FOREVER);
	} else {
		workitem = malloc(sizeof(cl_async_work));
		if (workitem == NULL) {
			return CITRUSLEAF_FAIL_CLIENT;
		}
	}

	//Compile the write buffer to be sent to the cluster
	if (n_values && ( values || operations) ){
		cl_compile(info1, info2, 0, ns, set, key, digest, values?*values:NULL, operator, operations?*operations:NULL,
				*n_values , &wr_buf, &wr_buf_sz, cl_w_p, &d_ret, *trid,NULL);
	}else{
		cl_compile(info1, info2, 0, ns, set, key, digest, 0, 0, 0, 0, &wr_buf, &wr_buf_sz, cl_w_p, &d_ret, *trid,NULL);
	}	

	deadline_ms = 0;
	progress_timeout_ms = 0;
	if (cl_w_p && cl_w_p->timeout_ms) {
		deadline_ms = cf_getms() + cl_w_p->timeout_ms;
		// policy: if asking for a long timeout, give enough time to try twice
		if (cl_w_p->timeout_ms > 700) {
			progress_timeout_ms = cl_w_p->timeout_ms / 2;
		}
		else {
			progress_timeout_ms = cl_w_p->timeout_ms;
		}
	}
	else {
		progress_timeout_ms = g_async_nw_progress_timeout;
	}

	//Initialize the async work unit
	workitem->trid = *trid;
	workitem->deadline = deadline_ms;
	workitem->starttime = cf_getms();
	workitem->udata = udata;

	int try = 0;
	// retry request based on the write_policy
	do {
		network_error = false;
		try++;
#ifdef DEBUG		
		if (try > 1) {
			cf_debug("request retrying try %d tid %zu", try, (uint64_t)pthread_self());
		}
#endif        

		// Get an FD from a cluster. First get the probable node for the given digest.
		node = cl_cluster_node_get(asc, ns, &d_ret, info2 & CL_MSG_INFO2_WRITE ? true : false);
		if (!node) {
#ifdef DEBUG
			cf_debug("warning: no healthy nodes in cluster, retrying");
#endif
			usleep(10000);	//Sleep for 10ms
			goto Retry;
		}

		// Now get the dedicated async FD of this node
		starttime = cf_getms();
		fd = cl_cluster_node_fd_get(node, true, asc->nbconnect);
		endtime = cf_getms();
		if ((endtime - starttime) > 10) {
			cf_debug("Time to get FD for a node (>10ms)=%"PRIu64, (endtime - starttime));
		}
		if (fd == -1) {
#ifdef DEBUG			
			cf_debug("warning: node %s has no async file descriptors, retrying transaction (tid %zu)",node->name,(uint64_t)pthread_self() );
#endif			
			usleep(1000);
			goto Retry;
		}

		// Hate special cases, but we have to clear the verify bit on delete verify
		if ( (info2 & CL_MSG_INFO2_DELETE) && (info1 & CL_MSG_INFO1_VERIFY))
		{
			as_msg *msgp = (as_msg *)wr_buf;
			msgp->m.info1 &= ~CL_MSG_INFO1_VERIFY;
		}
		
		// Send the command to the node
		starttime = cf_getms();
		rv = cf_socket_write_timeout(fd, wr_buf, wr_buf_sz, deadline_ms, progress_timeout_ms);
		endtime = cf_getms();
		if ((endtime - starttime) > 10) {
			cf_debug("Time to write to the socket (>10ms)=%"PRIu64, (endtime - starttime));
		}
		if (rv != 0) {
			cf_debug("Citrusleaf: write timeout or error when writing header to server - %d fd %d errno %d (tid %zu)",
					rv,fd,errno,(uint64_t)pthread_self());
			if (rv != ETIMEDOUT)
				network_error = true;
			goto Retry;
		}
		goto Ok;

Retry:
		if (network_error == true) {
			/* 
			 * In case of Async work (for XDS), it may be extreme to
			 * dun a node in case of network error. We just cleanup
			 * things and retry to connect to the remote cluster.
			 * The network error may be a transient one. As this is a
			 * network error, its is better to wait for some significant
			 * time before retrying.
			 */
			sleep(1);	//Sleep for 1sec
#if ONEASYNCFD
//Do not close the FD
#else
			cf_error("async sender: Closing the fd %d because of network error", fd);
			close(fd);
			fd = -1;
#endif
		}

		if (fd != -1) {
			cf_error("async sender: Closing the fd %d because of retry", fd);
			close(fd);
			fd = -1;
		}

		if (node) {
			cl_cluster_node_put(node); 
			node = 0; 
		}

		if (deadline_ms && (deadline_ms < cf_getms() ) ) {
#ifdef DEBUG            
			cf_debug("async sender: out of time : deadline %"PRIu64" now %"PRIu64, deadline_ms, cf_getms());
#endif            
			rv = CITRUSLEAF_FAIL_TIMEOUT;
			goto Error;
		}
	} while ( (cl_w_p == 0) || (cl_w_p->w_pol == CL_WRITE_RETRY) );

Error:	
#ifdef DEBUG	
	cf_debug("exiting with failure: network_error %d wpol %d timeleft %d rv %d",
			(int)network_error, (int)(cl_w_p ? cl_w_p->w_pol : 0), 
			(int)(deadline_ms - cf_getms() ), rv );
#endif	

	if (wr_buf != wr_stack_buf) {
		free(wr_buf);
	}

#if ONEASYNCFD
	//Do not close the FD
#else
	//If it is a network error, the fd would be closed and set to -1.
	//So, we reach this place with a valid FD in case of timeout.
	if (fd != -1) {
		cf_error("async sender: Closing the fd %d because of timeout", fd);
		close(fd);
	}
#endif

	return(rv);
Ok:
	/*
	 * We cannot release the node here as the asyc FD associated
	 * with this node may get closed. We should do it only when
	 * we got back the ack for the async command that we just did.
	 */

	//As we sent the command successfully, add it to the async work list
	workitem->node = node;
	workitem->fd = fd;
	//We are storing only the pointer to the workitem
#if ONEASYNCFD
	if (shash_put_unique(g_cl_async_hashtab, trid, &workitem) != SHASH_OK) {
		//This should always succeed.
		cf_error("Unable to add unique entry into the hash table");
	}
	cf_queue_push(node->asyncwork_q, &workitem);	//Also put in the node's q
#else
	cf_queue_push(g_cl_async_q, &workitem);
#endif

	if (wr_buf != wr_stack_buf) {
		free(wr_buf);
	}

	rv = CITRUSLEAF_OK;
	return rv;

}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x40b8, %rsp           # imm = 0x40B8
leaq 0xb0(%rsp), %rax
movq %rdi, 0x80(%rsp)
andq $0x0, 0x70(%rsp)
movq %r9, %rbx
movq %r8, %r12
movq %rcx, %r14
movl %edx, %ebp
movl %esi, %r15d
movq $0x4000, 0x78(%rsp)     # imm = 0x4000
movq %rax, 0x68(%rsp)
leaq 0xda92(%rip), %rax      # 0x17480
movq (%rax), %rdi
callq 0xbedd
cmpl 0xda9c(%rip), %eax      # 0x17498
jge 0x9a25
leaq 0xda9b(%rip), %r13      # 0x174a0
movq (%r13), %rdi
callq 0xbedd
testl %eax, %eax
jle 0x9a31
movq (%r13), %rdi
leaq 0x70(%rsp), %rsi
pushq $-0x1
popq %rdx
callq 0xc163
jmp 0x9a47
pushq $-0x3
popq %rax
movl %eax, 0x60(%rsp)
jmp 0x9e78
pushq $0x30
popq %rdi
callq 0x22e0
testq %rax, %rax
movq %rax, 0x70(%rsp)
je 0x9ade
movq 0x4110(%rsp), %rcx
movq 0x4128(%rsp), %r8
movq 0x40f0(%rsp), %rax
testq %rcx, %rcx
je 0x9a86
movq 0x40f8(%rsp), %rdx
movq 0x4108(%rsp), %rdi
movq %rdx, %rsi
orq %rdi, %rsi
je 0x9a86
testq %rdx, %rdx
je 0x9ae5
movq (%rdx), %rdx
jmp 0x9ae7
movq (%r8), %rcx
movq 0x4120(%rsp), %r13
andq $0x0, 0x50(%rsp)
andl $0x0, 0x20(%rsp)
andq $0x0, 0x18(%rsp)
andl $0x0, 0x10(%rsp)
andq $0x0, 0x8(%rsp)
leaq 0x9c(%rsp), %rdx
leaq 0x78(%rsp), %rsi
movq %rax, (%rsp)
movq %rdx, 0x40(%rsp)
leaq 0x68(%rsp), %rdx
movq %rsi, 0x30(%rsp)
movq %rdx, 0x28(%rsp)
movq %rcx, 0x48(%rsp)
movq %r13, 0x38(%rsp)
jmp 0x9b4e
pushq $-0x1
jmp 0x9a27
xorl %edx, %edx
movl 0x4100(%rsp), %esi
testq %rdi, %rdi
je 0x9af8
movq (%rdi), %rdi
jmp 0x9afa
xorl %edi, %edi
movl (%rcx), %ecx
movq (%r8), %r8
movq 0x4120(%rsp), %r13
andq $0x0, 0x50(%rsp)
leaq 0x9c(%rsp), %r9
leaq 0x78(%rsp), %r10
movq %rdi, 0x18(%rsp)
movl %esi, 0x10(%rsp)
movq %rdx, 0x8(%rsp)
movq %rax, (%rsp)
movq %r9, 0x40(%rsp)
leaq 0x68(%rsp), %r9
movq %r10, 0x30(%rsp)
movq %r9, 0x28(%rsp)
movq %r8, 0x48(%rsp)
movq %r13, 0x38(%rsp)
movl %ecx, 0x20(%rsp)
movl %r15d, %edi
movl %ebp, %esi
xorl %edx, %edx
movq %r14, %rcx
movq %r12, %r8
movq %rbx, %r9
callq 0x4780
testq %r13, %r13
je 0x9b8b
cmpl $0x0, 0xc(%r13)
je 0x9b8b
callq 0xa498
movq %rax, %rbx
movslq 0xc(%r13), %rax
cmpq $0x2bd, %rax            # imm = 0x2BD
setge %cl
addq %rax, %rbx
shrl %cl, %eax
jmp 0x9b93
movl 0xb733(%rip), %eax      # 0x152c4
xorl %ebx, %ebx
movq %rax, 0x88(%rsp)
movq 0x4128(%rsp), %rax
movq 0x70(%rsp), %rcx
movl %ebp, %r12d
movq (%rax), %rax
movq %rax, (%rcx)
movq 0x70(%rsp), %rax
movq %rbx, 0x8(%rax)
callq 0xa498
movq 0x70(%rsp), %rcx
movq 0x4130(%rsp), %rsi
testb $0x2, %r12b
sete %dl
testb $0x8, %r15b
movq %rax, 0x10(%rcx)
movq %rsi, 0x28(%rcx)
sete %cl
orb %dl, %cl
movb %cl, 0x67(%rsp)
pushq $-0x1
popq %rax
movq 0x80(%rsp), %r15
movq 0x4120(%rsp), %rbp
andl $0x1, %r12d
movl %eax, 0x60(%rsp)
movq %rbx, 0x90(%rsp)
movq %r15, %rdi
movq %r14, %rsi
leaq 0x9c(%rsp), %rdx
movl %r12d, %ecx
callq 0x7787
testq %rax, %rax
je 0x9d9d
movq %rax, %r13
callq 0xa498
movzbl 0x15(%r15), %edx
movq %rax, %rbp
movq %r13, %rdi
pushq $0x1
popq %rsi
callq 0x7d09
movl %eax, %ebx
callq 0xa498
subq %rbp, %rax
cmpq $0xb, %rax
jb 0x9c7e
leaq 0xb66c(%rip), %rcx      # 0x152c8
movl (%rcx), %ecx
cmpl $0x3, %ecx
jl 0x9c7e
leaq 0xb666(%rip), %rcx      # 0x152d0
movq (%rcx), %rcx
pushq $0x3
popq %rdi
movq %rax, %rdx
leaq 0x546d(%rip), %rsi      # 0xf0e7
xorl %eax, %eax
callq *%rcx
cmpl $-0x1, %ebx
je 0x9da9
cmpb $0x0, 0x67(%rsp)
jne 0x9c97
movq 0x68(%rsp), %rax
andb $-0x9, 0x9(%rax)
callq 0xa498
movq 0x68(%rsp), %rsi
movq 0x78(%rsp), %rdx
movq 0x90(%rsp), %rcx
movl %ebx, %edi
movq 0x88(%rsp), %r8
movq %rax, %rbp
callq 0xcdd4
movl %eax, 0x60(%rsp)
callq 0xa498
subq %rbp, %rax
cmpq $0xb, %rax
jb 0x9cfb
leaq 0xb5ef(%rip), %rcx      # 0x152c8
movl (%rcx), %ecx
cmpl $0x3, %ecx
jl 0x9cfb
leaq 0xb5e9(%rip), %rcx      # 0x152d0
movq (%rcx), %rcx
pushq $0x3
popq %rdi
movq %rax, %rdx
leaq 0x5416(%rip), %rsi      # 0xf10d
xorl %eax, %eax
callq *%rcx
cmpl $0x0, 0x60(%rsp)
je 0x9e3b
leaq 0xb5bb(%rip), %rax      # 0x152c8
movl (%rax), %eax
cmpl $0x3, %eax
jl 0x9d59
leaq 0xb5b5(%rip), %rax      # 0x152d0
movl %r12d, %r15d
movq %r14, %r12
movq (%rax), %r14
callq 0x2040
movl (%rax), %ebp
callq 0x2210
pushq $0x3
popq %rdi
movl 0x60(%rsp), %edx
movq %rax, %r9
leaq 0x53f4(%rip), %rsi      # 0xf135
movl %ebx, %ecx
movl %ebp, %r8d
xorl %eax, %eax
callq *%r14
movq %r12, %r14
movl %r15d, %r12d
movq 0x80(%rsp), %r15
cmpl $0x6e, 0x60(%rsp)
jne 0x9dbd
leaq 0xb561(%rip), %rax      # 0x152c8
movq 0x4120(%rsp), %rbp
cmpl $0x0, (%rax)
js 0x9d8d
leaq 0xb555(%rip), %rax      # 0x152d0
xorl %edi, %edi
leaq 0x5449(%rip), %rsi      # 0xf1cd
movl %ebx, %edx
movq (%rax), %rcx
xorl %eax, %eax
callq *%rcx
movl %ebx, %edi
callq 0x2550
pushq $0x6e
popq %rax
movl %eax, 0x60(%rsp)
jmp 0x9df9
movl $0x2710, %edi           # imm = 0x2710
callq 0x2360
jmp 0x9e09
movl $0x3e8, %edi            # imm = 0x3E8
callq 0x2360
movq 0x4120(%rsp), %rbp
jmp 0x9df9
pushq $0x1
popq %rdi
callq 0x2180
leaq 0xb4fc(%rip), %rax      # 0x152c8
movq 0x4120(%rsp), %rbp
cmpl $0x0, (%rax)
js 0x9df2
leaq 0xb4f0(%rip), %rax      # 0x152d0
xorl %edi, %edi
leaq 0x53ab(%rip), %rsi      # 0xf194
movl %ebx, %edx
movq (%rax), %rcx
xorl %eax, %eax
callq *%rcx
movl %ebx, %edi
callq 0x2550
movq %r13, %rdi
callq 0x7b74
movq 0x90(%rsp), %rbx
testq %rbx, %rbx
je 0x9e18
callq 0xa498
cmpq %rax, %rbx
jb 0x9e2d
testq %rbp, %rbp
je 0x9c0b
cmpl $0x2, 0x14(%rbp)
je 0x9c0b
jmp 0x9e34
pushq $-0x2
popq %rax
movl %eax, 0x60(%rsp)
movq 0x68(%rsp), %rdi
jmp 0x9e66
leaq 0x70(%rsp), %rsi
movq (%rsi), %rax
movq %r13, 0x18(%rax)
movl %ebx, 0x20(%rax)
leaq 0xd62f(%rip), %rax      # 0x17480
movq (%rax), %rdi
callq 0xc01b
movq 0x68(%rsp), %rdi
movl $0x0, 0x60(%rsp)
leaq 0xb0(%rsp), %rax
cmpq %rax, %rdi
je 0x9e78
callq 0x22c0
movl 0x60(%rsp), %eax
addq $0x40b8, %rsp           # imm = 0x40B8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq