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

soroban-rpc: Cache all ledger entries queried from DB in read transaction #845

Merged
merged 4 commits into from
Aug 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
36 changes: 30 additions & 6 deletions cmd/soroban-rpc/internal/db/ledgerentry.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const (
type LedgerEntryReader interface {
GetLatestLedgerSequence(ctx context.Context) (uint32, error)
NewTx(ctx context.Context) (LedgerEntryReadTx, error)
NewCachedTx(ctx context.Context) (LedgerEntryReadTx, error)
}

type LedgerEntryReadTx interface {
Expand Down Expand Up @@ -200,9 +201,15 @@ func (l *ledgerEntryReadTx) getBinaryLedgerEntry(key xdr.LedgerKey) (bool, strin
return false, "", err
}

entry, ok := l.ledgerEntryCacheReadTx.get(encodedKey)
if ok {
return ok, entry, nil
if l.ledgerEntryCacheReadTx != nil {
entry, ok := l.ledgerEntryCacheReadTx.get(encodedKey)
if ok {
if entry != nil {
return true, *entry, nil
} else {
return false, "", nil
}
}
}

sql := sq.Select("entry").From(ledgerEntriesTableName).Where(sq.Eq{"key": encodedKey})
Expand All @@ -212,13 +219,20 @@ func (l *ledgerEntryReadTx) getBinaryLedgerEntry(key xdr.LedgerKey) (bool, strin
}
switch len(results) {
case 0:
if l.ledgerEntryCacheReadTx != nil {
l.ledgerEntryCacheReadTx.upsert(encodedKey, nil)
}
return false, "", nil
case 1:
// expected length
result := results[0]
if l.ledgerEntryCacheReadTx != nil {
l.ledgerEntryCacheReadTx.upsert(encodedKey, &result)
}
return true, result, nil
default:
return false, "", fmt.Errorf("multiple entries (%d) for key %q in table %q", len(results), hex.EncodeToString([]byte(encodedKey)), ledgerEntriesTableName)
}
return true, results[0], nil
}

func (l *ledgerEntryReadTx) GetLedgerEntry(key xdr.LedgerKey, includeExpired bool) (bool, xdr.LedgerEntry, error) {
Expand Down Expand Up @@ -266,7 +280,7 @@ func (r ledgerEntryReader) GetLatestLedgerSequence(ctx context.Context) (uint32,
return getLatestLedgerSequence(ctx, r.db)
}

func (r ledgerEntryReader) NewTx(ctx context.Context) (LedgerEntryReadTx, error) {
func (r ledgerEntryReader) NewCachedTx(ctx context.Context) (LedgerEntryReadTx, error) {
txSession := r.db.Clone()
// We need to copy the cached ledger entries locally when we start the transaction
// since otherwise we would break the consistency between the transaction and the cache.
Expand All @@ -280,14 +294,24 @@ func (r ledgerEntryReader) NewTx(ctx context.Context) (LedgerEntryReadTx, error)
return nil, err
}
cacheReadTx := r.db.ledgerEntryCache.newReadTx()

return &ledgerEntryReadTx{
ledgerEntryCacheReadTx: cacheReadTx,
tx: txSession,
buffer: xdr.NewEncodingBuffer(),
}, nil
}

func (r ledgerEntryReader) NewTx(ctx context.Context) (LedgerEntryReadTx, error) {
txSession := r.db.Clone()
if err := txSession.BeginTx(ctx, &sql.TxOptions{ReadOnly: true}); err != nil {
return nil, err
}
return &ledgerEntryReadTx{
tx: txSession,
buffer: xdr.NewEncodingBuffer(),
}, nil
}

func encodeLedgerKey(buffer *xdr.EncodingBuffer, key xdr.LedgerKey) (string, error) {
// this is safe since we are converting to string right away, which causes a copy
binKey, err := buffer.LedgerKeyUnsafeMarshalBinaryCompress(key)
Expand Down
14 changes: 11 additions & 3 deletions cmd/soroban-rpc/internal/db/transactionalcache.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ func newTransactionalCache() transactionalCache {
func (c transactionalCache) newReadTx() transactionalCacheReadTx {
ret := make(transactionalCacheReadTx, len(c.entries))
for k, v := range c.entries {
ret[k] = v
localV := v
ret[k] = &localV
}
return ret
}
Expand All @@ -23,13 +24,20 @@ func (c transactionalCache) newWriteTx(estimatedWriteCount int) transactionalCac
}
}

type transactionalCacheReadTx map[string]string
// nil indicates not present in the underlying storage
type transactionalCacheReadTx map[string]*string

func (r transactionalCacheReadTx) get(key string) (string, bool) {
// nil indicates not present in the underlying storage
func (r transactionalCacheReadTx) get(key string) (*string, bool) {
val, ok := r[key]
return val, ok
}

// nil indicates not present in the underlying storage
func (r transactionalCacheReadTx) upsert(key string, value *string) {
r[key] = value
}

type transactionalCacheWriteTx struct {
// nil indicates deletion
pendingUpdates map[string]*string
Expand Down
4 changes: 4 additions & 0 deletions cmd/soroban-rpc/internal/methods/get_latest_ledger_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ func (entryReader *ConstantLedgerEntryReader) NewTx(ctx context.Context) (db.Led
return ConstantLedgerEntryReaderTx{}, nil
}

func (entryReader *ConstantLedgerEntryReader) NewCachedTx(ctx context.Context) (db.LedgerEntryReadTx, error) {
return ConstantLedgerEntryReaderTx{}, nil
}

func (entryReaderTx ConstantLedgerEntryReaderTx) GetLatestLedgerSequence() (uint32, error) {
return expectedLatestLedgerSequence, nil
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/soroban-rpc/internal/methods/simulate_transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ func NewSimulateTransactionHandler(logger *log.Entry, ledgerEntryReader db.Ledge
}
}

readTx, err := ledgerEntryReader.NewTx(ctx)
readTx, err := ledgerEntryReader.NewCachedTx(ctx)
if err != nil {
return SimulateTransactionResponse{
Error: "Cannot create read transaction",
Expand Down
2 changes: 1 addition & 1 deletion cmd/soroban-rpc/internal/preflight/preflight_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ func getPreflightParameters(t testing.TB, inMemory bool) PreflightParameters {
}
err = tx.Commit(2)
require.NoError(t, err)
ledgerEntryReadTx, err = db.NewLedgerEntryReader(dbInstance).NewTx(context.Background())
ledgerEntryReadTx, err = db.NewLedgerEntryReader(dbInstance).NewCachedTx(context.Background())
require.NoError(t, err)
}
argSymbol := xdr.ScSymbol("world")
Expand Down