Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Snapshot on each block #2723

Merged
merged 34 commits into from
Jul 15, 2024
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
22a7319
Add snapshot support
Bushstar Nov 17, 2023
f5ec14a
Generate snapshot on ConnectTip
Bushstar Nov 21, 2023
297ff52
Get snapshot on demand
Bushstar Nov 22, 2023
b378acd
Get changed map under lock
Bushstar Nov 23, 2023
53d44ec
Merge branch 'master' into bush/test-snapshot
Bushstar Nov 23, 2023
adc22c6
Update snapshot based on height
Bushstar Nov 23, 2023
86481f9
Revert "Update snapshot based on height"
Bushstar Nov 23, 2023
3913a4f
Do not Discard or Flush snapshot
Bushstar Nov 25, 2023
40f4348
Use snapshot in getblockcount
Bushstar Nov 26, 2023
d2de1a0
Merge branch 'master' into bush/test-snapshot
Bushstar Nov 27, 2023
8c6ea78
Snapshot on each block
Bushstar Nov 27, 2023
2bd966c
Merge branch 'master' into bush/snapshot-on-blk
Bushstar Dec 2, 2023
b48eb52
Resolve issues post-merge
Bushstar Dec 2, 2023
6a740ff
lint: circular deps
Bushstar Dec 2, 2023
384094c
Only snapshot on each block near tip
Bushstar Dec 4, 2023
1414018
Use IBD
Bushstar Dec 7, 2023
2688235
Merge branch 'master' into bush/snapshot-on-blk
Bushstar Mar 7, 2024
a54e6e4
Merge branch 'master' into bush/snapshot-on-blk
prasannavl Mar 22, 2024
01b1569
Merge branch 'master' into bush/snapshot-on-blk
prasannavl Mar 22, 2024
7e35d5c
Snapshot when current block near the current time
Bushstar Mar 22, 2024
aa86da1
Merge branch 'master' into bush/snapshot-on-blk
Bushstar Jun 12, 2024
b967635
lint: circular deps
Bushstar Jun 12, 2024
087f62c
Merge branch 'master' into bush/snapshot-on-blk
Bushstar Jun 17, 2024
8fa0cab
Merge branch 'master' into bush/snapshot-on-blk
Bushstar Jun 25, 2024
94253d3
Add history snapshots
Bushstar Jun 27, 2024
b7991dd
Merge branch 'master' into bush/snapshot-on-blk
Bushstar Jun 28, 2024
4e8424f
lint: circular deps
Bushstar Jun 29, 2024
063fa3b
Add vault snapshots
Bushstar Jun 29, 2024
b6612a4
Add GetVaultSnapshot wrapper
Bushstar Jun 29, 2024
654147b
lint: circular deps
Bushstar Jul 1, 2024
3a2ee85
Pass vaultDB
Bushstar Jul 4, 2024
308fd87
Merge branch 'master' into bush/snapshot-on-blk
Bushstar Jul 5, 2024
9a84497
Get all snapshots at once
Bushstar Jul 5, 2024
f90c2cd
Merge branch 'master' into bush/snapshot-on-blk
prasannavl Jul 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ DEFI_CORE_H = \
dfi/oracles.h \
dfi/poolpairs.h \
dfi/proposals.h \
dfi/snapshotmanager.h \
dfi/tokens.h \
dfi/threadpool.h \
dfi/coinselect.h \
Expand Down Expand Up @@ -461,6 +462,7 @@ libdefi_server_a_SOURCES = \
dfi/rpc_tokens.cpp \
dfi/rpc_vault.cpp \
dfi/skipped_txs.cpp \
dfi/snapshotmanager.cpp \
dfi/tokens.cpp \
dfi/threadpool.cpp \
dfi/undos.cpp \
Expand Down
8 changes: 6 additions & 2 deletions src/dbwrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -362,8 +362,12 @@ class CDBWrapper
return new CDBIterator(*this, pdb->NewIterator(readOptions));
}

[[nodiscard]] std::shared_ptr<CStorageSnapshot> GetStorageSnapshot() const {
return std::make_shared<CStorageSnapshot>(pdb);
[[nodiscard]] const leveldb::Snapshot* GetLevelDBSnapshot() const {
return pdb->GetSnapshot();
}

void ReleaseSnapshot(const leveldb::Snapshot* snapshot) const {
pdb->ReleaseSnapshot(snapshot);
}

/**
Expand Down
8 changes: 0 additions & 8 deletions src/dfi/masternodes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1399,11 +1399,3 @@ void CalcMissingRewardTempFix(CCustomCSView &mnview, const uint32_t targetHeight
}
}
}

std::unique_ptr<CCustomCSView> GetViewSnapshot() {
// Get database snapshot and flushable storage changed map
auto [changed, snapshotDB] = pcustomcsview->GetStorage().GetSnapshotPair();

// Create new view using snapshot and change map
return std::make_unique<CCustomCSView>(snapshotDB, changed);
}
2 changes: 0 additions & 2 deletions src/dfi/masternodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -628,8 +628,6 @@ class CCustomCSView : public CMasternodesView,

std::map<CKeyID, CKey> AmISignerNow(int height, const CAnchorData::CTeam &team);

std::unique_ptr<CCustomCSView> GetViewSnapshot();

/** Global DB and view that holds enhanced chainstate data (should be protected by cs_main) */
extern std::unique_ptr<CStorageLevelDB> pcustomcsDB;
extern std::unique_ptr<CCustomCSView> pcustomcsview;
Expand Down
123 changes: 123 additions & 0 deletions src/dfi/snapshotmanager.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#include <dfi/snapshotmanager.h>

#include <dfi/masternodes.h>

std::unique_ptr<CCustomCSView> GetViewSnapshot() {
MapKV changed;
std::unique_ptr<CStorageLevelDB> snapshotDB;

// Get database snapshot and flushable storage changed map
const auto res = psnapshotManager->CheckoutSnapshot(changed, snapshotDB);

// If snapshot not present get global snapshot
if (!res) {
// Get snapshot and changed map from global
psnapshotManager->GetGlobalSnapshot(changed, snapshotDB);

// Create new view using snapshot and change map
return std::make_unique<CCustomCSView>(snapshotDB, changed);
}

// Create new view using snapshot and change map
return std::make_unique<CCustomCSView>(snapshotDB, changed);
}

CCheckedOutSnapshot::~CCheckedOutSnapshot() {
// Check snapshot back in
psnapshotManager->ReturnSnapshot(key);
}

CSnapshotManager::CSnapshotManager(CStorageLevelDB *other) {
db = other;
}

void CSnapshotManager::SetBlockSnapshot(CCustomCSView &view, const CBlockIndex *block) {
std::unique_lock<std::mutex> lock(mtx);

// Get database snapshot and flushable storage changed map
auto [changed, snapshot] = view.GetStorage().GetSnapshotData();

// Release current entry if not in use
if (currentSnapshot && currentSnapshot->snapshot && !checkedOutMap.count(currentSnapshot->key)) {
db->GetDB()->ReleaseSnapshot(currentSnapshot->snapshot);
}

// Set current snapshot
currentSnapshot =
std::make_unique<CBlockSnapshot>(snapshot, changed, CBlockSnapshotKey{block->nHeight, block->GetBlockHash()});
}

void CSnapshotManager::GetGlobalSnapshot(MapKV &changed, std::unique_ptr<CStorageLevelDB> &snapshotDB) {
LOCK(cs_main);

// Get database snapshot and flushable storage changed map
auto [changedMap, snapshot] = pcustomcsview->GetStorage().GetSnapshotData();

// Create checked out snapshot
auto checkedSnapshot = std::make_unique<CCheckedOutSnapshot>(snapshot, CBlockSnapshotKey{});

// Set args
changed = changedMap;
snapshotDB = std::make_unique<CStorageLevelDB>(db->GetDB(), checkedSnapshot);
}

bool CSnapshotManager::CheckoutSnapshot(MapKV &changed, std::unique_ptr<CStorageLevelDB> &snapshotDB) {
std::unique_lock<std::mutex> lock(mtx);

if (!currentSnapshot) {
return false;
}

// Track checked out snapshot
if (checkedOutMap.count(currentSnapshot->key)) {
++checkedOutMap.at(currentSnapshot->key).count;
} else {
checkedOutMap[currentSnapshot->key] = {currentSnapshot->snapshot, 1};
}

// Create checked out snapshot
auto snapshot = std::make_unique<CCheckedOutSnapshot>(currentSnapshot->snapshot, currentSnapshot->key);

// Set args
changed = currentSnapshot->changed;
snapshotDB = std::make_unique<CStorageLevelDB>(db->GetDB(), snapshot);

return true;
}

void CSnapshotManager::EraseCurrentSnapshot() {
std::unique_lock<std::mutex> lock(mtx);

if (!currentSnapshot) {
return;
}

if (!checkedOutMap.count(currentSnapshot->key)) {
db->GetDB()->ReleaseSnapshot(currentSnapshot->snapshot);
}

currentSnapshot.reset();
}

void CSnapshotManager::ReturnSnapshot(const CBlockSnapshotKey &key) {
std::unique_lock<std::mutex> lock(mtx);

if (!checkedOutMap.count(key)) {
return;
}

--checkedOutMap.at(key).count;

bool isCurrentKey{};
if (currentSnapshot) {
isCurrentKey = currentSnapshot->key.hash == key.hash;
}

// Release if not in use and not the current block
if (!checkedOutMap.count(key) && !isCurrentKey) {
db->GetDB()->ReleaseSnapshot(checkedOutMap.at(key).snapshot);
checkedOutMap.erase(key);
}
}

std::unique_ptr<CSnapshotManager> psnapshotManager;
98 changes: 98 additions & 0 deletions src/dfi/snapshotmanager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
#ifndef DEFI_DFI_SNAPSHOTMANAGER_H
#define DEFI_DFI_SNAPSHOTMANAGER_H

#include <uint256.h>

#include <map>
#include <memory>
#include <mutex>
#include <optional>
#include <vector>

class CBlockIndex;
class CCustomCSView;
class CSnapshotManager;
class CStorageLevelDB;

namespace leveldb {
class Snapshot;
}

using TBytes = std::vector<unsigned char>;
using MapKV = std::map<TBytes, std::optional<TBytes>>;

std::unique_ptr<CCustomCSView> GetViewSnapshot();

struct CBlockSnapshotKey {
int64_t height{};
uint256 hash{};

struct Comparator {
bool operator()(const CBlockSnapshotKey &a, const CBlockSnapshotKey &b) const {
if (a.height < b.height) {
return true;
}
if (a.height > b.height) {
return false;
}
return a.hash < b.hash;
}
};
};

struct CBlockSnapshotValue {
const leveldb::Snapshot *snapshot;
int64_t count;
};

struct CBlockSnapshot {
const leveldb::Snapshot *snapshot{};
MapKV changed;
CBlockSnapshotKey key;

CBlockSnapshot(const leveldb::Snapshot *snapshot, MapKV changed, const CBlockSnapshotKey &key)
: snapshot(snapshot),
changed(std::move(changed)),
key(key) {}
};

class CCheckedOutSnapshot {
public:
explicit CCheckedOutSnapshot(const leveldb::Snapshot *other, const CBlockSnapshotKey &otherKey)
: snapshot(other),
key(otherKey) {}
CCheckedOutSnapshot(const CCheckedOutSnapshot &) = delete;
CCheckedOutSnapshot &operator=(const CCheckedOutSnapshot &) = delete;

~CCheckedOutSnapshot();

[[nodiscard]] const leveldb::Snapshot *GetLevelDBSnapshot() const { return snapshot; }

private:
const leveldb::Snapshot *snapshot;
CBlockSnapshotKey key;
};

class CSnapshotManager {
std::unique_ptr<CBlockSnapshot> currentSnapshot;
std::mutex mtx;
CStorageLevelDB *db;
std::map<CBlockSnapshotKey, CBlockSnapshotValue, CBlockSnapshotKey::Comparator> checkedOutMap;

public:
CSnapshotManager() = delete;
explicit CSnapshotManager(CStorageLevelDB *other);

CSnapshotManager(const CSnapshotManager &other) = delete;
CSnapshotManager &operator=(const CSnapshotManager &other) = delete;

void SetBlockSnapshot(CCustomCSView &view, const CBlockIndex *block);
bool CheckoutSnapshot(MapKV &changed, std::unique_ptr<CStorageLevelDB> &snapshotDB);
void GetGlobalSnapshot(MapKV &changed, std::unique_ptr<CStorageLevelDB> &snapshotDB);
void ReturnSnapshot(const CBlockSnapshotKey &key);
void EraseCurrentSnapshot();
};

extern std::unique_ptr<CSnapshotManager> psnapshotManager;

#endif // DEFI_DFI_SNAPSHOTMANAGER_H
43 changes: 12 additions & 31 deletions src/flushablestorage.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#ifndef DEFI_FLUSHABLESTORAGE_H
#define DEFI_FLUSHABLESTORAGE_H

#include <dfi/snapshotmanager.h>

#include <shutdown.h>

#include <dbwrapper.h>
Expand Down Expand Up @@ -142,8 +144,8 @@ class CStorageLevelDB : public CStorageKV {
: db{std::make_shared<CDBWrapper>(dbName, cacheSize, fMemory, fWipe)}, batch(*db) {}

// Snapshot constructor
CStorageLevelDB(std::shared_ptr<CDBWrapper> &db, std::shared_ptr<CStorageSnapshot> &otherSnapshot)
: db(db), batch(*db), snapshot(otherSnapshot) {
CStorageLevelDB(std::shared_ptr<CDBWrapper> &db, std::unique_ptr<CCheckedOutSnapshot> &otherSnapshot)
: db(db), batch(*db), snapshot(std::move(otherSnapshot)) {
options.snapshot = snapshot->GetLevelDBSnapshot();
}

Expand Down Expand Up @@ -201,9 +203,10 @@ class CStorageLevelDB : public CStorageKV {
return db->IsEmpty();
}

[[nodiscard]] std::shared_ptr<CStorageSnapshot> GetStorageSnapshot() const {
return db->GetStorageSnapshot();
[[nodiscard]] const leveldb::Snapshot* GetLevelDBSnapshot() const {
return db->GetLevelDBSnapshot();
}

[[nodiscard]] std::shared_ptr<CDBWrapper>& GetDB() {
return db;
}
Expand All @@ -215,7 +218,7 @@ class CStorageLevelDB : public CStorageKV {

// If this snapshot is set it will be used when
// reading from the DB.
std::shared_ptr<CStorageSnapshot> snapshot;
std::unique_ptr<CCheckedOutSnapshot> snapshot;
};

// Flushable storage
Expand Down Expand Up @@ -367,43 +370,21 @@ class CFlushableStorageKV : public CStorageKV {
return changed;
}

std::pair<MapKV, std::unique_ptr<CStorageLevelDB>> GetSnapshotPair() {
[[nodiscard]] CStorageLevelDB* GetStorageLevelDB() const {
const auto storageLevelDB = dynamic_cast<CStorageLevelDB*>(&db);
assert(storageLevelDB);
if (blockTipChanged.load()) {
// Lock cs_main when updating from tipSnapshot to avoid
// race with Dis/ConnectTip.
LOCK(cs_main);
// Double check bool for safety now we are under lock.
if (blockTipChanged.load()) {
tipSnapshot = storageLevelDB->GetStorageSnapshot();
changedCopy = changed;
blockTipChanged.store(false);
}
}

return {changedCopy, std::make_unique<CStorageLevelDB>(storageLevelDB->GetDB(), tipSnapshot)};
return storageLevelDB;
}

void BlockTipChanged() {
blockTipChanged.store(true);
std::pair<MapKV, const leveldb::Snapshot*> GetSnapshotData() {
return {changed, GetStorageLevelDB()->GetLevelDBSnapshot()};
}

private:
std::unique_ptr<CStorageLevelDB> snapshotDB;
CStorageKV& db;
MapKV changed;

// Used to create a CStorageLevelDB object.
std::shared_ptr<CStorageSnapshot> tipSnapshot;

// Copy of the changed map at the point of snapshot creation.
// Can be used lock free.
MapKV changedCopy;

// Used to determine whether the block tip has changed.
std::atomic<bool> blockTipChanged{true};

// Whether this view is using a snapshot
bool snapshot{};
};
Expand Down
4 changes: 4 additions & 0 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2267,6 +2267,10 @@ bool AppInitMain(InitInterfaces& interfaces)
block_notify_genesis_wait_connection.disconnect();
}

// Set snapshot now chain has loaded
psnapshotManager = std::make_unique<CSnapshotManager>(pcustomcsview->GetStorage().GetStorageLevelDB());


if (ShutdownRequested()) {
return false;
}
Expand Down
1 change: 1 addition & 0 deletions src/rpc/resultcache.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include <rpc/resultcache.h>
#include <rpc/util.h>
#include <logging.h>
#include <validation.h>

void RPCResultCache::Init(RPCCacheMode mode) {
std::unique_lock l{aMutex};
Expand Down
Loading
Loading