// File: tonymuu[P]distributed-kv-store/MP1Node.cpp
// Function: MP1Node::nodeLoopOps()
void MP1Node::nodeLoopOps() {
    long currTime = par->getcurrtime();
    auto shouldSendGossip = (currTime - timeLastGossip) >= TGOSSIP && memberNode->memberList.size() > 0;

    // select a random neighbour and send gossip
    if (shouldSendGossip) {
        memberNode->heartbeat++;
        timeLastGossip = currTime;
        int index = rand() % memberNode->memberList.size();
        auto neighbour = memberNode->memberList[index];
        Address neighbourAddr = createAddressFromIdAndPort(neighbour.id, neighbour.port);
        sendGossip(&neighbourAddr);
    }

    int id = 0;
    short port = 0;
    setIdAndPortFromAddress(memberNode->addr, &id, &port);

    // update any node that has failed, remove any failed nodes that are passed Tcleanup
    // If a node's heartbeat hasn't increased for more than Tfail (currentTime - node.timestamp), we mark it as failed
    // if a node is marked as failed for more than Tcleanup, remove the node from list, and log
    auto neighbour = memberNode->memberList.begin();
    while (neighbour != memberNode->memberList.end()) {
        Address neighbourAddr = createAddressFromIdAndPort(neighbour->id, neighbour->port);
        if (areAddressesEqual(memberNode->addr, neighbourAddr)) {
            neighbour++;
            continue;
        }

        auto hasFailed = failed.count(neighbour->id) != 0;
        long timeSinceLastUpdate = currTime - neighbour->timestamp;
        if (hasFailed && currTime - failed[neighbour->id] >= TREMOVE) { // remove node
            neighbour = memberNode->memberList.erase(neighbour);
            failed.erase(neighbour->id);
            log->logNodeRemove(&(memberNode->addr), &neighbourAddr);
            continue;
        }

        if (!hasFailed && timeSinceLastUpdate >= TFAIL) { // if node has failed, we don't send msg to it
            failed[neighbour->id] = currTime;
            hasFailed = true;
        }
        neighbour++;
    }

    return;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xe0, %rsp
movq %rdi, -0x8(%rbp)
movq -0x8(%rbp), %rax
movq %rax, -0xb0(%rbp)
movq 0x18(%rax), %rdi
callq 0x18c60
movl %eax, %ecx
movq -0xb0(%rbp), %rax
movslq %ecx, %rcx
movq %rcx, -0x10(%rbp)
movq -0x10(%rbp), %rcx
subq 0x30(%rax), %rcx
xorl %eax, %eax
cmpq $0x5, %rcx
movb %al, -0xa1(%rbp)
jl 0x616a
movq -0xb0(%rbp), %rax
movq 0x20(%rax), %rdi
addq $0x28, %rdi
callq 0x7330
cmpq $0x0, %rax
seta %al
movb %al, -0xa1(%rbp)
movb -0xa1(%rbp), %al
andb $0x1, %al
movb %al, -0x11(%rbp)
testb $0x1, -0x11(%rbp)
je 0x6222
movq -0xb0(%rbp), %rax
movq 0x20(%rax), %rcx
movq 0x18(%rcx), %rdx
addq $0x1, %rdx
movq %rdx, 0x18(%rcx)
movq -0x10(%rbp), %rcx
movq %rcx, 0x30(%rax)
callq 0x40e0
movl %eax, %ecx
movq -0xb0(%rbp), %rax
movslq %ecx, %rcx
movq %rcx, -0xb8(%rbp)
movq 0x20(%rax), %rdi
addq $0x28, %rdi
callq 0x7330
movq %rax, %rcx
movq -0xb8(%rbp), %rax
xorl %edx, %edx
divq %rcx
movq -0xb0(%rbp), %rax
movl %edx, %ecx
movl %ecx, -0x18(%rbp)
movq 0x20(%rax), %rdi
addq $0x28, %rdi
movslq -0x18(%rbp), %rsi
callq 0x7360
movq %rax, %rsi
leaq -0x30(%rbp), %rdi
callq 0x18f90
movq -0xb0(%rbp), %rsi
movl -0x30(%rbp), %edx
leaq -0x36(%rbp), %rdi
movswl -0x2c(%rbp), %ecx
callq 0x6b30
movq -0xb0(%rbp), %rdi
leaq -0x36(%rbp), %rsi
callq 0x6b80
movq -0xb0(%rbp), %rax
movl $0x0, -0x3c(%rbp)
movw $0x0, -0x3e(%rbp)
movq 0x20(%rax), %rsi
addq $0x8, %rsi
leaq -0x44(%rbp), %rdi
callq 0x18e40
movq -0xb0(%rbp), %rdi
leaq -0x44(%rbp), %rsi
leaq -0x3c(%rbp), %rdx
leaq -0x3e(%rbp), %rcx
callq 0x5ff0
movq -0xb0(%rbp), %rax
movq 0x20(%rax), %rdi
addq $0x28, %rdi
callq 0x7380
movq %rax, -0x50(%rbp)
movq -0xb0(%rbp), %rax
movq 0x20(%rax), %rdi
addq $0x28, %rdi
callq 0x73f0
movq %rax, -0x58(%rbp)
leaq -0x50(%rbp), %rdi
leaq -0x58(%rbp), %rsi
callq 0x73b0
testb $0x1, %al
jne 0x62a5
jmp 0x6499
leaq -0x50(%rbp), %rdi
callq 0x7420
movl (%rax), %eax
movl %eax, -0xbc(%rbp)
leaq -0x50(%rbp), %rdi
callq 0x7420
movl -0xbc(%rbp), %edx
movq -0xb0(%rbp), %rsi
leaq -0x5e(%rbp), %rdi
movswl 0x4(%rax), %ecx
callq 0x6b30
movq -0xb0(%rbp), %rax
movq 0x20(%rax), %rsi
addq $0x8, %rsi
leaq -0x64(%rbp), %rdi
callq 0x18e40
leaq -0x6a(%rbp), %rdi
leaq -0x5e(%rbp), %rsi
callq 0x18e40
movq -0xb0(%rbp), %rdi
leaq -0x64(%rbp), %rsi
leaq -0x6a(%rbp), %rdx
callq 0x6c20
testb $0x1, %al
jne 0x6318
jmp 0x632c
leaq -0x50(%rbp), %rdi
xorl %esi, %esi
callq 0x7440
movq %rax, -0x78(%rbp)
jmp 0x6277
leaq -0x50(%rbp), %rdi
callq 0x7420
movq %rax, %rsi
leaq 0x38061(%rip), %rdi     # 0x3e3a0
callq 0x7480
cmpq $0x0, %rax
setne %al
andb $0x1, %al
movb %al, -0x79(%rbp)
movq -0x10(%rbp), %rax
movq %rax, -0xc8(%rbp)
leaq -0x50(%rbp), %rdi
callq 0x7420
movq %rax, %rcx
movq -0xc8(%rbp), %rax
subq 0x10(%rcx), %rax
movq %rax, -0x88(%rbp)
testb $0x1, -0x79(%rbp)
je 0x6441
movq -0x10(%rbp), %rax
movq %rax, -0xd0(%rbp)
leaq -0x50(%rbp), %rdi
callq 0x7420
movq %rax, %rsi
leaq 0x37fff(%rip), %rdi     # 0x3e3a0
callq 0x74b0
movq %rax, %rcx
movq -0xd0(%rbp), %rax
subq (%rcx), %rax
cmpq $0x14, %rax
jl 0x6441
movq -0xb0(%rbp), %rax
movq 0x20(%rax), %rax
addq $0x28, %rax
movq %rax, -0xd8(%rbp)
leaq -0x98(%rbp), %rdi
leaq -0x50(%rbp), %rsi
callq 0x7550
movq -0xd8(%rbp), %rdi
movq -0x98(%rbp), %rsi
callq 0x74e0
movq %rax, -0x90(%rbp)
movq -0x90(%rbp), %rax
movq %rax, -0x50(%rbp)
leaq -0x50(%rbp), %rdi
callq 0x7420
movq %rax, %rsi
leaq 0x37f85(%rip), %rdi     # 0x3e3a0
callq 0x7590
movq -0xb0(%rbp), %rax
movq 0x10(%rax), %rdi
movq 0x20(%rax), %rsi
addq $0x8, %rsi
leaq -0x5e(%rbp), %rdx
callq 0x17f50
jmp 0x6277
testb $0x1, -0x79(%rbp)
jne 0x6482
cmpq $0x5, -0x88(%rbp)
jl 0x6482
movq -0x10(%rbp), %rax
movq %rax, -0xe0(%rbp)
leaq -0x50(%rbp), %rdi
callq 0x7420
movq %rax, %rsi
leaq 0x37f31(%rip), %rdi     # 0x3e3a0
callq 0x74b0
movq -0xe0(%rbp), %rcx
movq %rcx, (%rax)
movb $0x1, -0x79(%rbp)
leaq -0x50(%rbp), %rdi
xorl %esi, %esi
callq 0x7440
movq %rax, -0xa0(%rbp)
jmp 0x6277
addq $0xe0, %rsp
popq %rbp
retq
nopw %cs:(%rax,%rax)