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

Eval prefetch #1816

Merged
merged 27 commits into from
Jan 27, 2021
Merged
Changes from 14 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
034ea80
Add a cache for the roundCowBase
tsachiherman Sep 17, 2020
5f52560
Merge branch 'master' into tsachi/cacheRoundCowBase
tsachiherman Sep 19, 2020
0f03560
Merge branch 'master' into tsachi/cacheRoundCowBase
tsachiherman Sep 22, 2020
6454304
Merge branch 'master' into tsachi/cacheRoundCowBase
tsachiherman Sep 24, 2020
440a37d
Merge branch 'master' into tsachi/cacheRoundCowBase
tsachiherman Sep 24, 2020
86b0582
Add lock
tsachiherman Sep 24, 2020
9cd876e
Merge branch 'master' into tsachi/cacheRoundCowBase
tsachiherman Oct 1, 2020
1c7ba23
Merge branch 'master' into tsachi/cacheRoundCowBase
tsachiherman Oct 13, 2020
a8b26be
Merge branch 'master' into tsachi/cacheRoundCowBase
tsachiherman Oct 27, 2020
0df75f1
Merge branch 'master' into tsachi/cacheRoundCowBase
tsachiherman Nov 2, 2020
88e345f
Merge branch 'master' into tsachi/cacheRoundCowBase
tsachiherman Nov 23, 2020
f87f92f
Merge branch 'master' into tsachi/cacheRoundCowBase
tsachiherman Dec 2, 2020
f7aa6e4
Merge remote-tracking branch 'tsachi/tsachi/cacheRoundCowBase' into e…
brianolson Jan 8, 2021
071fe30
prefetch accounts at start of eval
brianolson Jan 8, 2021
5a93b3b
better context
brianolson Jan 12, 2021
d6446d1
Merge remote-tracking branch 'origin/master' into eval_prefetch
brianolson Jan 14, 2021
78984b5
Merge remote-tracking branch 'origin/master' into eval_prefetch
brianolson Jan 14, 2021
08a83ba
fix usage of amended roundCowBase
brianolson Jan 14, 2021
b4cada2
add non-prefetch option to eval(); mutex around deadlock.Opts.Disable
brianolson Jan 15, 2021
f79b3d7
Merge remote-tracking branch 'origin/master' into eval_prefetch
brianolson Jan 15, 2021
915b606
Merge remote-tracking branch 'origin/master' into eval_prefetch
brianolson Jan 21, 2021
ffc43a1
fmt
brianolson Jan 22, 2021
77054ac
This reverts commit ffc43a18e1536c8ab290e3332f24fd6b194a7061.
brianolson Jan 22, 2021
2ece811
TestArchivalFromNonArchival is incompatible with `go test -race`
brianolson Jan 25, 2021
2816c78
fmt
brianolson Jan 25, 2021
3a3fec8
Merge remote-tracking branch 'origin/master' into eval_prefetch
brianolson Jan 26, 2021
74643f0
wait for prefetchThread to complete before returning from eval()
brianolson Jan 26, 2021
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
71 changes: 66 additions & 5 deletions ledger/eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"context"
"errors"
"fmt"
"github.com/algorand/go-deadlock"

"github.com/algorand/go-algorand/config"
"github.com/algorand/go-algorand/crypto"
Expand Down Expand Up @@ -58,15 +59,41 @@ type roundCowBase struct {

// The current protocol consensus params.
proto config.ConsensusParams

// The accounts that we're already accessed during this round evaluation. This is a caching
// buffer used to avoid looking up the same account data more than once during a single evaluator
// execution. The AccountData is always an historical one, then therefore won't be changing.
// The underlying (accountupdates) infrastucture may provide additional cross-round caching which
// are beyond the scope of this cache.
// The account data store here is always the account data without the rewards.
accounts map[basics.Address]basics.AccountData

// accountsMu is the accounts read-write mutex, used to syncronize the access ot the accounts map.
accountsMu deadlock.RWMutex
}

func (x *roundCowBase) getCreator(cidx basics.CreatableIndex, ctype basics.CreatableType) (basics.Address, bool, error) {
return x.l.GetCreatorForRound(x.rnd, cidx, ctype)
}

func (x *roundCowBase) lookup(addr basics.Address) (acctData basics.AccountData, err error) {
acctData, _, err = x.l.LookupWithoutRewards(x.rnd, addr)
return acctData, err
// lookup returns the non-rewarded account data for the provided account address. It uses the internal per-round cache
// first, and if it cannot find it there, it would defer to the underlaying implementation.
// note that errors in accounts data retrivals are not cached as these typically cause the transaction evaluation to fail.
func (x *roundCowBase) lookup(addr basics.Address) (basics.AccountData, error) {
x.accountsMu.RLock()
if accountData, found := x.accounts[addr]; found {
x.accountsMu.RUnlock()
return accountData, nil
}
x.accountsMu.RUnlock()

accountData, _, err := x.l.LookupWithoutRewards(x.rnd, addr)
if err == nil {
x.accountsMu.Lock()
x.accounts[addr] = accountData
x.accountsMu.Unlock()
}
return accountData, err
}

func (x *roundCowBase) checkDup(firstValid, lastValid basics.Round, txid transactions.Txid, txl txlease) error {
Expand Down Expand Up @@ -240,8 +267,9 @@ func startEvaluator(l ledgerForEvaluator, hdr bookkeeping.BlockHeader, paysetHin
// the block at this round below, so underflow will be caught.
// If we are not validating, we must have previously checked
// an agreement.Certificate attesting that hdr is valid.
rnd: hdr.Round - 1,
proto: proto,
rnd: hdr.Round - 1,
proto: proto,
accounts: make(map[basics.Address]basics.AccountData),
}

eval := &BlockEvaluator{
Expand Down Expand Up @@ -963,6 +991,7 @@ func eval(ctx context.Context, l ledgerForEvaluator, blk bookkeeping.Block, vali
if err != nil {
return StateDelta{}, err
}
go prefetchThread(ctx, eval.state.lookupParent, blk.Payset)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ctx here might not be the best context to use. I think it would be better to copy the

validationCtx, validationCancel := context.WithCancel(ctx)
defer validationCancel()

from few lines below and use it here. That way, whenever this function exits OR the calling context is canceled, the prefetchThread would abort.


// Next, transactions
paysetgroups, err := blk.DecodePaysetGroups()
Expand Down Expand Up @@ -1035,6 +1064,38 @@ func eval(ctx context.Context, l ledgerForEvaluator, blk bookkeeping.Block, vali
return eval.state.mods, nil
}

func prefetchThread(ctx context.Context, state roundCowParent, payset []transactions.SignedTxnInBlock) {
maybelookup := func(addr basics.Address) {
if addr.IsZero() {
return
}
state.lookup(addr)
}
bail := 10
for _, stxn := range payset {
state.lookup(stxn.Txn.Sender)
maybelookup(stxn.Txn.Receiver)
maybelookup(stxn.Txn.CloseRemainderTo)
maybelookup(stxn.Txn.AssetSender)
maybelookup(stxn.Txn.AssetReceiver)
maybelookup(stxn.Txn.AssetCloseTo)
maybelookup(stxn.Txn.FreezeAccount)
for _, xa := range stxn.Txn.Accounts {
maybelookup(xa)
}
if bail == 0 {
bail = 10
select {
case <-ctx.Done():
return
default:
}
} else {
bail--
}
}
}

// Validate uses the ledger to validate block blk as a candidate next block.
// It returns an error if blk is not the expected next block, or if blk is
// not a valid block (e.g., it has duplicate transactions, overspends some
Expand Down