Refactor View classes:

The View hierarchy of classes is reorganized to include new
classes with member functions moved and renamed, to solve
defects in the original design:

OpenView accumulates raw state and tx changes and
can be applied to the base. ApplyView accumulates changes
for a single transaction, including metadata, and can be
applied to an OpenView. The Sandbox allows changes with
the option to apply or throw them out. The PaymentSandbox
provides a sandbox with account credit deferral.

Call sites are changed to use the class appropriate for
the task.
This commit is contained in:
Vinnie Falco
2015-07-04 10:55:07 -07:00
parent f3b172b0c9
commit 367c3a5bfc
116 changed files with 4392 additions and 3565 deletions

View File

@@ -53,6 +53,62 @@
namespace ripple {
class Ledger::txs_iter_impl
: public txs_type::iter_base
{
private:
bool metadata_;
ReadView const* view_;
SHAMap::iterator iter_;
public:
txs_iter_impl() = delete;
txs_iter_impl& operator= (txs_iter_impl const&) = delete;
txs_iter_impl (txs_iter_impl const&) = default;
txs_iter_impl (bool metadata,
SHAMap::iterator iter,
ReadView const& view)
: metadata_ (metadata)
, view_ (&view)
, iter_ (iter)
{
}
std::unique_ptr<base_type>
copy() const override
{
return std::make_unique<
txs_iter_impl>(*this);
}
bool
equal (base_type const& impl) const override
{
auto const& other = dynamic_cast<
txs_iter_impl const&>(impl);
return iter_ == other.iter_;
}
void
increment() override
{
++iter_;
}
txs_type::value_type
dereference() const override
{
auto const item = *iter_;
if (metadata_)
return deserializeTxPlusMeta(*item);
return { deserializeTx(*item), nullptr };
}
};
//------------------------------------------------------------------------------
/* Create the "genesis" account root.
The genesis account root contains all the XRP
that will ever exist in the system.
@@ -94,12 +150,12 @@ Ledger::Ledger (RippleAddress const& masterPublicKey,
{
// first ledger
info_.seq = 1;
auto sle = makeGenesisAccount(
auto const sle = makeGenesisAccount(
calcAccountID(masterPublicKey),
balanceInDrops);
WriteLog (lsTRACE, Ledger)
<< "root account: " << sle->getJson(0);
unchecked_insert(std::move(sle));
rawInsert(sle);
stateMap_->flushDirty (hotACCOUNT_NODE, info_.seq);
}
@@ -192,6 +248,7 @@ Ledger::Ledger (bool /* dummy */,
info_.hash = prevLedger.info().hash + uint256(1);
prevLedger.updateHash ();
// VFALCO TODO Require callers to update the hash
mParentHash = prevLedger.getHash ();
assert (mParentHash.isNonZero ());
@@ -247,14 +304,13 @@ Ledger::~Ledger ()
void Ledger::setImmutable ()
{
// Updates the hash and marks the ledger and its maps immutable
// Force update, since this is the only
// place the hash transitions to valid
updateHash ();
mImmutable = true;
mImmutable = true;
if (txMap_)
txMap_->setImmutable ();
if (stateMap_)
stateMap_->setImmutable ();
}
@@ -941,12 +997,18 @@ Ledger::succ (uint256 const& key,
std::shared_ptr<SLE const>
Ledger::read (Keylet const& k) const
{
auto const& value =
if (k.key == zero)
{
assert(false);
return nullptr;
}
auto const& item =
stateMap_->peekItem(k.key);
if (! value)
if (! item)
return nullptr;
auto sle = std::make_shared<SLE>(
SerialIter{value->data(), value->size()}, value->key());
SerialIter{item->data(),
item->size()}, item->key());
if (! k.check(*sle))
return nullptr;
// VFALCO TODO Eliminate "immutable" runtime property
@@ -958,138 +1020,100 @@ Ledger::read (Keylet const& k) const
//------------------------------------------------------------------------------
class Ledger::tx_iterator_impl
: public BasicView::iterator_impl
auto
Ledger::txsBegin() const ->
std::unique_ptr<txs_type::iter_base>
{
private:
SHAMap::iterator iter_;
return std::make_unique<
txs_iter_impl>(closed(),
txMap_->begin(), *this);
}
public:
explicit
tx_iterator_impl (SHAMap::iterator iter)
: iter_(iter)
{
}
std::unique_ptr<iterator_impl>
copy() const override
{
return std::make_unique<
tx_iterator_impl>(
iter_);
}
bool
equal (iterator_impl const& impl) const override
{
auto const& other = dynamic_cast<
tx_iterator_impl const&>(impl);
return iter_ == other.iter_;
}
void
increment() override
{
++iter_;
}
txs_type::value_type
dereference() const override
{
return deserializeTxPlusMeta(**iter_);
}
};
auto
Ledger::txsEnd() const ->
std::unique_ptr<txs_type::iter_base>
{
return std::make_unique<
txs_iter_impl>(closed(),
txMap_->end(), *this);
}
bool
Ledger::txEmpty() const
Ledger::txExists (uint256 const& key) const
{
return txMap_->getHash().isZero();
return txMap_->hasItem (key);
}
auto
Ledger::txBegin() const ->
std::unique_ptr<iterator_impl>
Ledger::txRead(
key_type const& key) const ->
tx_type
{
// Can't iterate open Ledger objects
// because they don't have the metadata!
assert(closed());
return std::make_unique<
tx_iterator_impl>(txMap_->begin());
auto const& item =
txMap_->peekItem(key);
if (! item)
return {};
if (closed())
{
auto result =
deserializeTxPlusMeta(*item);
return { std::move(result.first),
std::move(result.second) };
}
return { deserializeTx(*item), nullptr };
}
auto
Ledger::txEnd() const ->
std::unique_ptr<iterator_impl>
Ledger::digest (key_type const& key) const ->
boost::optional<digest_type>
{
// Can't iterate open Ledger objects
// because they don't have the metadata!
assert(closed());
return std::make_unique<
tx_iterator_impl>(txMap_->end());
digest_type digest;
// VFALCO Unfortunately this loads the item
// from the NodeStore needlessly.
if (! stateMap_->peekItem(key, digest))
return boost::none;
return digest;
}
//------------------------------------------------------------------------------
bool
Ledger::unchecked_erase(
uint256 const& key)
void
Ledger::rawErase(std::shared_ptr<SLE> const& sle)
{
return stateMap_->delItem(key);
if (! stateMap_->delItem(sle->key()))
LogicError("Ledger::rawErase: key not found");
}
void
Ledger::unchecked_insert(
std::shared_ptr<SLE>&& sle)
Ledger::rawInsert(std::shared_ptr<SLE> const& sle)
{
assert(! stateMap_->hasItem(sle->getIndex()));
Serializer ss;
sle->add(ss);
auto item = std::make_shared<
SHAMapItem const>(sle->key(),
std::move(ss));
// VFALCO NOTE addGiveItem should take ownership
auto const success =
stateMap_->addGiveItem(
std::move(item), false, false);
(void)success;
assert(success);
auto const ours = std::move(sle);
if (! stateMap_->addGiveItem(
std::move(item), false, false))
LogicError("Ledger::rawInsert: key already exists");
}
void
Ledger::unchecked_replace(
std::shared_ptr<SLE>&& sle)
Ledger::rawReplace(std::shared_ptr<SLE> const& sle)
{
assert(stateMap_->hasItem(sle->getIndex()));
Serializer ss;
sle->add(ss);
auto item = std::make_shared<
SHAMapItem const>(sle->key(),
std::move(ss));
// VFALCO NOTE updateGiveItem should take ownership
auto const success =
stateMap_->updateGiveItem(
std::move(item), false, false);
(void)success;
assert(success);
auto const ours = std::move(sle);
}
std::size_t
Ledger::txCount() const
{
// Always zero for closed ledgers.
return 0;
}
bool
Ledger::txExists (uint256 const& key) const
{
return txMap().hasItem (key);
if (! stateMap_->updateGiveItem(
std::move(item), false, false))
LogicError("Ledger::rawReplace: key not found");
}
void
Ledger::txInsert (uint256 const& key,
Ledger::rawTxInsert (uint256 const& key,
std::shared_ptr<Serializer const
> const& txn, std::shared_ptr<
Serializer const> const& metaData)
@@ -1123,17 +1147,6 @@ Ledger::txInsert (uint256 const& key,
touch();
}
std::vector<uint256>
Ledger::txList() const
{
std::vector<uint256> list;
for (auto const& item : *txMap_)
{
list.push_back(item->key());
}
return list;
}
std::shared_ptr<SLE>
Ledger::peek (Keylet const& k) const
{
@@ -1298,9 +1311,9 @@ void Ledger::updateSkipList ()
sle->setFieldV256 (sfHashes, STVector256 (hashes));
sle->setFieldU32 (sfLastLedgerSequence, prevIndex);
if (created)
unchecked_insert(std::move(sle));
rawInsert(sle);
else
unchecked_replace(std::move(sle));
rawReplace(sle);
}
// update record of past 256 ledger
@@ -1326,9 +1339,9 @@ void Ledger::updateSkipList ()
sle->setFieldV256 (sfHashes, STVector256 (hashes));
sle->setFieldU32 (sfLastLedgerSequence, prevIndex);
if (created)
unchecked_insert(std::move(sle));
rawInsert(sle);
else
unchecked_replace(std::move(sle));
rawReplace(sle);
}
/** Save, or arrange to save, a fully-validated ledger
@@ -1407,7 +1420,7 @@ void Ledger::deprecatedUpdateCachedFees() const
std::uint32_t reserveBase = getConfig ().FEE_ACCOUNT_RESERVE;
std::int64_t reserveIncrement = getConfig ().FEE_OWNER_RESERVE;
// VFALCO NOTE this doesn't go through the SLECache
// VFALCO NOTE this doesn't go through the CachedSLEs
auto const sle = this->read(keylet::fees());
if (sle)
{
@@ -1476,34 +1489,9 @@ std::vector<uint256> Ledger::getNeededAccountStateHashes (
//
//------------------------------------------------------------------------------
std::shared_ptr<SLE const>
cachedRead (Ledger const& ledger, uint256 const& key,
SLECache& cache, boost::optional<LedgerEntryType> type)
{
uint256 hash;
auto const& item =
ledger.stateMap().peekItem(key, hash);
if (! item)
return {};
if (auto const sle = cache.fetch(hash))
{
if (type && sle->getType() != type)
return {};
return sle;
}
SerialIter sit(make_Slice(item->peekData()));
auto sle = std::make_shared<SLE>(sit, item->key());
// VFALCO Should we still cache it if the type doesn't match?
if (type && sle->getType() != type)
return {};
sle->setImmutable ();
cache.canonicalize(hash, sle);
return sle;
}
boost::optional<uint256>
hashOfSeq (Ledger& ledger, LedgerIndex seq,
SLECache& cache, beast::Journal journal)
beast::Journal journal)
{
// Easy cases...
if (seq > ledger.seq())
@@ -1524,7 +1512,7 @@ hashOfSeq (Ledger& ledger, LedgerIndex seq,
if (diff <= 256)
{
auto const hashIndex = cachedRead(
ledger, getLedgerHashIndex(), cache);
ledger, getLedgerHashIndex());
if (hashIndex)
{
assert (hashIndex->getFieldU32 (sfLastLedgerSequence) ==
@@ -1555,7 +1543,7 @@ hashOfSeq (Ledger& ledger, LedgerIndex seq,
// in skiplist
auto const hashIndex = cachedRead(ledger,
getLedgerHashIndex(seq), cache);
getLedgerHashIndex(seq));
if (hashIndex)
{
auto const lastSeq =