// File: /workspace/github_c_makefile_star2_O2/sharpyfox[P]citrusleaf-client/src/citrusleaf.c
// Function: do_the_full_monte
static int
do_the_full_monte(cl_cluster *asc, int info1, int info2, int info3, 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, char **setname_r)
{
	int rv = -1;
#ifdef DEBUG_HISTOGRAM	
    uint64_t start_time = cf_getms();
#endif	
	

	uint8_t		rd_stack_buf[STACK_BUF_SZ];	
	uint8_t		*rd_buf = rd_stack_buf;
	size_t		rd_buf_sz = 0;
    
	uint8_t		wr_stack_buf[STACK_BUF_SZ];
	uint8_t		*wr_buf = wr_stack_buf;
	size_t		wr_buf_sz = sizeof(wr_stack_buf);

	as_msg 		msg;
    
    uint        progress_timeout_ms;
	uint64_t deadline_ms;
	cl_cluster_node *node = 0;

	int fd = -1;

//	if( *values ){
//		dump_values(*values, null, *n_values);
//	}else if( *operations ){
//		dump_values(null, *operations, *n_values);
//	}	
	 
	/* 
	 * Check if the current process is the one which spawned the background threads (tend,batch).
	 * If it is not, it means that this process is a forked child process. The threads would not
	 * be running in this case. So, spawn the background threads and remember that this process
	 * has started the threads.
	 */
	if(g_init_pid != getpid()) {
		cf_atomic32_set(&batch_initialized,0);
		g_clust_initialized = 0;
		citrusleaf_init();
	}

	cf_digest d_ret;	
	if (n_values && ( values || operations) ){
		if (cl_compile(info1, info2, info3, 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)) {
			return(rv);
		}
	}else{
		if (cl_compile(info1, info2, info3, ns, set, key, digest, 0, 0, 0, 0, &wr_buf, &wr_buf_sz, cl_w_p, &d_ret, *trid, NULL)) {
			return(rv);
		}
	}	

#ifdef DEBUG_VERBOSE
	dump_buf("sending request to cluster:", wr_buf, wr_buf_sz);
#endif	

	int try = 0;

#ifdef DEBUG_TIME
	uint64_t before_write_time = 0;
	uint64_t after_write_time = 0;
	uint64_t before_read_header_time = 0;
	uint64_t after_read_header_time = 0;
	uint64_t before_read_body_time = 0;
    uint64_t after_read_body_time = 0;	
#endif

    deadline_ms = 0;
    progress_timeout_ms = 0;
    if (cl_w_p && cl_w_p->timeout_ms) {
    	// policy: if asking for a long timeout, give enough time to try two servers
    	if (cl_w_p->timeout_ms > 700) {
			deadline_ms = cf_getms() + cl_w_p->timeout_ms;
			progress_timeout_ms = cl_w_p->timeout_ms / 2;
		}
		else {
			deadline_ms = cf_getms() + cl_w_p->timeout_ms;
			progress_timeout_ms = cl_w_p->timeout_ms;
		}
#ifdef DEBUG_VERBOSE        
        cf_debug("transaction has deadline: in %d deadlinems %"PRIu64" progress %d",
        	(int)cl_w_p->timeout_ms,deadline_ms,progress_timeout_ms);
#endif        
    }
    else {
        progress_timeout_ms = DEFAULT_PROGRESS_TIMEOUT;
    }
	
	// retry request based on the write_policy
	do {

#ifdef DEBUG_TIME
		before_write_time = 0;
		after_write_time = 0;
		before_read_header_time = 0;
		after_read_header_time = 0;
		before_read_body_time = 0;
		after_read_body_time = 0;
#endif
        
#ifdef DEBUG		
		if (try > 0)
			cf_debug("request retrying try %d tid %zu", try, (uint64_t)pthread_self());
#endif        
		try++;
		
		// Get an FD from a cluster
		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);
			goto Retry;
		}
		fd = cl_cluster_node_fd_get(node, false, asc->nbconnect);
		if (fd == -1) {
#ifdef DEBUG			
			cf_debug("warning: node %s has no file descriptors, retrying transaction (tid %zu)", node->name, (uint64_t)pthread_self());
#endif			
			usleep(1000);
			goto Retry;
		}

#ifdef DEBUG_VERBOSE
		cf_debug("node %s fd %d", node->name, fd);
#endif		
		
		// 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 it to the cluster - non blocking socket, but we're blocking

#ifdef DEBUG_TIME
        before_write_time = cf_getms();
#endif
		rv = cf_socket_write_timeout(fd, wr_buf, wr_buf_sz, deadline_ms, progress_timeout_ms);
#ifdef DEBUG_TIME
        after_write_time = cf_getms();
#endif

		if (rv != 0) {
#ifdef DEBUG			
			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());
#endif
#ifdef DEBUG_TIME
            debug_printf(before_write_time, after_write_time, before_read_header_time, after_read_header_time, before_read_body_time, after_read_body_time,
                         deadline_ms, progress_timeout_ms);           	
#endif

			cl_cluster_node_dun(node, rv == ETIMEDOUT ? NODE_DUN_TIMEOUT : NODE_DUN_NET_ERR);
			goto Retry;
		}

#ifdef DEBUG		
		memset(&msg, 0, sizeof(as_msg));
#endif
#ifdef DEBUG_TIME
        before_read_header_time = cf_getms();
#endif		
		
		// Now turn around and read into this fine cl_msg, which is the short header
		rv = cf_socket_read_timeout(fd, (uint8_t *) &msg, sizeof(as_msg), deadline_ms, progress_timeout_ms);
#ifdef DEBUG_TIME
        after_read_header_time = cf_getms();
#endif

		if (rv) {

#ifdef DEBUG            
			cf_debug("Citrusleaf: error when reading header from server - rv %d fd %d", rv, fd);
#endif
#ifdef DEBUG_TIME
            debug_printf(before_write_time, after_write_time, before_read_header_time, after_read_header_time, before_read_body_time, after_read_body_time,
                         deadline_ms, progress_timeout_ms);           	
#endif            

			cl_cluster_node_dun(node, rv == ETIMEDOUT ? NODE_DUN_TIMEOUT : NODE_DUN_NET_ERR);
			goto Retry;
	
		}
#ifdef DEBUG_VERBOSE
		dump_buf("read header from cluster", (uint8_t *) &msg, sizeof(cl_msg));
#endif	
		cl_proto_swap(&msg.proto);
		cl_msg_swap_header(&msg.m);

		if (/*(info1 & CL_MSG_INFO1_READ) &&*/ cl_gen) {
			*cl_gen = msg.m.generation;
		}
	
		
		// second read for the remainder of the message - expect this to cover everything requested
		// if there's no error
		rd_buf_sz =  msg.proto.sz  - msg.m.header_sz;
		if (rd_buf_sz > 0) {
			if (rd_buf_sz > sizeof(rd_stack_buf)) {
				rd_buf = malloc(rd_buf_sz);
				if (!rd_buf) {
                    cf_error("malloc fail: trying %zu", rd_buf_sz);
                    rv = -1; 
                    goto Error; 
                }
			}
#ifdef DEBUG_TIME
        before_read_body_time = cf_getms();
#endif            
			rv = cf_socket_read_timeout(fd, rd_buf, rd_buf_sz, deadline_ms, progress_timeout_ms);
#ifdef DEBUG_TIME
        after_read_body_time = cf_getms();
#endif
			if (rv) {
				if (rd_buf != rd_stack_buf) { free(rd_buf); }
                rd_buf = 0;
                
#ifdef DEBUG            
                cf_debug("Citrusleaf: error when reading from server - rv %d fd %d", rv, fd);
#endif
#ifdef DEBUG_TIME
				debug_printf(before_write_time, after_write_time, before_read_header_time, after_read_header_time, before_read_body_time, after_read_body_time, 
                             deadline_ms, progress_timeout_ms);           	
#endif

				cl_cluster_node_dun(node, rv == ETIMEDOUT ? NODE_DUN_TIMEOUT : NODE_DUN_NET_ERR);
				goto Retry;
			}

#ifdef DEBUG_VERBOSE
			dump_buf("read body from cluster", rd_buf, rd_buf_sz);
#endif	
			
			// todo: check error!!?!?!
		}

        goto Ok;
		
Retry:		

		if (fd != -1) {
			close(fd);
			fd = -1;
		}

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

        if (deadline_ms && (deadline_ms < cf_getms() ) ) {
#ifdef DEBUG            
            cf_debug("out of luck 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: wpol %d timeleft %d rv %d",
		(int)(cl_w_p ? cl_w_p->w_pol : 0),
		(int)(deadline_ms - cf_getms() ), rv );
#endif	

    if (fd != -1)   close(fd);

	if (wr_buf != wr_stack_buf)		free(wr_buf);
	if (rd_buf && (rd_buf != rd_stack_buf))		free(rd_buf);
	
	return(rv);
    
Ok:    

	cl_cluster_node_ok(node);
    cl_cluster_node_fd_put(node, fd, false);
	cl_cluster_node_put(node);
   
	if (wr_buf != wr_stack_buf)		free(wr_buf);

	if (rd_buf) {
		if (0 != cl_parse(&msg.m, rd_buf, rd_buf_sz, values, operations, n_values, trid, setname_r)) {
			rv = CITRUSLEAF_FAIL_UNKNOWN;
		}
		else {
			rv = msg.m.result_code;
			// special case: if there was a retry, and we're doing a delete, force 'not found'
			// errors to 'ok' because the first delete might have succeeded
			if ((try > 1) && (rv == 2) && (info2 & CL_MSG_INFO2_DELETE)) {
//				dump_key("delete: stomping error code on retransmitted delete", key);
				rv = 0;
			}
		}
    }
    else {
        rv = CITRUSLEAF_FAIL_UNKNOWN;
    }    
	if (rd_buf && (rd_buf != rd_stack_buf))		free(rd_buf);
	
	if (rv == 0 && (values || operations) && n_values) {
		for (int i=0;i<*n_values;i++) {
			cl_bin *bin = values? &(*values)[i] : &((*operations)[i].bin);
//			if ( bin->object.type == CL_NULL ) {
//				// raise(SIGINT);
//			}
		}
	}
#ifdef DEBUG_HISTOGRAM	
    cf_histogram_insert_data_point(cf_hist, start_time);
#endif	
#ifdef DEBUG_VERBOSE
	if (rv != 0) {
		cf_debug("exiting OK clause with failure: wpol %d timeleft %d rv %d",
			(int)(cl_w_p ? cl_w_p->w_pol : 0),
			(int)(deadline_ms - cf_getms() ), rv );
	}
#endif	

	return(rv);
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x8088, %rsp           # imm = 0x8088
leaq 0x4080(%rsp), %rax
movq 0x80e8(%rsp), %r12
movq %r9, %rbx
movq %r8, 0x30(%rsp)
movl %ecx, %ebp
movl %edx, %r15d
movl %esi, 0x8(%rsp)
movq %rdi, 0x28(%rsp)
movq $0x4000, 0x40(%rsp)     # imm = 0x4000
movq %rax, 0x20(%rsp)
leaq 0x120c4(%rip), %rax     # 0x173a4
movl (%rax), %r14d
callq 0x23a0
cmpl %eax, %r14d
je 0x5307
leaq 0x1213c(%rip), %rax     # 0x17430
xorl %ecx, %ecx
movl %ecx, (%rax)
leaq 0x120a9(%rip), %rax     # 0x173a8
andl $0x0, (%rax)
callq 0x657b
movq 0x8100(%rsp), %r13
movq 0x80e0(%rsp), %rdx
movq 0x80d0(%rsp), %rsi
movq 0x80c8(%rsp), %rax
movq 0x80c0(%rsp), %r9
testq %r12, %r12
je 0x534a
movq %rsi, %rcx
orq %rdx, %rcx
je 0x534a
movl 0x8(%rsp), %edi
testq %rsi, %rsi
je 0x538d
movq (%rsi), %r10
jmp 0x5390
subq $0x8, %rsp
movl 0x10(%rsp), %edi
movq 0x38(%rsp), %rcx
movl %r15d, %esi
movl %ebp, %edx
movq %rbx, %r8
leaq 0x56(%rsp), %r10
leaq 0x48(%rsp), %r11
leaq 0x28(%rsp), %r14
pushq $0x0
pushq (%r13)
pushq %r10
movq 0x8118(%rsp), %rbx
pushq %rbx
pushq %r11
pushq %r14
pushq $0x0
pushq $0x0
pushq $0x0
pushq $0x0
jmp 0x53e6
xorl %r10d, %r10d
testq %rdx, %rdx
je 0x539a
movq (%rdx), %r14
jmp 0x539d
xorl %r14d, %r14d
movl (%r12), %r12d
subq $0x8, %rsp
movq 0x38(%rsp), %rcx
movl %r15d, %esi
movl %ebp, %edx
movq %rbx, %r8
leaq 0x56(%rsp), %r11
pushq $0x0
pushq (%r13)
pushq %r11
movq 0x8118(%rsp), %rbx
pushq %rbx
leaq 0x68(%rsp), %r11
pushq %r11
leaq 0x50(%rsp), %r11
pushq %r11
pushq %r12
pushq %r14
movl 0x8120(%rsp), %r11d
pushq %r11
pushq %r10
pushq %rax
callq 0x4780
addq $0x60, %rsp
testl %eax, %eax
pushq $-0x1
popq %r12
jne 0x568b
pushq $0x32
popq %rax
testq %rbx, %rbx
movq $0x0, 0x38(%rsp)
je 0x543c
movl 0xc(%rbx), %ebp
movq 0x28(%rsp), %r14
testl %ebp, %ebp
je 0x544d
movq %rbx, %r12
callq 0x6609
movq %rax, %rbx
movslq 0xc(%r12), %rax
addq %rax, %rbx
cmpl $0x2bd, %ebp            # imm = 0x2BD
jl 0x544f
pushq $0x2
popq %rcx
cltd
idivl %ecx
jmp 0x544f
movq 0x28(%rsp), %r14
movq %rax, 0x18(%rsp)
xorl %ebx, %ebx
movl %r15d, %ebp
jmp 0x5457
xorl %ebx, %ebx
movl %r15d, %ebp
movq %rax, 0x18(%rsp)
movl 0x8(%rsp), %ecx
movl %ebp, %eax
andl $0x2, %eax
movl %eax, 0x48(%rsp)
sete %al
testb $0x8, %cl
sete %cl
orb %al, %cl
movb %cl, 0x8(%rsp)
pushq $-0x1
popq %r12
leaq 0x80(%rsp), %rax
andl $0x1, %ebp
leaq 0x4e(%rsp), %r13
movq %rax, 0x10(%rsp)
movl %ebp, 0xc(%rsp)
movq 0x30(%rsp), %rsi
movq %r14, %rdi
movq %r13, %rdx
movl %ebp, %ecx
callq 0x7787
testq %rax, %rax
je 0x5540
movzbl 0x15(%r14), %edx
movq %rax, %rdi
xorl %esi, %esi
movq %rax, %r15
callq 0x7d09
cmpl $-0x1, %eax
je 0x554c
movq 0x20(%rsp), %rbp
cmpb $0x0, 0x8(%rsp)
movl %eax, %r14d
jne 0x54d9
andb $-0x9, 0x9(%rbp)
movq 0x18(%rsp), %r13
movq 0x40(%rsp), %rdx
movl %r14d, %edi
movq %rbp, %rsi
movq %rbx, %rcx
movl %r13d, %r8d
callq 0xcdd4
testl %eax, %eax
jne 0x5516
movl %r14d, %edi
leaq 0x62(%rsp), %rsi
pushq $0x1e
popq %rdx
movq %rbx, %rcx
movl %r13d, %r8d
callq 0xc8d4
testl %eax, %eax
je 0x559e
movl %eax, %r12d
movl 0xc(%rsp), %ebp
leaq 0x4e(%rsp), %r13
cmpl $0x6e, %r12d
pushq $0x1
popq %rsi
je 0x552e
pushq $0x32
popq %rsi
movq %r15, %rdi
callq 0x7b79
movl %r14d, %edi
callq 0x2550
jmp 0x5556
movl $0x2710, %edi           # imm = 0x2710
callq 0x2360
jmp 0x5563
movl $0x3e8, %edi            # imm = 0x3E8
callq 0x2360
movq %r15, %rdi
callq 0x7b74
movq 0x28(%rsp), %r14
testq %rbx, %rbx
je 0x5576
callq 0x6609
cmpq %rax, %rbx
jb 0x5648
movq 0x80f8(%rsp), %rax
testq %rax, %rax
je 0x558d
cmpl $0x2, 0x14(%rax)
jne 0x564c
movq 0x38(%rsp), %rax
decl %eax
movq %rax, 0x38(%rsp)
jmp 0x5490
leaq 0x62(%rsp), %rdi
callq 0xbd64
leaq 0x6a(%rsp), %rdi
callq 0xbd80
movq 0x80f0(%rsp), %rcx
testq %rcx, %rcx
je 0x55c5
movl 0x70(%rsp), %eax
movl %eax, (%rcx)
movzwl 0x68(%rsp), %r13d
movl 0x64(%rsp), %eax
shlq $0x20, %r13
orq %rax, %r13
movzbl 0x6a(%rsp), %eax
subq %rax, %r13
je 0x56a5
cmpq $0x4001, %r13           # imm = 0x4001
jb 0x5603
movq %r13, %rdi
callq 0x22e0
testq %rax, %rax
movq %rax, 0x10(%rsp)
je 0x572c
movq 0x10(%rsp), %rbp
movl %r14d, %edi
movq %r13, %rdx
movq %rbx, %rcx
movq 0x18(%rsp), %r8
movq %rbp, %rsi
callq 0xc8d4
testl %eax, %eax
je 0x56a0
leaq 0x80(%rsp), %rcx
movl %eax, %r12d
cmpq %rcx, %rbp
je 0x563a
movq %rbp, %rdi
callq 0x22c0
movq $0x0, 0x10(%rsp)
jmp 0x5519
pushq $-0x2
popq %r12
movq 0x20(%rsp), %rbp
leaq 0x4080(%rsp), %rax
cmpq %rax, %rbp
je 0x5666
movq %rbp, %rdi
callq 0x22c0
movq 0x10(%rsp), %rbx
leaq 0x80(%rsp), %rcx
testq %rbx, %rbx
setne %al
cmpq %rcx, %rbx
setne %cl
testb %cl, %al
je 0x568b
movq %rbx, %rdi
callq 0x22c0
movl %r12d, %eax
addq $0x8088, %rsp           # imm = 0x8088
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x20(%rsp), %rbp
movq %r15, %rdi
callq 0x7b94
movq %r15, %rdi
movl %r14d, %esi
xorl %edx, %edx
callq 0x7d64
movq %r15, %rdi
callq 0x7b74
leaq 0x4080(%rsp), %rax
cmpq %rax, %rbp
je 0x56d7
movq %rbp, %rdi
callq 0x22c0
movq 0x10(%rsp), %rbx
testq %rbx, %rbx
je 0x5723
movq 0x80d0(%rsp), %rcx
movq 0x80e0(%rsp), %r8
movq 0x80e8(%rsp), %r9
leaq 0x6a(%rsp), %rdi
movq %rbx, %rsi
movq %r13, %rdx
pushq 0x8108(%rsp)
pushq 0x8108(%rsp)
callq 0x4ec1
popq %rcx
popq %rdx
testl %eax, %eax
je 0x576c
pushq $0x1
popq %r12
jmp 0x578b
pushq $0x1
popq %r12
jmp 0x568b
leaq 0xfb95(%rip), %rax      # 0x152c8
cmpl $0x0, (%rax)
js 0x5752
leaq 0xfb91(%rip), %rax      # 0x152d0
leaq 0x91e0(%rip), %rsi      # 0xe926
xorl %edi, %edi
movq %r13, %rdx
movq (%rax), %rcx
xorl %eax, %eax
callq *%rcx
movl %r14d, %edi
callq 0x2550
pushq $-0x1
popq %r12
movq $0x0, 0x10(%rsp)
jmp 0x5651
movb 0x6f(%rsp), %al
movl 0x48(%rsp), %r12d
movzbl %al, %eax
xorl $0x2, %r12d
cmpb $0x2, %al
cmovnel %eax, %r12d
cmpl $0x0, 0x38(%rsp)
cmovel %eax, %r12d
leaq 0x80(%rsp), %rax
cmpq %rax, %rbx
jne 0x5683
jmp 0x568b