mirror of
https://github.com/tendermint/tendermint.git
synced 2026-04-27 02:55:07 +00:00
* Performance improvements for the event query API (#7319) Rework the implementation of event query parsing and execution to improve performance and reduce memory usage. Previous memory and CPU profiles of the pubsub service showed query processing as a significant hotspot. While we don't have evidence that this is visibly hurting users, fixing it is fairly easy and self-contained. Updates #6439. Typical benchmark results comparing the original implementation (PEG) with the reworked implementation (Custom): ``` TEST TIME/OP BYTES/OP ALLOCS/OP SPEEDUP MEM SAVING BenchmarkParsePEG-12 51716 ns 526832 27 BenchmarkParseCustom-12 2167 ns 4616 17 23.8x 99.1% BenchmarkMatchPEG-12 3086 ns 1097 22 BenchmarkMatchCustom-12 294.2 ns 64 3 10.5x 94.1% ```
97 lines
1.9 KiB
Go
97 lines
1.9 KiB
Go
package kv
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
"strconv"
|
|
|
|
"github.com/google/orderedcode"
|
|
"github.com/tendermint/tendermint/libs/pubsub/query/syntax"
|
|
"github.com/tendermint/tendermint/types"
|
|
)
|
|
|
|
func intInSlice(a int, list []int) bool {
|
|
for _, b := range list {
|
|
if b == a {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
func int64FromBytes(bz []byte) int64 {
|
|
v, _ := binary.Varint(bz)
|
|
return v
|
|
}
|
|
|
|
func int64ToBytes(i int64) []byte {
|
|
buf := make([]byte, binary.MaxVarintLen64)
|
|
n := binary.PutVarint(buf, i)
|
|
return buf[:n]
|
|
}
|
|
|
|
func heightKey(height int64) ([]byte, error) {
|
|
return orderedcode.Append(
|
|
nil,
|
|
types.BlockHeightKey,
|
|
height,
|
|
)
|
|
}
|
|
|
|
func eventKey(compositeKey, typ, eventValue string, height int64) ([]byte, error) {
|
|
return orderedcode.Append(
|
|
nil,
|
|
compositeKey,
|
|
eventValue,
|
|
height,
|
|
typ,
|
|
)
|
|
}
|
|
|
|
func parseValueFromPrimaryKey(key []byte) (string, error) {
|
|
var (
|
|
compositeKey string
|
|
height int64
|
|
)
|
|
|
|
remaining, err := orderedcode.Parse(string(key), &compositeKey, &height)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to parse event key: %w", err)
|
|
}
|
|
|
|
if len(remaining) != 0 {
|
|
return "", fmt.Errorf("unexpected remainder in key: %s", remaining)
|
|
}
|
|
|
|
return strconv.FormatInt(height, 10), nil
|
|
}
|
|
|
|
func parseValueFromEventKey(key []byte) (string, error) {
|
|
var (
|
|
compositeKey, typ, eventValue string
|
|
height int64
|
|
)
|
|
|
|
remaining, err := orderedcode.Parse(string(key), &compositeKey, &eventValue, &height, &typ)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to parse event key: %w", err)
|
|
}
|
|
|
|
if len(remaining) != 0 {
|
|
return "", fmt.Errorf("unexpected remainder in key: %s", remaining)
|
|
}
|
|
|
|
return eventValue, nil
|
|
}
|
|
|
|
func lookForHeight(conditions []syntax.Condition) (int64, bool) {
|
|
for _, c := range conditions {
|
|
if c.Tag == types.BlockHeightKey && c.Op == syntax.TEq {
|
|
return int64(c.Arg.Number()), true
|
|
}
|
|
}
|
|
|
|
return 0, false
|
|
}
|