abci: make tendermint example+test clients manage a mutex (#7978)

This is the first step in removing the mutex from ABCI applications:
making our test applications hold mutexes, which this does, hopefully
with zero impact. If this lands well, then we can explore deleting the
other mutexes (in the ABCI server and the clients.) While this change
is not user impacting at all, removing the other mutexes *will* be. 

In persuit of this, I've changed the KV app somewhat, to put almost
all of the logic in the base application and make the persistent
application mostly be a wrapper on top of that with a different
storage layer.
This commit is contained in:
Sam Kleinman
2022-02-23 22:39:47 +00:00
committed by GitHub
parent f939f962b1
commit 61a81279bd
11 changed files with 351 additions and 372 deletions
+35 -4
View File
@@ -8,6 +8,7 @@ import (
"path/filepath"
"sort"
"strconv"
"sync"
"github.com/tendermint/tendermint/abci/example/code"
abci "github.com/tendermint/tendermint/abci/types"
@@ -21,6 +22,7 @@ import (
// to disk as JSON, taking state sync snapshots if requested.
type Application struct {
abci.BaseApplication
mu sync.Mutex
logger log.Logger
state *State
snapshots *SnapshotStore
@@ -98,8 +100,8 @@ func NewApplication(cfg *Config) (*Application, error) {
// Info implements ABCI.
func (app *Application) Info(req abci.RequestInfo) abci.ResponseInfo {
app.state.RLock()
defer app.state.RUnlock()
app.mu.Lock()
defer app.mu.Unlock()
return abci.ResponseInfo{
Version: version.ABCIVersion,
@@ -111,6 +113,9 @@ func (app *Application) Info(req abci.RequestInfo) abci.ResponseInfo {
// Info implements ABCI.
func (app *Application) InitChain(req abci.RequestInitChain) abci.ResponseInitChain {
app.mu.Lock()
defer app.mu.Unlock()
var err error
app.state.initialHeight = uint64(req.InitialHeight)
if len(req.AppStateBytes) > 0 {
@@ -135,6 +140,9 @@ func (app *Application) InitChain(req abci.RequestInitChain) abci.ResponseInitCh
// CheckTx implements ABCI.
func (app *Application) CheckTx(req abci.RequestCheckTx) abci.ResponseCheckTx {
app.mu.Lock()
defer app.mu.Unlock()
_, _, err := parseTx(req.Tx)
if err != nil {
return abci.ResponseCheckTx{
@@ -149,6 +157,9 @@ func (app *Application) CheckTx(req abci.RequestCheckTx) abci.ResponseCheckTx {
func (app *Application) FinalizeBlock(req abci.RequestFinalizeBlock) abci.ResponseFinalizeBlock {
var txs = make([]*abci.ResponseDeliverTx, len(req.Txs))
app.mu.Lock()
defer app.mu.Unlock()
for i, tx := range req.Txs {
key, value, err := parseTx(tx)
if err != nil {
@@ -187,6 +198,9 @@ func (app *Application) FinalizeBlock(req abci.RequestFinalizeBlock) abci.Respon
// Commit implements ABCI.
func (app *Application) Commit() abci.ResponseCommit {
app.mu.Lock()
defer app.mu.Unlock()
height, hash, err := app.state.Commit()
if err != nil {
panic(err)
@@ -214,6 +228,9 @@ func (app *Application) Commit() abci.ResponseCommit {
// Query implements ABCI.
func (app *Application) Query(req abci.RequestQuery) abci.ResponseQuery {
app.mu.Lock()
defer app.mu.Unlock()
return abci.ResponseQuery{
Height: int64(app.state.Height),
Key: req.Data,
@@ -223,6 +240,9 @@ func (app *Application) Query(req abci.RequestQuery) abci.ResponseQuery {
// ListSnapshots implements ABCI.
func (app *Application) ListSnapshots(req abci.RequestListSnapshots) abci.ResponseListSnapshots {
app.mu.Lock()
defer app.mu.Unlock()
snapshots, err := app.snapshots.List()
if err != nil {
panic(err)
@@ -232,6 +252,9 @@ func (app *Application) ListSnapshots(req abci.RequestListSnapshots) abci.Respon
// LoadSnapshotChunk implements ABCI.
func (app *Application) LoadSnapshotChunk(req abci.RequestLoadSnapshotChunk) abci.ResponseLoadSnapshotChunk {
app.mu.Lock()
defer app.mu.Unlock()
chunk, err := app.snapshots.LoadChunk(req.Height, req.Format, req.Chunk)
if err != nil {
panic(err)
@@ -241,6 +264,9 @@ func (app *Application) LoadSnapshotChunk(req abci.RequestLoadSnapshotChunk) abc
// OfferSnapshot implements ABCI.
func (app *Application) OfferSnapshot(req abci.RequestOfferSnapshot) abci.ResponseOfferSnapshot {
app.mu.Lock()
defer app.mu.Unlock()
if app.restoreSnapshot != nil {
panic("A snapshot is already being restored")
}
@@ -251,6 +277,9 @@ func (app *Application) OfferSnapshot(req abci.RequestOfferSnapshot) abci.Respon
// ApplySnapshotChunk implements ABCI.
func (app *Application) ApplySnapshotChunk(req abci.RequestApplySnapshotChunk) abci.ResponseApplySnapshotChunk {
app.mu.Lock()
defer app.mu.Unlock()
if app.restoreSnapshot == nil {
panic("No restore in progress")
}
@@ -270,12 +299,14 @@ func (app *Application) ApplySnapshotChunk(req abci.RequestApplySnapshotChunk) a
return abci.ResponseApplySnapshotChunk{Result: abci.ResponseApplySnapshotChunk_ACCEPT}
}
func (app *Application) PrepareProposal(
req abci.RequestPrepareProposal) abci.ResponsePrepareProposal {
func (app *Application) PrepareProposal(req abci.RequestPrepareProposal) abci.ResponsePrepareProposal {
return abci.ResponsePrepareProposal{BlockData: req.BlockData}
}
func (app *Application) Rollback() error {
app.mu.Lock()
defer app.mu.Unlock()
return app.state.Rollback()
}