-
Notifications
You must be signed in to change notification settings - Fork 493
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
tools: block-generator locked table retry and additional metrics #5653
Changes from 11 commits
d8e3789
f9c5492
c611672
03b0d41
fc37773
e4feb36
94f1910
07d17bf
18bd1df
3957417
baffa41
205a607
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,7 +17,6 @@ | |
package generator | ||
|
||
import ( | ||
_ "embed" | ||
"encoding/json" | ||
"errors" | ||
"fmt" | ||
|
@@ -32,49 +31,19 @@ import ( | |
"github.com/algorand/go-algorand/data/basics" | ||
"github.com/algorand/go-algorand/data/bookkeeping" | ||
txn "github.com/algorand/go-algorand/data/transactions" | ||
"github.com/algorand/go-algorand/data/transactions/logic" | ||
"github.com/algorand/go-algorand/ledger/ledgercore" | ||
"github.com/algorand/go-algorand/logging" | ||
"github.com/algorand/go-algorand/protocol" | ||
"github.com/algorand/go-algorand/rpcs" | ||
"github.com/algorand/go-algorand/tools/block-generator/util" | ||
) | ||
|
||
// ---- templates ---- | ||
|
||
//go:embed teal/poap_boxes.teal | ||
var approvalBoxes string | ||
var approvalBoxesBytes interface{} | ||
|
||
//go:embed teal/poap_clear.teal | ||
var clearBoxes string | ||
var clearBoxesBytes interface{} | ||
|
||
//go:embed teal/swap_amm.teal | ||
var approvalSwap string | ||
var approvalSwapBytes interface{} | ||
|
||
//go:embed teal/swap_clear.teal | ||
var clearSwap string | ||
var clearSwapBytes interface{} | ||
|
||
func init() { | ||
prog, err := logic.AssembleString(approvalBoxes) | ||
util.MaybeFail(err, "failed to assemble approval program") | ||
approvalBoxesBytes = prog.Program | ||
|
||
prog, err = logic.AssembleString(clearBoxes) | ||
util.MaybeFail(err, "failed to assemble clear program") | ||
clearBoxesBytes = prog.Program | ||
|
||
prog, err = logic.AssembleString(approvalSwap) | ||
util.MaybeFail(err, "failed to assemble approvalSwap program") | ||
approvalSwapBytes = prog.Program | ||
|
||
prog, err = logic.AssembleString(clearSwap) | ||
util.MaybeFail(err, "failed to assemble clearSwap program") | ||
clearSwapBytes = prog.Program | ||
} | ||
const ( | ||
BlockTotalSizeBytes = "blocks_total_size_bytes" | ||
CommitWaitTimeMS = "commit_wait_time_ms" | ||
BlockgenGenerateTimeMS = "blockgen_generate_time_ms" | ||
LedgerEvalTimeMS = "ledger_eval_time_ms" | ||
LedgerValidateTimeMS = "ledger_validate_time_ms" | ||
) | ||
|
||
// ---- constructors ---- | ||
|
||
|
@@ -105,10 +74,11 @@ func MakeGenerator(log logging.Logger, dbround uint64, bkGenesis bookkeeping.Gen | |
rewardsResidue: 0, | ||
rewardsRate: 0, | ||
rewardsRecalculationRound: 0, | ||
reportData: make(map[TxTypeID]TxData), | ||
latestData: make(map[TxTypeID]uint64), | ||
roundOffset: dbround, | ||
} | ||
gen.reportData.Transactions = make(map[TxTypeID]TxData) | ||
gen.reportData.Counters = make(map[string]uint64) | ||
|
||
gen.feeSink[31] = 1 | ||
gen.rewardsPool[31] = 2 | ||
|
@@ -357,7 +327,7 @@ func (g *generator) WriteBlock(output io.Writer, round uint64) error { | |
g.setBlockHeader(&cert) | ||
|
||
intra := uint64(0) | ||
txGroupsAD := [][]txn.SignedTxnWithAD{} | ||
var txGroupsAD [][]txn.SignedTxnWithAD | ||
for intra < minTxnsForBlock { | ||
txGroupAD, numTxns, err := g.generateTxGroup(g.round, intra) | ||
if err != nil { | ||
|
@@ -371,21 +341,25 @@ func (g *generator) WriteBlock(output io.Writer, round uint64) error { | |
intra += numTxns | ||
} | ||
generated = time.Now() | ||
g.reportData.Counters[BlockgenGenerateTimeMS] += uint64(generated.Sub(start).Milliseconds()) | ||
|
||
vBlock, ledgerTxnCount, err := g.evaluateBlock(cert.Block.BlockHeader, txGroupsAD, int(intra)) | ||
vBlock, ledgerTxnCount, commitWaitTime, err := g.evaluateBlock(cert.Block.BlockHeader, txGroupsAD, int(intra)) | ||
if err != nil { | ||
return fmt.Errorf("failed to evaluate block: %w", err) | ||
} | ||
if ledgerTxnCount != g.txnCounter+intra { | ||
return fmt.Errorf("evaluateBlock() txn count mismatches theoretical intra: %d != %d", ledgerTxnCount, g.txnCounter+intra) | ||
} | ||
evaluated = time.Now() | ||
g.reportData.Counters[LedgerEvalTimeMS] += uint64(evaluated.Sub(generated).Milliseconds()) | ||
winder marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
err = g.ledger.AddValidatedBlock(*vBlock, cert.Certificate) | ||
if err != nil { | ||
return fmt.Errorf("failed to add validated block: %w", err) | ||
} | ||
validated = time.Now() | ||
g.reportData.Counters[CommitWaitTimeMS] += uint64(commitWaitTime.Milliseconds()) | ||
g.reportData.Counters[LedgerValidateTimeMS] += uint64((validated.Sub(evaluated) - commitWaitTime).Milliseconds()) | ||
Comment on lines
+361
to
+362
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Collecting some additional metrics in the |
||
|
||
cert.Block.Payset = vBlock.Block().Payset | ||
|
||
|
@@ -400,6 +374,8 @@ func (g *generator) WriteBlock(output io.Writer, round uint64) error { | |
|
||
// write the msgpack bytes for a block | ||
g.latestBlockMsgp = protocol.EncodeMsgp(&cert) | ||
g.reportData.Counters[BlockTotalSizeBytes] += uint64(len(g.latestBlockMsgp)) | ||
winder marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
_, err = output.Write(g.latestBlockMsgp) | ||
if err != nil { | ||
return err | ||
|
@@ -812,7 +788,7 @@ func (g *generator) generateAssetTxnInternalHint(txType TxTypeID, round uint64, | |
} | ||
|
||
if g.balances[senderIndex] < txn.Fee.ToUint64() { | ||
fmt.Printf("\n\nthe sender account does not have enough algos for the transfer. idx %d, asset transaction type %v, num %d\n\n", senderIndex, actual, g.reportData[actual].GenerationCount) | ||
fmt.Printf("\n\nthe sender account does not have enough algos for the transfer. idx %d, asset transaction type %v, num %d\n\n", senderIndex, actual, g.reportData.Transactions[actual].GenerationCount) | ||
os.Exit(1) | ||
} | ||
|
||
|
@@ -835,10 +811,10 @@ func track(id TxTypeID) (TxTypeID, time.Time) { | |
|
||
func (g *generator) recordData(id TxTypeID, start time.Time) { | ||
g.latestData[id]++ | ||
data := g.reportData[id] | ||
data := g.reportData.Transactions[id] | ||
data.GenerationCount += 1 | ||
data.GenerationTime += time.Since(start) | ||
g.reportData[id] = data | ||
g.reportData.Transactions[id] = data | ||
} | ||
|
||
// ---- sign transactions ---- | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,6 +20,8 @@ import ( | |
"encoding/binary" | ||
"fmt" | ||
"os" | ||
"strings" | ||
"time" | ||
|
||
"github.com/algorand/avm-abi/apps" | ||
cconfig "github.com/algorand/go-algorand/config" | ||
|
@@ -167,19 +169,30 @@ func (g *generator) startEvaluator(hdr bookkeeping.BlockHeader, paysetHint int) | |
}) | ||
} | ||
|
||
func (g *generator) evaluateBlock(hdr bookkeeping.BlockHeader, txGroups [][]txn.SignedTxnWithAD, paysetHint int) (*ledgercore.ValidatedBlock, uint64 /* txnCount */, error) { | ||
func (g *generator) evaluateBlock(hdr bookkeeping.BlockHeader, txGroups [][]txn.SignedTxnWithAD, paysetHint int) (*ledgercore.ValidatedBlock, uint64 /* txnCount */, time.Duration /* commit wait time */, error) { | ||
commitWaitTime := time.Duration(0) | ||
waitDelay := 10 * time.Millisecond | ||
eval, err := g.startEvaluator(hdr, paysetHint) | ||
if err != nil { | ||
return nil, 0, fmt.Errorf("could not start evaluator: %w", err) | ||
return nil, 0, 0, fmt.Errorf("could not start evaluator: %w", err) | ||
} | ||
for i, txGroup := range txGroups { | ||
err := eval.TransactionGroup(txGroup) | ||
if err != nil { | ||
return nil, 0, fmt.Errorf("could not evaluate transaction group %d: %w", i, err) | ||
for { | ||
err := eval.TransactionGroup(txGroup) | ||
if err != nil { | ||
if strings.Contains(err.Error(), "database table is locked") { | ||
time.Sleep(waitDelay) | ||
commitWaitTime += waitDelay | ||
// sometimes the database is locked, so we retry | ||
continue | ||
} | ||
return nil, 0, 0, fmt.Errorf("could not evaluate transaction group %d: %w", i, err) | ||
} | ||
break | ||
Comment on lines
+180
to
+191
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is the "bug fix". The error always seems to happen on the first transaction group. Simply retrying until it works seems to allow the tests to complete. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider reporting a retry count as well (though I guess this is roughly There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Or maybe more informative would be a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was mainly looking for magnitude with this. In my first test the importer was waiting for ~5 seconds over the course of a 1h test, so I don't think we need to worry about the wait time too much. |
||
} | ||
} | ||
lvb, err := eval.GenerateBlock() | ||
return lvb, eval.TestingTxnCounter(), err | ||
return lvb, eval.TestingTxnCounter(), commitWaitTime, err | ||
} | ||
|
||
func countInners(ad txn.ApplyData) int { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -149,7 +149,10 @@ type assetHolding struct { | |
} | ||
|
||
// Report is the generation report. | ||
type Report map[TxTypeID]TxData | ||
type Report struct { | ||
Counters map[string]uint64 `json:"counters"` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. More data for the report. |
||
Transactions map[TxTypeID]TxData `json:"transactions"` | ||
} | ||
|
||
// EffectsReport collates transaction counts caused by a root transaction. | ||
type EffectsReport map[string]uint64 | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
moved to generate_apps.go