libbitcoin/libbitcoin-database

Optimize memory_map::resize using upgrade lock.

evoskuil opened this issue · 1 comments

The remap allocator starts with a unique lock and downgrades to shared lock. In the vast majority of cases there is no need for a unique lock. It is only require when size exceeds file_size_. Otherwise writes with sufficient file space are needlessly blocking reads.

memory_ptr memory_map::reserve(size_t size, size_t expansion)
{
    // Internally preventing resize during close is not possible because of
    // cross-file integrity. So we must coalesce all threads before closing.

    // Critical Section (internal)
    ///////////////////////////////////////////////////////////////////////////
    const auto memory = REMAP_ALLOCATOR(mutex_);

    // The store should only have been closed after all threads terminated.
    if (closed_)
        throw std::runtime_error("Resize failure, store already closed.");

    if (size > file_size_)
    {
        // TODO: manage overflow (requires ceiling_multiply).
        // Expansion is an integral number that represents a real number factor.
        const size_t target = size * ((expansion + 100.0) / 100.0);

        if (!truncate_mapped(target))
        {
            handle_error("resize", filename_);
            throw std::runtime_error("Resize failure, disk space may be low.");
        }
    }

    logical_size_ = size;
    REMAP_DOWNGRADE(memory, data_);

    return memory;
    ///////////////////////////////////////////////////////////////////////////
}

Resolved.