diff --git a/src/bucket/test/BucketManagerTests.cpp b/src/bucket/test/BucketManagerTests.cpp index 745a2ad955..0a92aa29f3 100644 --- a/src/bucket/test/BucketManagerTests.cpp +++ b/src/bucket/test/BucketManagerTests.cpp @@ -189,112 +189,90 @@ TEST_CASE("skip list", "[bucket][bucketmanager]") TEST_CASE_VERSIONS("bucketmanager ownership", "[bucket][bucketmanager]") { - auto test = [&](bool bucketListDB) { - VirtualClock clock; - Config cfg = getTestConfig(); - - // Make sure all Buckets serialize indexes to disk for test - cfg.BUCKETLIST_DB_INDEX_CUTOFF = 0; - cfg.MANUAL_CLOSE = false; - - if (bucketListDB) - { - // Enable BucketListDB with persistent indexes - cfg.NODE_IS_VALIDATOR = false; - cfg.FORCE_SCP = false; - } - - for_versions_with_differing_bucket_logic(cfg, [&](Config const& cfg) { - Application::pointer app = createTestApplication(clock, cfg); - - std::vector live( - LedgerTestUtils::generateValidUniqueLedgerEntriesWithExclusions( - {CONFIG_SETTING}, 10)); - std::vector dead{}; - - std::shared_ptr b1; - - { - std::shared_ptr b2 = LiveBucket::fresh( - app->getBucketManager(), getAppLedgerVersion(app), {}, live, - dead, /*countMergeEvents=*/true, clock.getIOContext(), - /*doFsync=*/true); - b1 = b2; - - // Bucket is referenced by b1, b2 and the BucketManager. - CHECK(b1.use_count() == 3); - - std::shared_ptr b3 = LiveBucket::fresh( - app->getBucketManager(), getAppLedgerVersion(app), {}, live, - dead, /*countMergeEvents=*/true, clock.getIOContext(), - /*doFsync=*/true); - std::shared_ptr b4 = LiveBucket::fresh( - app->getBucketManager(), getAppLedgerVersion(app), {}, live, - dead, /*countMergeEvents=*/true, clock.getIOContext(), - /*doFsync=*/true); - // Bucket is referenced by b1, b2, b3, b4 and the BucketManager. - CHECK(b1.use_count() == 5); - } - - // Take pointer by reference to not mess up use_count() - auto dropBucket = [&](std::shared_ptr& b) { - std::string filename = b->getFilename().string(); - std::string indexFilename = - app->getBucketManager().bucketIndexFilename(b->getHash()); - CHECK(fs::exists(filename)); - if (bucketListDB) - { - CHECK(fs::exists(indexFilename)); - } + VirtualClock clock; + Config cfg = getTestConfig(); - b.reset(); - app->getBucketManager().forgetUnreferencedBuckets(); - CHECK(!fs::exists(filename)); - CHECK(!fs::exists(indexFilename)); - }; + // Make sure all Buckets serialize indexes to disk for test + cfg.BUCKETLIST_DB_INDEX_CUTOFF = 0; + cfg.MANUAL_CLOSE = false; - // Bucket is now only referenced by b1 and the BucketManager. - CHECK(b1.use_count() == 2); + for_versions_with_differing_bucket_logic(cfg, [&](Config const& cfg) { + Application::pointer app = createTestApplication(clock, cfg); - // Drop bucket ourselves then purge bucketManager. - dropBucket(b1); + std::vector live( + LedgerTestUtils::generateValidUniqueLedgerEntriesWithExclusions( + {CONFIG_SETTING}, 10)); + std::vector dead{}; - // Try adding a bucket to the BucketManager's bucketlist - auto& bl = app->getBucketManager().getLiveBucketList(); - bl.addBatch(*app, 1, getAppLedgerVersion(app), {}, live, dead); - clearFutures(app, bl); - b1 = bl.getLevel(0).getCurr(); + std::shared_ptr b1; - // Bucket should be referenced by bucketlist itself, BucketManager - // cache and b1. - CHECK(b1.use_count() == 3); + { + std::shared_ptr b2 = LiveBucket::fresh( + app->getBucketManager(), getAppLedgerVersion(app), {}, live, + dead, /*countMergeEvents=*/true, clock.getIOContext(), + /*doFsync=*/true); + b1 = b2; - // This shouldn't change if we forget unreferenced buckets since - // it's referenced by bucketlist. - app->getBucketManager().forgetUnreferencedBuckets(); + // Bucket is referenced by b1, b2 and the BucketManager. CHECK(b1.use_count() == 3); - // But if we mutate the curr bucket of the bucketlist, it should. - live[0] = LedgerTestUtils::generateValidLedgerEntryWithExclusions( - {CONFIG_SETTING}); - bl.addBatch(*app, 1, getAppLedgerVersion(app), {}, live, dead); - clearFutures(app, bl); - CHECK(b1.use_count() == 2); - - // Drop it again. - dropBucket(b1); - }); - }; + std::shared_ptr b3 = LiveBucket::fresh( + app->getBucketManager(), getAppLedgerVersion(app), {}, live, + dead, /*countMergeEvents=*/true, clock.getIOContext(), + /*doFsync=*/true); + std::shared_ptr b4 = LiveBucket::fresh( + app->getBucketManager(), getAppLedgerVersion(app), {}, live, + dead, /*countMergeEvents=*/true, clock.getIOContext(), + /*doFsync=*/true); + // Bucket is referenced by b1, b2, b3, b4 and the BucketManager. + CHECK(b1.use_count() == 5); + } - SECTION("BucketListDB") - { - test(true); - } + // Take pointer by reference to not mess up use_count() + auto dropBucket = [&](std::shared_ptr& b) { + std::string filename = b->getFilename().string(); + std::string indexFilename = + app->getBucketManager().bucketIndexFilename(b->getHash()); + CHECK(fs::exists(filename)); + CHECK(fs::exists(indexFilename)); - SECTION("SQL") - { - test(false); - } + b.reset(); + app->getBucketManager().forgetUnreferencedBuckets(); + CHECK(!fs::exists(filename)); + CHECK(!fs::exists(indexFilename)); + }; + + // Bucket is now only referenced by b1 and the BucketManager. + CHECK(b1.use_count() == 2); + + // Drop bucket ourselves then purge bucketManager. + dropBucket(b1); + + // Try adding a bucket to the BucketManager's bucketlist + auto& bl = app->getBucketManager().getLiveBucketList(); + bl.addBatch(*app, 1, getAppLedgerVersion(app), {}, live, dead); + clearFutures(app, bl); + b1 = bl.getLevel(0).getCurr(); + + // Bucket should be referenced by bucketlist itself, BucketManager + // cache and b1. + CHECK(b1.use_count() == 3); + + // This shouldn't change if we forget unreferenced buckets since + // it's referenced by bucketlist. + app->getBucketManager().forgetUnreferencedBuckets(); + CHECK(b1.use_count() == 3); + + // But if we mutate the curr bucket of the bucketlist, it should. + live[0] = LedgerTestUtils::generateValidLedgerEntryWithExclusions( + {CONFIG_SETTING}); + bl.addBatch(*app, 1, getAppLedgerVersion(app), {}, live, dead); + clearFutures(app, bl); + CHECK(b1.use_count() == 2); + + // Drop it again. + dropBucket(b1); + }); } TEST_CASE("bucketmanager missing buckets fail", "[bucket][bucketmanager]") diff --git a/src/ledger/LedgerTxn.cpp b/src/ledger/LedgerTxn.cpp index cf322d447d..f2d6c1e79d 100644 --- a/src/ledger/LedgerTxn.cpp +++ b/src/ledger/LedgerTxn.cpp @@ -2015,66 +2015,11 @@ LedgerTxn::deleteOffersModifiedOnOrAfterLedger(uint32_t ledger) const } void -LedgerTxn::dropAccounts(bool rebuild) -{ - throw std::runtime_error("called dropAccounts on non-root LedgerTxn"); -} - -void -LedgerTxn::dropData(bool rebuild) -{ - throw std::runtime_error("called dropData on non-root LedgerTxn"); -} - -void -LedgerTxn::dropOffers(bool rebuild) +LedgerTxn::dropOffers() { throw std::runtime_error("called dropOffers on non-root LedgerTxn"); } -void -LedgerTxn::dropTrustLines(bool rebuild) -{ - throw std::runtime_error("called dropTrustLines on non-root LedgerTxn"); -} - -void -LedgerTxn::dropClaimableBalances(bool rebuild) -{ - throw std::runtime_error( - "called dropClaimableBalances on non-root LedgerTxn"); -} - -void -LedgerTxn::dropLiquidityPools(bool rebuild) -{ - throw std::runtime_error("called dropLiquidityPools on non-root LedgerTxn"); -} - -void -LedgerTxn::dropContractData(bool rebuild) -{ - throw std::runtime_error("called dropContractData on non-root LedgerTxn"); -} - -void -LedgerTxn::dropContractCode(bool rebuild) -{ - throw std::runtime_error("called dropContractCode on non-root LedgerTxn"); -} - -void -LedgerTxn::dropConfigSettings(bool rebuild) -{ - throw std::runtime_error("called dropConfigSettings on non-root LedgerTxn"); -} - -void -LedgerTxn::dropTTL(bool rebuild) -{ - throw std::runtime_error("called dropTTL on non-root LedgerTxn"); -} - double LedgerTxn::getPrefetchHitRate() const { @@ -2717,36 +2662,6 @@ LedgerTxnRoot::Impl::commitChild(EntryIterator iter, mPrefetchMisses = 0; } -std::string -LedgerTxnRoot::Impl::tableFromLedgerEntryType(LedgerEntryType let) -{ - switch (let) - { - case ACCOUNT: - return "accounts"; - case DATA: - return "accountdata"; - case OFFER: - return "offers"; - case TRUSTLINE: - return "trustlines"; - case CLAIMABLE_BALANCE: - return "claimablebalance"; - case LIQUIDITY_POOL: - return "liquiditypool"; - case CONTRACT_DATA: - return "contractdata"; - case CONTRACT_CODE: - return "contractcode"; - case CONFIG_SETTING: - return "configsettings"; - case TTL: - return "ttl"; - default: - throw std::runtime_error("Unknown ledger entry type"); - } -} - uint64_t LedgerTxnRoot::countOffers(LedgerRange const& ledgers) const { @@ -2783,69 +2698,14 @@ LedgerTxnRoot::Impl::deleteOffersModifiedOnOrAfterLedger(uint32_t ledger) const mEntryCache.clear(); mBestOffers.clear(); - std::string query = "DELETE FROM " + tableFromLedgerEntryType(OFFER) + - " WHERE lastmodified >= :v1"; + std::string query = "DELETE FROM offers WHERE lastmodified >= :v1"; mApp.getDatabase().getSession() << query, use(ledger); } void -LedgerTxnRoot::dropAccounts(bool rebuild) -{ - mImpl->dropAccounts(rebuild); -} - -void -LedgerTxnRoot::dropData(bool rebuild) -{ - mImpl->dropData(rebuild); -} - -void -LedgerTxnRoot::dropOffers(bool rebuild) -{ - mImpl->dropOffers(rebuild); -} - -void -LedgerTxnRoot::dropTrustLines(bool rebuild) -{ - mImpl->dropTrustLines(rebuild); -} - -void -LedgerTxnRoot::dropClaimableBalances(bool rebuild) -{ - mImpl->dropClaimableBalances(rebuild); -} - -void -LedgerTxnRoot::dropLiquidityPools(bool rebuild) -{ - mImpl->dropLiquidityPools(rebuild); -} - -void -LedgerTxnRoot::dropContractData(bool rebuild) -{ - mImpl->dropContractData(rebuild); -} - -void -LedgerTxnRoot::dropContractCode(bool rebuild) -{ - mImpl->dropContractCode(rebuild); -} - -void -LedgerTxnRoot::dropConfigSettings(bool rebuild) -{ - mImpl->dropConfigSettings(rebuild); -} - -void -LedgerTxnRoot::dropTTL(bool rebuild) +LedgerTxnRoot::dropOffers() { - mImpl->dropTTL(rebuild); + mImpl->dropOffers(); } uint32_t diff --git a/src/ledger/LedgerTxn.h b/src/ledger/LedgerTxn.h index 1c1cd4385b..a89ac6bac8 100644 --- a/src/ledger/LedgerTxn.h +++ b/src/ledger/LedgerTxn.h @@ -474,45 +474,9 @@ class AbstractLedgerTxnParent // when called on anything other than a (real or stub) root LedgerTxn. virtual void deleteOffersModifiedOnOrAfterLedger(uint32_t ledger) const = 0; - // Delete all account ledger entries in the database. Will throw when called - // on anything other than a (real or stub) root LedgerTxn. - virtual void dropAccounts(bool rebuild) = 0; - - // Delete all account-data ledger entries. Will throw when called on - // anything other than a (real or stub) root LedgerTxn. - virtual void dropData(bool rebuild) = 0; - // Delete all offer ledger entries. Will throw when called on anything other // than a (real or stub) root LedgerTxn. - virtual void dropOffers(bool rebuild) = 0; - - // Delete all trustline ledger entries. Will throw when called on anything - // other than a (real or stub) root LedgerTxn. - virtual void dropTrustLines(bool rebuild) = 0; - - // Delete all claimable balance ledger entries. Will throw when called on - // anything other than a (real or stub) root LedgerTxn. - virtual void dropClaimableBalances(bool rebuild) = 0; - - // Delete all liquidity pool ledger entries. Will throw when called on - // anything other than a (real or stub) root LedgerTxn. - virtual void dropLiquidityPools(bool rebuild) = 0; - - // Delete all contract data ledger entries. Will throw when called on - // anything other than a (real or stub) root LedgerTxn. - virtual void dropContractData(bool rebuild) = 0; - - // Delete all contract code ledger entries. Will throw when called on - // anything other than a (real or stub) root LedgerTxn. - virtual void dropContractCode(bool rebuild) = 0; - - // Delete all config setting ledger entries. Will throw when called on - // anything other than a (real or stub) root LedgerTxn. - virtual void dropConfigSettings(bool rebuild) = 0; - - // Delete all ttl ledger entries. Will throw when called on - // anything other than a (real or stub) root LedgerTxn. - virtual void dropTTL(bool rebuild) = 0; + virtual void dropOffers() = 0; // Return the current cache hit rate for prefetched ledger entries, as a // fraction from 0.0 to 1.0. Will throw when called on anything other than a @@ -813,16 +777,7 @@ class LedgerTxn : public AbstractLedgerTxn uint64_t countOffers(LedgerRange const& ledgers) const override; void deleteOffersModifiedOnOrAfterLedger(uint32_t ledger) const override; - void dropAccounts(bool rebuild) override; - void dropData(bool rebuild) override; - void dropOffers(bool rebuild) override; - void dropTrustLines(bool rebuild) override; - void dropClaimableBalances(bool rebuild) override; - void dropLiquidityPools(bool rebuild) override; - void dropContractData(bool rebuild) override; - void dropContractCode(bool rebuild) override; - void dropConfigSettings(bool rebuild) override; - void dropTTL(bool rebuild) override; + void dropOffers() override; double getPrefetchHitRate() const override; uint32_t prefetchClassic(UnorderedSet const& keys) override; @@ -877,16 +832,7 @@ class LedgerTxnRoot : public AbstractLedgerTxnParent void deleteOffersModifiedOnOrAfterLedger(uint32_t ledger) const override; - void dropAccounts(bool rebuild) override; - void dropData(bool rebuild) override; - void dropOffers(bool rebuild) override; - void dropTrustLines(bool rebuild) override; - void dropClaimableBalances(bool rebuild) override; - void dropLiquidityPools(bool rebuild) override; - void dropContractData(bool rebuild) override; - void dropContractCode(bool rebuild) override; - void dropConfigSettings(bool rebuild) override; - void dropTTL(bool rebuild) override; + void dropOffers() override; #ifdef BUILD_TESTS void resetForFuzzer() override; diff --git a/src/ledger/LedgerTxnAccountSQL.cpp b/src/ledger/LedgerTxnAccountSQL.cpp deleted file mode 100644 index 3313917893..0000000000 --- a/src/ledger/LedgerTxnAccountSQL.cpp +++ /dev/null @@ -1,679 +0,0 @@ -// Copyright 2018 Stellar Development Foundation and contributors. Licensed -// under the Apache License, Version 2.0. See the COPYING file at the root -// of this distribution or at http://www.apache.org/licenses/LICENSE-2.0 - -#include "crypto/KeyUtils.h" -#include "crypto/SecretKey.h" -#include "crypto/SignerKey.h" -#include "database/Database.h" -#include "database/DatabaseTypeSpecificOperation.h" -#include "ledger/LedgerTxnImpl.h" -#include "ledger/LedgerTypeUtils.h" -#include "main/Application.h" -#include "util/Decoder.h" -#include "util/GlobalChecks.h" -#include "util/Logging.h" -#include "util/XDROperators.h" -#include "util/types.h" -#include "xdrpp/marshal.h" -#include - -namespace stellar -{ - -std::shared_ptr -LedgerTxnRoot::Impl::loadAccount(LedgerKey const& key) const -{ - ZoneScoped; - std::string actIDStrKey = KeyUtils::toStrKey(key.account().accountID); - - std::string inflationDest, homeDomain, thresholds, signers; - soci::indicator inflationDestInd, signersInd; - std::string extensionStr; - soci::indicator extensionInd; - std::string ledgerExtStr; - soci::indicator ledgerExtInd; - - LedgerEntry le; - le.data.type(ACCOUNT); - auto& account = le.data.account(); - - auto prep = mApp.getDatabase().getPreparedStatement( - "SELECT balance, seqnum, numsubentries, " - "inflationdest, homedomain, thresholds, " - "flags, lastmodified, " - "signers, extension, " - "ledgerext FROM accounts WHERE accountid=:v1"); - auto& st = prep.statement(); - st.exchange(soci::into(account.balance)); - st.exchange(soci::into(account.seqNum)); - st.exchange(soci::into(account.numSubEntries)); - st.exchange(soci::into(inflationDest, inflationDestInd)); - st.exchange(soci::into(homeDomain)); - st.exchange(soci::into(thresholds)); - st.exchange(soci::into(account.flags)); - st.exchange(soci::into(le.lastModifiedLedgerSeq)); - st.exchange(soci::into(signers, signersInd)); - st.exchange(soci::into(extensionStr, extensionInd)); - st.exchange(soci::into(ledgerExtStr, ledgerExtInd)); - st.exchange(soci::use(actIDStrKey)); - st.define_and_bind(); - { - auto timer = mApp.getDatabase().getSelectTimer("account"); - st.execute(true); - } - if (!st.got_data()) - { - return nullptr; - } - - account.accountID = key.account().accountID; - decoder::decode_b64(homeDomain, account.homeDomain); - - bn::decode_b64(thresholds.begin(), thresholds.end(), - account.thresholds.begin()); - - if (inflationDestInd == soci::i_ok) - { - account.inflationDest.activate() = - KeyUtils::fromStrKey(inflationDest); - } - - if (signersInd == soci::i_ok) - { - std::vector signersOpaque; - decoder::decode_b64(signers, signersOpaque); - xdr::xdr_from_opaque(signersOpaque, account.signers); - releaseAssert( - std::adjacent_find(account.signers.begin(), account.signers.end(), - [](Signer const& lhs, Signer const& rhs) { - return !(lhs.key < rhs.key); - }) == account.signers.end()); - } - - decodeOpaqueXDR(extensionStr, extensionInd, account.ext); - - decodeOpaqueXDR(ledgerExtStr, ledgerExtInd, le.ext); - - return std::make_shared(std::move(le)); -} - -std::vector -LedgerTxnRoot::Impl::loadInflationWinners(size_t maxWinners, - int64_t minBalance) const -{ - InflationWinner w; - std::string inflationDest; - - auto prep = mApp.getDatabase().getPreparedStatement( - "SELECT sum(balance) AS votes, inflationdest" - " FROM accounts WHERE inflationdest IS NOT NULL" - " AND balance >= 1000000000 GROUP BY inflationdest" - " ORDER BY votes DESC, inflationdest DESC LIMIT :lim"); - auto& st = prep.statement(); - st.exchange(soci::into(w.votes)); - st.exchange(soci::into(inflationDest)); - st.exchange(soci::use(maxWinners)); - st.define_and_bind(); - st.execute(true); - - std::vector winners; - while (st.got_data()) - { - w.accountID = KeyUtils::fromStrKey(inflationDest); - if (w.votes < minBalance) - { - break; - } - winners.push_back(w); - st.fetch(); - } - return winners; -} - -class BulkUpsertAccountsOperation : public DatabaseTypeSpecificOperation -{ - Database& mDB; - std::vector mAccountIDs; - std::vector mBalances; - std::vector mSeqNums; - std::vector mSubEntryNums; - std::vector mInflationDests; - std::vector mInflationDestInds; - std::vector mFlags; - std::vector mHomeDomains; - std::vector mThresholds; - std::vector mSigners; - std::vector mSignerInds; - std::vector mLastModifieds; - std::vector mExtensions; - std::vector mExtensionInds; - std::vector mLedgerExtensions; - - public: - BulkUpsertAccountsOperation(Database& DB, - std::vector const& entries) - : mDB(DB) - { - mAccountIDs.reserve(entries.size()); - mBalances.reserve(entries.size()); - mSeqNums.reserve(entries.size()); - mSubEntryNums.reserve(entries.size()); - mInflationDests.reserve(entries.size()); - mInflationDestInds.reserve(entries.size()); - mFlags.reserve(entries.size()); - mHomeDomains.reserve(entries.size()); - mThresholds.reserve(entries.size()); - mSigners.reserve(entries.size()); - mSignerInds.reserve(entries.size()); - mLastModifieds.reserve(entries.size()); - mExtensions.reserve(entries.size()); - mExtensionInds.reserve(entries.size()); - mLedgerExtensions.reserve(entries.size()); - - for (auto const& e : entries) - { - releaseAssert(e.entryExists()); - releaseAssert(e.entry().type() == - InternalLedgerEntryType::LEDGER_ENTRY); - auto const& le = e.entry().ledgerEntry(); - releaseAssert(le.data.type() == ACCOUNT); - auto const& account = le.data.account(); - mAccountIDs.emplace_back(KeyUtils::toStrKey(account.accountID)); - mBalances.emplace_back(account.balance); - mSeqNums.emplace_back(account.seqNum); - mSubEntryNums.emplace_back(unsignedToSigned(account.numSubEntries)); - - if (account.inflationDest) - { - mInflationDests.emplace_back( - KeyUtils::toStrKey(*account.inflationDest)); - mInflationDestInds.emplace_back(soci::i_ok); - } - else - { - mInflationDests.emplace_back(""); - mInflationDestInds.emplace_back(soci::i_null); - } - mFlags.emplace_back(unsignedToSigned(account.flags)); - mHomeDomains.emplace_back(decoder::encode_b64(account.homeDomain)); - mThresholds.emplace_back(decoder::encode_b64(account.thresholds)); - if (account.signers.empty()) - { - mSigners.emplace_back(""); - mSignerInds.emplace_back(soci::i_null); - } - else - { - mSigners.emplace_back( - decoder::encode_b64(xdr::xdr_to_opaque(account.signers))); - mSignerInds.emplace_back(soci::i_ok); - } - mLastModifieds.emplace_back( - unsignedToSigned(le.lastModifiedLedgerSeq)); - - if (account.ext.v() >= 1) - { - mExtensions.emplace_back( - decoder::encode_b64(xdr::xdr_to_opaque(account.ext))); - mExtensionInds.emplace_back(soci::i_ok); - } - else - { - mExtensions.emplace_back(""); - mExtensionInds.emplace_back(soci::i_null); - } - - mLedgerExtensions.emplace_back( - decoder::encode_b64(xdr::xdr_to_opaque(le.ext))); - } - } - - void - doSociGenericOperation() - { - std::string sql = - "INSERT INTO accounts ( " - "accountid, balance, seqnum, numsubentries, inflationdest," - "homedomain, thresholds, signers, flags, lastmodified, " - "extension, ledgerext " - ") VALUES ( " - ":id, :v1, :v2, :v3, :v4, :v5, :v6, :v7, :v8, :v9, :v10, :v11 " - ") ON CONFLICT (accountid) DO UPDATE SET " - "balance = excluded.balance, " - "seqnum = excluded.seqnum, " - "numsubentries = excluded.numsubentries, " - "inflationdest = excluded.inflationdest, " - "homedomain = excluded.homedomain, " - "thresholds = excluded.thresholds, " - "signers = excluded.signers, " - "flags = excluded.flags, " - "lastmodified = excluded.lastmodified, " - "extension = excluded.extension, " - "ledgerext = excluded.ledgerext"; - auto prep = mDB.getPreparedStatement(sql); - soci::statement& st = prep.statement(); - st.exchange(soci::use(mAccountIDs)); - st.exchange(soci::use(mBalances)); - st.exchange(soci::use(mSeqNums)); - st.exchange(soci::use(mSubEntryNums)); - st.exchange(soci::use(mInflationDests, mInflationDestInds)); - st.exchange(soci::use(mHomeDomains)); - st.exchange(soci::use(mThresholds)); - st.exchange(soci::use(mSigners, mSignerInds)); - st.exchange(soci::use(mFlags)); - st.exchange(soci::use(mLastModifieds)); - st.exchange(soci::use(mExtensions, mExtensionInds)); - st.exchange(soci::use(mLedgerExtensions)); - st.define_and_bind(); - { - auto timer = mDB.getUpsertTimer("account"); - st.execute(true); - } - if (static_cast(st.get_affected_rows()) != mAccountIDs.size()) - { - throw std::runtime_error("Could not update data in SQL"); - } - } - - void - doSqliteSpecificOperation(soci::sqlite3_session_backend* sq) override - { - doSociGenericOperation(); - } - -#ifdef USE_POSTGRES - void - doPostgresSpecificOperation(soci::postgresql_session_backend* pg) override - { - std::string strAccountIDs, strBalances, strSeqNums, strSubEntryNums, - strInflationDests, strFlags, strHomeDomains, strThresholds, - strSigners, strLastModifieds, strExtensions, strLedgerExtensions; - - PGconn* conn = pg->conn_; - marshalToPGArray(conn, strAccountIDs, mAccountIDs); - marshalToPGArray(conn, strBalances, mBalances); - marshalToPGArray(conn, strSeqNums, mSeqNums); - marshalToPGArray(conn, strSubEntryNums, mSubEntryNums); - marshalToPGArray(conn, strInflationDests, mInflationDests, - &mInflationDestInds); - marshalToPGArray(conn, strFlags, mFlags); - marshalToPGArray(conn, strHomeDomains, mHomeDomains); - marshalToPGArray(conn, strThresholds, mThresholds); - marshalToPGArray(conn, strSigners, mSigners, &mSignerInds); - marshalToPGArray(conn, strLastModifieds, mLastModifieds); - marshalToPGArray(conn, strExtensions, mExtensions, &mExtensionInds); - marshalToPGArray(conn, strLedgerExtensions, mLedgerExtensions); - - std::string sql = "WITH r AS (SELECT " - "unnest(:ids::TEXT[]), " - "unnest(:v1::BIGINT[]), " - "unnest(:v2::BIGINT[]), " - "unnest(:v3::INT[]), " - "unnest(:v4::TEXT[]), " - "unnest(:v5::TEXT[]), " - "unnest(:v6::TEXT[]), " - "unnest(:v7::TEXT[]), " - "unnest(:v8::INT[]), " - "unnest(:v9::INT[]), " - "unnest(:v10::TEXT[]), " - "unnest(:v11::TEXT[]) " - ")" - "INSERT INTO accounts ( " - "accountid, balance, seqnum, " - "numsubentries, inflationdest, homedomain, " - "thresholds, signers, " - "flags, lastmodified, extension, " - "ledgerext " - ") SELECT * FROM r " - "ON CONFLICT (accountid) DO UPDATE SET " - "balance = excluded.balance, " - "seqnum = excluded.seqnum, " - "numsubentries = excluded.numsubentries, " - "inflationdest = excluded.inflationdest, " - "homedomain = excluded.homedomain, " - "thresholds = excluded.thresholds, " - "signers = excluded.signers, " - "flags = excluded.flags, " - "lastmodified = excluded.lastmodified, " - "extension = excluded.extension, " - "ledgerext = excluded.ledgerext"; - auto prep = mDB.getPreparedStatement(sql); - soci::statement& st = prep.statement(); - st.exchange(soci::use(strAccountIDs)); - st.exchange(soci::use(strBalances)); - st.exchange(soci::use(strSeqNums)); - st.exchange(soci::use(strSubEntryNums)); - st.exchange(soci::use(strInflationDests)); - st.exchange(soci::use(strHomeDomains)); - st.exchange(soci::use(strThresholds)); - st.exchange(soci::use(strSigners)); - st.exchange(soci::use(strFlags)); - st.exchange(soci::use(strLastModifieds)); - st.exchange(soci::use(strExtensions)); - st.exchange(soci::use(strLedgerExtensions)); - st.define_and_bind(); - { - auto timer = mDB.getUpsertTimer("account"); - st.execute(true); - } - if (static_cast(st.get_affected_rows()) != mAccountIDs.size()) - { - throw std::runtime_error("Could not update data in SQL"); - } - } -#endif -}; - -class BulkDeleteAccountsOperation : public DatabaseTypeSpecificOperation -{ - Database& mDB; - LedgerTxnConsistency mCons; - std::vector mAccountIDs; - - public: - BulkDeleteAccountsOperation(Database& DB, LedgerTxnConsistency cons, - std::vector const& entries) - : mDB(DB), mCons(cons) - { - for (auto const& e : entries) - { - releaseAssert(!e.entryExists()); - releaseAssert(e.key().type() == - InternalLedgerEntryType::LEDGER_ENTRY); - releaseAssert(e.key().ledgerKey().type() == ACCOUNT); - auto const& account = e.key().ledgerKey().account(); - mAccountIDs.emplace_back(KeyUtils::toStrKey(account.accountID)); - } - } - - void - doSociGenericOperation() - { - std::string sql = "DELETE FROM accounts WHERE accountid = :id"; - auto prep = mDB.getPreparedStatement(sql); - soci::statement& st = prep.statement(); - st.exchange(soci::use(mAccountIDs)); - st.define_and_bind(); - { - auto timer = mDB.getDeleteTimer("account"); - st.execute(true); - } - if (static_cast(st.get_affected_rows()) != mAccountIDs.size() && - mCons == LedgerTxnConsistency::EXACT) - { - throw std::runtime_error("Could not update data in SQL"); - } - } - - void - doSqliteSpecificOperation(soci::sqlite3_session_backend* sq) override - { - doSociGenericOperation(); - } - -#ifdef USE_POSTGRES - void - doPostgresSpecificOperation(soci::postgresql_session_backend* pg) override - { - PGconn* conn = pg->conn_; - std::string strAccountIDs; - marshalToPGArray(conn, strAccountIDs, mAccountIDs); - std::string sql = - "WITH r AS (SELECT unnest(:ids::TEXT[])) " - "DELETE FROM accounts WHERE accountid IN (SELECT * FROM r)"; - auto prep = mDB.getPreparedStatement(sql); - soci::statement& st = prep.statement(); - st.exchange(soci::use(strAccountIDs)); - st.define_and_bind(); - { - auto timer = mDB.getDeleteTimer("account"); - st.execute(true); - } - if (static_cast(st.get_affected_rows()) != mAccountIDs.size() && - mCons == LedgerTxnConsistency::EXACT) - { - throw std::runtime_error("Could not update data in SQL"); - } - } -#endif -}; - -void -LedgerTxnRoot::Impl::bulkUpsertAccounts( - std::vector const& entries) -{ - ZoneScoped; - ZoneValue(static_cast(entries.size())); - BulkUpsertAccountsOperation op(mApp.getDatabase(), entries); - mApp.getDatabase().doDatabaseTypeSpecificOperation(op); -} - -void -LedgerTxnRoot::Impl::bulkDeleteAccounts( - std::vector const& entries, LedgerTxnConsistency cons) -{ - ZoneScoped; - ZoneValue(static_cast(entries.size())); - BulkDeleteAccountsOperation op(mApp.getDatabase(), cons, entries); - mApp.getDatabase().doDatabaseTypeSpecificOperation(op); -} - -void -LedgerTxnRoot::Impl::dropAccounts(bool rebuild) -{ - throwIfChild(); - mEntryCache.clear(); - mBestOffers.clear(); - - mApp.getDatabase().getSession() << "DROP TABLE IF EXISTS accounts;"; - mApp.getDatabase().getSession() << "DROP TABLE IF EXISTS signers;"; - - if (rebuild) - { - std::string coll = mApp.getDatabase().getSimpleCollationClause(); - - mApp.getDatabase().getSession() - << "CREATE TABLE accounts" - << "(" - << "accountid VARCHAR(56) " << coll << " PRIMARY KEY," - << "balance BIGINT NOT NULL CHECK (balance >= 0)," - "buyingliabilities BIGINT CHECK (buyingliabilities >= 0)," - "sellingliabilities BIGINT CHECK (sellingliabilities >= 0)," - "seqnum BIGINT NOT NULL," - "numsubentries INT NOT NULL CHECK (numsubentries " - ">= 0)," - "inflationdest VARCHAR(56)," - "homedomain VARCHAR(44) NOT NULL," - "thresholds TEXT NOT NULL," - "flags INT NOT NULL," - "signers TEXT," - "lastmodified INT NOT NULL," - "extension TEXT," - "ledgerext TEXT NOT NULL" - ");"; - if (!mApp.getDatabase().isSqlite()) - { - mApp.getDatabase().getSession() << "ALTER TABLE accounts " - << "ALTER COLUMN accountid " - << "TYPE VARCHAR(56) COLLATE \"C\""; - } - } -} - -class BulkLoadAccountsOperation - : public DatabaseTypeSpecificOperation> -{ - Database& mDb; - std::vector mAccountIDs; - - std::vector - executeAndFetch(soci::statement& st) - { - std::string accountID, inflationDest, homeDomain, thresholds, signers; - int64_t balance; - uint64_t seqNum; - uint32_t numSubEntries, flags, lastModified; - std::string extension; - soci::indicator inflationDestInd, signersInd, extensionInd; - std::string ledgerExtension; - soci::indicator ledgerExtInd; - - st.exchange(soci::into(accountID)); - st.exchange(soci::into(balance)); - st.exchange(soci::into(seqNum)); - st.exchange(soci::into(numSubEntries)); - st.exchange(soci::into(inflationDest, inflationDestInd)); - st.exchange(soci::into(homeDomain)); - st.exchange(soci::into(thresholds)); - st.exchange(soci::into(flags)); - st.exchange(soci::into(lastModified)); - st.exchange(soci::into(extension, extensionInd)); - st.exchange(soci::into(signers, signersInd)); - st.exchange(soci::into(ledgerExtension, ledgerExtInd)); - st.define_and_bind(); - { - auto timer = mDb.getSelectTimer("account"); - st.execute(true); - } - - std::vector res; - while (st.got_data()) - { - res.emplace_back(); - auto& le = res.back(); - le.data.type(ACCOUNT); - auto& ae = le.data.account(); - - ae.accountID = KeyUtils::fromStrKey(accountID); - ae.balance = balance; - ae.seqNum = seqNum; - ae.numSubEntries = numSubEntries; - - if (inflationDestInd == soci::i_ok) - { - ae.inflationDest.activate() = - KeyUtils::fromStrKey(inflationDest); - } - - decoder::decode_b64(homeDomain, ae.homeDomain); - - bn::decode_b64(thresholds.begin(), thresholds.end(), - ae.thresholds.begin()); - - if (inflationDestInd == soci::i_ok) - { - ae.inflationDest.activate() = - KeyUtils::fromStrKey(inflationDest); - } - - ae.flags = flags; - le.lastModifiedLedgerSeq = lastModified; - - decodeOpaqueXDR(extension, extensionInd, ae.ext); - - if (signersInd == soci::i_ok) - { - std::vector signersOpaque; - decoder::decode_b64(signers, signersOpaque); - xdr::xdr_from_opaque(signersOpaque, ae.signers); - releaseAssert(std::adjacent_find( - ae.signers.begin(), ae.signers.end(), - [](Signer const& lhs, Signer const& rhs) { - return !(lhs.key < rhs.key); - }) == ae.signers.end()); - } - - decodeOpaqueXDR(ledgerExtension, ledgerExtInd, le.ext); - - st.fetch(); - } - return res; - } - - public: - BulkLoadAccountsOperation(Database& db, UnorderedSet const& keys) - : mDb(db) - { - mAccountIDs.reserve(keys.size()); - for (auto const& k : keys) - { - releaseAssert(k.type() == ACCOUNT); - mAccountIDs.emplace_back(KeyUtils::toStrKey(k.account().accountID)); - } - } - - virtual std::vector - doSqliteSpecificOperation(soci::sqlite3_session_backend* sq) override - { - std::vector accountIDcstrs; - accountIDcstrs.reserve(mAccountIDs.size()); - for (auto const& acc : mAccountIDs) - { - accountIDcstrs.emplace_back(acc.c_str()); - } - - std::string sql = - "SELECT accountid, balance, seqnum, numsubentries, " - "inflationdest, homedomain, thresholds, flags, lastmodified, " - "extension, signers, ledgerext" - " FROM accounts " - "WHERE accountid IN carray(?, ?, 'char*')"; - - auto prep = mDb.getPreparedStatement(sql); - auto be = prep.statement().get_backend(); - if (be == nullptr) - { - throw std::runtime_error("no sql backend"); - } - auto sqliteStatement = - dynamic_cast(be); - releaseAssertOrThrow(sqliteStatement); - auto st = sqliteStatement->stmt_; - - sqlite3_reset(st); - sqlite3_bind_pointer(st, 1, accountIDcstrs.data(), "carray", 0); - sqlite3_bind_int(st, 2, static_cast(accountIDcstrs.size())); - return executeAndFetch(prep.statement()); - } - -#ifdef USE_POSTGRES - virtual std::vector - doPostgresSpecificOperation(soci::postgresql_session_backend* pg) override - { - std::string strAccountIDs; - marshalToPGArray(pg->conn_, strAccountIDs, mAccountIDs); - - std::string sql = - "WITH r AS (SELECT unnest(:v1::TEXT[])) " - "SELECT accountid, balance, seqnum, numsubentries, " - "inflationdest, homedomain, thresholds, flags, lastmodified, " - "extension, signers, ledgerext" - " FROM accounts " - "WHERE accountid IN (SELECT * FROM r)"; - - auto prep = mDb.getPreparedStatement(sql); - auto& st = prep.statement(); - st.exchange(soci::use(strAccountIDs)); - return executeAndFetch(st); - } -#endif -}; - -UnorderedMap> -LedgerTxnRoot::Impl::bulkLoadAccounts(UnorderedSet const& keys) const -{ - ZoneScoped; - ZoneValue(static_cast(keys.size())); - if (!keys.empty()) - { - BulkLoadAccountsOperation op(mApp.getDatabase(), keys); - return populateLoadedEntries( - keys, mApp.getDatabase().doDatabaseTypeSpecificOperation(op)); - } - else - { - return {}; - } -} -} diff --git a/src/ledger/LedgerTxnClaimableBalanceSQL.cpp b/src/ledger/LedgerTxnClaimableBalanceSQL.cpp deleted file mode 100644 index 365efe95bf..0000000000 --- a/src/ledger/LedgerTxnClaimableBalanceSQL.cpp +++ /dev/null @@ -1,374 +0,0 @@ -// Copyright 2020 Stellar Development Foundation and contributors. Licensed -// under the Apache License, Version 2.0. See the COPYING file at the root -// of this distribution or at http://www.apache.org/licenses/LICENSE-2.0 - -#include "ledger/LedgerTxnImpl.h" -#include "ledger/LedgerTypeUtils.h" -#include "main/Application.h" -#include "util/GlobalChecks.h" -#include "util/types.h" - -namespace stellar -{ - -std::shared_ptr -LedgerTxnRoot::Impl::loadClaimableBalance(LedgerKey const& key) const -{ - auto balanceID = toOpaqueBase64(key.claimableBalance().balanceID); - - std::string claimableBalanceEntryStr; - LedgerEntry le; - - std::string sql = "SELECT ledgerentry " - "FROM claimablebalance " - "WHERE balanceid= :balanceid"; - auto prep = mApp.getDatabase().getPreparedStatement(sql); - auto& st = prep.statement(); - st.exchange(soci::into(claimableBalanceEntryStr)); - st.exchange(soci::use(balanceID)); - st.define_and_bind(); - st.execute(true); - if (!st.got_data()) - { - return nullptr; - } - - fromOpaqueBase64(le, claimableBalanceEntryStr); - releaseAssert(le.data.type() == CLAIMABLE_BALANCE); - - return std::make_shared(std::move(le)); -} - -class BulkLoadClaimableBalanceOperation - : public DatabaseTypeSpecificOperation> -{ - Database& mDb; - std::vector mBalanceIDs; - - std::vector - executeAndFetch(soci::statement& st) - { - std::string balanceIdStr, claimableBalanceEntryStr; - - st.exchange(soci::into(balanceIdStr)); - st.exchange(soci::into(claimableBalanceEntryStr)); - st.define_and_bind(); - { - auto timer = mDb.getSelectTimer("claimablebalance"); - st.execute(true); - } - - std::vector res; - while (st.got_data()) - { - res.emplace_back(); - auto& le = res.back(); - - fromOpaqueBase64(le, claimableBalanceEntryStr); - releaseAssert(le.data.type() == CLAIMABLE_BALANCE); - - st.fetch(); - } - return res; - } - - public: - BulkLoadClaimableBalanceOperation(Database& db, - UnorderedSet const& keys) - : mDb(db) - { - mBalanceIDs.reserve(keys.size()); - for (auto const& k : keys) - { - releaseAssert(k.type() == CLAIMABLE_BALANCE); - mBalanceIDs.emplace_back( - toOpaqueBase64(k.claimableBalance().balanceID)); - } - } - - std::vector - doSqliteSpecificOperation(soci::sqlite3_session_backend* sq) override - { - std::vector cstrBalanceIDs; - cstrBalanceIDs.reserve(mBalanceIDs.size()); - for (size_t i = 0; i < mBalanceIDs.size(); ++i) - { - cstrBalanceIDs.emplace_back(mBalanceIDs[i].c_str()); - } - - std::string sql = "WITH r AS (SELECT value FROM carray(?, ?, 'char*')) " - "SELECT balanceid, ledgerentry " - "FROM claimablebalance " - "WHERE balanceid IN r"; - - auto prep = mDb.getPreparedStatement(sql); - auto be = prep.statement().get_backend(); - if (be == nullptr) - { - throw std::runtime_error("no sql backend"); - } - auto sqliteStatement = - dynamic_cast(be); - releaseAssertOrThrow(sqliteStatement); - auto st = sqliteStatement->stmt_; - - sqlite3_reset(st); - sqlite3_bind_pointer(st, 1, cstrBalanceIDs.data(), "carray", 0); - sqlite3_bind_int(st, 2, static_cast(cstrBalanceIDs.size())); - return executeAndFetch(prep.statement()); - } - -#ifdef USE_POSTGRES - std::vector - doPostgresSpecificOperation(soci::postgresql_session_backend* pg) override - { - std::string strBalanceIDs; - marshalToPGArray(pg->conn_, strBalanceIDs, mBalanceIDs); - - std::string sql = "WITH r AS (SELECT unnest(:v1::TEXT[])) " - "SELECT balanceid, ledgerentry " - "FROM claimablebalance " - "WHERE balanceid IN (SELECT * from r)"; - - auto prep = mDb.getPreparedStatement(sql); - auto& st = prep.statement(); - st.exchange(soci::use(strBalanceIDs)); - return executeAndFetch(st); - } -#endif -}; - -UnorderedMap> -LedgerTxnRoot::Impl::bulkLoadClaimableBalance( - UnorderedSet const& keys) const -{ - if (!keys.empty()) - { - BulkLoadClaimableBalanceOperation op(mApp.getDatabase(), keys); - return populateLoadedEntries( - keys, mApp.getDatabase().doDatabaseTypeSpecificOperation(op)); - } - else - { - return {}; - } -} - -class BulkDeleteClaimableBalanceOperation - : public DatabaseTypeSpecificOperation -{ - Database& mDb; - LedgerTxnConsistency mCons; - std::vector mBalanceIDs; - - public: - BulkDeleteClaimableBalanceOperation( - Database& db, LedgerTxnConsistency cons, - std::vector const& entries) - : mDb(db), mCons(cons) - { - mBalanceIDs.reserve(entries.size()); - for (auto const& e : entries) - { - releaseAssert(!e.entryExists()); - releaseAssert(e.key().ledgerKey().type() == CLAIMABLE_BALANCE); - mBalanceIDs.emplace_back(toOpaqueBase64( - e.key().ledgerKey().claimableBalance().balanceID)); - } - } - - void - doSociGenericOperation() - { - std::string sql = "DELETE FROM claimablebalance WHERE balanceid = :id"; - auto prep = mDb.getPreparedStatement(sql); - auto& st = prep.statement(); - st.exchange(soci::use(mBalanceIDs)); - st.define_and_bind(); - { - auto timer = mDb.getDeleteTimer("claimablebalance"); - st.execute(true); - } - if (static_cast(st.get_affected_rows()) != mBalanceIDs.size() && - mCons == LedgerTxnConsistency::EXACT) - { - throw std::runtime_error("Could not update data in SQL"); - } - } - - void - doSqliteSpecificOperation(soci::sqlite3_session_backend* sq) override - { - doSociGenericOperation(); - } - -#ifdef USE_POSTGRES - void - doPostgresSpecificOperation(soci::postgresql_session_backend* pg) override - { - std::string strBalanceIDs; - marshalToPGArray(pg->conn_, strBalanceIDs, mBalanceIDs); - - std::string sql = "WITH r AS (SELECT unnest(:v1::TEXT[])) " - "DELETE FROM claimablebalance " - "WHERE balanceid IN (SELECT * FROM r)"; - - auto prep = mDb.getPreparedStatement(sql); - auto& st = prep.statement(); - st.exchange(soci::use(strBalanceIDs)); - st.define_and_bind(); - { - auto timer = mDb.getDeleteTimer("claimablebalance"); - st.execute(true); - } - if (static_cast(st.get_affected_rows()) != mBalanceIDs.size() && - mCons == LedgerTxnConsistency::EXACT) - { - throw std::runtime_error("Could not update data in SQL"); - } - } -#endif -}; - -void -LedgerTxnRoot::Impl::bulkDeleteClaimableBalance( - std::vector const& entries, LedgerTxnConsistency cons) -{ - BulkDeleteClaimableBalanceOperation op(mApp.getDatabase(), cons, entries); - mApp.getDatabase().doDatabaseTypeSpecificOperation(op); -} - -class BulkUpsertClaimableBalanceOperation - : public DatabaseTypeSpecificOperation -{ - Database& mDb; - std::vector mBalanceIDs; - std::vector mClaimableBalanceEntrys; - std::vector mLastModifieds; - - void - accumulateEntry(LedgerEntry const& entry) - { - releaseAssert(entry.data.type() == CLAIMABLE_BALANCE); - mBalanceIDs.emplace_back( - toOpaqueBase64(entry.data.claimableBalance().balanceID)); - mClaimableBalanceEntrys.emplace_back(toOpaqueBase64(entry)); - mLastModifieds.emplace_back( - unsignedToSigned(entry.lastModifiedLedgerSeq)); - } - - public: - BulkUpsertClaimableBalanceOperation( - Database& Db, std::vector const& entryIter) - : mDb(Db) - { - for (auto const& e : entryIter) - { - releaseAssert(e.entryExists()); - accumulateEntry(e.entry().ledgerEntry()); - } - } - - void - doSociGenericOperation() - { - std::string sql = "INSERT INTO claimablebalance " - "(balanceid, ledgerentry, lastmodified) " - "VALUES " - "( :id, :v1, :v2 ) " - "ON CONFLICT (balanceid) DO UPDATE SET " - "balanceid = excluded.balanceid, ledgerentry = " - "excluded.ledgerentry, lastmodified = " - "excluded.lastmodified"; - - auto prep = mDb.getPreparedStatement(sql); - soci::statement& st = prep.statement(); - st.exchange(soci::use(mBalanceIDs)); - st.exchange(soci::use(mClaimableBalanceEntrys)); - st.exchange(soci::use(mLastModifieds)); - st.define_and_bind(); - { - auto timer = mDb.getUpsertTimer("claimablebalance"); - st.execute(true); - } - if (static_cast(st.get_affected_rows()) != mBalanceIDs.size()) - { - throw std::runtime_error("Could not update data in SQL"); - } - } - - void - doSqliteSpecificOperation(soci::sqlite3_session_backend* sq) override - { - doSociGenericOperation(); - } - -#ifdef USE_POSTGRES - void - doPostgresSpecificOperation(soci::postgresql_session_backend* pg) override - { - std::string strBalanceIDs, strClaimableBalanceEntry, strLastModifieds; - - PGconn* conn = pg->conn_; - marshalToPGArray(conn, strBalanceIDs, mBalanceIDs); - marshalToPGArray(conn, strClaimableBalanceEntry, - mClaimableBalanceEntrys); - marshalToPGArray(conn, strLastModifieds, mLastModifieds); - - std::string sql = "WITH r AS " - "(SELECT unnest(:ids::TEXT[]), unnest(:v1::TEXT[]), " - "unnest(:v2::INT[]))" - "INSERT INTO claimablebalance " - "(balanceid, ledgerentry, lastmodified) " - "SELECT * FROM r " - "ON CONFLICT (balanceid) DO UPDATE SET " - "balanceid = excluded.balanceid, ledgerentry = " - "excluded.ledgerentry, " - "lastmodified = excluded.lastmodified"; - - auto prep = mDb.getPreparedStatement(sql); - soci::statement& st = prep.statement(); - st.exchange(soci::use(strBalanceIDs)); - st.exchange(soci::use(strClaimableBalanceEntry)); - st.exchange(soci::use(strLastModifieds)); - st.define_and_bind(); - { - auto timer = mDb.getUpsertTimer("claimablebalance"); - st.execute(true); - } - if (static_cast(st.get_affected_rows()) != mBalanceIDs.size()) - { - throw std::runtime_error("Could not update data in SQL"); - } - } -#endif -}; - -void -LedgerTxnRoot::Impl::bulkUpsertClaimableBalance( - std::vector const& entries) -{ - BulkUpsertClaimableBalanceOperation op(mApp.getDatabase(), entries); - mApp.getDatabase().doDatabaseTypeSpecificOperation(op); -} - -void -LedgerTxnRoot::Impl::dropClaimableBalances(bool rebuild) -{ - throwIfChild(); - mEntryCache.clear(); - mBestOffers.clear(); - - mApp.getDatabase().getSession() << "DROP TABLE IF EXISTS claimablebalance;"; - - if (rebuild) - { - std::string coll = mApp.getDatabase().getSimpleCollationClause(); - mApp.getDatabase().getSession() - << "CREATE TABLE claimablebalance (" - << "balanceid VARCHAR(48) " << coll << " PRIMARY KEY, " - << "ledgerentry TEXT NOT NULL, " - << "lastmodified INT NOT NULL);"; - } -} -} diff --git a/src/ledger/LedgerTxnConfigSettingSQL.cpp b/src/ledger/LedgerTxnConfigSettingSQL.cpp deleted file mode 100644 index dbfea378a7..0000000000 --- a/src/ledger/LedgerTxnConfigSettingSQL.cpp +++ /dev/null @@ -1,295 +0,0 @@ -// Copyright 2022 Stellar Development Foundation and contributors. Licensed -// under the Apache License, Version 2.0. See the COPYING file at the root -// of this distribution or at http://www.apache.org/licenses/LICENSE-2.0 - -#include "ledger/LedgerTxnImpl.h" -#include "ledger/LedgerTypeUtils.h" -#include "ledger/NonSociRelatedException.h" -#include "main/Application.h" -#include "util/GlobalChecks.h" -#include "util/types.h" - -namespace stellar -{ - -static void -throwIfNotConfigSetting(LedgerEntryType type) -{ - if (type != CONFIG_SETTING) - { - throw NonSociRelatedException("LedgerEntry is not a CONFIG_SETTING"); - } -} - -std::shared_ptr -LedgerTxnRoot::Impl::loadConfigSetting(LedgerKey const& key) const -{ - int32_t configSettingID = key.configSetting().configSettingID; - std::string configSettingEntryStr; - - std::string sql = "SELECT ledgerentry " - "FROM configsettings " - "WHERE configsettingid = :configsettingid"; - auto prep = mApp.getDatabase().getPreparedStatement(sql); - auto& st = prep.statement(); - st.exchange(soci::into(configSettingEntryStr)); - st.exchange(soci::use(configSettingID)); - st.define_and_bind(); - { - auto timer = mApp.getDatabase().getSelectTimer("configsetting"); - st.execute(true); - } - if (!st.got_data()) - { - return nullptr; - } - - LedgerEntry le; - fromOpaqueBase64(le, configSettingEntryStr); - throwIfNotConfigSetting(le.data.type()); - - return std::make_shared(std::move(le)); -} - -class bulkLoadConfigSettingsOperation - : public DatabaseTypeSpecificOperation> -{ - Database& mDb; - std::vector mConfigSettingIDs; - - std::vector - executeAndFetch(soci::statement& st) - { - std::string configSettingEntryStr; - - st.exchange(soci::into(configSettingEntryStr)); - st.define_and_bind(); - { - auto timer = mDb.getSelectTimer("configsetting"); - st.execute(true); - } - - std::vector res; - while (st.got_data()) - { - res.emplace_back(); - auto& le = res.back(); - - fromOpaqueBase64(le, configSettingEntryStr); - throwIfNotConfigSetting(le.data.type()); - - st.fetch(); - } - return res; - } - - public: - bulkLoadConfigSettingsOperation(Database& db, - UnorderedSet const& keys) - : mDb(db) - { - mConfigSettingIDs.reserve(keys.size()); - for (auto const& k : keys) - { - throwIfNotConfigSetting(k.type()); - mConfigSettingIDs.emplace_back(k.configSetting().configSettingID); - } - } - - std::vector - doSqliteSpecificOperation(soci::sqlite3_session_backend* sq) override - { - std::string sql = "WITH r AS (SELECT value FROM carray(?, ?, 'int32')) " - "SELECT ledgerentry " - "FROM configsettings " - "WHERE configsettingid IN r"; - - auto prep = mDb.getPreparedStatement(sql); - auto be = prep.statement().get_backend(); - if (be == nullptr) - { - throw std::runtime_error("no sql backend"); - } - auto sqliteStatement = - dynamic_cast(be); - releaseAssertOrThrow(sqliteStatement); - auto st = sqliteStatement->stmt_; - - sqlite3_reset(st); - sqlite3_bind_pointer(st, 1, (void*)mConfigSettingIDs.data(), "carray", - 0); - sqlite3_bind_int(st, 2, static_cast(mConfigSettingIDs.size())); - return executeAndFetch(prep.statement()); - } - -#ifdef USE_POSTGRES - std::vector - doPostgresSpecificOperation(soci::postgresql_session_backend* pg) override - { - std::string strConfigSettingIDs; - marshalToPGArray(pg->conn_, strConfigSettingIDs, mConfigSettingIDs); - - std::string sql = "WITH r AS (SELECT unnest(:v1::INT[])) " - "SELECT ledgerentry " - "FROM configsettings " - "WHERE configsettingid IN (SELECT * from r)"; - - auto prep = mDb.getPreparedStatement(sql); - auto& st = prep.statement(); - st.exchange(soci::use(strConfigSettingIDs)); - return executeAndFetch(st); - } -#endif -}; - -UnorderedMap> -LedgerTxnRoot::Impl::bulkLoadConfigSettings( - UnorderedSet const& keys) const -{ - if (!keys.empty()) - { - bulkLoadConfigSettingsOperation op(mApp.getDatabase(), keys); - return populateLoadedEntries( - keys, mApp.getDatabase().doDatabaseTypeSpecificOperation(op)); - } - else - { - return {}; - } -} - -class bulkUpsertConfigSettingsOperation - : public DatabaseTypeSpecificOperation -{ - Database& mDb; - std::vector mConfigSettingIDs; - std::vector mConfigSettingEntries; - std::vector mLastModifieds; - - void - accumulateEntry(LedgerEntry const& entry) - { - throwIfNotConfigSetting(entry.data.type()); - - mConfigSettingIDs.emplace_back( - entry.data.configSetting().configSettingID()); - mConfigSettingEntries.emplace_back(toOpaqueBase64(entry)); - mLastModifieds.emplace_back( - unsignedToSigned(entry.lastModifiedLedgerSeq)); - } - - public: - bulkUpsertConfigSettingsOperation( - Database& Db, std::vector const& entryIter) - : mDb(Db) - { - for (auto const& e : entryIter) - { - releaseAssert(e.entryExists()); - accumulateEntry(e.entry().ledgerEntry()); - } - } - - void - doSociGenericOperation() - { - std::string sql = "INSERT INTO configsettings " - "(configsettingid, ledgerentry, lastmodified) " - "VALUES " - "( :id, :v1, :v2 ) " - "ON CONFLICT (configsettingid) DO UPDATE SET " - "ledgerentry = excluded.ledgerentry, " - "lastmodified = excluded.lastmodified"; - - auto prep = mDb.getPreparedStatement(sql); - soci::statement& st = prep.statement(); - st.exchange(soci::use(mConfigSettingIDs)); - st.exchange(soci::use(mConfigSettingEntries)); - st.exchange(soci::use(mLastModifieds)); - st.define_and_bind(); - { - auto timer = mDb.getUpsertTimer("configsetting"); - st.execute(true); - } - if (static_cast(st.get_affected_rows()) != - mConfigSettingIDs.size()) - { - throw std::runtime_error("Could not update data in SQL"); - } - } - - void - doSqliteSpecificOperation(soci::sqlite3_session_backend* sq) override - { - doSociGenericOperation(); - } - -#ifdef USE_POSTGRES - void - doPostgresSpecificOperation(soci::postgresql_session_backend* pg) override - { - std::string strConfigSettingIDs, strConfigSettingEntries, - strLastModifieds; - - PGconn* conn = pg->conn_; - marshalToPGArray(conn, strConfigSettingIDs, mConfigSettingIDs); - marshalToPGArray(conn, strConfigSettingEntries, mConfigSettingEntries); - marshalToPGArray(conn, strLastModifieds, mLastModifieds); - - std::string sql = "WITH r AS " - "(SELECT unnest(:ids::INT[]), unnest(:v1::TEXT[]), " - "unnest(:v2::INT[])) " - "INSERT INTO configsettings " - "(configsettingid, ledgerentry, lastmodified) " - "SELECT * FROM r " - "ON CONFLICT (configsettingid) DO UPDATE SET " - "ledgerentry = excluded.ledgerentry, " - "lastmodified = excluded.lastmodified"; - - auto prep = mDb.getPreparedStatement(sql); - soci::statement& st = prep.statement(); - st.exchange(soci::use(strConfigSettingIDs)); - st.exchange(soci::use(strConfigSettingEntries)); - st.exchange(soci::use(strLastModifieds)); - st.define_and_bind(); - { - auto timer = mDb.getUpsertTimer("configsetting"); - st.execute(true); - } - if (static_cast(st.get_affected_rows()) != - mConfigSettingIDs.size()) - { - throw std::runtime_error("Could not update data in SQL"); - } - } -#endif -}; - -void -LedgerTxnRoot::Impl::bulkUpsertConfigSettings( - std::vector const& entries) -{ - bulkUpsertConfigSettingsOperation op(mApp.getDatabase(), entries); - mApp.getDatabase().doDatabaseTypeSpecificOperation(op); -} - -void -LedgerTxnRoot::Impl::dropConfigSettings(bool rebuild) -{ - throwIfChild(); - mEntryCache.clear(); - mBestOffers.clear(); - - mApp.getDatabase().getSession() << "DROP TABLE IF EXISTS configsettings;"; - - if (rebuild) - { - std::string coll = mApp.getDatabase().getSimpleCollationClause(); - mApp.getDatabase().getSession() - << "CREATE TABLE configsettings (" - << "configsettingid INT PRIMARY KEY, " - << "ledgerentry TEXT " << coll << " NOT NULL, " - << "lastmodified INT NOT NULL);"; - } -} -} \ No newline at end of file diff --git a/src/ledger/LedgerTxnContractCodeSQL.cpp b/src/ledger/LedgerTxnContractCodeSQL.cpp deleted file mode 100644 index ee0aecb7c6..0000000000 --- a/src/ledger/LedgerTxnContractCodeSQL.cpp +++ /dev/null @@ -1,387 +0,0 @@ -// Copyright 2022 Stellar Development Foundation and contributors. Licensed -// under the Apache License, Version 2.0. See the COPYING file at the root -// of this distribution or at http://www.apache.org/licenses/LICENSE-2.0 - -#include "ledger/LedgerTxnImpl.h" -#include "ledger/LedgerTypeUtils.h" -#include "ledger/NonSociRelatedException.h" -#include "main/Application.h" -#include "util/GlobalChecks.h" -#include "util/types.h" - -namespace stellar -{ - -static void -throwIfNotContractCode(LedgerEntryType type) -{ - if (type != CONTRACT_CODE) - { - throw NonSociRelatedException("LedgerEntry is not a CONTRACT_CODE"); - } -} - -std::shared_ptr -LedgerTxnRoot::Impl::loadContractCode(LedgerKey const& k) const -{ - auto hash = toOpaqueBase64(k.contractCode().hash); - std::string contractCodeEntryStr; - - std::string sql = "SELECT ledgerentry " - "FROM contractcode " - "WHERE hash = :hash"; - auto prep = mApp.getDatabase().getPreparedStatement(sql); - auto& st = prep.statement(); - st.exchange(soci::into(contractCodeEntryStr)); - st.exchange(soci::use(hash)); - st.define_and_bind(); - { - auto timer = mApp.getDatabase().getSelectTimer("contractcode"); - st.execute(true); - } - if (!st.got_data()) - { - return nullptr; - } - - LedgerEntry le; - fromOpaqueBase64(le, contractCodeEntryStr); - throwIfNotContractCode(le.data.type()); - - return std::make_shared(std::move(le)); -} - -class BulkLoadContractCodeOperation - : public DatabaseTypeSpecificOperation> -{ - Database& mDb; - std::vector mHashes; - - std::vector - executeAndFetch(soci::statement& st) - { - std::string contractCodeEntryStr; - - st.exchange(soci::into(contractCodeEntryStr)); - st.define_and_bind(); - { - auto timer = mDb.getSelectTimer("contractcode"); - st.execute(true); - } - - std::vector res; - while (st.got_data()) - { - res.emplace_back(); - auto& le = res.back(); - - fromOpaqueBase64(le, contractCodeEntryStr); - throwIfNotContractCode(le.data.type()); - - st.fetch(); - } - return res; - } - - public: - BulkLoadContractCodeOperation(Database& db, - UnorderedSet const& keys) - : mDb(db) - { - mHashes.reserve(keys.size()); - for (auto const& k : keys) - { - throwIfNotContractCode(k.type()); - mHashes.emplace_back(toOpaqueBase64(k.contractCode().hash)); - } - } - - std::vector - doSqliteSpecificOperation(soci::sqlite3_session_backend* sq) override - { - std::vector cStrHashes; - cStrHashes.reserve(mHashes.size()); - for (auto const& h : mHashes) - { - cStrHashes.emplace_back(h.c_str()); - } - std::string sql = "SELECT ledgerentry " - "FROM contractcode " - "WHERE hash IN carray(?, ?, 'char*')"; - - auto prep = mDb.getPreparedStatement(sql); - auto be = prep.statement().get_backend(); - if (be == nullptr) - { - throw std::runtime_error("no sql backend"); - } - auto sqliteStatement = - dynamic_cast(be); - releaseAssertOrThrow(sqliteStatement); - auto st = sqliteStatement->stmt_; - - sqlite3_reset(st); - sqlite3_bind_pointer(st, 1, (void*)cStrHashes.data(), "carray", 0); - sqlite3_bind_int(st, 2, static_cast(cStrHashes.size())); - return executeAndFetch(prep.statement()); - } - -#ifdef USE_POSTGRES - std::vector - doPostgresSpecificOperation(soci::postgresql_session_backend* pg) override - { - std::string strHashes; - marshalToPGArray(pg->conn_, strHashes, mHashes); - - std::string sql = "WITH r AS (SELECT unnest(:v1::TEXT[])) " - "SELECT ledgerentry " - "FROM contractcode " - "WHERE (hash) IN (SELECT * from r)"; - - auto prep = mDb.getPreparedStatement(sql); - auto& st = prep.statement(); - st.exchange(soci::use(strHashes)); - return executeAndFetch(st); - } -#endif -}; - -UnorderedMap> -LedgerTxnRoot::Impl::bulkLoadContractCode( - UnorderedSet const& keys) const -{ - if (!keys.empty()) - { - BulkLoadContractCodeOperation op(mApp.getDatabase(), keys); - return populateLoadedEntries( - keys, mApp.getDatabase().doDatabaseTypeSpecificOperation(op)); - } - else - { - return {}; - } -} - -class BulkDeleteContractCodeOperation - : public DatabaseTypeSpecificOperation -{ - Database& mDb; - LedgerTxnConsistency mCons; - std::vector mHashes; - - public: - BulkDeleteContractCodeOperation(Database& db, LedgerTxnConsistency cons, - std::vector const& entries) - : mDb(db), mCons(cons) - { - mHashes.reserve(entries.size()); - for (auto const& e : entries) - { - releaseAssert(!e.entryExists()); - throwIfNotContractCode(e.key().ledgerKey().type()); - mHashes.emplace_back( - toOpaqueBase64(e.key().ledgerKey().contractCode().hash)); - } - } - - void - doSociGenericOperation() - { - std::string sql = "DELETE FROM contractcode WHERE hash = :id"; - auto prep = mDb.getPreparedStatement(sql); - auto& st = prep.statement(); - st.exchange(soci::use(mHashes)); - st.define_and_bind(); - { - auto timer = mDb.getDeleteTimer("contractcode"); - st.execute(true); - } - if (static_cast(st.get_affected_rows()) != mHashes.size() && - mCons == LedgerTxnConsistency::EXACT) - { - throw std::runtime_error("Could not update data in SQL"); - } - } - - void - doSqliteSpecificOperation(soci::sqlite3_session_backend* sq) override - { - doSociGenericOperation(); - } - -#ifdef USE_POSTGRES - void - doPostgresSpecificOperation(soci::postgresql_session_backend* pg) override - { - std::string strHashes; - marshalToPGArray(pg->conn_, strHashes, mHashes); - - std::string sql = "WITH r AS (SELECT unnest(:v1::TEXT[])) " - "DELETE FROM contractcode " - "WHERE hash IN (SELECT * FROM r)"; - - auto prep = mDb.getPreparedStatement(sql); - auto& st = prep.statement(); - st.exchange(soci::use(strHashes)); - st.define_and_bind(); - { - auto timer = mDb.getDeleteTimer("contractcode"); - st.execute(true); - } - if (static_cast(st.get_affected_rows()) != mHashes.size() && - mCons == LedgerTxnConsistency::EXACT) - { - throw std::runtime_error("Could not update data in SQL"); - } - } -#endif -}; - -void -LedgerTxnRoot::Impl::bulkDeleteContractCode( - std::vector const& entries, LedgerTxnConsistency cons) -{ - BulkDeleteContractCodeOperation op(mApp.getDatabase(), cons, entries); - mApp.getDatabase().doDatabaseTypeSpecificOperation(op); -} - -class BulkUpsertContractCodeOperation - : public DatabaseTypeSpecificOperation -{ - Database& mDb; - std::vector mHashes; - std::vector mContractCodeEntries; - std::vector mLastModifieds; - - void - accumulateEntry(LedgerEntry const& entry) - { - throwIfNotContractCode(entry.data.type()); - - mHashes.emplace_back(toOpaqueBase64(entry.data.contractCode().hash)); - mContractCodeEntries.emplace_back(toOpaqueBase64(entry)); - mLastModifieds.emplace_back( - unsignedToSigned(entry.lastModifiedLedgerSeq)); - } - - public: - BulkUpsertContractCodeOperation(Database& Db, - std::vector const& entryIter) - : mDb(Db) - { - for (auto const& e : entryIter) - { - releaseAssert(e.entryExists()); - accumulateEntry(e.entry().ledgerEntry()); - } - } - - void - doSociGenericOperation() - { - std::string sql = "INSERT INTO contractCode " - "(hash, ledgerentry, lastmodified) " - "VALUES " - "( :hash, :v1, :v2 ) " - "ON CONFLICT (hash) DO UPDATE SET " - "ledgerentry = excluded.ledgerentry, " - "lastmodified = excluded.lastmodified"; - - auto prep = mDb.getPreparedStatement(sql); - soci::statement& st = prep.statement(); - st.exchange(soci::use(mHashes)); - st.exchange(soci::use(mContractCodeEntries)); - st.exchange(soci::use(mLastModifieds)); - st.define_and_bind(); - { - auto timer = mDb.getUpsertTimer("contractcode"); - st.execute(true); - } - if (static_cast(st.get_affected_rows()) != mHashes.size()) - { - throw std::runtime_error("Could not update data in SQL"); - } - } - - void - doSqliteSpecificOperation(soci::sqlite3_session_backend* sq) override - { - doSociGenericOperation(); - } - -#ifdef USE_POSTGRES - void - doPostgresSpecificOperation(soci::postgresql_session_backend* pg) override - { - std::string strHashes, strContractCodeEntries, strLastModifieds; - - PGconn* conn = pg->conn_; - marshalToPGArray(conn, strHashes, mHashes); - marshalToPGArray(conn, strContractCodeEntries, mContractCodeEntries); - marshalToPGArray(conn, strLastModifieds, mLastModifieds); - - std::string sql = "WITH r AS " - "(SELECT unnest(:v1::TEXT[]), " - "unnest(:v1::TEXT[]), unnest(:v2::INT[])) " - "INSERT INTO contractcode " - "(hash, ledgerentry, lastmodified) " - "SELECT * FROM r " - "ON CONFLICT (hash) DO UPDATE SET " - "ledgerentry = excluded.ledgerentry, " - "lastmodified = excluded.lastmodified"; - - auto prep = mDb.getPreparedStatement(sql); - soci::statement& st = prep.statement(); - st.exchange(soci::use(strHashes)); - st.exchange(soci::use(strContractCodeEntries)); - st.exchange(soci::use(strLastModifieds)); - st.define_and_bind(); - { - auto timer = mDb.getUpsertTimer("contractcode"); - st.execute(true); - } - if (static_cast(st.get_affected_rows()) != mHashes.size()) - { - throw std::runtime_error("Could not update data in SQL"); - } - } -#endif -}; - -void -LedgerTxnRoot::Impl::bulkUpsertContractCode( - std::vector const& entries) -{ - BulkUpsertContractCodeOperation op(mApp.getDatabase(), entries); - mApp.getDatabase().doDatabaseTypeSpecificOperation(op); -} - -void -LedgerTxnRoot::Impl::dropContractCode(bool rebuild) -{ - throwIfChild(); - mEntryCache.clear(); - mBestOffers.clear(); - - std::string coll = mApp.getDatabase().getSimpleCollationClause(); - - mApp.getDatabase().getSession() << "DROP TABLE IF EXISTS contractcode;"; - - if (rebuild) - { - mApp.getDatabase().getSession() - << "CREATE TABLE contractcode (" - << "hash TEXT " << coll << " NOT NULL, " - << "ledgerentry TEXT " << coll << " NOT NULL, " - << "lastmodified INT NOT NULL, " - << "PRIMARY KEY (hash));"; - if (!mApp.getDatabase().isSqlite()) - { - mApp.getDatabase().getSession() << "ALTER TABLE contractcode " - << "ALTER COLUMN hash " - << "TYPE TEXT COLLATE \"C\";"; - } - } -} - -} diff --git a/src/ledger/LedgerTxnContractDataSQL.cpp b/src/ledger/LedgerTxnContractDataSQL.cpp deleted file mode 100644 index 1c71f67cb7..0000000000 --- a/src/ledger/LedgerTxnContractDataSQL.cpp +++ /dev/null @@ -1,462 +0,0 @@ -// Copyright 2022 Stellar Development Foundation and contributors. Licensed -// under the Apache License, Version 2.0. See the COPYING file at the root -// of this distribution or at http://www.apache.org/licenses/LICENSE-2.0 - -#include "ledger/LedgerTxnImpl.h" -#include "ledger/LedgerTypeUtils.h" -#include "ledger/NonSociRelatedException.h" -#include "main/Application.h" -#include "util/GlobalChecks.h" -#include "util/types.h" - -namespace stellar -{ - -static void -throwIfNotContractData(LedgerEntryType type) -{ - if (type != CONTRACT_DATA) - { - throw NonSociRelatedException("LedgerEntry is not a CONTRACT_DATA"); - } -} - -std::shared_ptr -LedgerTxnRoot::Impl::loadContractData(LedgerKey const& k) const -{ - auto contractID = toOpaqueBase64(k.contractData().contract); - auto key = toOpaqueBase64(k.contractData().key); - int32_t type = k.contractData().durability; - std::string contractDataEntryStr; - - std::string sql = - "SELECT ledgerentry " - "FROM contractdata " - "WHERE contractID = :contractID AND key = :key AND type = :type"; - auto prep = mApp.getDatabase().getPreparedStatement(sql); - auto& st = prep.statement(); - st.exchange(soci::into(contractDataEntryStr)); - st.exchange(soci::use(contractID)); - st.exchange(soci::use(key)); - st.exchange(soci::use(type)); - st.define_and_bind(); - { - auto timer = mApp.getDatabase().getSelectTimer("contractdata"); - st.execute(true); - } - if (!st.got_data()) - { - return nullptr; - } - - LedgerEntry le; - fromOpaqueBase64(le, contractDataEntryStr); - throwIfNotContractData(le.data.type()); - - return std::make_shared(std::move(le)); -} - -class BulkLoadContractDataOperation - : public DatabaseTypeSpecificOperation> -{ - Database& mDb; - std::vector mContractIDs; - std::vector mKeys; - std::vector mTypes; - - std::vector - executeAndFetch(soci::statement& st) - { - std::string contractDataEntryStr; - - st.exchange(soci::into(contractDataEntryStr)); - st.define_and_bind(); - { - auto timer = mDb.getSelectTimer("contractdata"); - st.execute(true); - } - - std::vector res; - while (st.got_data()) - { - res.emplace_back(); - auto& le = res.back(); - - fromOpaqueBase64(le, contractDataEntryStr); - throwIfNotContractData(le.data.type()); - - st.fetch(); - } - return res; - } - - public: - BulkLoadContractDataOperation(Database& db, - UnorderedSet const& keys) - : mDb(db) - { - mContractIDs.reserve(keys.size()); - mKeys.reserve(keys.size()); - mTypes.reserve(keys.size()); - for (auto const& k : keys) - { - throwIfNotContractData(k.type()); - mContractIDs.emplace_back( - toOpaqueBase64(k.contractData().contract)); - mKeys.emplace_back(toOpaqueBase64(k.contractData().key)); - mTypes.emplace_back(k.contractData().durability); - } - } - - std::vector - doSqliteSpecificOperation(soci::sqlite3_session_backend* sq) override - { - std::vector cStrContractIDs, cStrKeys; - cStrContractIDs.reserve(mContractIDs.size()); - cStrKeys.reserve(cStrKeys.size()); - for (auto const& cid : mContractIDs) - { - cStrContractIDs.emplace_back(cid.c_str()); - } - for (auto const& key : mKeys) - { - cStrKeys.emplace_back(key.c_str()); - } - - std::string sqlJoin = "SELECT x.value, y.value, z.value " - "FROM " - "(SELECT rowid, value FROM carray(?, ?, 'char*') " - "ORDER BY rowid) AS x " - "INNER JOIN " - "(SELECT rowid, value FROM carray(?, ?, 'char*') " - "ORDER BY rowid) AS y " - "ON x.rowid = y.rowid " - "INNER JOIN " - "(SELECT rowid, value FROM carray(?, ?, 'int32') " - "ORDER BY rowid) AS z " - "ON x.rowid = z.rowid"; - - std::string sql = "WITH r AS (" + sqlJoin + - ") " - "SELECT ledgerentry " - "FROM contractdata " - "WHERE (contractid, key, type) IN (SELECT * FROM r)"; - - auto prep = mDb.getPreparedStatement(sql); - auto be = prep.statement().get_backend(); - if (be == nullptr) - { - throw std::runtime_error("no sql backend"); - } - auto sqliteStatement = - dynamic_cast(be); - releaseAssertOrThrow(sqliteStatement); - auto st = sqliteStatement->stmt_; - - sqlite3_reset(st); - sqlite3_bind_pointer(st, 1, (void*)cStrContractIDs.data(), "carray", 0); - sqlite3_bind_int(st, 2, static_cast(mContractIDs.size())); - sqlite3_bind_pointer(st, 3, (void*)cStrKeys.data(), "carray", 0); - sqlite3_bind_int(st, 4, static_cast(mKeys.size())); - sqlite3_bind_pointer(st, 5, (void*)mTypes.data(), "carray", 0); - sqlite3_bind_int(st, 6, static_cast(mTypes.size())); - return executeAndFetch(prep.statement()); - } - -#ifdef USE_POSTGRES - std::vector - doPostgresSpecificOperation(soci::postgresql_session_backend* pg) override - { - std::string strContractIDs, strKeys, strTypes; - marshalToPGArray(pg->conn_, strContractIDs, mContractIDs); - marshalToPGArray(pg->conn_, strKeys, mKeys); - marshalToPGArray(pg->conn_, strTypes, mTypes); - - std::string sql = "WITH r AS (SELECT unnest(:ids::TEXT[]), " - "unnest(:v1::TEXT[]), unnest(:v2::INT[])) " - "SELECT ledgerentry " - "FROM contractdata " - "WHERE (contractid, key, type) IN (SELECT * from r)"; - - auto prep = mDb.getPreparedStatement(sql); - auto& st = prep.statement(); - st.exchange(soci::use(strContractIDs)); - st.exchange(soci::use(strKeys)); - st.exchange(soci::use(strTypes)); - return executeAndFetch(st); - } -#endif -}; - -UnorderedMap> -LedgerTxnRoot::Impl::bulkLoadContractData( - UnorderedSet const& keys) const -{ - if (!keys.empty()) - { - BulkLoadContractDataOperation op(mApp.getDatabase(), keys); - return populateLoadedEntries( - keys, mApp.getDatabase().doDatabaseTypeSpecificOperation(op)); - } - else - { - return {}; - } -} - -class BulkDeleteContractDataOperation - : public DatabaseTypeSpecificOperation -{ - Database& mDb; - LedgerTxnConsistency mCons; - std::vector mContractIDs; - std::vector mKeys; - std::vector mTypes; - - public: - BulkDeleteContractDataOperation(Database& db, LedgerTxnConsistency cons, - std::vector const& entries) - : mDb(db), mCons(cons) - { - mContractIDs.reserve(entries.size()); - for (auto const& e : entries) - { - releaseAssert(!e.entryExists()); - throwIfNotContractData(e.key().ledgerKey().type()); - mContractIDs.emplace_back( - toOpaqueBase64(e.key().ledgerKey().contractData().contract)); - mKeys.emplace_back( - toOpaqueBase64(e.key().ledgerKey().contractData().key)); - mTypes.emplace_back(e.key().ledgerKey().contractData().durability); - } - } - - void - doSociGenericOperation() - { - std::string sql = "DELETE FROM contractdata WHERE contractid = :id " - "AND key = :key AND type = :type"; - auto prep = mDb.getPreparedStatement(sql); - auto& st = prep.statement(); - st.exchange(soci::use(mContractIDs)); - st.exchange(soci::use(mKeys)); - st.exchange(soci::use(mTypes)); - st.define_and_bind(); - { - auto timer = mDb.getDeleteTimer("contractdata"); - st.execute(true); - } - if (static_cast(st.get_affected_rows()) != - mContractIDs.size() && - mCons == LedgerTxnConsistency::EXACT) - { - throw std::runtime_error("Could not update data in SQL"); - } - } - - void - doSqliteSpecificOperation(soci::sqlite3_session_backend* sq) override - { - doSociGenericOperation(); - } - -#ifdef USE_POSTGRES - void - doPostgresSpecificOperation(soci::postgresql_session_backend* pg) override - { - std::string strContractIDs, strKeys, strTypes; - marshalToPGArray(pg->conn_, strContractIDs, mContractIDs); - marshalToPGArray(pg->conn_, strKeys, mKeys); - marshalToPGArray(pg->conn_, strTypes, mTypes); - - std::string sql = "WITH r AS (SELECT unnest(:ids::TEXT[]), " - "unnest(:v1::TEXT[]), unnest(:v2::INT[])) " - "DELETE FROM contractdata " - "WHERE (contractid, key, type) IN (SELECT * FROM r)"; - - auto prep = mDb.getPreparedStatement(sql); - auto& st = prep.statement(); - st.exchange(soci::use(strContractIDs)); - st.exchange(soci::use(strKeys)); - st.exchange(soci::use(strTypes)); - st.define_and_bind(); - { - auto timer = mDb.getDeleteTimer("contractdata"); - st.execute(true); - } - if (static_cast(st.get_affected_rows()) != - mContractIDs.size() && - mCons == LedgerTxnConsistency::EXACT) - { - throw std::runtime_error("Could not update data in SQL"); - } - } -#endif -}; - -void -LedgerTxnRoot::Impl::bulkDeleteContractData( - std::vector const& entries, LedgerTxnConsistency cons) -{ - BulkDeleteContractDataOperation op(mApp.getDatabase(), cons, entries); - mApp.getDatabase().doDatabaseTypeSpecificOperation(op); -} - -class BulkUpsertContractDataOperation - : public DatabaseTypeSpecificOperation -{ - Database& mDb; - std::vector mContractIDs; - std::vector mKeys; - std::vector mTypes; - std::vector mContractDataEntries; - std::vector mLastModifieds; - - void - accumulateEntry(LedgerEntry const& entry) - { - throwIfNotContractData(entry.data.type()); - - mContractIDs.emplace_back( - toOpaqueBase64(entry.data.contractData().contract)); - mKeys.emplace_back(toOpaqueBase64(entry.data.contractData().key)); - mTypes.emplace_back(entry.data.contractData().durability); - mContractDataEntries.emplace_back(toOpaqueBase64(entry)); - mLastModifieds.emplace_back( - unsignedToSigned(entry.lastModifiedLedgerSeq)); - } - - public: - BulkUpsertContractDataOperation(Database& Db, - std::vector const& entryIter) - : mDb(Db) - { - for (auto const& e : entryIter) - { - releaseAssert(e.entryExists()); - accumulateEntry(e.entry().ledgerEntry()); - } - } - - void - doSociGenericOperation() - { - std::string sql = "INSERT INTO contractData " - "(contractid, key, type, ledgerentry, lastmodified) " - "VALUES " - "( :id, :key, :type, :v1, :v2 ) " - "ON CONFLICT (contractid, key, type) DO UPDATE SET " - "ledgerentry = excluded.ledgerentry, " - "lastmodified = excluded.lastmodified"; - - auto prep = mDb.getPreparedStatement(sql); - soci::statement& st = prep.statement(); - st.exchange(soci::use(mContractIDs)); - st.exchange(soci::use(mKeys)); - st.exchange(soci::use(mTypes)); - st.exchange(soci::use(mContractDataEntries)); - st.exchange(soci::use(mLastModifieds)); - st.define_and_bind(); - { - auto timer = mDb.getUpsertTimer("contractdata"); - st.execute(true); - } - if (static_cast(st.get_affected_rows()) != mContractIDs.size()) - { - throw std::runtime_error("Could not update data in SQL"); - } - } - - void - doSqliteSpecificOperation(soci::sqlite3_session_backend* sq) override - { - doSociGenericOperation(); - } - -#ifdef USE_POSTGRES - void - doPostgresSpecificOperation(soci::postgresql_session_backend* pg) override - { - std::string strContractIDs, strKeys, strTypes, strContractDataEntries, - strLastModifieds; - - PGconn* conn = pg->conn_; - marshalToPGArray(conn, strContractIDs, mContractIDs); - marshalToPGArray(conn, strKeys, mKeys); - marshalToPGArray(conn, strTypes, mTypes); - marshalToPGArray(conn, strContractDataEntries, mContractDataEntries); - marshalToPGArray(conn, strLastModifieds, mLastModifieds); - - std::string sql = - "WITH r AS " - "(SELECT unnest(:ids::TEXT[]), unnest(:v1::TEXT[]), " - "unnest(:v2::INT[]), unnest(:v3::TEXT[]), unnest(:v4::INT[])) " - "INSERT INTO contractdata " - "(contractid, key, type, ledgerentry, lastmodified) " - "SELECT * FROM r " - "ON CONFLICT (contractid,key,type) DO UPDATE SET " - "ledgerentry = excluded.ledgerentry, " - "lastmodified = excluded.lastmodified"; - - auto prep = mDb.getPreparedStatement(sql); - soci::statement& st = prep.statement(); - st.exchange(soci::use(strContractIDs)); - st.exchange(soci::use(strKeys)); - st.exchange(soci::use(strTypes)); - st.exchange(soci::use(strContractDataEntries)); - st.exchange(soci::use(strLastModifieds)); - st.define_and_bind(); - { - auto timer = mDb.getUpsertTimer("contractdata"); - st.execute(true); - } - if (static_cast(st.get_affected_rows()) != mContractIDs.size()) - { - throw std::runtime_error("Could not update data in SQL"); - } - } -#endif -}; - -void -LedgerTxnRoot::Impl::bulkUpsertContractData( - std::vector const& entries) -{ - BulkUpsertContractDataOperation op(mApp.getDatabase(), entries); - mApp.getDatabase().doDatabaseTypeSpecificOperation(op); -} - -void -LedgerTxnRoot::Impl::dropContractData(bool rebuild) -{ - throwIfChild(); - mEntryCache.clear(); - mBestOffers.clear(); - - mApp.getDatabase().getSession() << "DROP TABLE IF EXISTS contractdata;"; - - if (rebuild) - { - std::string coll = mApp.getDatabase().getSimpleCollationClause(); - mApp.getDatabase().getSession() - << "CREATE TABLE contractdata (" - << "contractid TEXT " << coll << " NOT NULL, " - << "key TEXT " << coll << " NOT NULL, " - << "type INT NOT NULL, " - << "ledgerentry TEXT " << coll << " NOT NULL, " - << "lastmodified INT NOT NULL, " - << "PRIMARY KEY (contractid, key, type));"; - if (!mApp.getDatabase().isSqlite()) - { - mApp.getDatabase().getSession() << "ALTER TABLE contractdata " - << "ALTER COLUMN contractid " - << "TYPE TEXT COLLATE \"C\"," - << "ALTER COLUMN key " - << "TYPE TEXT COLLATE \"C\"," - << "ALTER COLUMN type " - << "TYPE INT;"; - } - } -} - -} \ No newline at end of file diff --git a/src/ledger/LedgerTxnDataSQL.cpp b/src/ledger/LedgerTxnDataSQL.cpp deleted file mode 100644 index 10f6ba7be5..0000000000 --- a/src/ledger/LedgerTxnDataSQL.cpp +++ /dev/null @@ -1,508 +0,0 @@ -// Copyright 2018 Stellar Development Foundation and contributors. Licensed -// under the Apache License, Version 2.0. See the COPYING file at the root -// of this distribution or at http://www.apache.org/licenses/LICENSE-2.0 - -#include "crypto/KeyUtils.h" -#include "crypto/SecretKey.h" -#include "database/Database.h" -#include "database/DatabaseTypeSpecificOperation.h" -#include "ledger/LedgerTxnImpl.h" -#include "ledger/LedgerTypeUtils.h" -#include "main/Application.h" -#include "util/Decoder.h" -#include "util/GlobalChecks.h" -#include "util/Logging.h" -#include "util/types.h" -#include - -namespace stellar -{ - -std::shared_ptr -LedgerTxnRoot::Impl::loadData(LedgerKey const& key) const -{ - ZoneScoped; - std::string actIDStrKey = KeyUtils::toStrKey(key.data().accountID); - std::string dataName = decoder::encode_b64(key.data().dataName); - - std::string dataValue; - soci::indicator dataValueIndicator; - std::string extensionStr; - soci::indicator extensionInd; - std::string ledgerExtStr; - soci::indicator ledgerExtInd; - - LedgerEntry le; - le.data.type(DATA); - DataEntry& de = le.data.data(); - - std::string sql = "SELECT datavalue, lastmodified, extension, " - "ledgerext " - "FROM accountdata " - "WHERE accountid= :id AND dataname= :dataname"; - auto prep = mApp.getDatabase().getPreparedStatement(sql); - auto& st = prep.statement(); - st.exchange(soci::into(dataValue, dataValueIndicator)); - st.exchange(soci::into(le.lastModifiedLedgerSeq)); - st.exchange(soci::into(extensionStr, extensionInd)); - st.exchange(soci::into(ledgerExtStr, ledgerExtInd)); - st.exchange(soci::use(actIDStrKey)); - st.exchange(soci::use(dataName)); - st.define_and_bind(); - st.execute(true); - if (!st.got_data()) - { - return nullptr; - } - - de.accountID = key.data().accountID; - de.dataName = key.data().dataName; - - if (dataValueIndicator != soci::i_ok) - { - throw std::runtime_error("bad database state"); - } - decoder::decode_b64(dataValue, de.dataValue); - - decodeOpaqueXDR(extensionStr, extensionInd, de.ext); - - decodeOpaqueXDR(ledgerExtStr, ledgerExtInd, le.ext); - - return std::make_shared(std::move(le)); -} - -class BulkUpsertDataOperation : public DatabaseTypeSpecificOperation -{ - Database& mDB; - std::vector mAccountIDs; - std::vector mDataNames; - std::vector mDataValues; - std::vector mLastModifieds; - std::vector mExtensions; - std::vector mLedgerExtensions; - - void - accumulateEntry(LedgerEntry const& entry) - { - releaseAssert(entry.data.type() == DATA); - DataEntry const& data = entry.data.data(); - mAccountIDs.emplace_back(KeyUtils::toStrKey(data.accountID)); - mDataNames.emplace_back(decoder::encode_b64(data.dataName)); - mDataValues.emplace_back(decoder::encode_b64(data.dataValue)); - mLastModifieds.emplace_back( - unsignedToSigned(entry.lastModifiedLedgerSeq)); - mExtensions.emplace_back( - decoder::encode_b64(xdr::xdr_to_opaque(data.ext))); - mLedgerExtensions.emplace_back( - decoder::encode_b64(xdr::xdr_to_opaque(entry.ext))); - } - - public: - BulkUpsertDataOperation(Database& DB, - std::vector const& entries) - : mDB(DB) - { - for (auto const& e : entries) - { - accumulateEntry(e); - } - } - - BulkUpsertDataOperation(Database& DB, - std::vector const& entryIter) - : mDB(DB) - { - for (auto const& e : entryIter) - { - releaseAssert(e.entryExists()); - releaseAssert(e.entry().type() == - InternalLedgerEntryType::LEDGER_ENTRY); - accumulateEntry(e.entry().ledgerEntry()); - } - } - - void - doSociGenericOperation() - { - std::string sql = - "INSERT INTO accountdata ( " - "accountid, dataname, datavalue, lastmodified, extension, " - "ledgerext " - ") VALUES ( " - ":id, :v1, :v2, :v3, :v4, :v5 " - ") ON CONFLICT (accountid, dataname) DO UPDATE SET " - "datavalue = excluded.datavalue, " - "lastmodified = excluded.lastmodified, " - "extension = excluded.extension, " - "ledgerext = excluded.ledgerext"; - auto prep = mDB.getPreparedStatement(sql); - soci::statement& st = prep.statement(); - st.exchange(soci::use(mAccountIDs)); - st.exchange(soci::use(mDataNames)); - st.exchange(soci::use(mDataValues)); - st.exchange(soci::use(mLastModifieds)); - st.exchange(soci::use(mExtensions)); - st.exchange(soci::use(mLedgerExtensions)); - st.define_and_bind(); - { - auto timer = mDB.getUpsertTimer("data"); - st.execute(true); - } - if (static_cast(st.get_affected_rows()) != mAccountIDs.size()) - { - throw std::runtime_error("Could not update data in SQL"); - } - } - - void - doSqliteSpecificOperation(soci::sqlite3_session_backend* sq) override - { - doSociGenericOperation(); - } -#ifdef USE_POSTGRES - void - doPostgresSpecificOperation(soci::postgresql_session_backend* pg) override - { - std::string strAccountIDs, strDataNames, strDataValues, - strLastModifieds, strExtensions, strLedgerExtensions; - - PGconn* conn = pg->conn_; - marshalToPGArray(conn, strAccountIDs, mAccountIDs); - marshalToPGArray(conn, strDataNames, mDataNames); - marshalToPGArray(conn, strDataValues, mDataValues); - marshalToPGArray(conn, strLastModifieds, mLastModifieds); - marshalToPGArray(conn, strExtensions, mExtensions); - marshalToPGArray(conn, strLedgerExtensions, mLedgerExtensions); - std::string sql = - "WITH r AS (SELECT " - "unnest(:ids::TEXT[]), " - "unnest(:v1::TEXT[]), " - "unnest(:v2::TEXT[]), " - "unnest(:v3::INT[]), " - "unnest(:v4::TEXT[]), " - "unnest(:v5::TEXT[]) " - ")" - "INSERT INTO accountdata ( " - "accountid, dataname, datavalue, lastmodified, extension, " - "ledgerext " - ") SELECT * FROM r " - "ON CONFLICT (accountid, dataname) DO UPDATE SET " - "datavalue = excluded.datavalue, " - "lastmodified = excluded.lastmodified, " - "extension = excluded.extension, " - "ledgerext = excluded.ledgerext"; - auto prep = mDB.getPreparedStatement(sql); - soci::statement& st = prep.statement(); - st.exchange(soci::use(strAccountIDs)); - st.exchange(soci::use(strDataNames)); - st.exchange(soci::use(strDataValues)); - st.exchange(soci::use(strLastModifieds)); - st.exchange(soci::use(strExtensions)); - st.exchange(soci::use(strLedgerExtensions)); - st.define_and_bind(); - { - auto timer = mDB.getUpsertTimer("data"); - st.execute(true); - } - if (static_cast(st.get_affected_rows()) != mAccountIDs.size()) - { - throw std::runtime_error("Could not update data in SQL"); - } - } -#endif -}; - -class BulkDeleteDataOperation : public DatabaseTypeSpecificOperation -{ - Database& mDB; - LedgerTxnConsistency mCons; - std::vector mAccountIDs; - std::vector mDataNames; - - public: - BulkDeleteDataOperation(Database& DB, LedgerTxnConsistency cons, - std::vector const& entries) - : mDB(DB), mCons(cons) - { - for (auto const& e : entries) - { - releaseAssert(!e.entryExists()); - releaseAssert(e.key().type() == - InternalLedgerEntryType::LEDGER_ENTRY); - releaseAssert(e.key().ledgerKey().type() == DATA); - auto const& data = e.key().ledgerKey().data(); - mAccountIDs.emplace_back(KeyUtils::toStrKey(data.accountID)); - mDataNames.emplace_back(decoder::encode_b64(data.dataName)); - } - } - - void - doSociGenericOperation() - { - std::string sql = "DELETE FROM accountdata WHERE accountid = :id AND " - " dataname = :v1 "; - auto prep = mDB.getPreparedStatement(sql); - soci::statement& st = prep.statement(); - st.exchange(soci::use(mAccountIDs)); - st.exchange(soci::use(mDataNames)); - st.define_and_bind(); - { - auto timer = mDB.getDeleteTimer("data"); - st.execute(true); - } - if (static_cast(st.get_affected_rows()) != mAccountIDs.size() && - mCons == LedgerTxnConsistency::EXACT) - { - throw std::runtime_error("Could not update data in SQL"); - } - } - - void - doSqliteSpecificOperation(soci::sqlite3_session_backend* sq) override - { - doSociGenericOperation(); - } - -#ifdef USE_POSTGRES - void - doPostgresSpecificOperation(soci::postgresql_session_backend* pg) override - { - std::string strAccountIDs; - std::string strDataNames; - PGconn* conn = pg->conn_; - marshalToPGArray(conn, strAccountIDs, mAccountIDs); - marshalToPGArray(conn, strDataNames, mDataNames); - std::string sql = - "WITH r AS ( SELECT " - "unnest(:ids::TEXT[])," - "unnest(:v1::TEXT[])" - " ) " - "DELETE FROM accountdata WHERE (accountid, dataname) IN " - "(SELECT * FROM r)"; - auto prep = mDB.getPreparedStatement(sql); - soci::statement& st = prep.statement(); - st.exchange(soci::use(strAccountIDs)); - st.exchange(soci::use(strDataNames)); - st.define_and_bind(); - { - auto timer = mDB.getDeleteTimer("data"); - st.execute(true); - } - if (static_cast(st.get_affected_rows()) != mAccountIDs.size() && - mCons == LedgerTxnConsistency::EXACT) - { - throw std::runtime_error("Could not update data in SQL"); - } - } -#endif -}; - -void -LedgerTxnRoot::Impl::bulkUpsertAccountData( - std::vector const& entries) -{ - ZoneScoped; - ZoneValue(static_cast(entries.size())); - BulkUpsertDataOperation op(mApp.getDatabase(), entries); - mApp.getDatabase().doDatabaseTypeSpecificOperation(op); -} - -void -LedgerTxnRoot::Impl::bulkDeleteAccountData( - std::vector const& entries, LedgerTxnConsistency cons) -{ - ZoneScoped; - ZoneValue(static_cast(entries.size())); - BulkDeleteDataOperation op(mApp.getDatabase(), cons, entries); - mApp.getDatabase().doDatabaseTypeSpecificOperation(op); -} - -void -LedgerTxnRoot::Impl::dropData(bool rebuild) -{ - throwIfChild(); - mEntryCache.clear(); - mBestOffers.clear(); - - mApp.getDatabase().getSession() << "DROP TABLE IF EXISTS accountdata;"; - - if (rebuild) - { - std::string coll = mApp.getDatabase().getSimpleCollationClause(); - mApp.getDatabase().getSession() - << "CREATE TABLE accountdata" - << "(" - << "accountid VARCHAR(56) " << coll << " NOT NULL," - << "dataname VARCHAR(88) " << coll << " NOT NULL," - << "datavalue VARCHAR(112) NOT NULL," - "lastmodified INT NOT NULL," - "extension TEXT," - "ledgerext TEXT NOT NULL," - "PRIMARY KEY (accountid, dataname)" - ");"; - if (!mApp.getDatabase().isSqlite()) - { - mApp.getDatabase().getSession() - << "ALTER TABLE accountdata " - << "ALTER COLUMN accountid " - << "TYPE VARCHAR(56) COLLATE \"C\", " - << "ALTER COLUMN dataname " - << "TYPE VARCHAR(88) COLLATE \"C\""; - } - } -} - -class BulkLoadDataOperation - : public DatabaseTypeSpecificOperation> -{ - Database& mDb; - std::vector mAccountIDs; - std::vector mDataNames; - - std::vector - executeAndFetch(soci::statement& st) - { - std::string accountID, dataName, dataValue; - uint32_t lastModified; - std::string extension; - soci::indicator extensionInd; - std::string ledgerExtension; - soci::indicator ledgerExtInd; - - st.exchange(soci::into(accountID)); - st.exchange(soci::into(dataName)); - st.exchange(soci::into(dataValue)); - st.exchange(soci::into(lastModified)); - st.exchange(soci::into(extension, extensionInd)); - st.exchange(soci::into(ledgerExtension, ledgerExtInd)); - st.define_and_bind(); - { - auto timer = mDb.getSelectTimer("data"); - st.execute(true); - } - - std::vector res; - while (st.got_data()) - { - res.emplace_back(); - auto& le = res.back(); - le.data.type(DATA); - auto& de = le.data.data(); - - de.accountID = KeyUtils::fromStrKey(accountID); - decoder::decode_b64(dataName, de.dataName); - decoder::decode_b64(dataValue, de.dataValue); - le.lastModifiedLedgerSeq = lastModified; - - decodeOpaqueXDR(extension, extensionInd, de.ext); - - decodeOpaqueXDR(ledgerExtension, ledgerExtInd, le.ext); - - st.fetch(); - } - return res; - } - - public: - BulkLoadDataOperation(Database& db, UnorderedSet const& keys) - : mDb(db) - { - mAccountIDs.reserve(keys.size()); - mDataNames.reserve(keys.size()); - for (auto const& k : keys) - { - releaseAssert(k.type() == DATA); - mAccountIDs.emplace_back(KeyUtils::toStrKey(k.data().accountID)); - mDataNames.emplace_back(decoder::encode_b64(k.data().dataName)); - } - } - - virtual std::vector - doSqliteSpecificOperation(soci::sqlite3_session_backend* sq) override - { - releaseAssert(mAccountIDs.size() == mDataNames.size()); - - std::vector cstrAccountIDs; - std::vector cstrDataNames; - cstrAccountIDs.reserve(mAccountIDs.size()); - cstrDataNames.reserve(mDataNames.size()); - for (size_t i = 0; i < mAccountIDs.size(); ++i) - { - cstrAccountIDs.emplace_back(mAccountIDs[i].c_str()); - cstrDataNames.emplace_back(mDataNames[i].c_str()); - } - - std::string sqlJoin = - "SELECT x.value, y.value FROM " - "(SELECT rowid, value FROM carray(?, ?, 'char*') ORDER BY rowid) " - "AS x " - "INNER JOIN (SELECT rowid, value FROM carray(?, ?, 'char*') ORDER " - "BY rowid) AS y ON x.rowid = y.rowid"; - std::string sql = "WITH r AS (" + sqlJoin + - ") SELECT accountid, dataname, datavalue, " - "lastmodified, extension, " - "ledgerext " - "FROM accountdata WHERE (accountid, dataname) IN r"; - - auto prep = mDb.getPreparedStatement(sql); - auto be = prep.statement().get_backend(); - if (be == nullptr) - { - throw std::runtime_error("no sql backend"); - } - auto sqliteStatement = - dynamic_cast(be); - releaseAssertOrThrow(sqliteStatement); - auto st = sqliteStatement->stmt_; - - sqlite3_reset(st); - sqlite3_bind_pointer(st, 1, cstrAccountIDs.data(), "carray", 0); - sqlite3_bind_int(st, 2, static_cast(cstrAccountIDs.size())); - sqlite3_bind_pointer(st, 3, cstrDataNames.data(), "carray", 0); - sqlite3_bind_int(st, 4, static_cast(cstrDataNames.size())); - return executeAndFetch(prep.statement()); - } - -#ifdef USE_POSTGRES - std::vector - doPostgresSpecificOperation(soci::postgresql_session_backend* pg) override - { - releaseAssert(mAccountIDs.size() == mDataNames.size()); - - std::string strAccountIDs; - std::string strDataNames; - marshalToPGArray(pg->conn_, strAccountIDs, mAccountIDs); - marshalToPGArray(pg->conn_, strDataNames, mDataNames); - - std::string sql = - "WITH r AS (SELECT unnest(:v1::TEXT[]), unnest(:v2::TEXT[])) " - "SELECT accountid, dataname, datavalue, lastmodified, extension, " - "ledgerext " - "FROM accountdata WHERE (accountid, dataname) IN (SELECT * FROM r)"; - - auto prep = mDb.getPreparedStatement(sql); - auto& st = prep.statement(); - st.exchange(soci::use(strAccountIDs)); - st.exchange(soci::use(strDataNames)); - return executeAndFetch(st); - } -#endif -}; - -UnorderedMap> -LedgerTxnRoot::Impl::bulkLoadData(UnorderedSet const& keys) const -{ - ZoneScoped; - ZoneValue(static_cast(keys.size())); - if (!keys.empty()) - { - BulkLoadDataOperation op(mApp.getDatabase(), keys); - return populateLoadedEntries( - keys, mApp.getDatabase().doDatabaseTypeSpecificOperation(op)); - } - else - { - return {}; - } -} -} diff --git a/src/ledger/LedgerTxnImpl.h b/src/ledger/LedgerTxnImpl.h index 82241b74ff..d9433abdc9 100644 --- a/src/ledger/LedgerTxnImpl.h +++ b/src/ledger/LedgerTxnImpl.h @@ -629,8 +629,6 @@ class LedgerTxnRoot::Impl void throwIfChild() const; - std::shared_ptr loadAccount(LedgerKey const& key) const; - std::shared_ptr loadData(LedgerKey const& key) const; std::shared_ptr loadOffer(LedgerKey const& key) const; std::vector loadAllOffers() const; std::deque::const_iterator @@ -646,57 +644,12 @@ class LedgerTxnRoot::Impl loadOffersByAccountAndAsset(AccountID const& accountID, Asset const& asset) const; std::vector loadOffers(StatementContext& prep) const; - std::vector loadInflationWinners(size_t maxWinners, - int64_t minBalance) const; - std::shared_ptr - loadTrustLine(LedgerKey const& key) const; - std::vector - loadPoolShareTrustLinesByAccountAndAsset(AccountID const& accountID, - Asset const& asset) const; - std::shared_ptr - loadClaimableBalance(LedgerKey const& key) const; - std::shared_ptr - loadLiquidityPool(LedgerKey const& key) const; - std::shared_ptr - loadContractData(LedgerKey const& key) const; - std::shared_ptr - loadContractCode(LedgerKey const& key) const; - std::shared_ptr - loadConfigSetting(LedgerKey const& key) const; - std::shared_ptr loadTTL(LedgerKey const& key) const; void bulkApply(BulkLedgerEntryChangeAccumulator& bleca, size_t bufferThreshold, LedgerTxnConsistency cons); - void bulkUpsertAccounts(std::vector const& entries); - void bulkDeleteAccounts(std::vector const& entries, - LedgerTxnConsistency cons); - void bulkUpsertTrustLines(std::vector const& entries); - void bulkDeleteTrustLines(std::vector const& entries, - LedgerTxnConsistency cons); void bulkUpsertOffers(std::vector const& entries); void bulkDeleteOffers(std::vector const& entries, LedgerTxnConsistency cons); - void bulkUpsertAccountData(std::vector const& entries); - void bulkDeleteAccountData(std::vector const& entries, - LedgerTxnConsistency cons); - void bulkUpsertClaimableBalance(std::vector const& entries); - void bulkDeleteClaimableBalance(std::vector const& entries, - LedgerTxnConsistency cons); - void bulkUpsertLiquidityPool(std::vector const& entries); - void bulkDeleteLiquidityPool(std::vector const& entries, - LedgerTxnConsistency cons); - void bulkUpsertContractData(std::vector const& entries); - void bulkDeleteContractData(std::vector const& entries, - LedgerTxnConsistency cons); - void bulkUpsertContractCode(std::vector const& entries); - void bulkDeleteContractCode(std::vector const& entries, - LedgerTxnConsistency cons); - void bulkUpsertConfigSettings(std::vector const& entries); - void bulkUpsertTTL(std::vector const& entries); - void bulkDeleteTTL(std::vector const& entries, - LedgerTxnConsistency cons); - - static std::string tableFromLedgerEntryType(LedgerEntryType let); // The entry cache maintains relatively strong invariants: // @@ -720,27 +673,8 @@ class LedgerTxnRoot::Impl BestOffersEntryPtr getFromBestOffers(Asset const& buying, Asset const& selling) const; - UnorderedMap> - bulkLoadAccounts(UnorderedSet const& keys) const; - UnorderedMap> - bulkLoadTrustLines(UnorderedSet const& keys) const; UnorderedMap> bulkLoadOffers(UnorderedSet const& keys) const; - UnorderedMap> - bulkLoadData(UnorderedSet const& keys) const; - UnorderedMap> - bulkLoadClaimableBalance(UnorderedSet const& keys) const; - UnorderedMap> - bulkLoadLiquidityPool(UnorderedSet const& keys) const; - UnorderedMap> - bulkLoadContractData(UnorderedSet const& keys) const; - UnorderedMap> - bulkLoadContractCode(UnorderedSet const& keys) const; - UnorderedMap> - bulkLoadConfigSettings(UnorderedSet const& keys) const; - UnorderedMap> - bulkLoadTTL(UnorderedSet const& keys) const; - std::deque::const_iterator loadNextBestOffersIntoCache(BestOffersEntryPtr cached, Asset const& buying, Asset const& selling); @@ -778,18 +712,8 @@ class LedgerTxnRoot::Impl // deleteOffersModifiedOnOrAfterLedger has no exception safety guarantees. void deleteOffersModifiedOnOrAfterLedger(uint32_t ledger) const; - // dropAccounts, dropData, dropOffers, and dropTrustLines have no exception - // safety guarantees. - void dropAccounts(bool rebuild); - void dropData(bool rebuild); - void dropOffers(bool rebuild); - void dropTrustLines(bool rebuild); - void dropClaimableBalances(bool rebuild); - void dropLiquidityPools(bool rebuild); - void dropContractData(bool rebuild); - void dropContractCode(bool rebuild); - void dropConfigSettings(bool rebuild); - void dropTTL(bool rebuild); + // no exception safety guarantees. + void dropOffers(); #ifdef BUILD_TESTS void resetForFuzzer(); diff --git a/src/ledger/LedgerTxnLiquidityPoolSQL.cpp b/src/ledger/LedgerTxnLiquidityPoolSQL.cpp deleted file mode 100644 index ae87665c5b..0000000000 --- a/src/ledger/LedgerTxnLiquidityPoolSQL.cpp +++ /dev/null @@ -1,420 +0,0 @@ -// Copyright 2020 Stellar Development Foundation and contributors. Licensed -// under the Apache License, Version 2.0. See the COPYING file at the root -// of this distribution or at http://www.apache.org/licenses/LICENSE-2.0 - -#include "ledger/LedgerTxnImpl.h" -#include "ledger/LedgerTypeUtils.h" -#include "ledger/NonSociRelatedException.h" -#include "main/Application.h" -#include "util/GlobalChecks.h" -#include "util/types.h" - -namespace stellar -{ - -static void -throwIfNotLiquidityPool(LedgerEntryType type) -{ - if (type != LIQUIDITY_POOL) - { - throw NonSociRelatedException("LedgerEntry is not a LIQUIDITY_POOL"); - } -} - -static std::string -getPrimaryKey(PoolID const& poolID) -{ - TrustLineAsset tla(ASSET_TYPE_POOL_SHARE); - tla.liquidityPoolID() = poolID; - return toOpaqueBase64(tla); -} - -std::shared_ptr -LedgerTxnRoot::Impl::loadLiquidityPool(LedgerKey const& key) const -{ - auto poolAsset = getPrimaryKey(key.liquidityPool().liquidityPoolID); - - std::string liquidityPoolEntryStr; - - std::string sql = "SELECT ledgerentry " - "FROM liquiditypool " - "WHERE poolasset= :poolasset"; - auto prep = mApp.getDatabase().getPreparedStatement(sql); - auto& st = prep.statement(); - st.exchange(soci::into(liquidityPoolEntryStr)); - st.exchange(soci::use(poolAsset)); - st.define_and_bind(); - { - auto timer = mApp.getDatabase().getSelectTimer("liquiditypool"); - st.execute(true); - } - if (!st.got_data()) - { - return nullptr; - } - - LedgerEntry le; - fromOpaqueBase64(le, liquidityPoolEntryStr); - throwIfNotLiquidityPool(le.data.type()); - - return std::make_shared(std::move(le)); -} - -class BulkLoadLiquidityPoolOperation - : public DatabaseTypeSpecificOperation> -{ - Database& mDb; - std::vector mPoolAssets; - - std::vector - executeAndFetch(soci::statement& st) - { - std::string liquidityPoolEntryStr; - - st.exchange(soci::into(liquidityPoolEntryStr)); - st.define_and_bind(); - { - auto timer = mDb.getSelectTimer("liquiditypool"); - st.execute(true); - } - - std::vector res; - while (st.got_data()) - { - res.emplace_back(); - auto& le = res.back(); - - fromOpaqueBase64(le, liquidityPoolEntryStr); - throwIfNotLiquidityPool(le.data.type()); - - st.fetch(); - } - return res; - } - - public: - BulkLoadLiquidityPoolOperation(Database& db, - UnorderedSet const& keys) - : mDb(db) - { - mPoolAssets.reserve(keys.size()); - for (auto const& k : keys) - { - throwIfNotLiquidityPool(k.type()); - mPoolAssets.emplace_back( - getPrimaryKey(k.liquidityPool().liquidityPoolID)); - } - } - - std::vector - doSqliteSpecificOperation(soci::sqlite3_session_backend* sq) override - { - std::vector cstrPoolAssets; - cstrPoolAssets.reserve(mPoolAssets.size()); - for (size_t i = 0; i < mPoolAssets.size(); ++i) - { - cstrPoolAssets.emplace_back(mPoolAssets[i].c_str()); - } - - std::string sql = "WITH r AS (SELECT value FROM carray(?, ?, 'char*')) " - "SELECT ledgerentry " - "FROM liquiditypool " - "WHERE poolasset IN r"; - - auto prep = mDb.getPreparedStatement(sql); - auto be = prep.statement().get_backend(); - if (be == nullptr) - { - throw std::runtime_error("no sql backend"); - } - auto sqliteStatement = - dynamic_cast(be); - releaseAssertOrThrow(sqliteStatement); - auto st = sqliteStatement->stmt_; - - sqlite3_reset(st); - sqlite3_bind_pointer(st, 1, cstrPoolAssets.data(), "carray", 0); - sqlite3_bind_int(st, 2, static_cast(cstrPoolAssets.size())); - return executeAndFetch(prep.statement()); - } - -#ifdef USE_POSTGRES - std::vector - doPostgresSpecificOperation(soci::postgresql_session_backend* pg) override - { - std::string strPoolAssets; - marshalToPGArray(pg->conn_, strPoolAssets, mPoolAssets); - - std::string sql = "WITH r AS (SELECT unnest(:v1::TEXT[])) " - "SELECT ledgerentry " - "FROM liquiditypool " - "WHERE poolasset IN (SELECT * from r)"; - - auto prep = mDb.getPreparedStatement(sql); - auto& st = prep.statement(); - st.exchange(soci::use(strPoolAssets)); - return executeAndFetch(st); - } -#endif -}; - -UnorderedMap> -LedgerTxnRoot::Impl::bulkLoadLiquidityPool( - UnorderedSet const& keys) const -{ - if (!keys.empty()) - { - BulkLoadLiquidityPoolOperation op(mApp.getDatabase(), keys); - return populateLoadedEntries( - keys, mApp.getDatabase().doDatabaseTypeSpecificOperation(op)); - } - else - { - return {}; - } -} - -class BulkDeleteLiquidityPoolOperation - : public DatabaseTypeSpecificOperation -{ - Database& mDb; - LedgerTxnConsistency mCons; - std::vector mPoolAssets; - - public: - BulkDeleteLiquidityPoolOperation(Database& db, LedgerTxnConsistency cons, - std::vector const& entries) - : mDb(db), mCons(cons) - { - mPoolAssets.reserve(entries.size()); - for (auto const& e : entries) - { - releaseAssert(!e.entryExists()); - throwIfNotLiquidityPool(e.key().ledgerKey().type()); - mPoolAssets.emplace_back(getPrimaryKey( - e.key().ledgerKey().liquidityPool().liquidityPoolID)); - } - } - - void - doSociGenericOperation() - { - std::string sql = "DELETE FROM liquiditypool WHERE poolasset = :id"; - auto prep = mDb.getPreparedStatement(sql); - auto& st = prep.statement(); - st.exchange(soci::use(mPoolAssets)); - st.define_and_bind(); - { - auto timer = mDb.getDeleteTimer("liquiditypool"); - st.execute(true); - } - if (static_cast(st.get_affected_rows()) != mPoolAssets.size() && - mCons == LedgerTxnConsistency::EXACT) - { - throw std::runtime_error("Could not update data in SQL"); - } - } - - void - doSqliteSpecificOperation(soci::sqlite3_session_backend* sq) override - { - doSociGenericOperation(); - } - -#ifdef USE_POSTGRES - void - doPostgresSpecificOperation(soci::postgresql_session_backend* pg) override - { - std::string strPoolAssets; - marshalToPGArray(pg->conn_, strPoolAssets, mPoolAssets); - - std::string sql = "WITH r AS (SELECT unnest(:v1::TEXT[])) " - "DELETE FROM liquiditypool " - "WHERE poolasset IN (SELECT * FROM r)"; - - auto prep = mDb.getPreparedStatement(sql); - auto& st = prep.statement(); - st.exchange(soci::use(strPoolAssets)); - st.define_and_bind(); - { - auto timer = mDb.getDeleteTimer("liquiditypool"); - st.execute(true); - } - if (static_cast(st.get_affected_rows()) != mPoolAssets.size() && - mCons == LedgerTxnConsistency::EXACT) - { - throw std::runtime_error("Could not update data in SQL"); - } - } -#endif -}; - -void -LedgerTxnRoot::Impl::bulkDeleteLiquidityPool( - std::vector const& entries, LedgerTxnConsistency cons) -{ - BulkDeleteLiquidityPoolOperation op(mApp.getDatabase(), cons, entries); - mApp.getDatabase().doDatabaseTypeSpecificOperation(op); -} - -class BulkUpsertLiquidityPoolOperation - : public DatabaseTypeSpecificOperation -{ - Database& mDb; - std::vector mPoolAssets; - std::vector mAssetAs; - std::vector mAssetBs; - std::vector mLiquidityPoolEntries; - std::vector mLastModifieds; - - void - accumulateEntry(LedgerEntry const& entry) - { - throwIfNotLiquidityPool(entry.data.type()); - - auto const& lp = entry.data.liquidityPool(); - auto const& cp = lp.body.constantProduct(); - mPoolAssets.emplace_back(getPrimaryKey(lp.liquidityPoolID)); - mAssetAs.emplace_back(toOpaqueBase64(cp.params.assetA)); - mAssetBs.emplace_back(toOpaqueBase64(cp.params.assetB)); - mLiquidityPoolEntries.emplace_back(toOpaqueBase64(entry)); - mLastModifieds.emplace_back( - unsignedToSigned(entry.lastModifiedLedgerSeq)); - } - - public: - BulkUpsertLiquidityPoolOperation( - Database& Db, std::vector const& entryIter) - : mDb(Db) - { - for (auto const& e : entryIter) - { - releaseAssert(e.entryExists()); - accumulateEntry(e.entry().ledgerEntry()); - } - } - - void - doSociGenericOperation() - { - std::string sql = - "INSERT INTO liquiditypool " - "(poolasset, asseta, assetb, ledgerentry, lastmodified) " - "VALUES " - "( :id, :v1, :v2, :v3, :v4 ) " - "ON CONFLICT (poolasset) DO UPDATE SET " - "asseta = excluded.asseta, " - "assetb = excluded.assetb, " - "ledgerentry = excluded.ledgerentry, " - "lastmodified = excluded.lastmodified"; - - auto prep = mDb.getPreparedStatement(sql); - soci::statement& st = prep.statement(); - st.exchange(soci::use(mPoolAssets)); - st.exchange(soci::use(mAssetAs)); - st.exchange(soci::use(mAssetBs)); - st.exchange(soci::use(mLiquidityPoolEntries)); - st.exchange(soci::use(mLastModifieds)); - st.define_and_bind(); - { - auto timer = mDb.getUpsertTimer("liquiditypool"); - st.execute(true); - } - if (static_cast(st.get_affected_rows()) != mPoolAssets.size()) - { - throw std::runtime_error("Could not update data in SQL"); - } - } - - void - doSqliteSpecificOperation(soci::sqlite3_session_backend* sq) override - { - doSociGenericOperation(); - } - -#ifdef USE_POSTGRES - void - doPostgresSpecificOperation(soci::postgresql_session_backend* pg) override - { - std::string strPoolAssets, strAssetAs, strAssetBs, - strLiquidityPoolEntry, strLastModifieds; - - PGconn* conn = pg->conn_; - marshalToPGArray(conn, strPoolAssets, mPoolAssets); - marshalToPGArray(conn, strAssetAs, mAssetAs); - marshalToPGArray(conn, strAssetBs, mAssetBs); - marshalToPGArray(conn, strLiquidityPoolEntry, mLiquidityPoolEntries); - marshalToPGArray(conn, strLastModifieds, mLastModifieds); - - std::string sql = - "WITH r AS " - "(SELECT unnest(:ids::TEXT[]), unnest(:v1::TEXT[]), " - "unnest(:v2::TEXT[]), unnest(:v3::TEXT[]), " - "unnest(:v4::INT[])) " - "INSERT INTO liquiditypool " - "(poolasset, asseta, assetb, ledgerentry, lastmodified) " - "SELECT * FROM r " - "ON CONFLICT (poolasset) DO UPDATE SET " - "asseta = excluded.asseta, " - "assetb = excluded.assetb, " - "ledgerentry = excluded.ledgerentry, " - "lastmodified = excluded.lastmodified"; - - auto prep = mDb.getPreparedStatement(sql); - soci::statement& st = prep.statement(); - st.exchange(soci::use(strPoolAssets)); - st.exchange(soci::use(strAssetAs)); - st.exchange(soci::use(strAssetBs)); - st.exchange(soci::use(strLiquidityPoolEntry)); - st.exchange(soci::use(strLastModifieds)); - st.define_and_bind(); - { - auto timer = mDb.getUpsertTimer("liquiditypool"); - st.execute(true); - } - if (static_cast(st.get_affected_rows()) != mPoolAssets.size()) - { - throw std::runtime_error("Could not update data in SQL"); - } - } -#endif -}; - -void -LedgerTxnRoot::Impl::bulkUpsertLiquidityPool( - std::vector const& entries) -{ - BulkUpsertLiquidityPoolOperation op(mApp.getDatabase(), entries); - mApp.getDatabase().doDatabaseTypeSpecificOperation(op); -} - -void -LedgerTxnRoot::Impl::dropLiquidityPools(bool rebuild) -{ - throwIfChild(); - mEntryCache.clear(); - mBestOffers.clear(); - - mApp.getDatabase().getSession() << "DROP TABLE IF EXISTS liquiditypool;"; - - if (rebuild) - { - std::string coll = mApp.getDatabase().getSimpleCollationClause(); - // The primary key is poolasset (the base-64 opaque TrustLineAsset - // containing the PoolID) instead of poolid (the base-64 opaque PoolID) - // so that we can perform the join in load pool share trust lines by - // account and asset. - mApp.getDatabase().getSession() - << "CREATE TABLE liquiditypool (" - << "poolasset TEXT " << coll << " PRIMARY KEY, " - << "asseta TEXT " << coll << " NOT NULL, " - << "assetb TEXT " << coll << " NOT NULL, " - << "ledgerentry TEXT NOT NULL, " - << "lastmodified INT NOT NULL);"; - mApp.getDatabase().getSession() << "CREATE INDEX liquiditypoolasseta " - << "ON liquiditypool(asseta);"; - mApp.getDatabase().getSession() << "CREATE INDEX liquiditypoolassetb " - << "ON liquiditypool(assetb);"; - } -} -} diff --git a/src/ledger/LedgerTxnOfferSQL.cpp b/src/ledger/LedgerTxnOfferSQL.cpp index c70e86cb6e..4cf1b23bc2 100644 --- a/src/ledger/LedgerTxnOfferSQL.cpp +++ b/src/ledger/LedgerTxnOfferSQL.cpp @@ -652,7 +652,7 @@ LedgerTxnRoot::Impl::bulkDeleteOffers(std::vector const& entries, } void -LedgerTxnRoot::Impl::dropOffers(bool rebuild) +LedgerTxnRoot::Impl::dropOffers() { throwIfChild(); mEntryCache.clear(); @@ -660,44 +660,39 @@ LedgerTxnRoot::Impl::dropOffers(bool rebuild) mApp.getDatabase().getSession() << "DROP TABLE IF EXISTS offers;"; - if (rebuild) + std::string coll = mApp.getDatabase().getSimpleCollationClause(); + mApp.getDatabase().getSession() + << "CREATE TABLE offers" + << "(" + << "sellerid VARCHAR(56) " << coll << "NOT NULL," + << "offerid BIGINT NOT NULL CHECK (offerid >= " + "0)," + << "sellingasset TEXT " << coll << " NOT NULL," + << "buyingasset TEXT " << coll << " NOT NULL," + << "amount BIGINT NOT NULL CHECK (amount >= 0)," + "pricen INT NOT NULL," + "priced INT NOT NULL," + "price DOUBLE PRECISION NOT NULL," + "flags INT NOT NULL," + "lastmodified INT NOT NULL," + "extension TEXT NOT NULL," + "ledgerext TEXT NOT NULL," + "PRIMARY KEY (offerid)" + ");"; + mApp.getDatabase().getSession() + << "CREATE INDEX bestofferindex ON offers " + "(sellingasset,buyingasset,price,offerid);"; + mApp.getDatabase().getSession() << "CREATE INDEX offerbyseller ON offers " + "(sellerid);"; + if (!mApp.getDatabase().isSqlite()) { - std::string coll = mApp.getDatabase().getSimpleCollationClause(); - mApp.getDatabase().getSession() - << "CREATE TABLE offers" - << "(" - << "sellerid VARCHAR(56) " << coll << "NOT NULL," - << "offerid BIGINT NOT NULL CHECK (offerid >= " - "0)," - << "sellingasset TEXT " << coll << " NOT NULL," - << "buyingasset TEXT " << coll << " NOT NULL," - << "amount BIGINT NOT NULL CHECK (amount >= 0)," - "pricen INT NOT NULL," - "priced INT NOT NULL," - "price DOUBLE PRECISION NOT NULL," - "flags INT NOT NULL," - "lastmodified INT NOT NULL," - "extension TEXT NOT NULL," - "ledgerext TEXT NOT NULL," - "PRIMARY KEY (offerid)" - ");"; - mApp.getDatabase().getSession() - << "CREATE INDEX bestofferindex ON offers " - "(sellingasset,buyingasset,price,offerid);"; - mApp.getDatabase().getSession() - << "CREATE INDEX offerbyseller ON offers " - "(sellerid);"; - if (!mApp.getDatabase().isSqlite()) - { - mApp.getDatabase().getSession() - << "ALTER TABLE offers " - << "ALTER COLUMN sellerid " - << "TYPE VARCHAR(56) COLLATE \"C\", " - << "ALTER COLUMN buyingasset " - << "TYPE TEXT COLLATE \"C\", " - << "ALTER COLUMN sellingasset " - << "TYPE TEXT COLLATE \"C\""; - } + mApp.getDatabase().getSession() << "ALTER TABLE offers " + << "ALTER COLUMN sellerid " + << "TYPE VARCHAR(56) COLLATE \"C\", " + << "ALTER COLUMN buyingasset " + << "TYPE TEXT COLLATE \"C\", " + << "ALTER COLUMN sellingasset " + << "TYPE TEXT COLLATE \"C\""; } } diff --git a/src/ledger/LedgerTxnTTLSQL.cpp b/src/ledger/LedgerTxnTTLSQL.cpp deleted file mode 100644 index 1773bca835..0000000000 --- a/src/ledger/LedgerTxnTTLSQL.cpp +++ /dev/null @@ -1,382 +0,0 @@ - -// Copyright 2023 Stellar Development Foundation and contributors. Licensed -// under the Apache License, Version 2.0. See the COPYING file at the root -// of this distribution or at http://www.apache.org/licenses/LICENSE-2.0 - -#include "ledger/LedgerTxnImpl.h" -#include "ledger/LedgerTypeUtils.h" -#include "ledger/NonSociRelatedException.h" -#include "main/Application.h" -#include "util/GlobalChecks.h" -#include "util/types.h" - -namespace stellar -{ - -static void -throwIfNotTTL(LedgerEntryType type) -{ - if (type != TTL) - { - throw NonSociRelatedException("LedgerEntry is not TTL"); - } -} - -std::shared_ptr -LedgerTxnRoot::Impl::loadTTL(LedgerKey const& key) const -{ - auto keyHash = toOpaqueBase64(key.ttl().keyHash); - std::string ttlEntryStr; - - std::string sql = "SELECT ledgerentry " - "FROM ttl " - "WHERE keyhash = :keyHash"; - auto prep = mApp.getDatabase().getPreparedStatement(sql); - auto& st = prep.statement(); - st.exchange(soci::into(ttlEntryStr)); - st.exchange(soci::use(keyHash)); - st.define_and_bind(); - { - auto timer = mApp.getDatabase().getSelectTimer("ttl"); - st.execute(true); - } - if (!st.got_data()) - { - return nullptr; - } - - LedgerEntry le; - fromOpaqueBase64(le, ttlEntryStr); - throwIfNotTTL(le.data.type()); - - return std::make_shared(std::move(le)); -} -class BulkLoadTTLOperation - : public DatabaseTypeSpecificOperation> -{ - Database& mDb; - std::vector mKeyHashes; - - std::vector - executeAndFetch(soci::statement& st) - { - std::string ttlEntryStr; - - st.exchange(soci::into(ttlEntryStr)); - st.define_and_bind(); - { - auto timer = mDb.getSelectTimer("ttl"); - st.execute(true); - } - - std::vector res; - while (st.got_data()) - { - res.emplace_back(); - auto& le = res.back(); - - fromOpaqueBase64(le, ttlEntryStr); - throwIfNotTTL(le.data.type()); - - st.fetch(); - } - return res; - } - - public: - BulkLoadTTLOperation(Database& db, UnorderedSet const& keys) - : mDb(db) - { - mKeyHashes.reserve(keys.size()); - for (auto const& k : keys) - { - throwIfNotTTL(k.type()); - mKeyHashes.emplace_back(toOpaqueBase64(k.ttl().keyHash)); - } - } - - std::vector - doSqliteSpecificOperation(soci::sqlite3_session_backend* sq) override - { - std::vector cStrKeyHashes; - cStrKeyHashes.reserve(mKeyHashes.size()); - for (auto const& h : mKeyHashes) - { - cStrKeyHashes.emplace_back(h.c_str()); - } - std::string sql = "SELECT ledgerentry " - "FROM ttl " - "WHERE keyhash IN carray(?, ?, 'char*')"; - - auto prep = mDb.getPreparedStatement(sql); - auto be = prep.statement().get_backend(); - if (be == nullptr) - { - throw std::runtime_error("no sql backend"); - } - auto sqliteStatement = - dynamic_cast(be); - releaseAssertOrThrow(sqliteStatement); - auto st = sqliteStatement->stmt_; - - sqlite3_reset(st); - sqlite3_bind_pointer(st, 1, (void*)cStrKeyHashes.data(), "carray", 0); - sqlite3_bind_int(st, 2, static_cast(cStrKeyHashes.size())); - return executeAndFetch(prep.statement()); - } - -#ifdef USE_POSTGRES - std::vector - doPostgresSpecificOperation(soci::postgresql_session_backend* pg) override - { - std::string strKeyHashes; - marshalToPGArray(pg->conn_, strKeyHashes, mKeyHashes); - - std::string sql = "WITH r AS (SELECT unnest(:v1::TEXT[])) " - "SELECT ledgerentry " - "FROM ttl " - "WHERE (keyHash) IN (SELECT * from r)"; - - auto prep = mDb.getPreparedStatement(sql); - auto& st = prep.statement(); - st.exchange(soci::use(strKeyHashes)); - return executeAndFetch(st); - } -#endif -}; - -UnorderedMap> -LedgerTxnRoot::Impl::bulkLoadTTL(UnorderedSet const& keys) const -{ - if (!keys.empty()) - { - BulkLoadTTLOperation op(mApp.getDatabase(), keys); - return populateLoadedEntries( - keys, mApp.getDatabase().doDatabaseTypeSpecificOperation(op)); - } - else - { - return {}; - } -} - -class BulkDeleteTTLOperation : public DatabaseTypeSpecificOperation -{ - Database& mDb; - LedgerTxnConsistency mCons; - std::vector mKeyHashes; - - public: - BulkDeleteTTLOperation(Database& db, LedgerTxnConsistency cons, - std::vector const& entries) - : mDb(db), mCons(cons) - { - mKeyHashes.reserve(entries.size()); - for (auto const& e : entries) - { - releaseAssertOrThrow(!e.entryExists()); - throwIfNotTTL(e.key().ledgerKey().type()); - mKeyHashes.emplace_back( - toOpaqueBase64(e.key().ledgerKey().ttl().keyHash)); - } - } - - void - doSociGenericOperation() - { - std::string sql = "DELETE FROM ttl WHERE keyhash = :id"; - auto prep = mDb.getPreparedStatement(sql); - auto& st = prep.statement(); - st.exchange(soci::use(mKeyHashes)); - st.define_and_bind(); - { - auto timer = mDb.getDeleteTimer("ttl"); - st.execute(true); - } - if (static_cast(st.get_affected_rows()) != mKeyHashes.size() && - mCons == LedgerTxnConsistency::EXACT) - { - throw std::runtime_error("Could not update data in SQL"); - } - } - - void - doSqliteSpecificOperation(soci::sqlite3_session_backend* sq) override - { - doSociGenericOperation(); - } - -#ifdef USE_POSTGRES - void - doPostgresSpecificOperation(soci::postgresql_session_backend* pg) override - { - std::string strKeyHashes; - marshalToPGArray(pg->conn_, strKeyHashes, mKeyHashes); - - std::string sql = "WITH r AS (SELECT unnest(:v1::TEXT[])) " - "DELETE FROM ttl " - "WHERE keyHash IN (SELECT * FROM r)"; - - auto prep = mDb.getPreparedStatement(sql); - auto& st = prep.statement(); - st.exchange(soci::use(strKeyHashes)); - st.define_and_bind(); - { - auto timer = mDb.getDeleteTimer("ttl"); - st.execute(true); - } - if (static_cast(st.get_affected_rows()) != mKeyHashes.size() && - mCons == LedgerTxnConsistency::EXACT) - { - throw std::runtime_error("Could not update data in SQL"); - } - } -#endif -}; - -void -LedgerTxnRoot::Impl::bulkDeleteTTL(std::vector const& entries, - LedgerTxnConsistency cons) -{ - BulkDeleteTTLOperation op(mApp.getDatabase(), cons, entries); - mApp.getDatabase().doDatabaseTypeSpecificOperation(op); -} - -class BulkUpsertTTLOperation : public DatabaseTypeSpecificOperation -{ - Database& mDb; - std::vector mKeyHashes; - std::vector mTTLEntries; - std::vector mLastModifieds; - - void - accumulateEntry(LedgerEntry const& entry) - { - throwIfNotTTL(entry.data.type()); - - mKeyHashes.emplace_back(toOpaqueBase64(entry.data.ttl().keyHash)); - mTTLEntries.emplace_back(toOpaqueBase64(entry)); - mLastModifieds.emplace_back( - unsignedToSigned(entry.lastModifiedLedgerSeq)); - } - - public: - BulkUpsertTTLOperation(Database& Db, - std::vector const& entryIter) - : mDb(Db) - { - for (auto const& e : entryIter) - { - releaseAssert(e.entryExists()); - accumulateEntry(e.entry().ledgerEntry()); - } - } - - void - doSociGenericOperation() - { - std::string sql = "INSERT INTO ttl " - "(keyhash, ledgerentry, lastmodified) " - "VALUES " - "( :keyHash, :v1, :v2 ) " - "ON CONFLICT (keyhash) DO UPDATE SET " - "ledgerentry = excluded.ledgerentry, " - "lastmodified = excluded.lastmodified"; - - auto prep = mDb.getPreparedStatement(sql); - soci::statement& st = prep.statement(); - st.exchange(soci::use(mKeyHashes)); - st.exchange(soci::use(mTTLEntries)); - st.exchange(soci::use(mLastModifieds)); - st.define_and_bind(); - { - auto timer = mDb.getUpsertTimer("ttl"); - st.execute(true); - } - if (static_cast(st.get_affected_rows()) != mKeyHashes.size()) - { - throw std::runtime_error("Could not update data in SQL"); - } - } - - void - doSqliteSpecificOperation(soci::sqlite3_session_backend* sq) override - { - doSociGenericOperation(); - } - -#ifdef USE_POSTGRES - void - doPostgresSpecificOperation(soci::postgresql_session_backend* pg) override - { - std::string strKeyHashes, strTTLEntries, strLastModifieds; - - PGconn* conn = pg->conn_; - marshalToPGArray(conn, strKeyHashes, mKeyHashes); - marshalToPGArray(conn, strTTLEntries, mTTLEntries); - marshalToPGArray(conn, strLastModifieds, mLastModifieds); - - std::string sql = "WITH r AS " - "(SELECT unnest(:v1::TEXT[]), " - "unnest(:v2::TEXT[]), unnest(:v3::INT[])) " - "INSERT INTO ttl " - "(keyHash, ledgerentry, lastmodified) " - "SELECT * FROM r " - "ON CONFLICT (keyhash) DO UPDATE SET " - "ledgerentry = excluded.ledgerentry, " - "lastmodified = excluded.lastmodified"; - - auto prep = mDb.getPreparedStatement(sql); - soci::statement& st = prep.statement(); - st.exchange(soci::use(strKeyHashes)); - st.exchange(soci::use(strTTLEntries)); - st.exchange(soci::use(strLastModifieds)); - st.define_and_bind(); - { - auto timer = mDb.getUpsertTimer("ttl"); - st.execute(true); - } - if (static_cast(st.get_affected_rows()) != mKeyHashes.size()) - { - throw std::runtime_error("Could not update data in SQL"); - } - } -#endif -}; - -void -LedgerTxnRoot::Impl::bulkUpsertTTL(std::vector const& entries) -{ - BulkUpsertTTLOperation op(mApp.getDatabase(), entries); - mApp.getDatabase().doDatabaseTypeSpecificOperation(op); -} - -void -LedgerTxnRoot::Impl::dropTTL(bool rebuild) -{ - throwIfChild(); - mEntryCache.clear(); - mBestOffers.clear(); - - std::string coll = mApp.getDatabase().getSimpleCollationClause(); - - mApp.getDatabase().getSession() << "DROP TABLE IF EXISTS ttl;"; - - if (rebuild) - { - mApp.getDatabase().getSession() - << "CREATE TABLE ttl (" - << "keyhash TEXT " << coll << " NOT NULL, " - << "ledgerentry TEXT " << coll << " NOT NULL, " - << "lastmodified INT NOT NULL, " - << "PRIMARY KEY (keyhash));"; - if (!mApp.getDatabase().isSqlite()) - { - mApp.getDatabase().getSession() << "ALTER TABLE ttl " - << "ALTER COLUMN keyhash " - << "TYPE TEXT COLLATE \"C\";"; - } - } -} - -} \ No newline at end of file diff --git a/src/ledger/LedgerTxnTrustLineSQL.cpp b/src/ledger/LedgerTxnTrustLineSQL.cpp deleted file mode 100644 index 5481bc5185..0000000000 --- a/src/ledger/LedgerTxnTrustLineSQL.cpp +++ /dev/null @@ -1,522 +0,0 @@ -// Copyright 2017 Stellar Development Foundation and contributors. Licensed -// under the Apache License, Version 2.0. See the COPYING file at the root -// of this distribution or at http://www.apache.org/licenses/LICENSE-2.0 - -#include "crypto/KeyUtils.h" -#include "crypto/SecretKey.h" -#include "database/Database.h" -#include "database/DatabaseTypeSpecificOperation.h" -#include "ledger/LedgerTxnImpl.h" -#include "ledger/LedgerTypeUtils.h" -#include "ledger/NonSociRelatedException.h" -#include "main/Application.h" -#include "util/GlobalChecks.h" -#include "util/Logging.h" -#include "util/XDROperators.h" -#include "util/types.h" -#include - -namespace stellar -{ - -void -validateTrustLineKey(uint32_t ledgerVersion, LedgerKey const& key) -{ - auto const& asset = key.trustLine().asset; - - if (!isAssetValid(asset, ledgerVersion)) - { - throw NonSociRelatedException("TrustLine asset is invalid"); - } - else if (asset.type() == ASSET_TYPE_NATIVE) - { - throw NonSociRelatedException("XLM TrustLine?"); - } - else if (isIssuer(key.trustLine().accountID, asset)) - { - throw NonSociRelatedException("TrustLine accountID is issuer"); - } -} - -std::shared_ptr -LedgerTxnRoot::Impl::loadTrustLine(LedgerKey const& key) const -{ - ZoneScoped; - - validateTrustLineKey(mHeader->ledgerVersion, key); - - std::string accountIDStr = KeyUtils::toStrKey(key.trustLine().accountID); - auto asset = toOpaqueBase64(key.trustLine().asset); - - std::string trustLineEntryStr; - - auto prep = mApp.getDatabase().getPreparedStatement( - "SELECT ledgerentry " - " FROM trustlines " - "WHERE accountid= :id AND asset= :asset"); - auto& st = prep.statement(); - st.exchange(soci::into(trustLineEntryStr)); - st.exchange(soci::use(accountIDStr)); - st.exchange(soci::use(asset)); - st.define_and_bind(); - { - auto timer = mApp.getDatabase().getSelectTimer("trust"); - st.execute(true); - } - if (!st.got_data()) - { - return nullptr; - } - - LedgerEntry le; - fromOpaqueBase64(le, trustLineEntryStr); - if (le.data.type() != TRUSTLINE) - { - throw NonSociRelatedException("Loaded non-trustline entry"); - } - - return std::make_shared(std::move(le)); -} - -std::vector -LedgerTxnRoot::Impl::loadPoolShareTrustLinesByAccountAndAsset( - AccountID const& accountID, Asset const& asset) const -{ - ZoneScoped; - - std::string accountIDStr = KeyUtils::toStrKey(accountID); - auto assetStr = toOpaqueBase64(asset); - - std::string trustLineEntryStr; - - auto prep = mApp.getDatabase().getPreparedStatement( - "SELECT trustlines.ledgerentry " - "FROM trustlines " - "INNER JOIN liquiditypool " - "ON trustlines.asset = liquiditypool.poolasset " - "AND trustlines.accountid = :v1 " - "AND (liquiditypool.asseta = :v2 OR liquiditypool.assetb = :v3)"); - auto& st = prep.statement(); - st.exchange(soci::into(trustLineEntryStr)); - st.exchange(soci::use(accountIDStr)); - st.exchange(soci::use(assetStr)); - st.exchange(soci::use(assetStr)); - st.define_and_bind(); - { - auto timer = mApp.getDatabase().getSelectTimer("trust"); - st.execute(true); - } - - std::vector trustLines; - while (st.got_data()) - { - trustLines.emplace_back(); - fromOpaqueBase64(trustLines.back(), trustLineEntryStr); - if (trustLines.back().data.type() != TRUSTLINE) - { - throw NonSociRelatedException("Loaded non-trustline entry"); - } - st.fetch(); - } - return trustLines; -} - -class BulkUpsertTrustLinesOperation : public DatabaseTypeSpecificOperation -{ - Database& mDB; - std::vector mAccountIDs; - std::vector mAssets; - std::vector mTrustLineEntries; - std::vector mLastModifieds; - - public: - BulkUpsertTrustLinesOperation(Database& DB, - std::vector const& entries, - uint32_t ledgerVersion) - : mDB(DB) - { - mAccountIDs.reserve(entries.size()); - mAssets.reserve(entries.size()); - mTrustLineEntries.reserve(entries.size()); - mLastModifieds.reserve(entries.size()); - - for (auto const& e : entries) - { - releaseAssert(e.entryExists()); - releaseAssert(e.entry().type() == - InternalLedgerEntryType::LEDGER_ENTRY); - auto const& le = e.entry().ledgerEntry(); - releaseAssert(le.data.type() == TRUSTLINE); - - auto const& tl = le.data.trustLine(); - - validateTrustLineKey(ledgerVersion, e.key().ledgerKey()); - - mAccountIDs.emplace_back(KeyUtils::toStrKey(tl.accountID)); - mAssets.emplace_back(toOpaqueBase64(tl.asset)); - mTrustLineEntries.emplace_back(toOpaqueBase64(le)); - mLastModifieds.emplace_back( - unsignedToSigned(le.lastModifiedLedgerSeq)); - } - } - - void - doSociGenericOperation() - { - std::string sql = "INSERT INTO trustlines ( " - "accountid, asset, ledgerentry, lastmodified)" - "VALUES ( " - ":id, :v1, :v2, :v3 " - ") ON CONFLICT (accountid, asset) DO UPDATE SET " - "ledgerentry = excluded.ledgerentry, " - "lastmodified = excluded.lastmodified"; - auto prep = mDB.getPreparedStatement(sql); - soci::statement& st = prep.statement(); - st.exchange(soci::use(mAccountIDs)); - st.exchange(soci::use(mAssets)); - st.exchange(soci::use(mTrustLineEntries)); - st.exchange(soci::use(mLastModifieds)); - st.define_and_bind(); - { - auto timer = mDB.getUpsertTimer("trustline"); - st.execute(true); - } - if (static_cast(st.get_affected_rows()) != mAccountIDs.size()) - { - throw std::runtime_error("Could not update data in SQL"); - } - } - - void - doSqliteSpecificOperation(soci::sqlite3_session_backend* sq) override - { - doSociGenericOperation(); - } - -#ifdef USE_POSTGRES - void - doPostgresSpecificOperation(soci::postgresql_session_backend* pg) override - { - PGconn* conn = pg->conn_; - - std::string strAccountIDs, strAssets, strTrustLineEntries, - strLastModifieds; - - marshalToPGArray(conn, strAccountIDs, mAccountIDs); - marshalToPGArray(conn, strAssets, mAssets); - marshalToPGArray(conn, strTrustLineEntries, mTrustLineEntries); - marshalToPGArray(conn, strLastModifieds, mLastModifieds); - - std::string sql = "WITH r AS (SELECT " - "unnest(:ids::TEXT[]), " - "unnest(:v1::TEXT[]), " - "unnest(:v2::TEXT[]), " - "unnest(:v3::INT[])) " - "INSERT INTO trustlines ( " - "accountid, asset, ledgerEntry, lastmodified" - ") SELECT * from r " - "ON CONFLICT (accountid, asset) DO UPDATE SET " - "ledgerentry = excluded.ledgerentry, " - "lastmodified = excluded.lastmodified"; - auto prep = mDB.getPreparedStatement(sql); - soci::statement& st = prep.statement(); - st.exchange(soci::use(strAccountIDs)); - st.exchange(soci::use(strAssets)); - st.exchange(soci::use(strTrustLineEntries)); - st.exchange(soci::use(strLastModifieds)); - st.define_and_bind(); - { - auto timer = mDB.getUpsertTimer("trustline"); - st.execute(true); - } - if (static_cast(st.get_affected_rows()) != mAccountIDs.size()) - { - throw std::runtime_error("Could not update data in SQL"); - } - } -#endif -}; - -class BulkDeleteTrustLinesOperation : public DatabaseTypeSpecificOperation -{ - Database& mDB; - LedgerTxnConsistency mCons; - std::vector mAccountIDs; - std::vector mAssets; - - public: - BulkDeleteTrustLinesOperation(Database& DB, LedgerTxnConsistency cons, - std::vector const& entries, - uint32_t ledgerVersion) - : mDB(DB), mCons(cons) - { - mAccountIDs.reserve(entries.size()); - mAssets.reserve(entries.size()); - for (auto const& e : entries) - { - releaseAssert(!e.entryExists()); - releaseAssert(e.key().type() == - InternalLedgerEntryType::LEDGER_ENTRY); - releaseAssert(e.key().ledgerKey().type() == TRUSTLINE); - auto const& tl = e.key().ledgerKey().trustLine(); - - validateTrustLineKey(ledgerVersion, e.key().ledgerKey()); - - mAccountIDs.emplace_back(KeyUtils::toStrKey(tl.accountID)); - mAssets.emplace_back(toOpaqueBase64(tl.asset)); - } - } - - void - doSociGenericOperation() - { - std::string sql = "DELETE FROM trustlines WHERE accountid = :id " - "AND asset = :v1"; - auto prep = mDB.getPreparedStatement(sql); - soci::statement& st = prep.statement(); - st.exchange(soci::use(mAccountIDs)); - st.exchange(soci::use(mAssets)); - st.define_and_bind(); - { - auto timer = mDB.getDeleteTimer("trustline"); - st.execute(true); - } - if (static_cast(st.get_affected_rows()) != mAccountIDs.size() && - mCons == LedgerTxnConsistency::EXACT) - { - throw std::runtime_error("Could not update data in SQL"); - } - } - - void - doSqliteSpecificOperation(soci::sqlite3_session_backend* sq) override - { - doSociGenericOperation(); - } - -#ifdef USE_POSTGRES - void - doPostgresSpecificOperation(soci::postgresql_session_backend* pg) override - { - std::string strAccountIDs, strAssets; - PGconn* conn = pg->conn_; - marshalToPGArray(conn, strAccountIDs, mAccountIDs); - marshalToPGArray(conn, strAssets, mAssets); - std::string sql = "WITH r AS (SELECT " - "unnest(:ids::TEXT[]), " - "unnest(:v1::TEXT[])" - ") " - "DELETE FROM trustlines WHERE " - "(accountid, asset) IN (SELECT * FROM r)"; - auto prep = mDB.getPreparedStatement(sql); - soci::statement& st = prep.statement(); - st.exchange(soci::use(strAccountIDs)); - st.exchange(soci::use(strAssets)); - st.define_and_bind(); - { - auto timer = mDB.getDeleteTimer("trustline"); - st.execute(true); - } - if (static_cast(st.get_affected_rows()) != mAccountIDs.size() && - mCons == LedgerTxnConsistency::EXACT) - { - throw std::runtime_error("Could not update data in SQL"); - } - } -#endif -}; - -void -LedgerTxnRoot::Impl::bulkUpsertTrustLines( - std::vector const& entries) -{ - ZoneScoped; - ZoneValue(static_cast(entries.size())); - BulkUpsertTrustLinesOperation op(mApp.getDatabase(), entries, - mHeader->ledgerVersion); - mApp.getDatabase().doDatabaseTypeSpecificOperation(op); -} - -void -LedgerTxnRoot::Impl::bulkDeleteTrustLines( - std::vector const& entries, LedgerTxnConsistency cons) -{ - ZoneScoped; - ZoneValue(static_cast(entries.size())); - BulkDeleteTrustLinesOperation op(mApp.getDatabase(), cons, entries, - mHeader->ledgerVersion); - mApp.getDatabase().doDatabaseTypeSpecificOperation(op); -} - -void -LedgerTxnRoot::Impl::dropTrustLines(bool rebuild) -{ - throwIfChild(); - mEntryCache.clear(); - mBestOffers.clear(); - - mApp.getDatabase().getSession() << "DROP TABLE IF EXISTS trustlines;"; - - if (rebuild) - { - std::string coll = mApp.getDatabase().getSimpleCollationClause(); - mApp.getDatabase().getSession() - << "CREATE TABLE trustlines" - << "(" - << "accountid VARCHAR(56) " << coll << " NOT NULL," - << "asset TEXT " << coll << " NOT NULL," - << "ledgerentry TEXT NOT NULL," - << "lastmodified INT NOT NULL," - << "PRIMARY KEY (accountid, asset));"; - } -} - -class BulkLoadTrustLinesOperation - : public DatabaseTypeSpecificOperation> -{ - Database& mDb; - std::vector mAccountIDs; - std::vector mAssets; - - std::vector - executeAndFetch(soci::statement& st) - { - std::string accountID, asset, trustLineEntryStr; - - st.exchange(soci::into(accountID)); - st.exchange(soci::into(asset)); - st.exchange(soci::into(trustLineEntryStr)); - st.define_and_bind(); - { - auto timer = mDb.getSelectTimer("trust"); - st.execute(true); - } - - std::vector res; - while (st.got_data()) - { - res.emplace_back(); - auto& le = res.back(); - - fromOpaqueBase64(le, trustLineEntryStr); - releaseAssert(le.data.type() == TRUSTLINE); - releaseAssert(le.data.trustLine().asset.type() != - ASSET_TYPE_NATIVE); - - st.fetch(); - } - return res; - } - - public: - BulkLoadTrustLinesOperation(Database& db, - UnorderedSet const& keys) - : mDb(db) - { - mAccountIDs.reserve(keys.size()); - mAssets.reserve(keys.size()); - - for (auto const& k : keys) - { - releaseAssert(k.type() == TRUSTLINE); - if (k.trustLine().asset.type() == ASSET_TYPE_NATIVE) - { - throw NonSociRelatedException( - "TrustLine asset can't be native"); - } - - mAccountIDs.emplace_back( - KeyUtils::toStrKey(k.trustLine().accountID)); - mAssets.emplace_back(toOpaqueBase64(k.trustLine().asset)); - } - } - - virtual std::vector - doSqliteSpecificOperation(soci::sqlite3_session_backend* sq) override - { - releaseAssert(mAccountIDs.size() == mAssets.size()); - - std::vector cstrAccountIDs; - std::vector cstrAssets; - cstrAccountIDs.reserve(mAccountIDs.size()); - cstrAssets.reserve(mAssets.size()); - for (size_t i = 0; i < mAccountIDs.size(); ++i) - { - cstrAccountIDs.emplace_back(mAccountIDs[i].c_str()); - cstrAssets.emplace_back(mAssets[i].c_str()); - } - - std::string sqlJoin = "SELECT x.value, y.value FROM " - "(SELECT rowid, value FROM carray(?, ?, " - "'char*') ORDER BY rowid) " - "AS x " - "INNER JOIN (SELECT rowid, value FROM " - "carray(?, ?, 'char*') ORDER " - "BY rowid) AS y ON x.rowid = y.rowid "; - std::string sql = "WITH r AS (" + sqlJoin + - ") SELECT accountid, asset, ledgerentry " - "FROM trustlines WHERE (accountid, asset) IN r"; - - auto prep = mDb.getPreparedStatement(sql); - auto be = prep.statement().get_backend(); - if (be == nullptr) - { - throw std::runtime_error("no sql backend"); - } - auto sqliteStatement = - dynamic_cast(be); - releaseAssertOrThrow(sqliteStatement); - auto st = sqliteStatement->stmt_; - - sqlite3_reset(st); - sqlite3_bind_pointer(st, 1, cstrAccountIDs.data(), "carray", 0); - sqlite3_bind_int(st, 2, static_cast(cstrAccountIDs.size())); - sqlite3_bind_pointer(st, 3, cstrAssets.data(), "carray", 0); - sqlite3_bind_int(st, 4, static_cast(cstrAssets.size())); - return executeAndFetch(prep.statement()); - } - -#ifdef USE_POSTGRES - virtual std::vector - doPostgresSpecificOperation(soci::postgresql_session_backend* pg) override - { - releaseAssert(mAccountIDs.size() == mAssets.size()); - - std::string strAccountIDs; - std::string strAssets; - marshalToPGArray(pg->conn_, strAccountIDs, mAccountIDs); - marshalToPGArray(pg->conn_, strAssets, mAssets); - - auto prep = mDb.getPreparedStatement( - "WITH r AS (SELECT unnest(:v1::TEXT[]), " - "unnest(:v2::TEXT[])) SELECT accountid, asset, " - "ledgerentry " - " FROM trustlines " - "WHERE (accountid, asset) IN (SELECT * " - "FROM r)"); - auto& st = prep.statement(); - st.exchange(soci::use(strAccountIDs)); - st.exchange(soci::use(strAssets)); - return executeAndFetch(st); - } -#endif -}; - -UnorderedMap> -LedgerTxnRoot::Impl::bulkLoadTrustLines( - UnorderedSet const& keys) const -{ - ZoneScoped; - ZoneValue(static_cast(keys.size())); - if (!keys.empty()) - { - BulkLoadTrustLinesOperation op(mApp.getDatabase(), keys); - return populateLoadedEntries( - keys, mApp.getDatabase().doDatabaseTypeSpecificOperation(op)); - } - else - { - return {}; - } -} -} diff --git a/src/ledger/test/InMemoryLedgerTxn.cpp b/src/ledger/test/InMemoryLedgerTxn.cpp index e213ace9ba..beeab8d270 100644 --- a/src/ledger/test/InMemoryLedgerTxn.cpp +++ b/src/ledger/test/InMemoryLedgerTxn.cpp @@ -360,9 +360,9 @@ InMemoryLedgerTxn::getPoolShareTrustLinesByAccountAndAsset( } void -InMemoryLedgerTxn::dropOffers(bool rebuild) +InMemoryLedgerTxn::dropOffers() { - mRealRootForOffers.dropOffers(rebuild); + mRealRootForOffers.dropOffers(); } uint64_t diff --git a/src/ledger/test/InMemoryLedgerTxn.h b/src/ledger/test/InMemoryLedgerTxn.h index 6a14d217fa..7e2f3d9ee7 100644 --- a/src/ledger/test/InMemoryLedgerTxn.h +++ b/src/ledger/test/InMemoryLedgerTxn.h @@ -133,7 +133,7 @@ class InMemoryLedgerTxn : public LedgerTxn getBestOffer(Asset const& buying, Asset const& selling, OfferDescriptor const& worseThan) override; - void dropOffers(bool rebuild) override; + void dropOffers() override; uint64_t countOffers(LedgerRange const& ledgers) const override; void deleteOffersModifiedOnOrAfterLedger(uint32_t ledger) const override; diff --git a/src/ledger/test/InMemoryLedgerTxnRoot.cpp b/src/ledger/test/InMemoryLedgerTxnRoot.cpp index 3d37ba9ae7..4ff9ca435f 100644 --- a/src/ledger/test/InMemoryLedgerTxnRoot.cpp +++ b/src/ledger/test/InMemoryLedgerTxnRoot.cpp @@ -109,52 +109,7 @@ InMemoryLedgerTxnRoot::deleteOffersModifiedOnOrAfterLedger( } void -InMemoryLedgerTxnRoot::dropAccounts(bool) -{ -} - -void -InMemoryLedgerTxnRoot::dropData(bool) -{ -} - -void -InMemoryLedgerTxnRoot::dropOffers(bool) -{ -} - -void -InMemoryLedgerTxnRoot::dropTrustLines(bool) -{ -} - -void -InMemoryLedgerTxnRoot::dropClaimableBalances(bool) -{ -} - -void -InMemoryLedgerTxnRoot::dropLiquidityPools(bool) -{ -} - -void -InMemoryLedgerTxnRoot::dropContractData(bool) -{ -} - -void -InMemoryLedgerTxnRoot::dropContractCode(bool) -{ -} - -void -InMemoryLedgerTxnRoot::dropConfigSettings(bool) -{ -} - -void -InMemoryLedgerTxnRoot::dropTTL(bool) +InMemoryLedgerTxnRoot::dropOffers() { } diff --git a/src/ledger/test/InMemoryLedgerTxnRoot.h b/src/ledger/test/InMemoryLedgerTxnRoot.h index 1fb4fd4617..9b925172aa 100644 --- a/src/ledger/test/InMemoryLedgerTxnRoot.h +++ b/src/ledger/test/InMemoryLedgerTxnRoot.h @@ -68,16 +68,7 @@ class InMemoryLedgerTxnRoot : public AbstractLedgerTxnParent void deleteOffersModifiedOnOrAfterLedger(uint32_t ledger) const override; - void dropAccounts(bool rebuild) override; - void dropData(bool rebuild) override; - void dropOffers(bool rebuild) override; - void dropTrustLines(bool rebuild) override; - void dropClaimableBalances(bool rebuild) override; - void dropLiquidityPools(bool rebuild) override; - void dropContractData(bool rebuild) override; - void dropContractCode(bool rebuild) override; - void dropConfigSettings(bool rebuild) override; - void dropTTL(bool rebuild) override; + void dropOffers() override; double getPrefetchHitRate() const override; uint32_t prefetchClassic(UnorderedSet const& keys) override; uint32_t prefetchSoroban(UnorderedSet const& keys, diff --git a/src/main/ApplicationImpl.cpp b/src/main/ApplicationImpl.cpp index 409c819030..e92dcf306f 100644 --- a/src/main/ApplicationImpl.cpp +++ b/src/main/ApplicationImpl.cpp @@ -185,8 +185,7 @@ maybeRebuildLedger(Application& app, bool applyBuckets) app.getDatabase().clearPreparedStatementCache(); soci::transaction tx(app.getDatabase().getSession()); LOG_INFO(DEFAULT_LOG, "Dropping offers"); - app.getLedgerTxnRoot().dropOffers(/*rebuild=*/true); - + app.getLedgerTxnRoot().dropOffers(); tx.commit(); // No transaction is needed. ApplyBucketsWork breaks the apply into many diff --git a/src/main/CommandLine.cpp b/src/main/CommandLine.cpp index d3728c5541..0c2a3c717c 100644 --- a/src/main/CommandLine.cpp +++ b/src/main/CommandLine.cpp @@ -1177,9 +1177,8 @@ runNewDB(CommandLineArgs const& args) }; return runWithHelp(args, - { - configurationParser(configOption), - }, + {configurationParser(configOption), + minimalDBParser(minimalForInMemoryMode)}, [&] { auto cfg = configOption.getConfig(); initializeDatabase(cfg); @@ -1486,8 +1485,9 @@ run(CommandLineArgs const& args) args, {configurationParser(configOption), disableBucketGCParser(disableBucketGC), - metadataOutputStreamParser(stream), - waitForConsensusParser(waitForConsensus)}, + metadataOutputStreamParser(stream), inMemoryParser(inMemory), + waitForConsensusParser(waitForConsensus), + startAtLedgerParser(startAtLedger), startAtHashParser(startAtHash)}, [&] { Config cfg; std::shared_ptr clock; diff --git a/test-tx-meta-baseline-current/InvokeHostFunctionTests.json b/test-tx-meta-baseline-current/InvokeHostFunctionTests.json index 6386579190..6f2d88e86e 100644 --- a/test-tx-meta-baseline-current/InvokeHostFunctionTests.json +++ b/test-tx-meta-baseline-current/InvokeHostFunctionTests.json @@ -1387,9 +1387,7 @@ "bKDF6V5IzTo=", "bKDF6V5IzTo=" ], - "temp entry eviction|BucketListDB|background scan" : [ "bKDF6V5IzTo=", "bKDF6V5IzTo=" ], - "temp entry eviction|BucketListDB|legacy main thread scan" : [ "bKDF6V5IzTo=", "bKDF6V5IzTo=" ], - "temp entry eviction|sql" : [ "bKDF6V5IzTo=", "bKDF6V5IzTo=" ], + "temp entry eviction" : [ "bKDF6V5IzTo=", "bKDF6V5IzTo=" ], "transaction validation diagnostics" : [ "bKDF6V5IzTo=" ], "version test" : [ "766L+TYsWqA=" ] } diff --git a/test-tx-meta-baseline-next/InvokeHostFunctionTests.json b/test-tx-meta-baseline-next/InvokeHostFunctionTests.json index 9fc2508fea..c5dfd2de4e 100644 --- a/test-tx-meta-baseline-next/InvokeHostFunctionTests.json +++ b/test-tx-meta-baseline-next/InvokeHostFunctionTests.json @@ -1391,9 +1391,7 @@ "bKDF6V5IzTo=", "bKDF6V5IzTo=" ], - "temp entry eviction|BucketListDB|background scan" : [ "bKDF6V5IzTo=", "bKDF6V5IzTo=" ], - "temp entry eviction|BucketListDB|legacy main thread scan" : [ "bKDF6V5IzTo=", "bKDF6V5IzTo=" ], - "temp entry eviction|sql" : [ "bKDF6V5IzTo=", "bKDF6V5IzTo=" ], + "temp entry eviction" : [ "bKDF6V5IzTo=", "bKDF6V5IzTo=" ], "transaction validation diagnostics" : [ "bKDF6V5IzTo=" ], "version test" : [ "766L+TYsWqA=" ] }