Skip to content

src/storage/trie/impl/topper_trie_batch_impl.cpp

Namespaces

Name
sgns
sgns::storage
sgns::storage::trie

Functions

Name
OUTCOME_CPP_DEFINE_CATEGORY_3(sgns::storage::trie , TopperTrieBatchImpl::Error , e )

Functions Documentation

function OUTCOME_CPP_DEFINE_CATEGORY_3

OUTCOME_CPP_DEFINE_CATEGORY_3(
    sgns::storage::trie ,
    TopperTrieBatchImpl::Error ,
    e 
)

Source code

#include "storage/trie/impl/topper_trie_batch_impl.hpp"

#include "storage/trie/supergenius_trie/trie_error.hpp"

OUTCOME_CPP_DEFINE_CATEGORY_3(sgns::storage::trie,
                            TopperTrieBatchImpl::Error,
                            e) {
  using E = sgns::storage::trie::TopperTrieBatchImpl::Error;
  switch (e) {
    case E::PARENT_EXPIRED:
      return "Pointer to the parent batch expired";
  }
  return "Unknown error";
}

namespace sgns::storage::trie {

  TopperTrieBatchImpl::TopperTrieBatchImpl(
      const std::shared_ptr<TrieBatch> &parent)
      : parent_(parent) {}

  outcome::result<Buffer> TopperTrieBatchImpl::get(const Buffer &key) const {
    if (auto it = cache_.find(key); it != cache_.end()) {
      if (it->second.has_value()) {
        return it->second.value();
      }
      return TrieError::NO_VALUE;
    }
    if (wasClearedByPrefix(key)) {
      return TrieError::NO_VALUE;
    }
    if (auto p = parent_.lock(); p != nullptr) {
      return p->get(key);
    }
    return Error::PARENT_EXPIRED;
  }

  std::unique_ptr<BufferMapCursor> TopperTrieBatchImpl::cursor() {
    if (auto p = parent_.lock(); p != nullptr) {
      return p->cursor();
    }
    return nullptr;
  }

  bool TopperTrieBatchImpl::contains(const Buffer &key) const {
    if (auto it = cache_.find(key); it != cache_.end()) {
      return it->second.has_value();
    }
    if (wasClearedByPrefix(key)) {
      return false;
    }
    if (auto p = parent_.lock(); p != nullptr) {
      return p->contains(key);
    }
    return false;
  }

  bool TopperTrieBatchImpl::empty() const {
    if (!cache_.empty()
        && std::any_of(cache_.begin(), cache_.end(), [](auto &p) {
              return p.second.has_value();
            })) {
      return false;
    }
    // TODO(Harrm) PRE-462 consider clearPrefix here. Not an easy thing and is
    // barely possible to happen, so leave it for the future
    if (auto p = parent_.lock(); p != nullptr) {
      return p->empty();
    }
    return true;
  }

  outcome::result<void> TopperTrieBatchImpl::put(const Buffer &key,
                                                 const Buffer &value) {
    return put(key, Buffer(value));
  }

  outcome::result<void> TopperTrieBatchImpl::put(const Buffer &key,
                                                 Buffer &&value) {
    cache_[key] = std::move(value);
    return outcome::success();
  }

  outcome::result<void> TopperTrieBatchImpl::remove(const Buffer &key) {
    cache_[key] = boost::none;
    return outcome::success();
  }

  outcome::result<void> TopperTrieBatchImpl::clearPrefix(const Buffer &prefix) {
    for (auto &p : cache_) {
      if (p.first.subbuffer(0, prefix.size()) == prefix) {
        cache_[p.first] = boost::none;
      }
    }
    cleared_prefixes_.push_back(prefix);
    if (parent_.lock() != nullptr) {
      return outcome::success();
    }
    return Error::PARENT_EXPIRED;
  }

  outcome::result<void> TopperTrieBatchImpl::writeBack() {
    if (auto p = parent_.lock(); p != nullptr) {
      auto it = cache_.begin();
      for (auto &prefix : cleared_prefixes_) {
        BOOST_OUTCOME_TRYV2(auto &&, p->clearPrefix(prefix));
      }
      for (; it != cache_.end(); it++) {
        if (it->second.has_value()) {
          BOOST_OUTCOME_TRYV2(auto &&, p->put(it->first, it->second.value()));
        } else {
          BOOST_OUTCOME_TRYV2(auto &&, p->remove(it->first));
        }
      }
      return outcome::success();
    }
    return Error::PARENT_EXPIRED;
  }

  bool TopperTrieBatchImpl::wasClearedByPrefix(const Buffer &key) const {
    for (auto prefix : cleared_prefixes_) {
      auto key_end = key.begin();
      std::advance(key_end, std::min(key.size(), prefix.size()) - 1);
      auto is_cleared = std::equal(key.begin(), key_end, prefix.begin());
      if (is_cleared) return true;
    }
    return false;
  }

}  // namespace sgns::storage::trie

Updated on 2026-03-04 at 13:10:45 -0800