Compare commits

...

5 Commits

Author SHA1 Message Date
Bronek Kozicki
8d01f35eb9 Set version to 2.6.1-rc1 2025-09-16 15:35:54 -04:00
Bronek Kozicki
1020a32d76 Downgrade to boost 1.83 2025-09-16 15:35:47 -04:00
Michael Legleux
2df7dcfdeb Set version to 2.6.0 2025-08-27 10:25:53 -07:00
Ed Hennis
c5fe970646 Set version to 2.6.0-rc3 2025-08-22 17:32:31 -04:00
Ed Hennis
c57cd8b23e Revert "perf: Move mutex to the partition level (#5486)"
This reverts commit 94decc753b.
2025-08-22 17:30:08 -04:00
12 changed files with 149 additions and 138 deletions

View File

@@ -26,6 +26,9 @@ tools.build:cxxflags=['-Wno-missing-template-arg-list-after-template-kw']
{% if compiler == "apple-clang" and compiler_version >= 17 %} {% if compiler == "apple-clang" and compiler_version >= 17 %}
tools.build:cxxflags=['-Wno-missing-template-arg-list-after-template-kw'] tools.build:cxxflags=['-Wno-missing-template-arg-list-after-template-kw']
{% endif %} {% endif %}
{% if compiler == "clang" and compiler_version == 16 %}
tools.build:cxxflags=['-DBOOST_ASIO_DISABLE_CONCEPTS']
{% endif %}
{% if compiler == "gcc" and compiler_version < 13 %} {% if compiler == "gcc" and compiler_version < 13 %}
tools.build:cxxflags=['-Wno-restrict'] tools.build:cxxflags=['-Wno-restrict']
{% endif %} {% endif %}

View File

@@ -104,7 +104,7 @@ class Xrpl(ConanFile):
def requirements(self): def requirements(self):
# Conan 2 requires transitive headers to be specified # Conan 2 requires transitive headers to be specified
transitive_headers_opt = {'transitive_headers': True} if conan_version.split('.')[0] == '2' else {} transitive_headers_opt = {'transitive_headers': True} if conan_version.split('.')[0] == '2' else {}
self.requires('boost/1.86.0', force=True, **transitive_headers_opt) self.requires('boost/1.83.0', force=True, **transitive_headers_opt)
self.requires('date/3.0.4', **transitive_headers_opt) self.requires('date/3.0.4', **transitive_headers_opt)
self.requires('lz4/1.10.0', force=True) self.requires('lz4/1.10.0', force=True)
self.requires('protobuf/3.21.12', force=True) self.requires('protobuf/3.21.12', force=True)

View File

@@ -21,6 +21,7 @@
#define RIPPLE_BASICS_SHAMAP_HASH_H_INCLUDED #define RIPPLE_BASICS_SHAMAP_HASH_H_INCLUDED
#include <xrpl/basics/base_uint.h> #include <xrpl/basics/base_uint.h>
#include <xrpl/basics/partitioned_unordered_map.h>
#include <ostream> #include <ostream>

View File

@@ -90,6 +90,9 @@ public:
int int
getCacheSize() const; getCacheSize() const;
int
getTrackSize() const;
float float
getHitRate(); getHitRate();
@@ -167,6 +170,9 @@ public:
bool bool
retrieve(key_type const& key, T& data); retrieve(key_type const& key, T& data);
mutex_type&
peekMutex();
std::vector<key_type> std::vector<key_type>
getKeys() const; getKeys() const;
@@ -187,14 +193,11 @@ public:
private: private:
SharedPointerType SharedPointerType
initialFetch(key_type const& key); initialFetch(key_type const& key, std::lock_guard<mutex_type> const& l);
void void
collect_metrics(); collect_metrics();
Mutex&
lockPartition(key_type const& key) const;
private: private:
struct Stats struct Stats
{ {
@@ -297,8 +300,8 @@ private:
[[maybe_unused]] clock_type::time_point const& now, [[maybe_unused]] clock_type::time_point const& now,
typename KeyValueCacheType::map_type& partition, typename KeyValueCacheType::map_type& partition,
SweptPointersVector& stuffToSweep, SweptPointersVector& stuffToSweep,
std::atomic<int>& allRemoval, std::atomic<int>& allRemovals,
Mutex& partitionLock); std::lock_guard<std::recursive_mutex> const&);
[[nodiscard]] std::thread [[nodiscard]] std::thread
sweepHelper( sweepHelper(
@@ -307,12 +310,14 @@ private:
typename KeyOnlyCacheType::map_type& partition, typename KeyOnlyCacheType::map_type& partition,
SweptPointersVector&, SweptPointersVector&,
std::atomic<int>& allRemovals, std::atomic<int>& allRemovals,
Mutex& partitionLock); std::lock_guard<std::recursive_mutex> const&);
beast::Journal m_journal; beast::Journal m_journal;
clock_type& m_clock; clock_type& m_clock;
Stats m_stats; Stats m_stats;
mutex_type mutable m_mutex;
// Used for logging // Used for logging
std::string m_name; std::string m_name;
@@ -323,11 +328,10 @@ private:
clock_type::duration const m_target_age; clock_type::duration const m_target_age;
// Number of items cached // Number of items cached
std::atomic<int> m_cache_count; int m_cache_count;
cache_type m_cache; // Hold strong reference to recent objects cache_type m_cache; // Hold strong reference to recent objects
std::atomic<std::uint64_t> m_hits; std::uint64_t m_hits;
std::atomic<std::uint64_t> m_misses; std::uint64_t m_misses;
mutable std::vector<mutex_type> partitionLocks_;
}; };
} // namespace ripple } // namespace ripple

View File

@@ -22,7 +22,6 @@
#include <xrpl/basics/IntrusivePointer.ipp> #include <xrpl/basics/IntrusivePointer.ipp>
#include <xrpl/basics/TaggedCache.h> #include <xrpl/basics/TaggedCache.h>
#include <xrpl/beast/core/CurrentThreadName.h>
namespace ripple { namespace ripple {
@@ -61,7 +60,6 @@ inline TaggedCache<
, m_hits(0) , m_hits(0)
, m_misses(0) , m_misses(0)
{ {
partitionLocks_ = std::vector<mutex_type>(m_cache.partitions());
} }
template < template <
@@ -107,13 +105,8 @@ TaggedCache<
KeyEqual, KeyEqual,
Mutex>::size() const Mutex>::size() const
{ {
std::size_t totalSize = 0; std::lock_guard lock(m_mutex);
for (size_t i = 0; i < partitionLocks_.size(); ++i) return m_cache.size();
{
std::lock_guard<Mutex> lock(partitionLocks_[i]);
totalSize += m_cache.map()[i].size();
}
return totalSize;
} }
template < template <
@@ -136,7 +129,32 @@ TaggedCache<
KeyEqual, KeyEqual,
Mutex>::getCacheSize() const Mutex>::getCacheSize() const
{ {
return m_cache_count.load(std::memory_order_relaxed); std::lock_guard lock(m_mutex);
return m_cache_count;
}
template <
class Key,
class T,
bool IsKeyCache,
class SharedWeakUnionPointer,
class SharedPointerType,
class Hash,
class KeyEqual,
class Mutex>
inline int
TaggedCache<
Key,
T,
IsKeyCache,
SharedWeakUnionPointer,
SharedPointerType,
Hash,
KeyEqual,
Mutex>::getTrackSize() const
{
std::lock_guard lock(m_mutex);
return m_cache.size();
} }
template < template <
@@ -159,10 +177,9 @@ TaggedCache<
KeyEqual, KeyEqual,
Mutex>::getHitRate() Mutex>::getHitRate()
{ {
auto const hits = m_hits.load(std::memory_order_relaxed); std::lock_guard lock(m_mutex);
auto const misses = m_misses.load(std::memory_order_relaxed); auto const total = static_cast<float>(m_hits + m_misses);
float const total = float(hits + misses); return m_hits * (100.0f / std::max(1.0f, total));
return hits * (100.0f / std::max(1.0f, total));
} }
template < template <
@@ -185,12 +202,9 @@ TaggedCache<
KeyEqual, KeyEqual,
Mutex>::clear() Mutex>::clear()
{ {
for (auto& mutex : partitionLocks_) std::lock_guard lock(m_mutex);
mutex.lock();
m_cache.clear(); m_cache.clear();
for (auto& mutex : partitionLocks_) m_cache_count = 0;
mutex.unlock();
m_cache_count.store(0, std::memory_order_relaxed);
} }
template < template <
@@ -213,9 +227,11 @@ TaggedCache<
KeyEqual, KeyEqual,
Mutex>::reset() Mutex>::reset()
{ {
clear(); std::lock_guard lock(m_mutex);
m_hits.store(0, std::memory_order_relaxed); m_cache.clear();
m_misses.store(0, std::memory_order_relaxed); m_cache_count = 0;
m_hits = 0;
m_misses = 0;
} }
template < template <
@@ -239,7 +255,7 @@ TaggedCache<
KeyEqual, KeyEqual,
Mutex>::touch_if_exists(KeyComparable const& key) Mutex>::touch_if_exists(KeyComparable const& key)
{ {
std::lock_guard<Mutex> lock(lockPartition(key)); std::lock_guard lock(m_mutex);
auto const iter(m_cache.find(key)); auto const iter(m_cache.find(key));
if (iter == m_cache.end()) if (iter == m_cache.end())
{ {
@@ -281,6 +297,8 @@ TaggedCache<
auto const start = std::chrono::steady_clock::now(); auto const start = std::chrono::steady_clock::now();
{ {
std::lock_guard lock(m_mutex);
if (m_target_size == 0 || if (m_target_size == 0 ||
(static_cast<int>(m_cache.size()) <= m_target_size)) (static_cast<int>(m_cache.size()) <= m_target_size))
{ {
@@ -312,13 +330,12 @@ TaggedCache<
m_cache.map()[p], m_cache.map()[p],
allStuffToSweep[p], allStuffToSweep[p],
allRemovals, allRemovals,
partitionLocks_[p])); lock));
} }
for (std::thread& worker : workers) for (std::thread& worker : workers)
worker.join(); worker.join();
int removals = allRemovals.load(std::memory_order_relaxed); m_cache_count -= allRemovals;
m_cache_count.fetch_sub(removals, std::memory_order_relaxed);
} }
// At this point allStuffToSweep will go out of scope outside the lock // At this point allStuffToSweep will go out of scope outside the lock
// and decrement the reference count on each strong pointer. // and decrement the reference count on each strong pointer.
@@ -352,8 +369,7 @@ TaggedCache<
{ {
// Remove from cache, if !valid, remove from map too. Returns true if // Remove from cache, if !valid, remove from map too. Returns true if
// removed from cache // removed from cache
std::lock_guard lock(m_mutex);
std::lock_guard<Mutex> lock(lockPartition(key));
auto cit = m_cache.find(key); auto cit = m_cache.find(key);
@@ -366,7 +382,7 @@ TaggedCache<
if (entry.isCached()) if (entry.isCached())
{ {
m_cache_count.fetch_sub(1, std::memory_order_relaxed); --m_cache_count;
entry.ptr.convertToWeak(); entry.ptr.convertToWeak();
ret = true; ret = true;
} }
@@ -404,16 +420,17 @@ TaggedCache<
{ {
// Return canonical value, store if needed, refresh in cache // Return canonical value, store if needed, refresh in cache
// Return values: true=we had the data already // Return values: true=we had the data already
std::lock_guard lock(m_mutex);
std::lock_guard<Mutex> lock(lockPartition(key));
auto cit = m_cache.find(key); auto cit = m_cache.find(key);
if (cit == m_cache.end()) if (cit == m_cache.end())
{ {
m_cache.emplace( m_cache.emplace(
std::piecewise_construct, std::piecewise_construct,
std::forward_as_tuple(key), std::forward_as_tuple(key),
std::forward_as_tuple(m_clock.now(), data)); std::forward_as_tuple(m_clock.now(), data));
m_cache_count.fetch_add(1, std::memory_order_relaxed); ++m_cache_count;
return false; return false;
} }
@@ -462,12 +479,12 @@ TaggedCache<
data = cachedData; data = cachedData;
} }
m_cache_count.fetch_add(1, std::memory_order_relaxed); ++m_cache_count;
return true; return true;
} }
entry.ptr = data; entry.ptr = data;
m_cache_count.fetch_add(1, std::memory_order_relaxed); ++m_cache_count;
return false; return false;
} }
@@ -543,11 +560,10 @@ TaggedCache<
KeyEqual, KeyEqual,
Mutex>::fetch(key_type const& key) Mutex>::fetch(key_type const& key)
{ {
std::lock_guard<Mutex> lock(lockPartition(key)); std::lock_guard<mutex_type> l(m_mutex);
auto ret = initialFetch(key, l);
auto ret = initialFetch(key);
if (!ret) if (!ret)
m_misses.fetch_add(1, std::memory_order_relaxed); ++m_misses;
return ret; return ret;
} }
@@ -611,8 +627,8 @@ TaggedCache<
Mutex>::insert(key_type const& key) Mutex>::insert(key_type const& key)
-> std::enable_if_t<IsKeyCache, ReturnType> -> std::enable_if_t<IsKeyCache, ReturnType>
{ {
std::lock_guard lock(m_mutex);
clock_type::time_point const now(m_clock.now()); clock_type::time_point const now(m_clock.now());
std::lock_guard<Mutex> lock(lockPartition(key));
auto [it, inserted] = m_cache.emplace( auto [it, inserted] = m_cache.emplace(
std::piecewise_construct, std::piecewise_construct,
std::forward_as_tuple(key), std::forward_as_tuple(key),
@@ -652,6 +668,29 @@ TaggedCache<
return true; return true;
} }
template <
class Key,
class T,
bool IsKeyCache,
class SharedWeakUnionPointer,
class SharedPointerType,
class Hash,
class KeyEqual,
class Mutex>
inline auto
TaggedCache<
Key,
T,
IsKeyCache,
SharedWeakUnionPointer,
SharedPointerType,
Hash,
KeyEqual,
Mutex>::peekMutex() -> mutex_type&
{
return m_mutex;
}
template < template <
class Key, class Key,
class T, class T,
@@ -675,13 +714,10 @@ TaggedCache<
std::vector<key_type> v; std::vector<key_type> v;
{ {
std::lock_guard lock(m_mutex);
v.reserve(m_cache.size()); v.reserve(m_cache.size());
for (std::size_t i = 0; i < partitionLocks_.size(); ++i) for (auto const& _ : m_cache)
{ v.push_back(_.first);
std::lock_guard<Mutex> lock(partitionLocks_[i]);
for (auto const& entry : m_cache.map()[i])
v.push_back(entry.first);
}
} }
return v; return v;
@@ -707,12 +743,11 @@ TaggedCache<
KeyEqual, KeyEqual,
Mutex>::rate() const Mutex>::rate() const
{ {
auto const hits = m_hits.load(std::memory_order_relaxed); std::lock_guard lock(m_mutex);
auto const misses = m_misses.load(std::memory_order_relaxed); auto const tot = m_hits + m_misses;
auto const tot = hits + misses;
if (tot == 0) if (tot == 0)
return 0.0; return 0;
return double(hits) / tot; return double(m_hits) / tot;
} }
template < template <
@@ -736,16 +771,18 @@ TaggedCache<
KeyEqual, KeyEqual,
Mutex>::fetch(key_type const& digest, Handler const& h) Mutex>::fetch(key_type const& digest, Handler const& h)
{ {
std::lock_guard<Mutex> lock(lockPartition(digest)); {
std::lock_guard l(m_mutex);
if (auto ret = initialFetch(digest)) if (auto ret = initialFetch(digest, l))
return ret; return ret;
}
auto sle = h(); auto sle = h();
if (!sle) if (!sle)
return {}; return {};
m_misses.fetch_add(1, std::memory_order_relaxed); std::lock_guard l(m_mutex);
++m_misses;
auto const [it, inserted] = auto const [it, inserted] =
m_cache.emplace(digest, Entry(m_clock.now(), std::move(sle))); m_cache.emplace(digest, Entry(m_clock.now(), std::move(sle)));
if (!inserted) if (!inserted)
@@ -772,10 +809,9 @@ TaggedCache<
SharedPointerType, SharedPointerType,
Hash, Hash,
KeyEqual, KeyEqual,
Mutex>::initialFetch(key_type const& key) Mutex>::
initialFetch(key_type const& key, std::lock_guard<mutex_type> const& l)
{ {
std::lock_guard<Mutex> lock(lockPartition(key));
auto cit = m_cache.find(key); auto cit = m_cache.find(key);
if (cit == m_cache.end()) if (cit == m_cache.end())
return {}; return {};
@@ -783,7 +819,7 @@ TaggedCache<
Entry& entry = cit->second; Entry& entry = cit->second;
if (entry.isCached()) if (entry.isCached())
{ {
m_hits.fetch_add(1, std::memory_order_relaxed); ++m_hits;
entry.touch(m_clock.now()); entry.touch(m_clock.now());
return entry.ptr.getStrong(); return entry.ptr.getStrong();
} }
@@ -791,13 +827,12 @@ TaggedCache<
if (entry.isCached()) if (entry.isCached())
{ {
// independent of cache size, so not counted as a hit // independent of cache size, so not counted as a hit
m_cache_count.fetch_add(1, std::memory_order_relaxed); ++m_cache_count;
entry.touch(m_clock.now()); entry.touch(m_clock.now());
return entry.ptr.getStrong(); return entry.ptr.getStrong();
} }
m_cache.erase(cit); m_cache.erase(cit);
return {}; return {};
} }
@@ -826,11 +861,10 @@ TaggedCache<
{ {
beast::insight::Gauge::value_type hit_rate(0); beast::insight::Gauge::value_type hit_rate(0);
{ {
auto const hits = m_hits.load(std::memory_order_relaxed); std::lock_guard lock(m_mutex);
auto const misses = m_misses.load(std::memory_order_relaxed); auto const total(m_hits + m_misses);
auto const total = hits + misses;
if (total != 0) if (total != 0)
hit_rate = (hits * 100) / total; hit_rate = (m_hits * 100) / total;
} }
m_stats.hit_rate.set(hit_rate); m_stats.hit_rate.set(hit_rate);
} }
@@ -861,16 +895,12 @@ TaggedCache<
typename KeyValueCacheType::map_type& partition, typename KeyValueCacheType::map_type& partition,
SweptPointersVector& stuffToSweep, SweptPointersVector& stuffToSweep,
std::atomic<int>& allRemovals, std::atomic<int>& allRemovals,
Mutex& partitionLock) std::lock_guard<std::recursive_mutex> const&)
{ {
return std::thread([&, this]() { return std::thread([&, this]() {
beast::setCurrentThreadName("sweep-KVCache");
int cacheRemovals = 0; int cacheRemovals = 0;
int mapRemovals = 0; int mapRemovals = 0;
std::lock_guard<Mutex> lock(partitionLock);
// Keep references to all the stuff we sweep // Keep references to all the stuff we sweep
// so that we can destroy them outside the lock. // so that we can destroy them outside the lock.
stuffToSweep.reserve(partition.size()); stuffToSweep.reserve(partition.size());
@@ -954,16 +984,12 @@ TaggedCache<
typename KeyOnlyCacheType::map_type& partition, typename KeyOnlyCacheType::map_type& partition,
SweptPointersVector&, SweptPointersVector&,
std::atomic<int>& allRemovals, std::atomic<int>& allRemovals,
Mutex& partitionLock) std::lock_guard<std::recursive_mutex> const&)
{ {
return std::thread([&, this]() { return std::thread([&, this]() {
beast::setCurrentThreadName("sweep-KCache");
int cacheRemovals = 0; int cacheRemovals = 0;
int mapRemovals = 0; int mapRemovals = 0;
std::lock_guard<Mutex> lock(partitionLock);
// Keep references to all the stuff we sweep // Keep references to all the stuff we sweep
// so that we can destroy them outside the lock. // so that we can destroy them outside the lock.
{ {
@@ -998,29 +1024,6 @@ TaggedCache<
}); });
} }
template <
class Key,
class T,
bool IsKeyCache,
class SharedWeakUnionPointer,
class SharedPointerType,
class Hash,
class KeyEqual,
class Mutex>
inline Mutex&
TaggedCache<
Key,
T,
IsKeyCache,
SharedWeakUnionPointer,
SharedPointerType,
Hash,
KeyEqual,
Mutex>::lockPartition(key_type const& key) const
{
return partitionLocks_[m_cache.partition_index(key)];
}
} // namespace ripple } // namespace ripple
#endif #endif

View File

@@ -277,12 +277,6 @@ public:
return map_; return map_;
} }
partition_map_type const&
map() const
{
return map_;
}
iterator iterator
begin() begin()
{ {
@@ -327,12 +321,6 @@ public:
return cend(); return cend();
} }
std::size_t
partition_index(key_type const& key) const
{
return partitioner(key);
}
private: private:
template <class T> template <class T>
void void

View File

@@ -22,6 +22,7 @@
#include <xrpl/basics/ByteUtilities.h> #include <xrpl/basics/ByteUtilities.h>
#include <xrpl/basics/base_uint.h> #include <xrpl/basics/base_uint.h>
#include <xrpl/basics/partitioned_unordered_map.h>
#include <cstdint> #include <cstdint>

View File

@@ -36,7 +36,7 @@ namespace BuildInfo {
// and follow the format described at http://semver.org/ // and follow the format described at http://semver.org/
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// clang-format off // clang-format off
char const* const versionString = "2.6.0-rc2" char const* const versionString = "2.6.1-rc1"
// clang-format on // clang-format on
#if defined(DEBUG) || defined(SANITIZER) #if defined(DEBUG) || defined(SANITIZER)

View File

@@ -58,10 +58,10 @@ public:
// Insert an item, retrieve it, and age it so it gets purged. // Insert an item, retrieve it, and age it so it gets purged.
{ {
BEAST_EXPECT(c.getCacheSize() == 0); BEAST_EXPECT(c.getCacheSize() == 0);
BEAST_EXPECT(c.size() == 0); BEAST_EXPECT(c.getTrackSize() == 0);
BEAST_EXPECT(!c.insert(1, "one")); BEAST_EXPECT(!c.insert(1, "one"));
BEAST_EXPECT(c.getCacheSize() == 1); BEAST_EXPECT(c.getCacheSize() == 1);
BEAST_EXPECT(c.size() == 1); BEAST_EXPECT(c.getTrackSize() == 1);
{ {
std::string s; std::string s;
@@ -72,7 +72,7 @@ public:
++clock; ++clock;
c.sweep(); c.sweep();
BEAST_EXPECT(c.getCacheSize() == 0); BEAST_EXPECT(c.getCacheSize() == 0);
BEAST_EXPECT(c.size() == 0); BEAST_EXPECT(c.getTrackSize() == 0);
} }
// Insert an item, maintain a strong pointer, age it, and // Insert an item, maintain a strong pointer, age it, and
@@ -80,7 +80,7 @@ public:
{ {
BEAST_EXPECT(!c.insert(2, "two")); BEAST_EXPECT(!c.insert(2, "two"));
BEAST_EXPECT(c.getCacheSize() == 1); BEAST_EXPECT(c.getCacheSize() == 1);
BEAST_EXPECT(c.size() == 1); BEAST_EXPECT(c.getTrackSize() == 1);
{ {
auto p = c.fetch(2); auto p = c.fetch(2);
@@ -88,14 +88,14 @@ public:
++clock; ++clock;
c.sweep(); c.sweep();
BEAST_EXPECT(c.getCacheSize() == 0); BEAST_EXPECT(c.getCacheSize() == 0);
BEAST_EXPECT(c.size() == 1); BEAST_EXPECT(c.getTrackSize() == 1);
} }
// Make sure its gone now that our reference is gone // Make sure its gone now that our reference is gone
++clock; ++clock;
c.sweep(); c.sweep();
BEAST_EXPECT(c.getCacheSize() == 0); BEAST_EXPECT(c.getCacheSize() == 0);
BEAST_EXPECT(c.size() == 0); BEAST_EXPECT(c.getTrackSize() == 0);
} }
// Insert the same key/value pair and make sure we get the same result // Insert the same key/value pair and make sure we get the same result
@@ -111,7 +111,7 @@ public:
++clock; ++clock;
c.sweep(); c.sweep();
BEAST_EXPECT(c.getCacheSize() == 0); BEAST_EXPECT(c.getCacheSize() == 0);
BEAST_EXPECT(c.size() == 0); BEAST_EXPECT(c.getTrackSize() == 0);
} }
// Put an object in but keep a strong pointer to it, advance the clock a // Put an object in but keep a strong pointer to it, advance the clock a
@@ -121,24 +121,24 @@ public:
// Put an object in // Put an object in
BEAST_EXPECT(!c.insert(4, "four")); BEAST_EXPECT(!c.insert(4, "four"));
BEAST_EXPECT(c.getCacheSize() == 1); BEAST_EXPECT(c.getCacheSize() == 1);
BEAST_EXPECT(c.size() == 1); BEAST_EXPECT(c.getTrackSize() == 1);
{ {
// Keep a strong pointer to it // Keep a strong pointer to it
auto const p1 = c.fetch(4); auto const p1 = c.fetch(4);
BEAST_EXPECT(p1 != nullptr); BEAST_EXPECT(p1 != nullptr);
BEAST_EXPECT(c.getCacheSize() == 1); BEAST_EXPECT(c.getCacheSize() == 1);
BEAST_EXPECT(c.size() == 1); BEAST_EXPECT(c.getTrackSize() == 1);
// Advance the clock a lot // Advance the clock a lot
++clock; ++clock;
c.sweep(); c.sweep();
BEAST_EXPECT(c.getCacheSize() == 0); BEAST_EXPECT(c.getCacheSize() == 0);
BEAST_EXPECT(c.size() == 1); BEAST_EXPECT(c.getTrackSize() == 1);
// Canonicalize a new object with the same key // Canonicalize a new object with the same key
auto p2 = std::make_shared<std::string>("four"); auto p2 = std::make_shared<std::string>("four");
BEAST_EXPECT(c.canonicalize_replace_client(4, p2)); BEAST_EXPECT(c.canonicalize_replace_client(4, p2));
BEAST_EXPECT(c.getCacheSize() == 1); BEAST_EXPECT(c.getCacheSize() == 1);
BEAST_EXPECT(c.size() == 1); BEAST_EXPECT(c.getTrackSize() == 1);
// Make sure we get the original object // Make sure we get the original object
BEAST_EXPECT(p1.get() == p2.get()); BEAST_EXPECT(p1.get() == p2.get());
} }
@@ -146,7 +146,7 @@ public:
++clock; ++clock;
c.sweep(); c.sweep();
BEAST_EXPECT(c.getCacheSize() == 0); BEAST_EXPECT(c.getCacheSize() == 0);
BEAST_EXPECT(c.size() == 0); BEAST_EXPECT(c.getTrackSize() == 0);
} }
} }
}; };

View File

@@ -681,7 +681,7 @@ class ServerStatus_test : public beast::unit_test::suite,
resp["Upgrade"] == "websocket"); resp["Upgrade"] == "websocket");
BEAST_EXPECT( BEAST_EXPECT(
resp.find("Connection") != resp.end() && resp.find("Connection") != resp.end() &&
resp["Connection"] == "Upgrade"); resp["Connection"] == "upgrade");
} }
void void

View File

@@ -63,6 +63,8 @@ LedgerHistory::insert(
ledger->stateMap().getHash().isNonZero(), ledger->stateMap().getHash().isNonZero(),
"ripple::LedgerHistory::insert : nonzero hash"); "ripple::LedgerHistory::insert : nonzero hash");
std::unique_lock sl(m_ledgers_by_hash.peekMutex());
bool const alreadyHad = m_ledgers_by_hash.canonicalize_replace_cache( bool const alreadyHad = m_ledgers_by_hash.canonicalize_replace_cache(
ledger->info().hash, ledger); ledger->info().hash, ledger);
if (validated) if (validated)
@@ -74,6 +76,7 @@ LedgerHistory::insert(
LedgerHash LedgerHash
LedgerHistory::getLedgerHash(LedgerIndex index) LedgerHistory::getLedgerHash(LedgerIndex index)
{ {
std::unique_lock sl(m_ledgers_by_hash.peekMutex());
if (auto it = mLedgersByIndex.find(index); it != mLedgersByIndex.end()) if (auto it = mLedgersByIndex.find(index); it != mLedgersByIndex.end())
return it->second; return it->second;
return {}; return {};
@@ -83,11 +86,13 @@ std::shared_ptr<Ledger const>
LedgerHistory::getLedgerBySeq(LedgerIndex index) LedgerHistory::getLedgerBySeq(LedgerIndex index)
{ {
{ {
std::unique_lock sl(m_ledgers_by_hash.peekMutex());
auto it = mLedgersByIndex.find(index); auto it = mLedgersByIndex.find(index);
if (it != mLedgersByIndex.end()) if (it != mLedgersByIndex.end())
{ {
uint256 hash = it->second; uint256 hash = it->second;
sl.unlock();
return getLedgerByHash(hash); return getLedgerByHash(hash);
} }
} }
@@ -103,6 +108,7 @@ LedgerHistory::getLedgerBySeq(LedgerIndex index)
{ {
// Add this ledger to the local tracking by index // Add this ledger to the local tracking by index
std::unique_lock sl(m_ledgers_by_hash.peekMutex());
XRPL_ASSERT( XRPL_ASSERT(
ret->isImmutable(), ret->isImmutable(),
@@ -452,6 +458,8 @@ LedgerHistory::builtLedger(
XRPL_ASSERT( XRPL_ASSERT(
!hash.isZero(), "ripple::LedgerHistory::builtLedger : nonzero hash"); !hash.isZero(), "ripple::LedgerHistory::builtLedger : nonzero hash");
std::unique_lock sl(m_consensus_validated.peekMutex());
auto entry = std::make_shared<cv_entry>(); auto entry = std::make_shared<cv_entry>();
m_consensus_validated.canonicalize_replace_client(index, entry); m_consensus_validated.canonicalize_replace_client(index, entry);
@@ -492,6 +500,8 @@ LedgerHistory::validatedLedger(
!hash.isZero(), !hash.isZero(),
"ripple::LedgerHistory::validatedLedger : nonzero hash"); "ripple::LedgerHistory::validatedLedger : nonzero hash");
std::unique_lock sl(m_consensus_validated.peekMutex());
auto entry = std::make_shared<cv_entry>(); auto entry = std::make_shared<cv_entry>();
m_consensus_validated.canonicalize_replace_client(index, entry); m_consensus_validated.canonicalize_replace_client(index, entry);
@@ -525,9 +535,10 @@ LedgerHistory::validatedLedger(
bool bool
LedgerHistory::fixIndex(LedgerIndex ledgerIndex, LedgerHash const& ledgerHash) LedgerHistory::fixIndex(LedgerIndex ledgerIndex, LedgerHash const& ledgerHash)
{ {
auto ledger = m_ledgers_by_hash.fetch(ledgerHash); std::unique_lock sl(m_ledgers_by_hash.peekMutex());
auto it = mLedgersByIndex.find(ledgerIndex); auto it = mLedgersByIndex.find(ledgerIndex);
if (ledger && (it != mLedgersByIndex.end()) && (it->second != ledgerHash))
if ((it != mLedgersByIndex.end()) && (it->second != ledgerHash))
{ {
it->second = ledgerHash; it->second = ledgerHash;
return false; return false;

View File

@@ -114,7 +114,7 @@ getCountsJson(Application& app, int minObjectCount)
ret[jss::treenode_cache_size] = ret[jss::treenode_cache_size] =
app.getNodeFamily().getTreeNodeCache()->getCacheSize(); app.getNodeFamily().getTreeNodeCache()->getCacheSize();
ret[jss::treenode_track_size] = ret[jss::treenode_track_size] =
static_cast<int>(app.getNodeFamily().getTreeNodeCache()->size()); app.getNodeFamily().getTreeNodeCache()->getTrackSize();
std::string uptime; std::string uptime;
auto s = UptimeClock::now(); auto s = UptimeClock::now();