Skip to content

Commit

Permalink
use syscall.Gettimeofday to get current time (#961)
Browse files Browse the repository at this point in the history
* use syscall.Gettimeofday to get current time

* use Gettimeofday in just linux and darwin

* rename file and add some test case

* fix test file syntax

* fix within check

* fix code problem

---------

Co-authored-by: lance6716 <lance6716@gmail.com>
  • Loading branch information
hjweddie and lance6716 authored Jan 1, 2025
1 parent a66e74e commit dc262fe
Show file tree
Hide file tree
Showing 13 changed files with 100 additions and 24 deletions.
5 changes: 3 additions & 2 deletions canal/canal.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/go-mysql-org/go-mysql/mysql"
"github.com/go-mysql-org/go-mysql/replication"
"github.com/go-mysql-org/go-mysql/schema"
"github.com/go-mysql-org/go-mysql/utils"
"github.com/pingcap/errors"
"github.com/pingcap/tidb/pkg/parser"
"github.com/siddontang/go-log/log"
Expand Down Expand Up @@ -231,7 +232,7 @@ func (c *Canal) run() error {
c.cancel()
}()

c.master.UpdateTimestamp(uint32(time.Now().Unix()))
c.master.UpdateTimestamp(uint32(utils.Now().Unix()))

if !c.dumped {
c.dumped = true
Expand Down Expand Up @@ -373,7 +374,7 @@ func (c *Canal) GetTable(db string, table string) (*schema.Table, error) {
// if DiscardNoMetaRowEvent is true, we just log this error
if c.cfg.DiscardNoMetaRowEvent {
c.tableLock.Lock()
c.errorTablesGetTime[key] = time.Now()
c.errorTablesGetTime[key] = utils.Now()
c.tableLock.Unlock()
// log error and return ErrMissingTableMeta
c.cfg.Logger.Errorf("canal get table meta err: %v", errors.Trace(err))
Expand Down
3 changes: 2 additions & 1 deletion canal/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (

"github.com/go-mysql-org/go-mysql/client"
"github.com/go-mysql-org/go-mysql/mysql"
"github.com/go-mysql-org/go-mysql/utils"
)

type DumpConfig struct {
Expand Down Expand Up @@ -142,7 +143,7 @@ func NewDefaultConfig() *Config {
c.User = mysql.DEFAULT_USER
c.Password = mysql.DEFAULT_PASSWORD
c.Charset = mysql.DEFAULT_CHARSET
c.ServerID = uint32(rand.New(rand.NewSource(time.Now().Unix())).Intn(1000)) + 1001
c.ServerID = uint32(rand.New(rand.NewSource(utils.Now().Unix())).Intn(1000)) + 1001
c.Flavor = mysql.DEFAULT_FLAVOR

c.Dump.ExecutionPath = mysql.DEFAULT_DUMP_EXECUTION_PATH
Expand Down
5 changes: 3 additions & 2 deletions canal/dump.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

"github.com/go-mysql-org/go-mysql/mysql"
"github.com/go-mysql-org/go-mysql/schema"
"github.com/go-mysql-org/go-mysql/utils"
"github.com/pingcap/errors"
"github.com/shopspring/decimal"
)
Expand Down Expand Up @@ -142,7 +143,7 @@ func (c *Canal) dump() error {
return errors.New("mysqldump does not exist")
}

c.master.UpdateTimestamp(uint32(time.Now().Unix()))
c.master.UpdateTimestamp(uint32(utils.Now().Unix()))

h := &dumpParseHandler{c: c}
// If users call StartFromGTID with empty position to start dumping with gtid,
Expand All @@ -167,7 +168,7 @@ func (c *Canal) dump() error {
h.pos = uint64(pos.Pos)
}

start := time.Now()
start := utils.Now()
c.cfg.Logger.Info("try dump MySQL and parse")
if err := c.dumper.DumpAndParse(h); err != nil {
return errors.Trace(err)
Expand Down
3 changes: 2 additions & 1 deletion canal/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/go-mysql-org/go-mysql/mysql"
"github.com/go-mysql-org/go-mysql/replication"
"github.com/go-mysql-org/go-mysql/schema"
"github.com/go-mysql-org/go-mysql/utils"
"github.com/pingcap/errors"
"github.com/pingcap/tidb/pkg/parser/ast"
)
Expand Down Expand Up @@ -253,7 +254,7 @@ func (c *Canal) updateTable(header *replication.EventHeader, db, table string) (
}
func (c *Canal) updateReplicationDelay(ev *replication.BinlogEvent) {
var newDelay uint32
now := uint32(time.Now().Unix())
now := uint32(utils.Now().Unix())
if now >= ev.Header.Timestamp {
newDelay = now - ev.Header.Timestamp
}
Expand Down
5 changes: 3 additions & 2 deletions client/pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"sync"
"time"

"github.com/go-mysql-org/go-mysql/utils"
"github.com/pingcap/errors"
)

Expand Down Expand Up @@ -247,7 +248,7 @@ func (pool *Pool) putConnection(connection Connection) {
}

func (pool *Pool) nowTs() Timestamp {
return Timestamp(time.Now().Unix())
return Timestamp(utils.Now().Unix())
}

func (pool *Pool) getConnection(ctx context.Context) (Connection, error) {
Expand Down Expand Up @@ -553,7 +554,7 @@ func (pool *Pool) startNewConnections(count int) {
}

func (pool *Pool) ping(conn *Conn) error {
deadline := time.Now().Add(100 * time.Millisecond)
deadline := utils.Now().Add(100 * time.Millisecond)
_ = conn.SetDeadline(deadline)
err := conn.Ping()
if err != nil {
Expand Down
6 changes: 3 additions & 3 deletions packet/conn.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ func (c *Conn) ReadPacketReuseMem(dst []byte) ([]byte, error) {
// newCompressedPacketReader creates a new compressed packet reader.
func (c *Conn) newCompressedPacketReader() (io.Reader, error) {
if c.readTimeout != 0 {
if err := c.SetReadDeadline(time.Now().Add(c.readTimeout)); err != nil {
if err := c.SetReadDeadline(utils.Now().Add(c.readTimeout)); err != nil {
return nil, err
}
}
Expand Down Expand Up @@ -200,7 +200,7 @@ func (c *Conn) copyN(dst io.Writer, n int64) (int64, error) {
// Call ReadAtLeast with the currentPacketReader as it may change on every iteration
// of this loop.
if c.readTimeout != 0 {
if err := c.SetReadDeadline(time.Now().Add(c.readTimeout)); err != nil {
if err := c.SetReadDeadline(utils.Now().Add(c.readTimeout)); err != nil {
return written, err
}
}
Expand Down Expand Up @@ -344,7 +344,7 @@ func (c *Conn) WritePacket(data []byte) error {

func (c *Conn) writeWithTimeout(b []byte) (n int, err error) {
if c.writeTimeout != 0 {
if err := c.SetWriteDeadline(time.Now().Add(c.writeTimeout)); err != nil {
if err := c.SetWriteDeadline(utils.Now().Add(c.writeTimeout)); err != nil {
return n, err
}
}
Expand Down
7 changes: 4 additions & 3 deletions replication/binlogsyncer.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (

"github.com/go-mysql-org/go-mysql/client"
. "github.com/go-mysql-org/go-mysql/mysql"
"github.com/go-mysql-org/go-mysql/utils"
)

var (
Expand Down Expand Up @@ -227,7 +228,7 @@ func (b *BinlogSyncer) close() {
b.cancel()

if b.c != nil {
err := b.c.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
err := b.c.SetReadDeadline(utils.Now().Add(100 * time.Millisecond))
if err != nil {
b.cfg.Logger.Warnf(`could not set read deadline: %s`, err)
}
Expand Down Expand Up @@ -288,7 +289,7 @@ func (b *BinlogSyncer) registerSlave() error {

//set read timeout
if b.cfg.ReadTimeout > 0 {
_ = b.c.SetReadDeadline(time.Now().Add(b.cfg.ReadTimeout))
_ = b.c.SetReadDeadline(utils.Now().Add(b.cfg.ReadTimeout))
}

if b.cfg.RecvBufferSize > 0 {
Expand Down Expand Up @@ -791,7 +792,7 @@ func (b *BinlogSyncer) onStream(s *BinlogStreamer) {

//set read timeout
if b.cfg.ReadTimeout > 0 {
_ = b.c.SetReadDeadline(time.Now().Add(b.cfg.ReadTimeout))
_ = b.c.SetReadDeadline(utils.Now().Add(b.cfg.ReadTimeout))
}

// Reset retry count on successful packet receieve
Expand Down
3 changes: 2 additions & 1 deletion replication/replication_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/go-mysql-org/go-mysql/client"
"github.com/go-mysql-org/go-mysql/mysql"
"github.com/go-mysql-org/go-mysql/test_util"
"github.com/go-mysql-org/go-mysql/utils"
)

var testOutputLogs = flag.Bool("out", false, "output binlog event")
Expand Down Expand Up @@ -335,7 +336,7 @@ func (t *testSyncerSuite) testPositionSync() {

// Test re-sync.
time.Sleep(100 * time.Millisecond)
_ = t.b.c.SetReadDeadline(time.Now().Add(time.Millisecond))
_ = t.b.c.SetReadDeadline(utils.Now().Add(time.Millisecond))
time.Sleep(100 * time.Millisecond)

t.testSync(s)
Expand Down
9 changes: 5 additions & 4 deletions server/caching_sha2_cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"github.com/go-mysql-org/go-mysql/mysql"
"github.com/go-mysql-org/go-mysql/test_util"
"github.com/go-mysql-org/go-mysql/test_util/test_keys"
"github.com/go-mysql-org/go-mysql/utils"
)

var delay = 50
Expand Down Expand Up @@ -131,13 +132,13 @@ func (s *cacheTestSuite) runSelect() {

func (s *cacheTestSuite) TestCache() {
// first connection
t1 := time.Now()
t1 := utils.Now()
var err error
s.db, err = sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s)/%s?tls=%s", *testUser, *testPassword, s.serverAddr, *testDB, s.tlsPara))
require.NoError(s.T(), err)
s.db.SetMaxIdleConns(4)
s.runSelect()
t2 := time.Now()
t2 := utils.Now()

d1 := int(t2.Sub(t1).Nanoseconds() / 1e6)
//log.Debugf("first connection took %d milliseconds", d1)
Expand All @@ -149,12 +150,12 @@ func (s *cacheTestSuite) TestCache() {
}

// second connection
t3 := time.Now()
t3 := utils.Now()
s.db, err = sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s)/%s?tls=%s", *testUser, *testPassword, s.serverAddr, *testDB, s.tlsPara))
require.NoError(s.T(), err)
s.db.SetMaxIdleConns(4)
s.runSelect()
t4 := time.Now()
t4 := utils.Now()

d2 := int(t4.Sub(t3).Nanoseconds() / 1e6)
//log.Debugf("second connection took %d milliseconds", d2)
Expand Down
11 changes: 6 additions & 5 deletions server/ssl.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import (
"crypto/x509/pkix"
"encoding/pem"
"math/big"
"time"

"github.com/go-mysql-org/go-mysql/utils"
)

// NewServerTLSConfig: generate TLS config for server side
Expand Down Expand Up @@ -75,8 +76,8 @@ func generateAndSignRSACerts(caPem, caKey []byte) ([]byte, []byte) {
StreetAddress: []string{"ADDRESS"},
PostalCode: []string{"POSTAL_CODE"},
},
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(10, 0, 0),
NotBefore: utils.Now(),
NotAfter: utils.Now().AddDate(10, 0, 0),
SubjectKeyId: []byte{1, 2, 3, 4, 6},
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
KeyUsage: x509.KeyUsageDigitalSignature,
Expand Down Expand Up @@ -112,8 +113,8 @@ func generateCA() ([]byte, []byte) {
StreetAddress: []string{"ADDRESS"},
PostalCode: []string{"POSTAL_CODE"},
},
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(10, 0, 0),
NotBefore: utils.Now(),
NotAfter: utils.Now().AddDate(10, 0, 0),
IsCA: true,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth},
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign | x509.KeyUsageKeyEncipherment,
Expand Down
7 changes: 7 additions & 0 deletions utils/now.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
//go:build !unix

package utils

import "time"

var Now = time.Now
19 changes: 19 additions & 0 deletions utils/now_unix.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//go:build unix

package utils

import (
"syscall"
"time"
)

// Now is a faster method to get current time
func Now() time.Time {
var tv syscall.Timeval
if err := syscall.Gettimeofday(&tv); err != nil {
// If it failed at syscall, use time package instead
return time.Now()
}

return time.Unix(0, syscall.TimevalToNsec(tv))
}
41 changes: 41 additions & 0 deletions utils/now_unix_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//go:build unix

package utils

import (
"fmt"
"testing"
"time"

"github.com/stretchr/testify/assert"
)

func TestCustomTimeNow(t *testing.T) {
precision := time.Millisecond

for i := 0; i < 1000; i++ {
timestamp := time.Now()
customTimestamp := Now()

// two timestamp should within 1 percistion
assert.WithinDuration(t, timestamp, customTimestamp, precision, fmt.Sprintf("Loop: %d: customTimestamp should within %s. timestamp: %d, customTimestamp: %d", i, precision.String(), timestamp.UnixNano(), customTimestamp.UnixNano()))

time.Sleep(time.Nanosecond)
}
}

func BenchmarkGoTimeNow(t *testing.B) {
t.ResetTimer()
for n := 0; n < t.N; n++ {
_ = time.Now()
}
t.StopTimer()
}

func BenchmarkCustomTimeNow(t *testing.B) {
t.ResetTimer()
for n := 0; n < t.N; n++ {
_ = Now()
}
t.StopTimer()
}

0 comments on commit dc262fe

Please sign in to comment.