rpc/jsonrpc/server: ws server optimizations (#5312)

* docs: goleveldb is much more stable now

Refs https://github.com/syndtr/goleveldb/issues/226#issuecomment-682495490

* rpc/core/events: make sure WS client receives every event

previously, if the write buffer was full, the response would've been
lost without any trace (log msg, etc.)

* rpc/jsonrpc/server: set defaultWSWriteChanCapacity to 1

Refs #3905
Closes #3829

setting write buffer capacity to 1 makes transactions count per block
more stable and also reduces the pauses length by 20s.

before: https://github.com/tendermint/tendermint/issues/3905#issuecomment-681854328 net.Read - 20s
after: net.Read - 0.66s

* rpc/jsonrpc/server: buffer writes and avoid io.ReadAll during read
This commit is contained in:
Anton Kaliaev
2020-09-04 10:58:47 +04:00
committed by GitHub
parent 39d2ac4dbc
commit 59ec3d91e4
6 changed files with 133 additions and 75 deletions
+43 -39
View File
@@ -28,7 +28,7 @@ func MakeTxKV() ([]byte, []byte, []byte) {
func TestHeaderEvents(t *testing.T) {
for i, c := range GetClients() {
i, c := i, c // capture params
i, c := i, c
t.Run(reflect.TypeOf(c).String(), func(t *testing.T) {
// start for this test it if it wasn't already running
if !c.IsRunning() {
@@ -48,35 +48,39 @@ func TestHeaderEvents(t *testing.T) {
}
}
// subscribe to new blocks and make sure height increments by 1
func TestBlockEvents(t *testing.T) {
for i, c := range GetClients() {
i, c := i, c // capture params
for _, c := range GetClients() {
c := c
t.Run(reflect.TypeOf(c).String(), func(t *testing.T) {
// start for this test it if it wasn't already running
if !c.IsRunning() {
// if so, then we start it, listen, and stop it.
err := c.Start()
require.Nil(t, err, "%d: %+v", i, err)
require.Nil(t, err)
defer c.Stop()
}
// listen for a new block; ensure height increases by 1
const subscriber = "TestBlockEvents"
eventCh, err := c.Subscribe(context.Background(), subscriber, types.QueryForEvent(types.EventNewBlock).String())
require.NoError(t, err)
defer c.UnsubscribeAll(context.Background(), subscriber)
var firstBlockHeight int64
for j := 0; j < 3; j++ {
evtTyp := types.EventNewBlock
evt, err := client.WaitForOneEvent(c, evtTyp, waitForEventTimeout)
require.Nil(t, err, "%d: %+v", j, err)
blockEvent, ok := evt.(types.EventDataNewBlock)
require.True(t, ok, "%d: %#v", j, evt)
for i := int64(0); i < 3; i++ {
event := <-eventCh
blockEvent, ok := event.Data.(types.EventDataNewBlock)
require.True(t, ok)
block := blockEvent.Block
if j == 0 {
if firstBlockHeight == 0 {
firstBlockHeight = block.Header.Height
continue
}
require.Equal(t, block.Header.Height, firstBlockHeight+int64(j))
require.Equal(t, firstBlockHeight+i, block.Header.Height)
}
})
}
@@ -86,48 +90,48 @@ func TestTxEventsSentWithBroadcastTxAsync(t *testing.T) { testTxEventsSent(t, "a
func TestTxEventsSentWithBroadcastTxSync(t *testing.T) { testTxEventsSent(t, "sync") }
func testTxEventsSent(t *testing.T, broadcastMethod string) {
for i, c := range GetClients() {
i, c := i, c // capture params
for _, c := range GetClients() {
c := c
t.Run(reflect.TypeOf(c).String(), func(t *testing.T) {
// start for this test it if it wasn't already running
if !c.IsRunning() {
// if so, then we start it, listen, and stop it.
err := c.Start()
require.Nil(t, err, "%d: %+v", i, err)
require.Nil(t, err)
defer c.Stop()
}
// wait for the client subscription to get set up
time.Sleep(100 * time.Millisecond)
// make the tx
_, _, tx := MakeTxKV()
evtTyp := types.EventTx
// send
var (
txres *ctypes.ResultBroadcastTx
err error
)
switch broadcastMethod {
case "async":
txres, err = c.BroadcastTxAsync(tx)
case "sync":
txres, err = c.BroadcastTxSync(tx)
default:
panic(fmt.Sprintf("Unknown broadcastMethod %s", broadcastMethod))
}
require.NoError(t, err)
require.Equal(t, txres.Code, abci.CodeTypeOK)
go func() {
var (
txres *ctypes.ResultBroadcastTx
err error
)
switch broadcastMethod {
case "async":
txres, err = c.BroadcastTxAsync(tx)
case "sync":
txres, err = c.BroadcastTxSync(tx)
default:
panic(fmt.Sprintf("Unknown broadcastMethod %s", broadcastMethod))
}
if assert.NoError(t, err) {
assert.Equal(t, txres.Code, abci.CodeTypeOK)
}
}()
// and wait for confirmation
evt, err := client.WaitForOneEvent(c, evtTyp, waitForEventTimeout)
require.Nil(t, err, "%d: %+v", i, err)
evt, err := client.WaitForOneEvent(c, types.EventTx, waitForEventTimeout)
require.Nil(t, err)
// and make sure it has the proper info
txe, ok := evt.(types.EventDataTx)
require.True(t, ok, "%d: %#v", i, evt)
require.True(t, ok)
// make sure this is the proper tx
require.EqualValues(t, tx, txe.Tx)
require.True(t, txe.Result.IsOK())
+2
View File
@@ -18,6 +18,7 @@ func TestMain(m *testing.M) {
if err != nil {
panic(err)
}
app := kvstore.NewPersistentKVStoreApplication(dir)
node = rpctest.StartTendermint(app)
@@ -25,5 +26,6 @@ func TestMain(m *testing.M) {
// and shut down proper at the end
rpctest.StopTendermint(node)
_ = os.RemoveAll(dir)
os.Exit(code)
}