From fda50186e3732ef086fd5130de45d5d0a3aaadf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philip=20Dub=C3=A9?= Date: Thu, 20 Feb 2025 22:53:06 +0000 Subject: [PATCH 1/3] Use math/bits OnesCount to preallocate slices --- client/conn.go | 5 +++-- replication/row_event.go | 13 +++++++++---- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/client/conn.go b/client/conn.go index 928e1dfd1..12dcb9fef 100644 --- a/client/conn.go +++ b/client/conn.go @@ -5,6 +5,7 @@ import ( "context" "crypto/tls" "fmt" + "math/bits" "net" "runtime" "runtime/debug" @@ -557,8 +558,8 @@ func (c *Conn) execSend(query string) error { // separated by "|". Examples of capability names are CLIENT_DEPRECATE_EOF and CLIENT_PROTOCOL_41. // These are defined as constants in the mysql package. func (c *Conn) CapabilityString() string { - var caps []string capability := c.capability + caps := make([]string, 0, bits.OnesCount32(capability)) for i := 0; capability != 0; i++ { field := uint32(1 << i) if capability&field == 0 { @@ -642,8 +643,8 @@ func (c *Conn) CapabilityString() string { // StatusString returns a "|" separated list of status fields. Example status values are SERVER_QUERY_WAS_SLOW and SERVER_STATUS_AUTOCOMMIT. // These are defined as constants in the mysql package. func (c *Conn) StatusString() string { - var stats []string status := c.status + stats := make([]string, 0, bits.OnesCount16(status)) for i := 0; status != 0; i++ { field := uint16(1 << i) if status&field == 0 { diff --git a/replication/row_event.go b/replication/row_event.go index d1fe9afa8..1c18706db 100644 --- a/replication/row_event.go +++ b/replication/row_event.go @@ -5,6 +5,7 @@ import ( "encoding/hex" "fmt" "io" + "math/bits" "strconv" "strings" "time" @@ -754,7 +755,7 @@ func (e *TableMapEvent) VisibilityMap() map[int]bool { if len(e.VisibilityBitmap) == 0 { return nil } - ret := make(map[int]bool) + ret := make(map[int]bool, len(e.VisibilityBitmap)*8) i := 0 for _, field := range e.VisibilityBitmap { for c := 0x80; c != 0; c >>= 1 { @@ -1146,15 +1147,19 @@ func (e *RowsEvent) decodeImage(data []byte, bitmap []byte, rowImageType EnumRow } row := make([]interface{}, e.ColumnCount) - skips := make([]int, 0) // refer: https://github.com/alibaba/canal/blob/c3e38e50e269adafdd38a48c63a1740cde304c67/dbsync/src/main/java/com/taobao/tddl/dbsync/binlog/event/RowsLogBuffer.java#L63 count := 0 - for i := 0; i < int(e.ColumnCount); i++ { - if isBitSet(bitmap, i) { + col := 0 + for ; col+8 <= int(e.ColumnCount); col += 8 { + count += bits.OnesCount8(bitmap[col>>3]) + } + for ; col < int(e.ColumnCount); col++ { + if isBitSet(bitmap, col) { count++ } } + skips := make([]int, 0, int(e.ColumnCount)-count) count = bitmapByteSize(count) nullBitmap := data[pos : pos+count] From afa234b0a05b1d137b7a608bd2a1a8475cd06e46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philip=20Dub=C3=A9?= Date: Fri, 21 Feb 2025 05:18:26 +0000 Subject: [PATCH 2/3] trailing zeroes to scan flags --- client/conn.go | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/client/conn.go b/client/conn.go index 12dcb9fef..f82b3c465 100644 --- a/client/conn.go +++ b/client/conn.go @@ -560,11 +560,8 @@ func (c *Conn) execSend(query string) error { func (c *Conn) CapabilityString() string { capability := c.capability caps := make([]string, 0, bits.OnesCount32(capability)) - for i := 0; capability != 0; i++ { - field := uint32(1 << i) - if capability&field == 0 { - continue - } + for capability != 0 { + field := uint32(1 << bits.TrailingZeros32(capability)) capability ^= field switch field { @@ -645,11 +642,8 @@ func (c *Conn) CapabilityString() string { func (c *Conn) StatusString() string { status := c.status stats := make([]string, 0, bits.OnesCount16(status)) - for i := 0; status != 0; i++ { - field := uint16(1 << i) - if status&field == 0 { - continue - } + for status != 0 { + field := uint16(1 << bits.TrailingZeros16(status)) status ^= field switch field { From aa908a4075d18eb865aa215b32f3ddf41ad65a62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philip=20Dub=C3=A9?= Date: Fri, 21 Feb 2025 05:23:30 +0000 Subject: [PATCH 3/3] avoid epilogue loop --- replication/row_event.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/replication/row_event.go b/replication/row_event.go index 1c18706db..d64bfdef2 100644 --- a/replication/row_event.go +++ b/replication/row_event.go @@ -1154,10 +1154,8 @@ func (e *RowsEvent) decodeImage(data []byte, bitmap []byte, rowImageType EnumRow for ; col+8 <= int(e.ColumnCount); col += 8 { count += bits.OnesCount8(bitmap[col>>3]) } - for ; col < int(e.ColumnCount); col++ { - if isBitSet(bitmap, col) { - count++ - } + if col < int(e.ColumnCount) { + count += bits.OnesCount8(bitmap[col>>3] & byte((1<<(int(e.ColumnCount)-col))-1)) } skips := make([]int, 0, int(e.ColumnCount)-count) count = bitmapByteSize(count)