// File: /workspace/github_cpp_makefile_star2_O3/cybozu[P]yrmcds/src/memcache/gc.cpp
// Function: yrmcds::memcache::gc_thread::gc()
void gc_thread::gc() {
    std::time_t t = g_stats.flush_time.load();
    bool flush = (t != 0) && (std::time(nullptr) >= t);
    unsigned int evict_age = 0;
    if( (! flush) &&
        (g_stats.used_memory.load(std::memory_order_relaxed) >
         g_config.memory_limit()) ) {
        unsigned int oldest_age =
            g_stats.oldest_age.load(std::memory_order_relaxed);
        unsigned int one_hour = 3600U / g_config.gc_interval() + 1;
        if( oldest_age < (one_hour * 2) ) {
            evict_age = std::max(1U, oldest_age / 2);
        } else {
            evict_age = oldest_age - one_hour;
        }
        cybozu::logger::warning() << "Evicting object of "
                                  << evict_age << " gc old";
    }

    auto pred =
        [this,flush,evict_age](const cybozu::hash_key& k, object& obj) ->bool {
        if( flush && (! obj.locked()) ) {
            if( ! m_slaves.empty() )
                repl_delete(m_slaves, k);
            return true;
        }
        if( evict_age > 0 && obj.age() >= evict_age && (! obj.locked()) ) {
            ++ m_last_evictions;
            if( ! m_slaves.empty() )
                repl_delete(m_slaves, k);
            return true;
        }
        if( obj.expired() ) {
            ++ m_last_expirations;
            if( ! m_slaves.empty() )
                repl_delete(m_slaves, k);
            return true;
        }

        obj.survive(m_flushers);
        if( ++m_objects_in_bucket == 2 )
            ++ m_conflicts;
        ++ m_objects;
        std::size_t size = obj.size();
        if( size < 1024 ) {
            ++ m_objects_under_1k;
        } else if( size < 4096 ) {
            ++ m_objects_under_4k;
        } else if( size < (16 <<10) ) {
            ++ m_objects_under_16k;
        } else if( size < (64 <<10) ) {
            ++ m_objects_under_64k;
        } else if( size < (256 <<10) ) {
            ++ m_objects_under_256k;
        } else if( size < (1 <<20) ) {
            ++ m_objects_under_1m;
        } else if( size < (4 <<20) ) {
            ++ m_objects_under_4m;
        } else {
            ++ m_objects_huge;
        }
        m_used_memory += sizeof(cybozu::hash_key) + k.length() + sizeof(object);
        if( g_config.heap_data_limit() >= obj.size() )
            m_used_memory += obj.size();
        m_oldest_age = std::max(m_oldest_age, obj.age());
        m_largest_object_size = std::max(m_largest_object_size, obj.size());
        if( ! m_new_slaves.empty() )
            repl_object(m_new_slaves, k, obj, false);
        return false;
    };

    // Putting the thread to sleep tens of microseconds with each loop is desired, but due to the precision of the timer,
    // it's not appropriate to sleep with each loop. The `initial_repl_sleep_delay_usec` is accumulated until it
    // exceeds 10000 microseconds (10 milliseconds), and then the thread is put to sleep all at once when this limit is exceeded.
    constexpr std::uint64_t SLEEP_THRESHOLD = 10000;
    std::uint64_t sleep_sum = 0;

    for( auto it = m_hash.begin(); it != m_hash.end(); ++it ) {
        m_objects_in_bucket = 0;
        it->gc(pred);
        m_flushers.clear();

        if( ! m_new_slaves.empty() ) {
            sleep_sum += g_config.initial_repl_sleep_delay_usec();
            if( sleep_sum >= SLEEP_THRESHOLD ) {
                std::this_thread::sleep_for(
                    std::chrono::microseconds(sleep_sum));
                sleep_sum = 0;
            }
        }
    }

    if( flush )
        g_stats.flush_time.store(0);
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x38, %rsp
movq %rdi, %rbx
leaq 0x23c0e(%rip), %r15     # 0x46ec0
movq 0xc0(%r15), %r14
testq %r14, %r14
je 0x232e3
movq $0x0, 0x30(%rsp)
xorl %edi, %edi
callq 0x7490
movb $0x1, %cl
movl %ecx, 0xc(%rsp)
movb $0x1, %cl
movl %ecx, 0x8(%rsp)
cmpq %r14, %rax
jge 0x233d7
movq 0x28(%r15), %rax
leaq 0x238d2(%rip), %rcx     # 0x46bc0
movl $0x0, 0xc(%rsp)
movl $0x0, 0x8(%rsp)
movl $0x0, %edx
movq %rdx, 0x30(%rsp)
cmpq 0xe8(%rcx), %rax
jbe 0x233d7
movl 0x38(%r15), %esi
movl $0xe10, %eax            # imm = 0xE10
xorl %edx, %edx
divl 0x108(%rcx)
leal 0x2(,%rax,2), %ecx
incl %eax
movl %esi, %edx
shrl %edx
cmpl $0x1, %edx
adcl $0x0, %edx
movl %esi, %edi
subl %eax, %edi
cmpl %ecx, %esi
cmovbl %edx, %edi
movq %rdi, 0x30(%rsp)
leaq 0x2373a(%rip), %rax     # 0x46a88
movl (%rax), %eax
xorl %esi, %esi
testl %eax, %eax
setg %sil
leaq 0x1124c(%rip), %rdx     # 0x345ab
leaq 0x10(%rsp), %r14
movq %r14, %rdi
callq 0x96e6
movb (%r14), %al
cmpb $0x1, %al
jne 0x2338d
movq 0x18(%rsp), %rdi
leaq 0x1387a(%rip), %rsi     # 0x36bf9
movl $0x13, %edx
callq 0x7570
movb 0x10(%rsp), %al
testb $0x1, %al
je 0x233a3
movq 0x18(%rsp), %rdi
movl 0x30(%rsp), %esi
callq 0x7330
movb 0x10(%rsp), %al
testb $0x1, %al
je 0x233bd
movq 0x18(%rsp), %rdi
leaq 0x1385a(%rip), %rsi     # 0x36c0d
movl $0x7, %edx
callq 0x7570
leaq 0x10(%rsp), %rdi
callq 0x8f4e
movl $0x0, 0xc(%rsp)
movl $0x0, 0x8(%rsp)
movq 0x10(%rbx), %rax
movq 0x8(%rax), %r14
cmpq 0x10(%rax), %r14
je 0x23511
xorl %r13d, %r13d
leaq 0x10(%rsp), %r15
movl $0x0, 0x90(%rbx)
movq $0x0, 0x18(%rsp)
movq %rbx, 0x10(%rsp)
movl 0xc(%rsp), %eax
movb %al, 0x18(%rsp)
movq 0x30(%rsp), %rax
movl %eax, 0x1c(%rsp)
leaq 0x153(%rip), %rax       # 0x23574
movq %rax, 0x28(%rsp)
leaq 0x33b(%rip), %rax       # 0x23768
movq %rax, 0x20(%rsp)
movq %r14, %rdi
movq %r15, %rsi
callq 0x237c4
movq 0x20(%rsp), %rax
testq %rax, %rax
je 0x23454
movq %r15, %rdi
movq %r15, %rsi
movl $0x3, %edx
callq *%rax
movq 0x98(%rbx), %rbp
movq 0xa0(%rbx), %r12
cmpq %rbp, %r12
je 0x2348d
movq %r13, %r15
movq %rbp, %r13
movq %r13, %rdi
callq 0x181b4
addq $0x4, %r13
cmpq %r12, %r13
jne 0x2346d
movq %rbp, 0xa0(%rbx)
movq %r15, %r13
leaq 0x10(%rsp), %r15
movq 0x30(%rbx), %rax
cmpq 0x38(%rbx), %rax
je 0x234ff
leaq 0x23722(%rip), %rax     # 0x46bc0
addq 0xf8(%rax), %r13
cmpq $0x2710, %r13           # imm = 0x2710
jb 0x234ff
testq %r13, %r13
jle 0x234fc
movq %r13, %rax
movabsq $0x431bde82d7b634db, %rcx # imm = 0x431BDE82D7B634DB
mulq %rcx
shrq $0x12, %rdx
imulq $-0xf4240, %rdx, %rax   # imm = 0xFFF0BDC0
addq %r13, %rax
imulq $0x3e8, %rax, %rax      # imm = 0x3E8
movq %rdx, 0x10(%rsp)
movq %rax, 0x18(%rsp)
movq %r15, %rdi
movq %r15, %rsi
callq 0x7110
cmpl $-0x1, %eax
jne 0x234fc
callq 0x7040
cmpl $0x4, (%rax)
je 0x234e2
xorl %r13d, %r13d
addq $0x30, %r14
movq 0x10(%rbx), %rax
cmpq 0x10(%rax), %r14
jne 0x233f1
cmpb $0x0, 0x8(%rsp)
je 0x23528
xorl %eax, %eax
leaq 0x2399f(%rip), %rcx     # 0x46ec0
xchgq %rax, 0xc0(%rcx)
addq $0x38, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %rax, %rbx
leaq 0x10(%rsp), %rdi
callq 0x8f4e
jmp 0x23564
jmp 0x2356c
movq %rax, %rbx
movq 0x20(%rsp), %rax
testq %rax, %rax
je 0x23564
leaq 0x10(%rsp), %rdi
movq %rdi, %rsi
movl $0x3, %edx
callq *%rax
movq %rbx, %rdi
callq 0x79a0
movq %rax, %rdi
callq 0x8f80