diff --git a/builds/cmake/install-cmake.sh b/builds/cmake/install-cmake.sh
index 31eb60046..54f9b3769 100755
--- a/builds/cmake/install-cmake.sh
+++ b/builds/cmake/install-cmake.sh
@@ -446,21 +446,23 @@ main()
UltrafastSecp256k1_FLAGS=()
UltrafastSecp256k1_OPTIONS=(
- "-DSECP256K1_BUILD_TESTS=OFF"
- "-DSECP256K1_BUILD_BENCH=OFF"
- "-DSECP256K1_BUILD_EXAMPLES=OFF"
- "-DSECP256K1_BUILD_JAVA=OFF"
- "-DUFSECP_BUILD_SHARED=OFF"
"-DSECP256K1_BUILD_CABI=ON"
"-DSECP256K1_BUILD_CPU=ON"
"-DSECP256K1_BUILD_SHIM=ON"
+ "-DSECP256K1_USE_ULTRAFAST=ON"
"-DSECP256K1_BUILD_CUDA=ON"
"-DSECP256K1_BUILD_ROCM=ON"
"-DSECP256K1_BUILD_OPENCL=ON"
"-DSECP256K1_BUILD_METAL=ON"
+ "-DSECP256K1_BUILD_BENCH=OFF"
+ "-DSECP256K1_BUILD_EXAMPLES=OFF"
+ "-DSECP256K1_BUILD_JAVA=OFF"
+ "-DSECP256K1_BUILD_TESTS=OFF"
+ "-DSECP256K1_SHIM_BUILD_SHARED=OFF"
+ "-DUFSECP_BUILD_SHARED=OFF"
"-DSECP256K1_INSTALL=ON"
- "-DSECP256K1_INSTALL_PKGCONFIG=ON"
- "-DSECP256K1_USE_ULTRAFAST=ON")
+ "-DSECP256K1_SHIM_INSTALL=ON"
+ "-DSECP256K1_INSTALL_PKGCONFIG=ON")
libbitcoin_system_FLAGS=()
diff --git a/builds/cmake/install-presets.sh b/builds/cmake/install-presets.sh
index a16a2dbc5..700ec5c99 100755
--- a/builds/cmake/install-presets.sh
+++ b/builds/cmake/install-presets.sh
@@ -462,21 +462,23 @@ main()
UltrafastSecp256k1_FLAGS=()
UltrafastSecp256k1_OPTIONS=(
- "-DSECP256K1_BUILD_TESTS=OFF"
- "-DSECP256K1_BUILD_BENCH=OFF"
- "-DSECP256K1_BUILD_EXAMPLES=OFF"
- "-DSECP256K1_BUILD_JAVA=OFF"
- "-DUFSECP_BUILD_SHARED=OFF"
"-DSECP256K1_BUILD_CABI=ON"
"-DSECP256K1_BUILD_CPU=ON"
"-DSECP256K1_BUILD_SHIM=ON"
+ "-DSECP256K1_USE_ULTRAFAST=ON"
"-DSECP256K1_BUILD_CUDA=ON"
"-DSECP256K1_BUILD_ROCM=ON"
"-DSECP256K1_BUILD_OPENCL=ON"
"-DSECP256K1_BUILD_METAL=ON"
+ "-DSECP256K1_BUILD_BENCH=OFF"
+ "-DSECP256K1_BUILD_EXAMPLES=OFF"
+ "-DSECP256K1_BUILD_JAVA=OFF"
+ "-DSECP256K1_BUILD_TESTS=OFF"
+ "-DSECP256K1_SHIM_BUILD_SHARED=OFF"
+ "-DUFSECP_BUILD_SHARED=OFF"
"-DSECP256K1_INSTALL=ON"
- "-DSECP256K1_INSTALL_PKGCONFIG=ON"
- "-DSECP256K1_USE_ULTRAFAST=ON")
+ "-DSECP256K1_SHIM_INSTALL=ON"
+ "-DSECP256K1_INSTALL_PKGCONFIG=ON")
libbitcoin_system_FLAGS=()
diff --git a/builds/gnu/Makefile.am b/builds/gnu/Makefile.am
index 066f222b7..779dd0c99 100644
--- a/builds/gnu/Makefile.am
+++ b/builds/gnu/Makefile.am
@@ -91,7 +91,6 @@ include_bitcoin_database_impl_memorydir = \
${includedir}/bitcoin/database/impl/memory
include_bitcoin_database_impl_memory_HEADERS = \
- ${srcdir}/../../include/bitcoin/database/impl/memory/accessor.ipp \
${srcdir}/../../include/bitcoin/database/impl/memory/mmap.ipp \
${srcdir}/../../include/bitcoin/database/impl/memory/mmap_dispatch.ipp \
${srcdir}/../../include/bitcoin/database/impl/memory/mmap_private.ipp \
@@ -231,7 +230,6 @@ include_bitcoin_database_memory_interfacesdir = \
${includedir}/bitcoin/database/memory/interfaces
include_bitcoin_database_memory_interfaces_HEADERS = \
- ${srcdir}/../../include/bitcoin/database/memory/interfaces/memory.hpp \
${srcdir}/../../include/bitcoin/database/memory/interfaces/storage.hpp
include_bitcoin_database_primitivesdir = \
diff --git a/builds/gnu/install-gnu.sh b/builds/gnu/install-gnu.sh
index 1a67860ee..149ed7be1 100755
--- a/builds/gnu/install-gnu.sh
+++ b/builds/gnu/install-gnu.sh
@@ -474,21 +474,23 @@ main()
UltrafastSecp256k1_FLAGS=()
UltrafastSecp256k1_OPTIONS=(
- "-DSECP256K1_BUILD_TESTS=OFF"
- "-DSECP256K1_BUILD_BENCH=OFF"
- "-DSECP256K1_BUILD_EXAMPLES=OFF"
- "-DSECP256K1_BUILD_JAVA=OFF"
- "-DUFSECP_BUILD_SHARED=OFF"
"-DSECP256K1_BUILD_CABI=ON"
"-DSECP256K1_BUILD_CPU=ON"
"-DSECP256K1_BUILD_SHIM=ON"
+ "-DSECP256K1_USE_ULTRAFAST=ON"
"-DSECP256K1_BUILD_CUDA=ON"
"-DSECP256K1_BUILD_ROCM=ON"
"-DSECP256K1_BUILD_OPENCL=ON"
"-DSECP256K1_BUILD_METAL=ON"
+ "-DSECP256K1_BUILD_BENCH=OFF"
+ "-DSECP256K1_BUILD_EXAMPLES=OFF"
+ "-DSECP256K1_BUILD_JAVA=OFF"
+ "-DSECP256K1_BUILD_TESTS=OFF"
+ "-DSECP256K1_SHIM_BUILD_SHARED=OFF"
+ "-DUFSECP_BUILD_SHARED=OFF"
"-DSECP256K1_INSTALL=ON"
- "-DSECP256K1_INSTALL_PKGCONFIG=ON"
- "-DSECP256K1_USE_ULTRAFAST=ON")
+ "-DSECP256K1_SHIM_INSTALL=ON"
+ "-DSECP256K1_INSTALL_PKGCONFIG=ON")
libbitcoin_system_FLAGS=()
diff --git a/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj b/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj
index 975320042..efedb59c9 100644
--- a/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj
+++ b/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj
@@ -153,7 +153,6 @@
-
@@ -222,7 +221,6 @@
-
diff --git a/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj.filters b/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj.filters
index e6d4b5e27..0d8fcc5f1 100644
--- a/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj.filters
+++ b/builds/msvc/vs2022/libbitcoin-database/libbitcoin-database.vcxproj.filters
@@ -176,9 +176,6 @@
include\bitcoin\database\memory
-
- include\bitcoin\database\memory\interfaces
-
include\bitcoin\database\memory\interfaces
@@ -379,9 +376,6 @@
-
- include\bitcoin\database\impl\memory
-
include\bitcoin\database\impl\memory
diff --git a/builds/msvc/vs2026/libbitcoin-database/libbitcoin-database.vcxproj b/builds/msvc/vs2026/libbitcoin-database/libbitcoin-database.vcxproj
index 15d03af47..3cba41c76 100644
--- a/builds/msvc/vs2026/libbitcoin-database/libbitcoin-database.vcxproj
+++ b/builds/msvc/vs2026/libbitcoin-database/libbitcoin-database.vcxproj
@@ -153,7 +153,6 @@
-
@@ -222,7 +221,6 @@
-
diff --git a/builds/msvc/vs2026/libbitcoin-database/libbitcoin-database.vcxproj.filters b/builds/msvc/vs2026/libbitcoin-database/libbitcoin-database.vcxproj.filters
index e6d4b5e27..0d8fcc5f1 100644
--- a/builds/msvc/vs2026/libbitcoin-database/libbitcoin-database.vcxproj.filters
+++ b/builds/msvc/vs2026/libbitcoin-database/libbitcoin-database.vcxproj.filters
@@ -176,9 +176,6 @@
include\bitcoin\database\memory
-
- include\bitcoin\database\memory\interfaces
-
include\bitcoin\database\memory\interfaces
@@ -379,9 +376,6 @@
-
- include\bitcoin\database\impl\memory
-
include\bitcoin\database\impl\memory
diff --git a/include/bitcoin/database.hpp b/include/bitcoin/database.hpp
index 8aa84be17..2989b4496 100644
--- a/include/bitcoin/database.hpp
+++ b/include/bitcoin/database.hpp
@@ -38,7 +38,6 @@
#include
#include
#include
-#include
#include
#include
#include
diff --git a/include/bitcoin/database/impl/memory/accessor.ipp b/include/bitcoin/database/impl/memory/accessor.ipp
deleted file mode 100644
index ddf104746..000000000
--- a/include/bitcoin/database/impl/memory/accessor.ipp
+++ /dev/null
@@ -1,96 +0,0 @@
-/**
- * Copyright (c) 2011-2026 libbitcoin developers (see AUTHORS)
- *
- * This file is part of libbitcoin.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-#ifndef LIBBITCOIN_DATABASE_MEMORY_ACCESSOR_IPP
-#define LIBBITCOIN_DATABASE_MEMORY_ACCESSOR_IPP
-
-////#include
-#include
-
-// Zero/negative size is allowed (automatically handled by bc streams).
-
-namespace libbitcoin {
-namespace database {
-
-BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
-
-TEMPLATE
-inline CLASS::accessor(Mutex& mutex) NOEXCEPT
- : shared_lock_(mutex)
-{
-}
-
-TEMPLATE
-inline void CLASS::assign(uint8_t* begin, uint8_t* end) NOEXCEPT
-{
- begin_ = begin;
- end_ = end;
- ////BC_ASSERT(!system::is_negative(size()));
-}
-
-TEMPLATE
-inline uint8_t* CLASS::offset(size_t bytes) const NOEXCEPT
-{
- if (system::is_greater(bytes, size()))
- return nullptr;
-
- BC_PUSH_WARNING(NO_POINTER_ARITHMETIC)
- return begin_ + bytes;
- BC_POP_WARNING()
- ////return std::next(begin_, bytes);
-}
-
-TEMPLATE
-inline ptrdiff_t CLASS::size() const NOEXCEPT
-{
- BC_PUSH_WARNING(NO_POINTER_ARITHMETIC)
- return system::possible_narrow_and_sign_cast(end_ - begin_);
- BC_POP_WARNING()
- ////return std::distance(begin_, end_);
-}
-
-TEMPLATE
-inline uint8_t* CLASS::data() const NOEXCEPT
-{
- return begin();
-}
-
-TEMPLATE
-inline CLASS::operator system::data_slab() const NOEXCEPT
-{
- return { begin(), end() };
-};
-
-TEMPLATE
-inline uint8_t* CLASS::begin() const NOEXCEPT
-{
- return begin_;
-}
-
-TEMPLATE
-inline uint8_t* CLASS::end() const NOEXCEPT
-{
- return end_;
-}
-
-BC_POP_WARNING()
-
-} // namespace database
-} // namespace libbitcoin
-
-#endif
diff --git a/include/bitcoin/database/impl/memory/mmap_dispatch.ipp b/include/bitcoin/database/impl/memory/mmap_dispatch.ipp
index efbbdeec9..f2ca4b458 100644
--- a/include/bitcoin/database/impl/memory/mmap_dispatch.ipp
+++ b/include/bitcoin/database/impl/memory/mmap_dispatch.ipp
@@ -33,30 +33,6 @@ namespace database {
// Dispatch.
// ----------------------------------------------------------------------------
-TEMPLATE
-memory_ptr CLASS::get_capacity(size_t offset) const NOEXCEPT
-{
- const auto allocated = to_width(capacity());
-
- const auto ptr = std::make_shared(remap_mutex_);
- if (!loaded_ || is_null(ptr))
- return {};
-
- auto data = memory_map_.front();
- ptr->assign(std::next(data, offset), std::next(data, allocated));
- return ptr;
-}
-
-TEMPLATE
-memory::iterator CLASS::get_raw(size_t offset) const NOEXCEPT
-{
- // Pointer otherwise unguarded, not remap safe (use for fixed table heads).
- if (offset > to_width(size()))
- return {};
-
- return std::next(memory_map_.front(), offset);
-}
-
TEMPLATE
memory_ptr CLASS::set(size_t offset, size_t size, uint8_t backfill) NOEXCEPT
{
@@ -93,6 +69,37 @@ memory_ptr CLASS::set(size_t offset, size_t size, uint8_t backfill) NOEXCEPT
return get(offset);
}
+TEMPLATE
+memory_ptr CLASS::get_capacity(size_t offset) const NOEXCEPT
+{
+ const auto allocated = to_width(capacity());
+
+ const auto ptr = std::make_shared(remap_mutex_);
+ if (!loaded_ || is_null(ptr))
+ return {};
+
+ auto data = memory_map_.front();
+ ptr->assign(std::next(data, offset), std::next(data, allocated));
+ return ptr;
+}
+
+TEMPLATE
+memory::iterator CLASS::get_raw(size_t offset) const NOEXCEPT
+{
+ // Pointer otherwise unguarded, not remap safe (use for fixed table heads).
+ return get_at_raw(zero, offset);
+}
+
+TEMPLATE
+memory::iterator CLASS::get_at_raw(size_t column, size_t offset) const NOEXCEPT
+{
+ // get_raw not used for variably-sized heads, so should always be bounded.
+ BC_ASSERT(offset < (size() * widths.at(column)));
+
+ // Pointer otherwise unguarded, not remap safe (use for nopmaps columns).
+ return std::next(memory_map_.at(column), offset);
+}
+
TEMPLATE
memory_ptr CLASS::get(size_t offset) const NOEXCEPT
{
@@ -109,7 +116,7 @@ memory_ptr CLASS::get_at(size_t column, size_t offset) const NOEXCEPT
const auto allocated = size() * widths.at(column);
// Takes a shared lock on remap_mutex_ until destruct, blocking remap.
- const auto ptr = std::make_shared(remap_mutex_);
+ const auto ptr = std::make_shared(remap_mutex_);
// loaded_ update is precluded by above lock, making this read atomic.
if (!loaded_ || is_null(ptr))
@@ -121,6 +128,34 @@ memory_ptr CLASS::get_at(size_t column, size_t offset) const NOEXCEPT
return ptr;
}
+TEMPLATE
+memory CLASS::get1(size_t offset) const NOEXCEPT
+{
+ return get_at1(zero, offset);
+}
+
+TEMPLATE
+memory CLASS::get_at1(size_t column, size_t offset) const NOEXCEPT
+{
+ if (column >= columns)
+ return {};
+
+ // Obtaining size before access prevents mutual mutex wait (deadlock).
+ const auto allocated = size() * widths.at(column);
+
+ // Takes a shared lock on remap_mutex_ until destruct, blocking remap.
+ memory out{ remap_mutex_ };
+
+ // loaded_ update is precluded by above lock, making this read atomic.
+ if (!loaded_)
+ return {};
+
+ // With offset > size the assignment is negative (stream is exhausted).
+ auto data = memory_map_.at(column);
+ out.assign(std::next(data, offset), std::next(data, allocated));
+ return out;
+}
+
} // namespace database
} // namespace libbitcoin
diff --git a/include/bitcoin/database/impl/primitives/manager.ipp b/include/bitcoin/database/impl/primitives/manager.ipp
index 834b6a4e1..a1a0b0cba 100644
--- a/include/bitcoin/database/impl/primitives/manager.ipp
+++ b/include/bitcoin/database/impl/primitives/manager.ipp
@@ -34,12 +34,22 @@ inline memory_ptr CLASS::get() const NOEXCEPT
return files_.get_at(Column);
}
+TEMPLATE
+template
+inline memory CLASS::get1() const NOEXCEPT
+{
+ if constexpr (is_one(columns))
+ return files_.get1();
+ else
+ return files_.get_at1(Column);
+}
+
TEMPLATE
template
inline memory_ptr CLASS::get(const Link& link) const NOEXCEPT
{
if (link.is_terminal())
- return nullptr;
+ return {};
const auto position = link_to_position(link);
@@ -50,12 +60,44 @@ inline memory_ptr CLASS::get(const Link& link) const NOEXCEPT
return files_.get_at(Column, position);
}
+TEMPLATE
+template
+inline memory CLASS::get1(const Link& link) const NOEXCEPT
+{
+ if (link.is_terminal())
+ return {};
+
+ const auto position = link_to_position(link);
+
+ // memory.size() may be negative (stream treats as exhausted).
+ if constexpr (is_one(columns))
+ return files_.get1(position);
+ else
+ return files_.get_at1(Column, position);
+}
+
+TEMPLATE
+template
+inline memory::iterator CLASS::get_raw1(const Link& link) const NOEXCEPT
+{
+ if (link.is_terminal())
+ return {};
+
+ const auto position = link_to_position(link);
+
+ // memory.size() may be negative (stream treats as exhausted).
+ if constexpr (is_one(columns))
+ return files_.get_raw(position);
+ else
+ return files_.get_at_raw(Column, position);
+}
+
TEMPLATE
template >
inline memory_ptr CLASS::get_capacity(const Link& link) const NOEXCEPT
{
if (link.is_terminal())
- return nullptr;
+ return {};
return files_.get_capacity(link_to_position(link));
}
diff --git a/include/bitcoin/database/impl/primitives/nomaps.ipp b/include/bitcoin/database/impl/primitives/nomaps.ipp
index a649e461a..39f59c2c9 100644
--- a/include/bitcoin/database/impl/primitives/nomaps.ipp
+++ b/include/bitcoin/database/impl/primitives/nomaps.ipp
@@ -128,34 +128,39 @@ code CLASS::reload() NOEXCEPT
// query interface
// ----------------------------------------------------------------------------
+TEMPLATE
+memory CLASS::guard() const NOEXCEPT
+{
+ return get_memory();
+}
+
TEMPLATE
template
-memory_ptr CLASS::get_memory() const NOEXCEPT
+memory CLASS::get_memory() const NOEXCEPT
{
- return manager_.template get();
+ return manager_.template get1();
}
// static
TEMPLATE
template
-bool CLASS::get(const memory_ptr& ptr, const Link& link,
- Element& element) NOEXCEPT
+bool CLASS::get(const memory& ptr, const Link& link, Element& element) NOEXCEPT
{
- static_assert(Element::size == width, "element size != width");
- using namespace system;
+ static_assert(Element::size == width);
if (!ptr || link.is_terminal())
return false;
+ using namespace system;
const auto start = body::template link_to_position(link);
if (is_limited(start))
return false;
- const auto size = ptr->size();
+ const auto size = ptr.size();
const auto position = possible_narrow_and_sign_cast(start);
if (position >= size)
return false;
- const auto offset = ptr->offset(start);
+ const auto offset = ptr.offset(start);
if (is_null(offset))
return false;
@@ -166,6 +171,7 @@ bool CLASS::get(const memory_ptr& ptr, const Link& link,
return element.from_data(source);
}
+// TODO: gets are not optimized for shared remap guard.
TEMPLATE
template
bool CLASS::get(const Link& link, Element& element) const NOEXCEPT
@@ -173,25 +179,26 @@ bool CLASS::get(const Link& link, Element& element) const NOEXCEPT
return get(get_memory(), link, element);
}
+// TODO: puts are optimized for shared remap guard (required).
TEMPLATE
template
bool CLASS::put(const Link& link, const Element& element) NOEXCEPT
{
- using namespace system;
- const auto ptr = manager_.template get(link);
+ const auto ptr = manager_.template get_raw1(link);
return put(ptr, element);
}
+// protected (unguarded memory access)
TEMPLATE
template
-bool CLASS::put(const memory_ptr& ptr, const Element& element) NOEXCEPT
+bool CLASS::put(memory::iterator it, const Element& element) NOEXCEPT
{
- static_assert(Element::size == width, "element size != width");
- using namespace system;
- if (!ptr)
+ static_assert(Element::size == width);
+ if (is_null(it))
return false;
- iostream stream{ *ptr };
+ using namespace system;
+ iostream stream{ it, system::maximum };
flipper sink{ stream };
BC_DEBUG_ONLY(sink.set_limit(width * element.count());)
diff --git a/include/bitcoin/database/impl/query/batch/ecdsa.ipp b/include/bitcoin/database/impl/query/batch/ecdsa.ipp
index d4d0f3087..be2f522fb 100644
--- a/include/bitcoin/database/impl/query/batch/ecdsa.ipp
+++ b/include/bitcoin/database/impl/query/batch/ecdsa.ipp
@@ -41,10 +41,10 @@ bool CLASS::verify_ecdsa_signatures(const stopper& cancel,
using signature_t = const table::ecdsa_signature::span;
using namespace system;
- const auto correlate = pointer_cast(correlate_ptr->data());
- const auto digest = pointer_cast(digest_ptr->data());
- const auto compressed = pointer_cast(compressed_ptr->data());
- const auto signature = pointer_cast(signature_ptr->data());
+ const auto correlate = pointer_cast(correlate_ptr.data());
+ const auto digest = pointer_cast(digest_ptr.data());
+ const auto compressed = pointer_cast(compressed_ptr.data());
+ const auto signature = pointer_cast(signature_ptr.data());
// Shortest column.
const auto count = store_.ecdsa.count();
@@ -91,11 +91,13 @@ bool CLASS::set_signature(const hash_digest& digest,
const auto row = possible_narrow_cast(one);
// Allocate 1 row across all columns.
- // TODO: this could provide a single remap lock for all puts below.
const auto fk = store_.ecdsa.allocate(row);
if (fk.is_terminal())
return false;
+ // Guard against remap (required for nomaps::put(fk)).
+ const auto guard = store_.ecdsa.guard();
+
// Write one value to each column in corresponding positions.
return
store_.ecdsa.correlate.put(fk, correlate_t{ {}, link, id }) &&
@@ -116,23 +118,25 @@ bool CLASS::set_signatures(const hash_digest& digest,
using compressed_t = table::ecdsa_compressed::put_refs;
using signature_t = table::ecdsa_signature::put_refs;
+ using namespace system;
const auto csigs = sigs.size();
const auto ckeys = keys.size();
- const auto count = system::chain::multisig::rows(csigs, ckeys);
+ const auto count = chain::multisig::rows(csigs, ckeys);
// Caller must guard reads, this is writing into hot storage.
// ========================================================================
const auto scope = get_transactor();
- using namespace system;
const auto rows = possible_narrow_cast(count);
// Allocate rows across all columns.
- // TODO: this could provide a single remap lock for all puts below.
const auto fk = store_.ecdsa.allocate(rows);
if (fk.is_terminal())
return false;
+ // Guard against remap (required for nomaps::put(fk)).
+ const auto guard = store_.ecdsa.guard();
+
// Write values to each column in corresponding positions.
return
store_.ecdsa.correlate.put(fk, correlate_t{ {}, count, link, ckeys, csigs, id }) &&
diff --git a/include/bitcoin/database/impl/query/batch/schnorr.ipp b/include/bitcoin/database/impl/query/batch/schnorr.ipp
index 6916cf47c..d8189585a 100644
--- a/include/bitcoin/database/impl/query/batch/schnorr.ipp
+++ b/include/bitcoin/database/impl/query/batch/schnorr.ipp
@@ -40,10 +40,10 @@ bool CLASS::verify_schnorr_signatures(const stopper& cancel,
using signature_t = const table::schnorr_signature::span;
using namespace system;
- const auto correlate = pointer_cast(correlate_ptr->data());
- const auto digest = pointer_cast(digest_ptr->data());
- const auto xonly = pointer_cast(xonly_ptr->data());
- const auto signature = pointer_cast(signature_ptr->data());
+ const auto correlate = pointer_cast(correlate_ptr.data());
+ const auto digest = pointer_cast(digest_ptr.data());
+ const auto xonly = pointer_cast(xonly_ptr.data());
+ const auto signature = pointer_cast(signature_ptr.data());
// Shortest column.
const auto count = store_.schnorr.count();
@@ -89,11 +89,13 @@ bool CLASS::set_signature(const hash_digest& digest, const ec_xonly& point,
const auto row = possible_narrow_cast(one);
// Allocate 1 row across all columns.
- // TODO: this could provide a single remap lock for all puts below.
const auto fk = store_.schnorr.allocate(row);
if (fk.is_terminal())
return false;
+ // Guard against remap (required for nomaps::put(fk)).
+ const auto guard = store_.schnorr.guard();
+
// Write one value to each column in corresponding positions.
return
store_.schnorr.correlate.put(fk, correlate_t{ {}, link }) &&
@@ -131,6 +133,9 @@ bool CLASS::set_signature(const schnorr_link& schnorr_fk,
// ========================================================================
const auto scope = get_transactor();
+ // Guard against remap (required for nomaps::put(fk)).
+ const auto guard = store_.schnorr.guard();
+
return
store_.schnorr.correlate.put(schnorr_fk, correlate_t{ {}, link }) &&
store_.schnorr.digest.put(schnorr_fk, digest_t{ {}, digest }) &&
diff --git a/include/bitcoin/database/impl/query/batch/silent.ipp b/include/bitcoin/database/impl/query/batch/silent.ipp
index 3813db19e..36bab992c 100644
--- a/include/bitcoin/database/impl/query/batch/silent.ipp
+++ b/include/bitcoin/database/impl/query/batch/silent.ipp
@@ -40,9 +40,9 @@ bool CLASS::scan_silent(const stopper& cancel, const ec_secret& scan_key,
using compressed_t = const table::silent_compressed::span;
using namespace system;
- const auto correlate = pointer_cast(correlate_ptr->data());
- const auto prefix = pointer_cast(prefix_ptr->data());
- const auto compressed = pointer_cast(compressed_ptr->data());
+ const auto correlate = pointer_cast(correlate_ptr.data());
+ const auto prefix = pointer_cast(prefix_ptr.data());
+ const auto compressed = pointer_cast(compressed_ptr.data());
// Shortest column.
const auto count = store_.silent.count();
@@ -117,7 +117,10 @@ bool CLASS::set_silent(const tx_link& link,
using prefix_t = table::silent_prefix::put_ref;
using compressed_t = table::silent_compressed::put_ref;
- // TODO: caller must guard reads, this is writing into hot storage.
+ // TODO: Caller must guard reads, this is writing into hot storage. This
+ // TODO: requires caller to chase writers and account for the last contig-
+ // TODO: uously populated row (for searching) and to update subscriptions
+ // TODO: with additional scans as this position increases.
// ========================================================================
const auto scope = get_transactor();
@@ -125,11 +128,13 @@ bool CLASS::set_silent(const tx_link& link,
auto rows = possible_narrow_cast(prefixes.size());
// Allocate rows across all columns.
- // TODO: this could provide a single remap lock for all puts below.
const auto fk = store_.silent.allocate(rows);
if (fk.is_terminal())
return false;
+ // Guard against remap (required for nomaps::put(fk)).
+ const auto guard = store_.silent.guard();
+
// Write values to each column in corresponding positions.
return
store_.silent.correlate.put(fk, correlate_t{ {}, rows, link }) &&
diff --git a/include/bitcoin/database/memory/accessor.hpp b/include/bitcoin/database/memory/accessor.hpp
index 4fe08225a..c4a1cb541 100644
--- a/include/bitcoin/database/memory/accessor.hpp
+++ b/include/bitcoin/database/memory/accessor.hpp
@@ -21,57 +21,109 @@
#include
#include
-#include
namespace libbitcoin {
namespace database {
/// Shared r/w access to a memory buffer, mutex blocks memory remap.
-template
-class accessor
- : public memory
+/// Zero/negative size is allowed (automatically handled by bc streams).
+class accessor final
{
public:
- DELETE_COPY_MOVE_DESTRUCT(accessor);
+ typedef uint8_t value_type;
+ typedef value_type* iterator;
+ typedef const value_type* const_iterator;
+ typedef std::shared_ptr ptr;
+
+ DELETE_COPY(accessor);
+ DEFAULT_MOVE(accessor);
+
+ /// Fault construction, invalid object, no lock taken.
+ inline accessor() NOEXCEPT
+ : shared_lock_{}
+ {
+ }
/// Mutex guards against remap while object in scope.
- inline accessor(Mutex& mutex) NOEXCEPT;
+ inline accessor(std::shared_mutex& mutex) NOEXCEPT
+ : shared_lock_{ mutex }
+ {
+ }
/// Set the buffer, where end is within allocated space.
/// End should be initialized to logical space though that may contract or
/// expand during accessor lifetime. The only guarantee offered by end is
/// that it remains within allocated space and is initially logical space.
- inline void assign(uint8_t* begin, uint8_t* end) NOEXCEPT;
+ inline void assign(uint8_t* begin, uint8_t* end) NOEXCEPT
+ {
+ begin_ = begin;
+ end_ = end;
+ ////BC_ASSERT(!system::is_negative(size()));
+ }
+
+ /// memory interface
+ /// -----------------------------------------------------------------------
+
+ inline operator bool() const NOEXCEPT
+ {
+ return !is_null(begin_);
+ }
/// Return an offset from begin, nullptr if end or past end.
- inline uint8_t* offset(size_t bytes) const NOEXCEPT override;
+ inline uint8_t* offset(size_t bytes) const NOEXCEPT
+ {
+ if (system::is_greater(bytes, size()))
+ return nullptr;
+
+ BC_PUSH_WARNING(NO_POINTER_ARITHMETIC)
+ return begin_ + bytes;
+ BC_POP_WARNING()
+ ////return std::next(begin_, bytes);
+ }
/// The logical buffer size (from begin to end).
- inline ptrdiff_t size() const NOEXCEPT override;
+ inline ptrdiff_t size() const NOEXCEPT
+ {
+ BC_PUSH_WARNING(NO_POINTER_ARITHMETIC)
+ return system::possible_narrow_and_sign_cast(end_ - begin_);
+ BC_POP_WARNING()
+ ////return std::distance(begin_, end_);
+ }
/// Alias for begin.
- inline uint8_t* data() const NOEXCEPT override;
+ inline uint8_t* data() const NOEXCEPT
+ {
+ return begin();
+ }
/// Get logical buffer (guarded against remap only).
- inline operator system::data_slab() const NOEXCEPT override;
- inline uint8_t* begin() const NOEXCEPT override;
- inline uint8_t* end() const NOEXCEPT override;
+ inline operator system::data_slab() const NOEXCEPT
+ {
+ return { begin(), end() };
+ };
+
+ /// Buffer start.
+ inline uint8_t* begin() const NOEXCEPT
+ {
+ return begin_;
+ }
+
+ /// Buffer end.
+ inline uint8_t* end() const NOEXCEPT
+ {
+ return end_;
+ }
private:
uint8_t* begin_{};
uint8_t* end_{};
- std::shared_lock shared_lock_;
+ std::shared_lock shared_lock_;
};
+using memory = accessor;
+using memory_ptr = accessor::ptr;
+
} // namespace database
} // namespace libbitcoin
-#define TEMPLATE template
-#define CLASS accessor
-
-#include
-
-#undef CLASS
-#undef TEMPLATE
-
#endif
diff --git a/include/bitcoin/database/memory/interfaces/memory.hpp b/include/bitcoin/database/memory/interfaces/memory.hpp
deleted file mode 100644
index d033c5c91..000000000
--- a/include/bitcoin/database/memory/interfaces/memory.hpp
+++ /dev/null
@@ -1,57 +0,0 @@
-/**
- * Copyright (c) 2011-2026 libbitcoin developers (see AUTHORS)
- *
- * This file is part of libbitcoin.
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-#ifndef LIBBITCOIN_DATABASE_MEMORY_INTERFACES_MEMORY_HPP
-#define LIBBITCOIN_DATABASE_MEMORY_INTERFACES_MEMORY_HPP
-
-#include
-#include
-
-namespace libbitcoin {
-namespace database {
-
-/// Protected memory access interface.
-class memory
-{
-public:
- typedef uint8_t value_type;
- typedef value_type* iterator;
- typedef const value_type* const_iterator;
- typedef std::shared_ptr ptr;
-
- /// Return an offset from begin, nullptr if end or past end.
- virtual uint8_t* offset(size_t value) const NOEXCEPT = 0;
-
- /// The logical buffer size (from begin to end).
- virtual ptrdiff_t size() const NOEXCEPT = 0;
-
- /// Alias begin.
- virtual uint8_t* data() const NOEXCEPT = 0;
-
- /// Get logical buffer.
- virtual operator system::data_slab() const NOEXCEPT = 0;
- virtual uint8_t* begin() const NOEXCEPT = 0;
- virtual uint8_t* end() const NOEXCEPT = 0;
-};
-
-typedef memory::ptr memory_ptr;
-
-} // namespace database
-} // namespace libbitcoin
-
-#endif
diff --git a/include/bitcoin/database/memory/interfaces/storage.hpp b/include/bitcoin/database/memory/interfaces/storage.hpp
index e190c1ebb..7c7343dad 100644
--- a/include/bitcoin/database/memory/interfaces/storage.hpp
+++ b/include/bitcoin/database/memory/interfaces/storage.hpp
@@ -21,7 +21,7 @@
#include
#include
-#include
+#include
namespace libbitcoin {
namespace database {
@@ -88,6 +88,10 @@ class storage
/// Increase logical by specified rows/bytes, return row of first (or eof).
virtual size_t allocate(size_t count) NOEXCEPT = 0;
+ /// Get remap-protected r/w access to offset (or null) allocated to size.
+ virtual memory_ptr set(size_t offset, size_t size,
+ uint8_t backfill) NOEXCEPT = 0;
+
/// Get remap-protected r/w access to start/offset of memory map (or null).
/// Pointer is constrained to starting write within full capacity.
virtual memory_ptr get_capacity(size_t offset=zero) const NOEXCEPT = 0;
@@ -96,9 +100,10 @@ class storage
/// Pointer is constrained to starting write within full capacity.
virtual memory::iterator get_raw(size_t offset=zero) const NOEXCEPT = 0;
- /// Get remap-protected r/w access to offset (or null) allocated to size.
- virtual memory_ptr set(size_t offset, size_t size,
- uint8_t backfill) NOEXCEPT = 0;
+ /// Get unprotected r/w access to start/offset of memory map (or null).
+ /// Pointer is constrained to starting write within full capacity.
+ virtual memory::iterator get_at_raw(size_t column,
+ size_t offset=zero) const NOEXCEPT = 0;
/// Get remap-protected r/w access to start/offset of memory map (or null).
/// Pointer is constrained to starting write within logical allocation.
@@ -108,6 +113,15 @@ class storage
/// Pointer is constrained to starting write within logical allocation.
virtual memory_ptr get_at(size_t column,
size_t offset=zero) const NOEXCEPT = 0;
+
+ /// Get remap-protected r/w access to start/offset of memory map (or null).
+ /// Pointer is constrained to starting write within logical allocation.
+ virtual memory get1(size_t offset=zero) const NOEXCEPT = 0;
+
+ /// Same as get() but within specified column (or null for invalid column).
+ /// Pointer is constrained to starting write within logical allocation.
+ virtual memory get_at1(size_t column,
+ size_t offset=zero) const NOEXCEPT = 0;
};
} // namespace database
diff --git a/include/bitcoin/database/memory/memory.hpp b/include/bitcoin/database/memory/memory.hpp
index 0d8002f60..8742fba66 100644
--- a/include/bitcoin/database/memory/memory.hpp
+++ b/include/bitcoin/database/memory/memory.hpp
@@ -21,7 +21,6 @@
#include
#include
-#include
#include
#include
#include
diff --git a/include/bitcoin/database/memory/mmap.hpp b/include/bitcoin/database/memory/mmap.hpp
index c425b981a..b78d6ec33 100644
--- a/include/bitcoin/database/memory/mmap.hpp
+++ b/include/bitcoin/database/memory/mmap.hpp
@@ -27,7 +27,6 @@
#include
#include
#include
-#include
#include
namespace libbitcoin {
@@ -132,15 +131,19 @@ class mmap
/// Increase logical by specified rows/bytes, return row of first (or eof).
size_t allocate(size_t count) NOEXCEPT override;
+ /// Remap-protected r/w access to offset (or null) allocated to size.
+ memory_ptr set(size_t offset, size_t size,
+ uint8_t backfill) NOEXCEPT override;
+
/// Remap-protected r/w access to start/offset (or null), within capacity.
memory_ptr get_capacity(size_t offset=zero) const NOEXCEPT override;
/// Unprotected r/w access to start/offset (or null), within logical.
memory::iterator get_raw(size_t offset=zero) const NOEXCEPT override;
- /// Remap-protected r/w access to offset (or null) allocated to size.
- memory_ptr set(size_t offset, size_t size,
- uint8_t backfill) NOEXCEPT override;
+ /// Unprotected r/w access to start/offset (or null), within logical.
+ memory::iterator get_at_raw(size_t column,
+ size_t offset=zero) const NOEXCEPT override;
/// Remap-protected r/w access to start/offset (or null), within logical.
memory_ptr get(size_t offset=zero) const NOEXCEPT override;
@@ -149,6 +152,12 @@ class mmap
memory_ptr get_at(size_t column,
size_t offset=zero) const NOEXCEPT override;
+ /// Remap-protected r/w access to start/offset (or null), within logical.
+ memory get1(size_t offset=zero) const NOEXCEPT override;
+
+ /// Same as get() but within specified column (or null for invalid column).
+ memory get_at1(size_t column, size_t offset=zero) const NOEXCEPT override;
+
protected:
template
static constexpr size_t to_width(size_t offset) NOEXCEPT
@@ -174,7 +183,6 @@ class mmap
private:
static constexpr auto fail = -1;
- using access = accessor;
using sequence = std::make_index_sequence;
// mman dispatch, not thread safe.
diff --git a/include/bitcoin/database/memory/reader.hpp b/include/bitcoin/database/memory/reader.hpp
index 97e31caac..351e062dc 100644
--- a/include/bitcoin/database/memory/reader.hpp
+++ b/include/bitcoin/database/memory/reader.hpp
@@ -20,7 +20,7 @@
#define LIBBITCOIN_DATABASE_MEMORY_READER_HPP
#include
-#include
+#include
namespace libbitcoin {
namespace database {
diff --git a/include/bitcoin/database/memory/streamers.hpp b/include/bitcoin/database/memory/streamers.hpp
index f64868937..652a4c01f 100644
--- a/include/bitcoin/database/memory/streamers.hpp
+++ b/include/bitcoin/database/memory/streamers.hpp
@@ -20,7 +20,7 @@
#define LIBBITCOIN_DATABASE_MEMORY_STREAMERS_HPP
#include
-#include
+#include
namespace libbitcoin {
namespace database {
diff --git a/include/bitcoin/database/primitives/column.hpp b/include/bitcoin/database/primitives/column.hpp
index 09b6e777f..748c53987 100644
--- a/include/bitcoin/database/primitives/column.hpp
+++ b/include/bitcoin/database/primitives/column.hpp
@@ -20,6 +20,7 @@
#define LIBBITCOIN_DATABASE_PRIMITIVES_COLUMN_HPP
#include
+#include
namespace libbitcoin {
namespace database {
@@ -36,7 +37,7 @@ class column
{
}
- INLINE memory_ptr get_memory() const NOEXCEPT
+ INLINE memory get_memory() const NOEXCEPT
{
return table_.template get_memory();
}
@@ -48,7 +49,7 @@ class column
}
template
- static INLINE bool get(const memory_ptr& ptr, const link& record,
+ static INLINE bool get(const memory& ptr, const link& record,
Element& element) NOEXCEPT
{
return Table::template get(ptr, record, element);
@@ -61,7 +62,7 @@ class column
}
template
- INLINE bool put(const memory_ptr& ptr, const Element& element) NOEXCEPT
+ INLINE bool put(const memory& ptr, const Element& element) NOEXCEPT
{
return table_.template put(ptr, element);
}
diff --git a/include/bitcoin/database/primitives/manager.hpp b/include/bitcoin/database/primitives/manager.hpp
index 12da24fc1..6f9cbbeb0 100644
--- a/include/bitcoin/database/primitives/manager.hpp
+++ b/include/bitcoin/database/primitives/manager.hpp
@@ -45,11 +45,17 @@ class managers
/// Return memory object for column full map (null only if oom or unloaded).
template
inline memory_ptr get() const NOEXCEPT;
+ template
+ inline memory get1() const NOEXCEPT;
- /// Return memory object for column record at position (null possible).
+ /// Return memory object for column record (null only if oom or unloaded).
/// Pointer is constrained to starting write within logical allocation.
template
inline memory_ptr get(const Link& link) const NOEXCEPT;
+ template
+ inline memory get1(const Link& link) const NOEXCEPT;
+ template
+ inline memory::iterator get_raw1(const Link& link) const NOEXCEPT;
/// Return memory object (limited to AoS) within capacity.
template = true>
diff --git a/include/bitcoin/database/primitives/nomaps.hpp b/include/bitcoin/database/primitives/nomaps.hpp
index 5690f8ce0..f68b2b25f 100644
--- a/include/bitcoin/database/primitives/nomaps.hpp
+++ b/include/bitcoin/database/primitives/nomaps.hpp
@@ -72,30 +72,34 @@ class nomaps
/// Query interface (columnar).
/// -----------------------------------------------------------------------
+ /// Must hold as remap guard across puts().
+ memory guard() const NOEXCEPT;
+
/// Column base ptr for batch processing (holds shared lock on body remap).
template
- memory_ptr get_memory() const NOEXCEPT;
+ memory get_memory() const NOEXCEPT;
/// Get element from column at link using column base ptr (deserialize).
template
- static bool get(const memory_ptr& ptr, const Link& link,
+ static bool get(const memory& ptr, const Link& link,
Element& element) NOEXCEPT;
/// Get element from column at link.
template
bool get(const Link& link, Element& element) const NOEXCEPT;
- /// Put previously allocated element to column at link.
+ /// Put previously allocated element to column at link (guard required).
template
bool put(const Link& link, const Element& element) NOEXCEPT;
- template
- bool put(const memory_ptr& ptr, const Element& element) NOEXCEPT;
protected:
using head = database::nohead;
using body = database::managers,
Columns::width...>;
+ template
+ bool put(memory::iterator it, const Element& element) NOEXCEPT;
+
// Thread safe (index/top/push).
// Not thread safe (create/open/close/backup/restore).
head head_;
diff --git a/test/memory/accessor.cpp b/test/memory/accessor.cpp
index 6293fd30e..4bcfd1fa5 100644
--- a/test/memory/accessor.cpp
+++ b/test/memory/accessor.cpp
@@ -22,10 +22,11 @@ BOOST_AUTO_TEST_SUITE(accessor_tests)
using namespace system;
-BOOST_AUTO_TEST_CASE(accessor__construct_shared_mutex__unassigned__nulls)
+BOOST_AUTO_TEST_CASE(accessor__construct_shared_mutex__unassigned__invalid_nulls)
{
std::shared_mutex mutex;
accessor instance(mutex);
+ BOOST_REQUIRE(!instance);
BOOST_REQUIRE(is_null(instance.data()));
BOOST_REQUIRE(is_null(instance.begin()));
BOOST_REQUIRE(is_null(instance.end()));
@@ -34,7 +35,7 @@ BOOST_AUTO_TEST_CASE(accessor__construct_shared_mutex__unassigned__nulls)
BOOST_AUTO_TEST_CASE(accessor__destruct__shared_lock__released)
{
std::shared_mutex mutex;
- auto access = std::make_shared>(mutex);
+ auto access = std::make_shared(mutex);
BOOST_REQUIRE(!mutex.try_lock());
access.reset();
BOOST_REQUIRE(mutex.try_lock());
diff --git a/test/mocks/chunk_storage.hpp b/test/mocks/chunk_storage.hpp
index b98d4fa53..55a97ce59 100644
--- a/test/mocks/chunk_storage.hpp
+++ b/test/mocks/chunk_storage.hpp
@@ -240,20 +240,6 @@ class chunk_storages
// access
// ------------------------------------------------------------------------
- memory_ptr get_capacity(size_t offset=zero) const NOEXCEPT override
- {
- using namespace system;
- auto& buffer = at(zero);
- const auto ptr = emplace_shared>(map_mutex_);
- ptr->assign(get_raw(offset), std::next(buffer.data(), buffer.size()));
- return ptr;
- }
-
- memory::iterator get_raw(size_t offset=zero) const NOEXCEPT override
- {
- return std::next(at(zero).data(), offset);
- }
-
memory_ptr set(size_t offset, size_t size, uint8_t backfill) NOEXCEPT override
{
{
@@ -275,6 +261,26 @@ class chunk_storages
return get(offset);
}
+ memory_ptr get_capacity(size_t offset=zero) const NOEXCEPT override
+ {
+ using namespace system;
+ auto& buffer = at(zero);
+ const auto ptr = emplace_shared(map_mutex_);
+ ptr->assign(get_raw(offset), std::next(buffer.data(), buffer.size()));
+ return ptr;
+ }
+
+ memory::iterator get_raw(size_t offset=zero) const NOEXCEPT override
+ {
+ return std::next(at(zero).data(), offset);
+ }
+
+ memory::iterator get_at_raw(size_t column,
+ size_t offset=zero) const NOEXCEPT override
+ {
+ return std::next(at(column).data(), offset);
+ }
+
memory_ptr get(size_t offset=zero) const NOEXCEPT override
{
return get_at(zero, offset);
@@ -285,11 +291,26 @@ class chunk_storages
using namespace system;
auto data = at(column).data();
const auto allocated = size() * widths.at(column);
- const auto ptr = emplace_shared>(map_mutex_);
+ const auto ptr = emplace_shared(map_mutex_);
ptr->assign(std::next(data, offset), std::next(data, allocated));
return ptr;
}
+ memory get1(size_t offset=zero) const NOEXCEPT override
+ {
+ return get_at1(zero, offset);
+ }
+
+ memory get_at1(size_t column, size_t offset=zero) const NOEXCEPT override
+ {
+ using namespace system;
+ auto data = at(column).data();
+ const auto allocated = size() * widths.at(column);
+ accessor out(map_mutex_);
+ out.assign(std::next(data, offset), std::next(data, allocated));
+ return out;
+ }
+
// This is protected by mutex.
mutable std::array buffers_{};