From 86c7e844f4e99607af51dcdf67b6b4caa827bc0d Mon Sep 17 00:00:00 2001 From: Kashiwa <13825170+ksw2000@users.noreply.github.com> Date: Sun, 21 Jul 2024 01:20:26 +0800 Subject: [PATCH] Optimize struct field order to reduce memory usage (#1809) 1. Reduce RequestHeader from 368 bytes to 360 bytes 2. Reduce Request from 816 bytes to 800 bytes 3. Reduce Response from 432 bytes to 416 bytes 4. Reduce Client from 312 bytes to 288 bytes 5. Reduce HostClient from 416 bytes to 392 bytes 6. Reduce PipelineClient from 176 bytes to 168 bytes 7. Reduce pipelineConnClient from 216 bytes to 208 bytes 8. Reduce Cookie from 232 bytes to 224 bytes 9. Reduce FS from 184 bytes to 160 bytes 10. Reduce fsHandler from 168 bytes to 160 bytes 11. Reduce ResponseHeader from 328 bytes to 320 bytes 12. Reduce headerScanner from 128 bytes to 120 bytes 13. Reduce TCPDialer from 104 bytes to 96 bytes 14. Reduce workerPool from 152 btyes to 144 btyes --- client.go | 159 +++++++++++++++++++++++++------------------------- cookie.go | 2 +- fs.go | 62 ++++++++++---------- header.go | 29 +++++---- http.go | 19 +++--- tcpdialer.go | 5 +- workerpool.go | 2 +- 7 files changed, 139 insertions(+), 139 deletions(-) diff --git a/client.go b/client.go index 5cae78d..c73c4d3 100644 --- a/client.go +++ b/client.go @@ -180,10 +180,6 @@ type Client struct { // Default client name is used if not set. Name string - // NoDefaultUserAgentHeader when set to true, causes the default - // User-Agent header to be excluded from the Request. - NoDefaultUserAgentHeader bool - // Callback for establishing new connections to hosts. // // Default DialTimeout is used if not set. @@ -197,15 +193,6 @@ type Client struct { // If not set, DialTimeout is used. Dial DialFunc - // Attempt to connect to both ipv4 and ipv6 addresses if set to true. - // - // This option is used only if default TCP dialer is used, - // i.e. if Dial is blank. - // - // By default client connects only to ipv4 addresses, - // since unfortunately ipv6 remains broken in many networks worldwide :) - DialDualStack bool - // TLS config for https connections. // // Default TLS config is used if not set. @@ -261,6 +248,19 @@ type Client struct { // By default response body size is unlimited. MaxResponseBodySize int + // NoDefaultUserAgentHeader when set to true, causes the default + // User-Agent header to be excluded from the Request. + NoDefaultUserAgentHeader bool + + // Attempt to connect to both ipv4 and ipv6 addresses if set to true. + // + // This option is used only if default TCP dialer is used, + // i.e. if Dial is blank. + // + // By default client connects only to ipv4 addresses, + // since unfortunately ipv6 remains broken in many networks worldwide :) + DialDualStack bool + // Header names are passed as-is without normalization // if this option is set. // @@ -288,6 +288,9 @@ type Client struct { // extra slashes are removed, special characters are encoded. DisablePathNormalizing bool + // StreamResponseBody enables response body streaming. + StreamResponseBody bool + // Maximum duration for waiting for a free connection. // // By default will not waiting, return ErrNoFreeConns immediately. @@ -301,9 +304,6 @@ type Client struct { // Connection pool strategy. Can be either LIFO or FIFO (default). ConnPoolStrategy ConnPoolStrategyType - // StreamResponseBody enables response body streaming. - StreamResponseBody bool - // ConfigureClient configures the fasthttp.HostClient. ConfigureClient func(hc *HostClient) error @@ -698,10 +698,6 @@ type HostClient struct { // Client name. Used in User-Agent request header. Name string - // NoDefaultUserAgentHeader when set to true, causes the default - // User-Agent header to be excluded from the Request. - NoDefaultUserAgentHeader bool - // Callback for establishing new connections to hosts. // // Default DialTimeout is used if not set. @@ -715,19 +711,6 @@ type HostClient struct { // If not set, DialTimeout is used. Dial DialFunc - // Attempt to connect to both ipv4 and ipv6 host addresses - // if set to true. - // - // This option is used only if default TCP dialer is used, - // i.e. if Dial and DialTimeout are blank. - // - // By default client connects only to ipv4 addresses, - // since unfortunately ipv6 remains broken in many networks worldwide :) - DialDualStack bool - - // Whether to use TLS (aka SSL or HTTPS) for host connections. - IsTLS bool - // Optional TLS config. TLSConfig *tls.Config @@ -785,6 +768,64 @@ type HostClient struct { // By default response body size is unlimited. MaxResponseBodySize int + // Maximum duration for waiting for a free connection. + // + // By default will not waiting, return ErrNoFreeConns immediately + MaxConnWaitTimeout time.Duration + + // RetryIf controls whether a retry should be attempted after an error. + // + // By default will use isIdempotent function + RetryIf RetryIfFunc + + // Transport defines a transport-like mechanism that wraps every request/response. + Transport RoundTripper + + // Connection pool strategy. Can be either LIFO or FIFO (default). + ConnPoolStrategy ConnPoolStrategyType + + connsLock sync.Mutex + connsCount int + conns []*clientConn + connsWait *wantConnQueue + + addrsLock sync.Mutex + addrs []string + addrIdx uint32 + lastUseTime uint32 + + tlsConfigMap map[string]*tls.Config + tlsConfigMapLock sync.Mutex + + readerPool sync.Pool + writerPool sync.Pool + + clientReaderPool *sync.Pool + clientWriterPool *sync.Pool + + pendingRequests int32 + + // pendingClientRequests counts the number of requests that a Client is currently running using this HostClient. + // It will be incremented earlier than pendingRequests and will be used by Client to see if the HostClient is still in use. + pendingClientRequests int32 + + // NoDefaultUserAgentHeader when set to true, causes the default + // User-Agent header to be excluded from the Request. + NoDefaultUserAgentHeader bool + + // Attempt to connect to both ipv4 and ipv6 host addresses + // if set to true. + // + // This option is used only if default TCP dialer is used, + // i.e. if Dial and DialTimeout are blank. + // + // By default client connects only to ipv4 addresses, + // since unfortunately ipv6 remains broken in many networks worldwide :) + DialDualStack bool + + // Whether to use TLS (aka SSL or HTTPS) for host connections. + IsTLS bool + // Header names are passed as-is without normalization // if this option is set. // @@ -820,51 +861,9 @@ type HostClient struct { // Client logs full errors by default. SecureErrorLogMessage bool - // Maximum duration for waiting for a free connection. - // - // By default will not waiting, return ErrNoFreeConns immediately - MaxConnWaitTimeout time.Duration - - // RetryIf controls whether a retry should be attempted after an error. - // - // By default will use isIdempotent function - RetryIf RetryIfFunc - - // Transport defines a transport-like mechanism that wraps every request/response. - Transport RoundTripper - - // Connection pool strategy. Can be either LIFO or FIFO (default). - ConnPoolStrategy ConnPoolStrategyType - // StreamResponseBody enables response body streaming. StreamResponseBody bool - lastUseTime uint32 - - connsLock sync.Mutex - connsCount int - conns []*clientConn - connsWait *wantConnQueue - - addrsLock sync.Mutex - addrs []string - addrIdx uint32 - - tlsConfigMap map[string]*tls.Config - tlsConfigMapLock sync.Mutex - - readerPool sync.Pool - writerPool sync.Pool - - clientReaderPool *sync.Pool - clientWriterPool *sync.Pool - - pendingRequests int32 - - // pendingClientRequests counts the number of requests that a Client is currently running using this HostClient. - // It will be incremented earlier than pendingRequests and will be used by Client to see if the HostClient is still in use. - pendingClientRequests int32 - connsCleanerRun bool } @@ -2174,10 +2173,6 @@ type PipelineClient struct { // PipelineClient name. Used in User-Agent request header. Name string - // NoDefaultUserAgentHeader when set to true, causes the default - // User-Agent header to be excluded from the Request. - NoDefaultUserAgentHeader bool - // The maximum number of concurrent connections to the Addr. // // A single connection is used by default. @@ -2200,6 +2195,10 @@ type PipelineClient struct { // Default Dial is used if not set. Dial DialFunc + // NoDefaultUserAgentHeader when set to true, causes the default + // User-Agent header to be excluded from the Request. + NoDefaultUserAgentHeader bool + // Attempt to connect to both ipv4 and ipv6 host addresses // if set to true. // @@ -2284,10 +2283,10 @@ type pipelineConnClient struct { Addr string Name string - NoDefaultUserAgentHeader bool MaxPendingRequests int MaxBatchDelay time.Duration Dial DialFunc + NoDefaultUserAgentHeader bool DialDualStack bool DisableHeaderNamesNormalizing bool DisablePathNormalizing bool diff --git a/cookie.go b/cookie.go index e99ea67..4771e6f 100644 --- a/cookie.go +++ b/cookie.go @@ -74,9 +74,9 @@ type Cookie struct { domain []byte path []byte + sameSite CookieSameSite httpOnly bool secure bool - sameSite CookieSameSite partitioned bool bufKV argsKV diff --git a/fs.go b/fs.go index 7738ca2..0f9b7dd 100644 --- a/fs.go +++ b/fs.go @@ -259,12 +259,6 @@ type FS struct { // Path to the root directory to serve files from. Root string - // AllowEmptyRoot controls what happens when Root is empty. When false (default) it will default to the - // current working directory. An empty root is mostly useful when you want to use absolute paths - // on windows that are on different filesystems. On linux setting your Root to "/" already allows you to use - // absolute paths on any filesystem. - AllowEmptyRoot bool - // List of index file names to try opening during directory access. // // For example: @@ -276,6 +270,36 @@ type FS struct { // By default the list is empty. IndexNames []string + // Path to the compressed root directory to serve files from. If this value + // is empty, Root is used. + CompressRoot string + + // Path rewriting function. + // + // By default request path is not modified. + PathRewrite PathRewriteFunc + + // PathNotFound fires when file is not found in filesystem + // this functions tries to replace "Cannot open requested path" + // server response giving to the programmer the control of server flow. + // + // By default PathNotFound returns + // "Cannot open requested path" + PathNotFound RequestHandler + + // AllowEmptyRoot controls what happens when Root is empty. When false (default) it will default to the + // current working directory. An empty root is mostly useful when you want to use absolute paths + // on windows that are on different filesystems. On linux setting your Root to "/" already allows you to use + // absolute paths on any filesystem. + AllowEmptyRoot bool + + // Uses brotli encoding and fallbacks to gzip in responses if set to true, uses gzip if set to false. + // + // This value has sense only if Compress is set. + // + // Brotli encoding is disabled by default. + CompressBrotli bool + // Index pages for directories without files matching IndexNames // are automatically generated if set. // @@ -298,35 +322,11 @@ type FS struct { // Transparent compression is disabled by default. Compress bool - // Uses brotli encoding and fallbacks to gzip in responses if set to true, uses gzip if set to false. - // - // This value has sense only if Compress is set. - // - // Brotli encoding is disabled by default. - CompressBrotli bool - - // Path to the compressed root directory to serve files from. If this value - // is empty, Root is used. - CompressRoot string - // Enables byte range requests if set to true. // // Byte range requests are disabled by default. AcceptByteRange bool - // Path rewriting function. - // - // By default request path is not modified. - PathRewrite PathRewriteFunc - - // PathNotFound fires when file is not found in filesystem - // this functions tries to replace "Cannot open requested path" - // server response giving to the programmer the control of server flow. - // - // By default PathNotFound returns - // "Cannot open requested path" - PathNotFound RequestHandler - // SkipCache if true, will cache no file handler. // // By default is false. @@ -510,8 +510,8 @@ type fsHandler struct { generateIndexPages bool compress bool compressBrotli bool - compressRoot string acceptByteRange bool + compressRoot string compressedFileSuffixes map[string]string cacheManager cacheManager diff --git a/header.go b/header.go index bfef5ff..3cfe825 100644 --- a/header.go +++ b/header.go @@ -26,19 +26,19 @@ const ( type ResponseHeader struct { noCopy noCopy - disableNormalizing bool - noHTTP11 bool - connectionClose bool - noDefaultContentType bool - noDefaultDate bool - - statusCode int - statusMessage []byte - protocol []byte - contentLength int - contentLengthBytes []byte + disableNormalizing bool + noHTTP11 bool + connectionClose bool + noDefaultContentType bool + noDefaultDate bool secureErrorLogMessage bool + statusCode int + statusMessage []byte + protocol []byte + contentLength int + contentLengthBytes []byte + contentType []byte contentEncoding []byte server []byte @@ -71,9 +71,9 @@ type RequestHeader struct { // for reducing RequestHeader object size. cookiesCollected bool + secureErrorLogMessage bool contentLength int contentLengthBytes []byte - secureErrorLogMessage bool method []byte requestURI []byte @@ -3239,8 +3239,6 @@ type headerScanner struct { // hLen stores header subslice len hLen int - disableNormalizing bool - // by checking whether the next line contains a colon or not to tell // it's a header entry or a multi line value of current header entry. // the side effect of this operation is that we know the index of the @@ -3249,7 +3247,8 @@ type headerScanner struct { nextColon int nextNewLine int - initialized bool + disableNormalizing bool + initialized bool } func (s *headerScanner) next() bool { diff --git a/http.go b/http.go index 75d8b6c..827474e 100644 --- a/http.go +++ b/http.go @@ -53,6 +53,11 @@ type Request struct { multipartForm *multipart.Form multipartFormBoundary string + + // Request timeout. Usually set by DoDeadline or DoTimeout + // if <= 0, means not set + timeout time.Duration + secureErrorLogMessage bool // Group bool members in order to reduce Request object size. @@ -65,10 +70,6 @@ type Request struct { // Client/HostClient shouldn't use this field but should depend on the uri.scheme instead. isTLS bool - // Request timeout. Usually set by DoDeadline or DoTimeout - // if <= 0, means not set - timeout time.Duration - // Use Host header (request.Header.SetHost) instead of the host from SetRequestURI, SetHost, or URI().SetHost UseHostHeader bool @@ -101,11 +102,6 @@ type Response struct { // Use SetBodyStream to set the body stream. StreamBody bool - bodyStream io.Reader - w responseBodyWriter - body *bytebufferpool.ByteBuffer - bodyRaw []byte - // Response.Read() skips reading body if set to true. // Use it for reading HEAD responses. // @@ -116,6 +112,11 @@ type Response struct { keepBodyBuffer bool secureErrorLogMessage bool + bodyStream io.Reader + w responseBodyWriter + body *bytebufferpool.ByteBuffer + bodyRaw []byte + // Remote TCPAddr from concurrently net.Conn. raddr net.Addr // Local TCPAddr from concurrently net.Conn. diff --git a/tcpdialer.go b/tcpdialer.go index e5f06bd..933cee8 100644 --- a/tcpdialer.go +++ b/tcpdialer.go @@ -152,8 +152,6 @@ type TCPDialer struct { // } Resolver Resolver - // DisableDNSResolution may be used to disable DNS resolution - DisableDNSResolution bool // DNSCacheDuration may be used to override the default DNS cache duration (DefaultDNSCacheDuration) DNSCacheDuration time.Duration @@ -161,6 +159,9 @@ type TCPDialer struct { concurrencyCh chan struct{} + // DisableDNSResolution may be used to disable DNS resolution + DisableDNSResolution bool + once sync.Once } diff --git a/workerpool.go b/workerpool.go index 235eec1..1e76785 100644 --- a/workerpool.go +++ b/workerpool.go @@ -22,6 +22,7 @@ type workerPool struct { MaxWorkersCount int LogAllErrors bool + mustStop bool MaxIdleWorkerDuration time.Duration @@ -29,7 +30,6 @@ type workerPool struct { lock sync.Mutex workersCount int - mustStop bool ready []*workerChan