mirror of
https://github.com/XRPLF/rippled.git
synced 2026-08-21 22:30:57 +00:00
Five sites copied the top entry out and then popped it. `SHAMapTreeNodePtr` is refcounted, so each copy bumped its atomic strong-ref count; `release()` moves the pointer out instead, a plain pointer swap with no atomic. `SHAMapNodeID` also derives from `CountedObject`, but `CountedObject` declares no move constructor, so moving a `SHAMapNodeID` still runs its copy constructor; `release()` saves nothing on the ID half of the pair. `dirtyUp` and `delItem` walk up to 64 levels per insert or delete on the ledger write path, so this removes up to 64 atomic operations per call, not 128. The two sites that read without popping now bind a reference rather than copying. `dirtyUp` and `delItem` both drop a `dynamicPointerCast`/null check for a static cast, on the reasoning that by the time either receives the stack, `addGiveItem`/`updateGiveItem` have already consumed the terminal leaf entry via `release()`, so every remaining entry is provably an inner node. That reasoning holds today, but an `XRPL_ASSERT` is a no-op under `NDEBUG`, so both get a real `UNREACHABLE`-guarded check instead: a release build that somehow violated the invariant would otherwise write through a misinterpreted node via `setChild`, silent memory corruption in place of the clean crash `dynamicPointerCast` used to produce. `updateGiveItem`'s own cast needed the same treatment for a different reason: an absent tag leaves an inner node on top of the stack, and the cast that followed the assertion there would have reinterpreted an `SHAMapInnerNode` as a `SHAMapLeafNode`. Replaced with `if (!top->isLeaf()) return false;`, pinned by a regression test. The `std::move` these sites previously applied to `staticPointerCast`/`dynamicPointerCast` was dropped rather than fixed: both only had a `TT const&` overload, so the move bound to that const ref and copied anyway, silently defeating the `SHAMapTreeNodePtr` refcount saving described above. Adds the missing rvalue overload to each, tied to `SharedIntrusive<TT>&&` rather than a bare `TT&&` so it cannot also bind to an lvalue in preference to the const-ref overload, and restores `std::move` at the three call sites that own a soon-to-be-discarded pointer.
Basics
Utility functions and classes.
The module xrpl/basics should contain no dependencies on other modules.
Choosing an xrpld container.
-
std::vector- For ordered containers with most insertions or erases at the end.
-
std::deque- For ordered containers with most insertions or erases at the start or end.
-
std::list- For ordered containers with inserts and erases to the middle.
- For containers with iterators stable over insert and erase.
- Generally slower and bigger than
std::vectororstd::dequeexcept for those cases.
-
std::set- For sorted containers.
-
xrpl::hash_set- Where inserts and contains need to be O(1).
- For "small" sets,
std::setmight be faster and smaller.
-
xrpl::hardened_hash_set- For data sets where the key could be manipulated by an attacker in an attempt to mount an algorithmic complexity attack: see http://en.wikipedia.org/wiki/Algorithmic_complexity_attack
The following container is deprecated
std::unordered_set- Use
xrpl::hash_setinstead, which uses a better hashing algorithm. - Or use
xrpl::hardened_hash_setto prevent algorithmic complexity attacks.