Skip to content

Commit

Permalink
perf: improve performance and modify some abci (#287)
Browse files Browse the repository at this point in the history
* feat: more prometheus metrics for monitoring performance (#146) (#175)

* chore: config timeout and connection pool (#150) (#171)

* fix: use line/tm-db instead of tendermint/tm-db

* bump up tm-db, iavl; re-apply #201

* chore: use default db backend among the available ones (#212)

* chore: use default db backend among the available ones

* chore: bump up iavl, tm-db

* feat: concurrent checkTx #213; fix tm-db call

* fix: rename TM to OC

* fix: modify key name; tendermint -> ostracon

* chore: rename tendermint to ostracon

* chore: remove mempool.postCheck (#158) (#217)

* fix: error handling after check tx

* fix: typo

* chore: (mempool) remove postCheck and impl reserve

* chore: fix tests

* chore: revise log (remove checkTx.Code)

* chore: add `CONTRACT` for `mem.proxyAppConn.CheckTxAsync()`

* chore: revise numTxs, txsBytes for `ErrMempoolIsFull` in reserve()

* chore: revise to remove redundant `isFull()`

* fix: remove tx from cache when `app errors` or `failed to reserve`

* Revert "chore: revise to remove redundant `isFull()`"

This reverts commit 55990ec.

* fix: revise to call Begin/EndRecheck even though mem.Size() is 0 (#219)

* fix: revise to call Begin/EndRecheck even though `mem.Size()` is 0

* chore: revise local_client.go

* fix: lint error

* chore: recheckTxs() just return if mem.Size() == 0

* feat: concurrent recheckTx (#163) (#221)

* chore: increase the value of maxPerPage (#223)

* chore: fix the type of consensus_block_interval_seconds from histogram to gauge (#224)

* feat: impl checkTxAsyncReactor() (#168) (#225)

* feat: impl checkTxAsyncReactor() (#168)

* fix: tests

* fix: lint errors

* chore: revise abci.Client, Async() interfaces (#169) (#226)

* chore: revise abci.Client, Async() interfaces

* chore: regen mock w/ mockery 2.7.4

* fix: lint error

* fix: test_race

* mempool.Flush() flushes all txs from mempool so it should get `Lock()` instead of `RLock()`

* chore: remove iavl dependency (#228)

* chore: remove iavl dependency

* chore: fix lint error

* fix: add more fixing for abci.Client, Async()

* feat: revise metric for measuring performance

* build: remove needless build tag `!libsecp256k1` (#246)

The build tag makes disable go implementation of secp256k1.
Cause there is no C implementation, a build error will occur when using tag `libsecp256k1`.

* feat: add duration metrics of gauge type (#256)

* perf: optimize checking the txs size (#264)

* perf: optimize checking the txs size

* ci: add GOPRIVATE to workflows

* test: add a unit test

* fix: fix lint errors

* perf: do not flush wal when receive consensus msgs (#273)

* perf: do not flush wal when receive consensus msgs

* fix: ci failure

* fix: lint failure

* fix: ci-e2e build failure

* fix: bump up tm-db

* fix: missing abci api

* fix: bump up tm-db; use memdb

* test: add test case to raise test coverage

* fix: race error

* fix: race error

* fix: race error

* fix: increase e2e test timeout

* fix: add test case for coverage

* fix: e2e docker file

* fix: apply comments

* fix: a Ostracon to an Ostracon
  • Loading branch information
Woosang Son authored Aug 26, 2021
1 parent 92e2b95 commit f10d45a
Show file tree
Hide file tree
Showing 214 changed files with 4,071 additions and 2,074 deletions.
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/feature-request.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ v without deliberation

<!-- Why do we need this feature?
What problems may be addressed by introducing this feature?
What benefits does Tendermint stand to gain by including this feature?
What benefits does Ostracon stand to gain by including this feature?
Are there any disadvantages of including this feature? -->

## Proposal
Expand Down
2 changes: 1 addition & 1 deletion .github/auto-comment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ pullRequestOpened: |
- [ ] Applied Appropriate Labels
Thank you for your contribution to Tendermint! :rocket:
Thank you for your contribution to Ostracon! :rocket:
2 changes: 1 addition & 1 deletion .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ on:
jobs:
e2e-test:
runs-on: ubuntu-latest
timeout-minutes: 15
timeout-minutes: 30
steps:
- uses: actions/setup-go@v2
with:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/lint.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: Lint
# Lint runs golangci-lint over the entire Tendermint repository
# Lint runs golangci-lint over the entire Ostracon repository
# This workflow is run on every pull request and push to master
# The `golangci` job will pass without running if no *.{go, mod, sum} files have been modified.
on:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/proto-docker.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Build & Push TM Proto Builder
name: Build & Push OC Proto Builder
on:
pull_request:
paths:
Expand Down
8 changes: 4 additions & 4 deletions DOCKER/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ LABEL maintainer="[email protected]"
# private validator file into /ostracon/config.
#
# The /ostracon/data dir is used by ostracon to store state.
ENV TMHOME /ostracon
ENV OCHOME /ostracon

# OS environment setup
# Set user right away for determinism, create directory for persistence and give our user ownership
Expand All @@ -27,12 +27,12 @@ RUN apk update && \
apk upgrade && \
apk add --no-cache git make gcc libc-dev build-base curl jq bash file gmp-dev clang && \
addgroup ostracon && \
adduser -S -G ostracon ostracon -h "$TMHOME"
adduser -S -G ostracon ostracon -h "$OCHOME"

# Run the container with ostracon by default. (UID=100, GID=1000)
USER ostracon

WORKDIR $TMHOME
WORKDIR $OCHOME

# p2p, rpc and prometheus port
EXPOSE 26656 26657 26660
Expand All @@ -52,5 +52,5 @@ ENTRYPOINT ["docker-entrypoint.sh"]
CMD ["node"]

# Expose the data directory as a volume since there's mutable state in there
VOLUME [ "$TMHOME" ]
VOLUME [ "$OCHOME" ]

8 changes: 4 additions & 4 deletions DOCKER/docker-entrypoint.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/bin/bash
set -e

if [ ! -d "$TMHOME/config" ]; then
if [ ! -d "$OCHOME/config" ]; then
echo "Running ostracon init to create (default) configuration for docker run."
ostracon init

Expand All @@ -13,11 +13,11 @@ if [ ! -d "$TMHOME/config" ]; then
-e 's/^index_all_tags\s*=.*/index_all_tags = true/' \
-e 's,^laddr = "tcp://127.0.0.1:26657",laddr = "tcp://0.0.0.0:26657",' \
-e 's/^prometheus\s*=.*/prometheus = true/' \
"$TMHOME/config/config.toml"
"$OCHOME/config/config.toml"

jq ".chain_id = \"$CHAIN_ID\" | .consensus_params.block.time_iota_ms = \"500\"" \
"$TMHOME/config/genesis.json" > "$TMHOME/config/genesis.json.new"
mv "$TMHOME/config/genesis.json.new" "$TMHOME/config/genesis.json"
"$OCHOME/config/genesis.json" > "$OCHOME/config/genesis.json.new"
mv "$OCHOME/config/genesis.json.new" "$OCHOME/config/genesis.json"
fi

exec ostracon "$@"
121 changes: 58 additions & 63 deletions abci/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
tmsync "github.com/line/ostracon/libs/sync"
)

//go:generate mockery --case underscore --name Client
const (
dialRetryIntervalSeconds = 3
echoRetryIntervalSeconds = 1
Expand All @@ -22,27 +23,30 @@ const (
type Client interface {
service.Service

SetResponseCallback(Callback)
SetGlobalCallback(GlobalCallback)
GetGlobalCallback() GlobalCallback
Error() error

FlushAsync() *ReqRes
EchoAsync(msg string) *ReqRes
InfoAsync(types.RequestInfo) *ReqRes
SetOptionAsync(types.RequestSetOption) *ReqRes
DeliverTxAsync(types.RequestDeliverTx) *ReqRes
CheckTxAsync(types.RequestCheckTx) *ReqRes
QueryAsync(types.RequestQuery) *ReqRes
CommitAsync() *ReqRes
InitChainAsync(types.RequestInitChain) *ReqRes
BeginBlockAsync(types.RequestBeginBlock) *ReqRes
EndBlockAsync(types.RequestEndBlock) *ReqRes
ListSnapshotsAsync(types.RequestListSnapshots) *ReqRes
OfferSnapshotAsync(types.RequestOfferSnapshot) *ReqRes
LoadSnapshotChunkAsync(types.RequestLoadSnapshotChunk) *ReqRes
ApplySnapshotChunkAsync(types.RequestApplySnapshotChunk) *ReqRes

FlushSync() error
EchoSync(msg string) (*types.ResponseEcho, error)
FlushAsync(ResponseCallback) *ReqRes
EchoAsync(string, ResponseCallback) *ReqRes
InfoAsync(types.RequestInfo, ResponseCallback) *ReqRes
SetOptionAsync(types.RequestSetOption, ResponseCallback) *ReqRes
DeliverTxAsync(types.RequestDeliverTx, ResponseCallback) *ReqRes
CheckTxAsync(types.RequestCheckTx, ResponseCallback) *ReqRes
QueryAsync(types.RequestQuery, ResponseCallback) *ReqRes
CommitAsync(ResponseCallback) *ReqRes
InitChainAsync(types.RequestInitChain, ResponseCallback) *ReqRes
BeginBlockAsync(types.RequestBeginBlock, ResponseCallback) *ReqRes
EndBlockAsync(types.RequestEndBlock, ResponseCallback) *ReqRes
BeginRecheckTxAsync(types.RequestBeginRecheckTx, ResponseCallback) *ReqRes
EndRecheckTxAsync(types.RequestEndRecheckTx, ResponseCallback) *ReqRes
ListSnapshotsAsync(types.RequestListSnapshots, ResponseCallback) *ReqRes
OfferSnapshotAsync(types.RequestOfferSnapshot, ResponseCallback) *ReqRes
LoadSnapshotChunkAsync(types.RequestLoadSnapshotChunk, ResponseCallback) *ReqRes
ApplySnapshotChunkAsync(types.RequestApplySnapshotChunk, ResponseCallback) *ReqRes

FlushSync() (*types.ResponseFlush, error)
EchoSync(string) (*types.ResponseEcho, error)
InfoSync(types.RequestInfo) (*types.ResponseInfo, error)
SetOptionSync(types.RequestSetOption) (*types.ResponseSetOption, error)
DeliverTxSync(types.RequestDeliverTx) (*types.ResponseDeliverTx, error)
Expand All @@ -52,6 +56,8 @@ type Client interface {
InitChainSync(types.RequestInitChain) (*types.ResponseInitChain, error)
BeginBlockSync(types.RequestBeginBlock) (*types.ResponseBeginBlock, error)
EndBlockSync(types.RequestEndBlock) (*types.ResponseEndBlock, error)
BeginRecheckTxSync(types.RequestBeginRecheckTx) (*types.ResponseBeginRecheckTx, error)
EndRecheckTxSync(types.RequestEndRecheckTx) (*types.ResponseEndRecheckTx, error)
ListSnapshotsSync(types.RequestListSnapshots) (*types.ResponseListSnapshots, error)
OfferSnapshotSync(types.RequestOfferSnapshot) (*types.ResponseOfferSnapshot, error)
LoadSnapshotChunkSync(types.RequestLoadSnapshotChunk) (*types.ResponseLoadSnapshotChunk, error)
Expand All @@ -74,73 +80,62 @@ func NewClient(addr, transport string, mustConnect bool) (client Client, err err
return
}

type Callback func(*types.Request, *types.Response)
type GlobalCallback func(*types.Request, *types.Response)
type ResponseCallback func(*types.Response)

type ReqRes struct {
*types.Request
*sync.WaitGroup
*types.Response // Not set atomically, so be sure to use WaitGroup.

mtx tmsync.Mutex
done bool // Gets set to true once *after* WaitGroup.Done().
cb func(*types.Response) // A single callback that may be set.
wg *sync.WaitGroup
done bool // Gets set to true once *after* WaitGroup.Done().
cb ResponseCallback // A single callback that may be set.
}

func NewReqRes(req *types.Request) *ReqRes {
func NewReqRes(req *types.Request, cb ResponseCallback) *ReqRes {
return &ReqRes{
Request: req,
WaitGroup: waitGroup1(),
Response: nil,
Request: req,
Response: nil,

wg: waitGroup1(),
done: false,
cb: nil,
cb: cb,
}
}

// Sets sets the callback. If reqRes is already done, it will call the cb
// immediately. Note, reqRes.cb should not change if reqRes.done and only one
// callback is supported.
func (r *ReqRes) SetCallback(cb func(res *types.Response)) {
r.mtx.Lock()
// InvokeCallback invokes a thread-safe execution of the configured callback
// if non-nil.
func (reqRes *ReqRes) InvokeCallback() {
reqRes.mtx.Lock()
defer reqRes.mtx.Unlock()

if r.done {
r.mtx.Unlock()
cb(r.Response)
return
if reqRes.cb != nil {
reqRes.cb(reqRes.Response)
}

r.cb = cb
r.mtx.Unlock()
}

// InvokeCallback invokes a thread-safe execution of the configured callback
// if non-nil.
func (r *ReqRes) InvokeCallback() {
r.mtx.Lock()
defer r.mtx.Unlock()
func (reqRes *ReqRes) SetDone(res *types.Response) (set bool) {
reqRes.mtx.Lock()
// TODO should we panic if it's already done?
set = !reqRes.done
if set {
reqRes.Response = res
reqRes.done = true
reqRes.wg.Done()
}
reqRes.mtx.Unlock()

if r.cb != nil {
r.cb(r.Response)
// NOTE `reqRes.cb` is immutable so we're safe to access it at here without `mtx`
if set && reqRes.cb != nil {
reqRes.cb(res)
}
}

// GetCallback returns the configured callback of the ReqRes object which may be
// nil. Note, it is not safe to concurrently call this in cases where it is
// marked done and SetCallback is called before calling GetCallback as that
// will invoke the callback twice and create a potential race condition.
//
// ref: https://github.com/tendermint/tendermint/issues/5439
func (r *ReqRes) GetCallback() func(*types.Response) {
r.mtx.Lock()
defer r.mtx.Unlock()
return r.cb
return set
}

// SetDone marks the ReqRes object as done.
func (r *ReqRes) SetDone() {
r.mtx.Lock()
r.done = true
r.mtx.Unlock()
func (reqRes *ReqRes) Wait() {
reqRes.wg.Wait()
}

func waitGroup1() (wg *sync.WaitGroup) {
Expand Down
Loading

0 comments on commit f10d45a

Please sign in to comment.