diff --git a/client.go b/client.go index 5c25f55acc..3f49e9e8d4 100644 --- a/client.go +++ b/client.go @@ -1041,7 +1041,7 @@ func (c *HostClient) doNonNilReqResp(req *Request, resp *Response) (bool, error) panic("BUG: resp cannot be nil") } - atomic.StoreUint32(&c.lastUseTime, uint32(coarseTimeNow().Unix()-startTimeUnix)) + atomic.StoreUint32(&c.lastUseTime, uint32(CoarseTimeNow().Unix()-startTimeUnix)) // Free up resources occupied by response before sending the request, // so the GC may reclaim these resources (e.g. response body). @@ -1057,7 +1057,7 @@ func (c *HostClient) doNonNilReqResp(req *Request, resp *Response) (bool, error) // Optimization: update write deadline only if more than 25% // of the last write deadline exceeded. // See https://github.com/golang/go/issues/15133 for details. - currentTime := coarseTimeNow() + currentTime := CoarseTimeNow() if currentTime.Sub(cc.lastWriteDeadlineTime) > (c.WriteTimeout >> 2) { if err = conn.SetWriteDeadline(currentTime.Add(c.WriteTimeout)); err != nil { c.closeConn(cc) @@ -1101,7 +1101,7 @@ func (c *HostClient) doNonNilReqResp(req *Request, resp *Response) (bool, error) // Optimization: update read deadline only if more than 25% // of the last read deadline exceeded. // See https://github.com/golang/go/issues/15133 for details. - currentTime := coarseTimeNow() + currentTime := CoarseTimeNow() if currentTime.Sub(cc.lastReadDeadlineTime) > (c.ReadTimeout >> 2) { if err = conn.SetReadDeadline(currentTime.Add(c.ReadTimeout)); err != nil { c.closeConn(cc) @@ -1276,7 +1276,7 @@ func acquireClientConn(conn net.Conn) *clientConn { } cc := v.(*clientConn) cc.c = conn - cc.createdTime = coarseTimeNow() + cc.createdTime = CoarseTimeNow() return cc } @@ -1288,7 +1288,7 @@ func releaseClientConn(cc *clientConn) { var clientConnPool sync.Pool func (c *HostClient) releaseConn(cc *clientConn) { - cc.lastUseTime = coarseTimeNow() + cc.lastUseTime = CoarseTimeNow() c.connsLock.Lock() c.conns = append(c.conns, cc) c.connsLock.Unlock() @@ -1988,7 +1988,7 @@ func (c *pipelineConnClient) writer(conn net.Conn, stopCh <-chan struct{}) error // Optimization: update write deadline only if more than 25% // of the last write deadline exceeded. // See https://github.com/golang/go/issues/15133 for details. - currentTime := coarseTimeNow() + currentTime := CoarseTimeNow() if currentTime.Sub(lastWriteDeadlineTime) > (writeTimeout >> 2) { if err = conn.SetWriteDeadline(currentTime.Add(writeTimeout)); err != nil { w.err = err @@ -2069,7 +2069,7 @@ func (c *pipelineConnClient) reader(conn net.Conn, stopCh <-chan struct{}) error // Optimization: update read deadline only if more than 25% // of the last read deadline exceeded. // See https://github.com/golang/go/issues/15133 for details. - currentTime := coarseTimeNow() + currentTime := CoarseTimeNow() if currentTime.Sub(lastReadDeadlineTime) > (readTimeout >> 2) { if err = conn.SetReadDeadline(currentTime.Add(readTimeout)); err != nil { w.err = err diff --git a/coarseTime.go b/coarseTime.go index cb3f598d0e..03c14f39a8 100644 --- a/coarseTime.go +++ b/coarseTime.go @@ -5,18 +5,21 @@ import ( "time" ) -func coarseTimeNow() time.Time { +// CoarseTimeNow returns the current time truncated to the nearest second. +// +// This is a faster alternative to time.Now(). +func CoarseTimeNow() time.Time { tp := coarseTime.Load().(*time.Time) return *tp } func init() { - t := time.Now() + t := time.Now().Truncate(time.Second) coarseTime.Store(&t) go func() { for { time.Sleep(time.Second) - t := time.Now() + t := time.Now().Truncate(time.Second) coarseTime.Store(&t) } }() diff --git a/coarseTime_test.go b/coarseTime_test.go index 15715c5c2a..b2f2334ee3 100644 --- a/coarseTime_test.go +++ b/coarseTime_test.go @@ -10,7 +10,7 @@ func BenchmarkCoarseTimeNow(b *testing.B) { var zeroTimeCount uint64 b.RunParallel(func(pb *testing.PB) { for pb.Next() { - t := coarseTimeNow() + t := CoarseTimeNow() if t.IsZero() { atomic.AddUint64(&zeroTimeCount, 1) } diff --git a/server.go b/server.go index e893cc3c17..edf646d12b 100644 --- a/server.go +++ b/server.go @@ -592,13 +592,18 @@ func (ctx *RequestCtx) ConnID() uint64 { return ctx.connID } -// Time returns RequestHandler call time. +// Time returns RequestHandler call time truncated to the nearest second. +// +// Call time.Now() at the beginning of RequestHandler in order to obtain +// percise RequestHandler call time. func (ctx *RequestCtx) Time() time.Time { return ctx.time } // ConnTime returns the time server starts serving the connection // the current request came from. +// +// The returned time is truncated to the nearest second. func (ctx *RequestCtx) ConnTime() time.Time { return ctx.connTime } @@ -1280,7 +1285,7 @@ func (s *Server) Serve(ln net.Listener) error { if time.Since(lastOverflowErrorTime) > time.Minute { s.logger().Printf("The incoming connection cannot be served, because %d concurrent connections are served. "+ "Try increasing Server.Concurrency", maxWorkersCount) - lastOverflowErrorTime = coarseTimeNow() + lastOverflowErrorTime = CoarseTimeNow() } // The current server reached concurrency limit, @@ -1322,7 +1327,7 @@ func acceptConn(s *Server, ln net.Listener, lastPerIPErrorTime *time.Time) (net. if time.Since(*lastPerIPErrorTime) > time.Minute { s.logger().Printf("The number of connections from %s exceeds MaxConnsPerIP=%d", getConnIP4(c), s.MaxConnsPerIP) - *lastPerIPErrorTime = coarseTimeNow() + *lastPerIPErrorTime = CoarseTimeNow() } continue } @@ -1437,7 +1442,7 @@ func (s *Server) serveConn(c net.Conn) error { serverName := s.getServerName() connRequestNum := uint64(0) connID := nextConnID() - currentTime := coarseTimeNow() + currentTime := CoarseTimeNow() connTime := currentTime maxRequestBodySize := s.MaxRequestBodySize if maxRequestBodySize <= 0 { @@ -1494,7 +1499,7 @@ func (s *Server) serveConn(c net.Conn) error { } } - currentTime = coarseTimeNow() + currentTime = CoarseTimeNow() ctx.lastReadDuration = currentTime.Sub(ctx.time) if err != nil { @@ -1635,7 +1640,7 @@ func (s *Server) serveConn(c net.Conn) error { break } - currentTime = coarseTimeNow() + currentTime = CoarseTimeNow() } if br != nil { @@ -1691,7 +1696,7 @@ func (s *Server) updateWriteDeadline(c net.Conn, ctx *RequestCtx, lastDeadlineTi // Optimization: update write deadline only if more than 25% // of the last write deadline exceeded. // See https://github.com/golang/go/issues/15133 for details. - currentTime := coarseTimeNow() + currentTime := CoarseTimeNow() if currentTime.Sub(lastDeadlineTime) > (writeTimeout >> 2) { if err := c.SetWriteDeadline(currentTime.Add(writeTimeout)); err != nil { panic(fmt.Sprintf("BUG: error in SetWriteDeadline(%s): %s", writeTimeout, err)) @@ -1874,7 +1879,7 @@ func (ctx *RequestCtx) Init2(conn net.Conn, logger Logger, reduceMemoryUsage boo ctx.connID = nextConnID() ctx.s = fakeServer ctx.connRequestNum = 0 - ctx.connTime = coarseTimeNow() + ctx.connTime = CoarseTimeNow() ctx.time = ctx.connTime keepBodyBuffer := !reduceMemoryUsage diff --git a/workerpool.go b/workerpool.go index 1faee33442..cf602e0507 100644 --- a/workerpool.go +++ b/workerpool.go @@ -187,7 +187,7 @@ func (wp *workerPool) getCh() *workerChan { } func (wp *workerPool) release(ch *workerChan) bool { - ch.lastUseTime = coarseTimeNow() + ch.lastUseTime = CoarseTimeNow() wp.lock.Lock() if wp.mustStop { wp.lock.Unlock()