Skip to content

Commit

Permalink
v3: Use Named Fields Instead of Positional and Align Structures to Re…
Browse files Browse the repository at this point in the history
…duce Memory Usage (#3079)

* Use composites for internal structures. Fix alignment of structures across Fiber

* Update struct alignment in test files

* Enable alignment check with govet

* Fix ctx autoformat unit-test

* Revert app Config struct. Add betteralign to Makefile

* Disable comment on alert since it wont work for forks

* Update benchmark.yml

* Update benchmark.yml

* Remove warning from using positional fields

* Update router.go
  • Loading branch information
gaby committed Jul 23, 2024
1 parent f413bfe commit 8c3f81e
Show file tree
Hide file tree
Showing 74 changed files with 693 additions and 687 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/benchmark.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ permissions:
deployments: write
# contents permission to update benchmark contents in gh-pages branch
contents: write
# allow posting comments to pull request
pull-requests: write

name: Benchmark
jobs:
Expand Down
1 change: 0 additions & 1 deletion .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,6 @@ linters-settings:
govet:
enable-all: true
disable:
- fieldalignment
- shadow

grouper:
Expand Down
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,8 @@ longtest:
.PHONY: tidy
tidy:
go mod tidy -v

## betteralign: 📐 Optimize alignment of fields in structs
.PHONY: betteralign
betteralign:
go run github.com/dkorunic/betteralign/cmd/betteralign@latest -test_files -generated_files -apply ./...
4 changes: 2 additions & 2 deletions addon/retry/exponential_backoff_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ import (
func Test_ExponentialBackoff_Retry(t *testing.T) {
t.Parallel()
tests := []struct {
name string
expErr error
expBackoff *ExponentialBackoff
f func() error
expErr error
name string
}{
{
name: "With default values - successful",
Expand Down
38 changes: 19 additions & 19 deletions app.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,29 +80,16 @@ type ErrorHandler = func(Ctx, error) error

// Error represents an error that occurred while handling a request.
type Error struct {
Code int `json:"code"`
Message string `json:"message"`
Code int `json:"code"`
}

// App denotes the Fiber application.
type App struct {
mutex sync.Mutex
// Route stack divided by HTTP methods
stack [][]*Route
// Route stack divided by HTTP methods and route prefixes
treeStack []map[string][]*Route
// contains the information if the route stack has been changed to build the optimized tree
routesRefreshed bool
// Amount of registered routes
routesCount uint32
// Amount of registered handlers
handlersCount uint32
// Ctx pool
pool sync.Pool
// Fasthttp server
server *fasthttp.Server
// App config
config Config
// Converts string to a byte slice
getBytes func(s string) (b []byte)
// Converts byte slice to a string
Expand All @@ -113,24 +100,37 @@ type App struct {
latestRoute *Route
// newCtxFunc
newCtxFunc func(app *App) CustomCtx
// custom binders
customBinders []CustomBinder
// TLS handler
tlsHandler *TLSHandler
// Mount fields
mountFields *mountFields
// Indicates if the value was explicitly configured
configured Config
// Route stack divided by HTTP methods
stack [][]*Route
// Route stack divided by HTTP methods and route prefixes
treeStack []map[string][]*Route
// custom binders
customBinders []CustomBinder
// customConstraints is a list of external constraints
customConstraints []CustomConstraint
// sendfiles stores configurations for handling ctx.SendFile operations
sendfiles []*sendFileStore
// App config
config Config
// Indicates if the value was explicitly configured
configured Config
// sendfilesMutex is a mutex used for sendfile operations
sendfilesMutex sync.RWMutex
mutex sync.Mutex
// Amount of registered routes
routesCount uint32
// Amount of registered handlers
handlersCount uint32
// contains the information if the route stack has been changed to build the optimized tree
routesRefreshed bool
}

// Config is a struct holding the server settings.
type Config struct {
type Config struct { //nolint:govet // Aligning the struct fields is not necessary. betteralign:ignore
// Enables the "Server: value" HTTP header.
//
// Default: ""
Expand Down
40 changes: 20 additions & 20 deletions bind_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ func Test_Bind_Query(t *testing.T) {
c := app.AcquireCtx(&fasthttp.RequestCtx{})

type Query struct {
ID int
Name string
Hobby []string
ID int
}
c.Request().SetBody([]byte(``))
c.Request().Header.SetContentType("")
Expand All @@ -53,14 +53,14 @@ func Test_Bind_Query(t *testing.T) {
require.Empty(t, empty.Hobby)

type Query2 struct {
Bool bool
ID int
Name string
Hobby string
FavouriteDrinks []string
Empty []string
Alloc []string
No []int64
ID int
Bool bool
}

c.Request().URI().SetQueryString("id=1&name=tom&hobby=basketball,football&favouriteDrinks=milo,coke,pepsi&alloc=&no=1")
Expand Down Expand Up @@ -237,8 +237,8 @@ func Test_Bind_Query_Schema(t *testing.T) {
require.Equal(t, "nested.age is empty", c.Bind().Query(q2).Error())

type Node struct {
Value int `query:"val,required"`
Next *Node `query:"next,required"`
Value int `query:"val,required"`
}
c.Request().URI().SetQueryString("val=1&next.val=3")
n := new(Node)
Expand Down Expand Up @@ -292,9 +292,9 @@ func Test_Bind_Header(t *testing.T) {
c := app.AcquireCtx(&fasthttp.RequestCtx{})

type Header struct {
ID int
Name string
Hobby []string
ID int
}
c.Request().SetBody([]byte(``))
c.Request().Header.SetContentType("")
Expand All @@ -318,14 +318,14 @@ func Test_Bind_Header(t *testing.T) {
require.Empty(t, empty.Hobby)

type Header2 struct {
Bool bool
ID int
Name string
Hobby string
FavouriteDrinks []string
Empty []string
Alloc []string
No []int64
ID int
Bool bool
}

c.Request().Header.Add("id", "2")
Expand Down Expand Up @@ -502,8 +502,8 @@ func Test_Bind_Header_Schema(t *testing.T) {
require.Equal(t, "Nested.age is empty", c.Bind().Header(h2).Error())

type Node struct {
Value int `header:"Val,required"`
Next *Node `header:"Next,required"`
Value int `header:"Val,required"`
}
c.Request().Header.Add("Val", "1")
c.Request().Header.Add("Next.Val", "3")
Expand Down Expand Up @@ -533,9 +533,9 @@ func Test_Bind_RespHeader(t *testing.T) {
c := app.AcquireCtx(&fasthttp.RequestCtx{})

type Header struct {
ID int
Name string
Hobby []string
ID int
}
c.Request().SetBody([]byte(``))
c.Request().Header.SetContentType("")
Expand All @@ -559,14 +559,14 @@ func Test_Bind_RespHeader(t *testing.T) {
require.Empty(t, empty.Hobby)

type Header2 struct {
Bool bool
ID int
Name string
Hobby string
FavouriteDrinks []string
Empty []string
Alloc []string
No []int64
ID int
Bool bool
}

c.Response().Header.Add("id", "2")
Expand Down Expand Up @@ -635,9 +635,9 @@ func Benchmark_Bind_Query(b *testing.B) {
c := app.AcquireCtx(&fasthttp.RequestCtx{})

type Query struct {
ID int
Name string
Hobby []string
ID int
}
c.Request().SetBody([]byte(``))
c.Request().Header.SetContentType("")
Expand Down Expand Up @@ -708,9 +708,9 @@ func Benchmark_Bind_Query_Comma(b *testing.B) {
c := app.AcquireCtx(&fasthttp.RequestCtx{})

type Query struct {
ID int
Name string
Hobby []string
ID int
}
c.Request().SetBody([]byte(``))
c.Request().Header.SetContentType("")
Expand All @@ -732,9 +732,9 @@ func Benchmark_Bind_Header(b *testing.B) {
c := app.AcquireCtx(&fasthttp.RequestCtx{})

type ReqHeader struct {
ID int
Name string
Hobby []string
ID int
}
c.Request().SetBody([]byte(``))
c.Request().Header.SetContentType("")
Expand Down Expand Up @@ -782,9 +782,9 @@ func Benchmark_Bind_RespHeader(b *testing.B) {
c := app.AcquireCtx(&fasthttp.RequestCtx{})

type ReqHeader struct {
ID int
Name string
Hobby []string
ID int
}
c.Request().SetBody([]byte(``))
c.Request().Header.SetContentType("")
Expand Down Expand Up @@ -1252,9 +1252,9 @@ func Test_Bind_Cookie(t *testing.T) {
c := app.AcquireCtx(&fasthttp.RequestCtx{})

type Cookie struct {
ID int
Name string
Hobby []string
ID int
}
c.Request().SetBody([]byte(``))
c.Request().Header.SetContentType("")
Expand All @@ -1278,14 +1278,14 @@ func Test_Bind_Cookie(t *testing.T) {
require.Empty(t, empty.Hobby)

type Cookie2 struct {
Bool bool
ID int
Name string
Hobby string
FavouriteDrinks []string
Empty []string
Alloc []string
No []int64
ID int
Bool bool
}

c.Request().Header.SetCookie("id", "2")
Expand Down Expand Up @@ -1463,8 +1463,8 @@ func Test_Bind_Cookie_Schema(t *testing.T) {
require.Equal(t, "Nested.Age is empty", c.Bind().Cookie(h2).Error())

type Node struct {
Value int `cookie:"Val,required"`
Next *Node `cookie:"Next,required"`
Value int `cookie:"Val,required"`
}
c.Request().Header.SetCookie("Val", "1")
c.Request().Header.SetCookie("Next.Val", "3")
Expand Down Expand Up @@ -1495,9 +1495,9 @@ func Benchmark_Bind_Cookie(b *testing.B) {
c := app.AcquireCtx(&fasthttp.RequestCtx{})

type Cookie struct {
ID int
Name string
Hobby []string
ID int
}
c.Request().SetBody([]byte(``))
c.Request().Header.SetContentType("")
Expand Down
2 changes: 1 addition & 1 deletion binder/mapping.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ import (

// ParserConfig form decoder config for SetParserDecoder
type ParserConfig struct {
IgnoreUnknownKeys bool
SetAliasTag string
ParserType []ParserType
IgnoreUnknownKeys bool
ZeroEmpty bool
}

Expand Down
Loading

1 comment on commit 8c3f81e

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Performance Alert ⚠️

Possible performance regression was detected for benchmark.
Benchmark result of this commit is worse than the previous benchmark result exceeding threshold 1.50.

Benchmark suite Current: 8c3f81e Previous: 87bb93e Ratio
Benchmark_Ctx_Send 7.127 ns/op 0 B/op 0 allocs/op 4.661 ns/op 0 B/op 0 allocs/op 1.53
Benchmark_Ctx_Send - ns/op 7.127 ns/op 4.661 ns/op 1.53
Benchmark_Utils_GetOffer/1_parameter 227.4 ns/op 0 B/op 0 allocs/op 136.1 ns/op 0 B/op 0 allocs/op 1.67
Benchmark_Utils_GetOffer/1_parameter - ns/op 227.4 ns/op 136.1 ns/op 1.67
Benchmark_Utils_getGroupPath - allocs/op 4 allocs/op 2 allocs/op 2
Benchmark_Middleware_BasicAuth - B/op 80 B/op 48 B/op 1.67
Benchmark_Middleware_BasicAuth - allocs/op 5 allocs/op 3 allocs/op 1.67
Benchmark_Middleware_BasicAuth_Upper - B/op 80 B/op 48 B/op 1.67
Benchmark_Middleware_BasicAuth_Upper - allocs/op 5 allocs/op 3 allocs/op 1.67
Benchmark_CORS_NewHandler - B/op 16 B/op 0 B/op +∞
Benchmark_CORS_NewHandler - allocs/op 1 allocs/op 0 allocs/op +∞
Benchmark_CORS_NewHandlerSingleOrigin - B/op 16 B/op 0 B/op +∞
Benchmark_CORS_NewHandlerSingleOrigin - allocs/op 1 allocs/op 0 allocs/op +∞
Benchmark_CORS_NewHandlerPreflight 1174 ns/op 104 B/op 5 allocs/op 759.2 ns/op 0 B/op 0 allocs/op 1.55
Benchmark_CORS_NewHandlerPreflight - ns/op 1174 ns/op 759.2 ns/op 1.55
Benchmark_CORS_NewHandlerPreflight - B/op 104 B/op 0 B/op +∞
Benchmark_CORS_NewHandlerPreflight - allocs/op 5 allocs/op 0 allocs/op +∞
Benchmark_CORS_NewHandlerPreflightSingleOrigin 1165 ns/op 104 B/op 5 allocs/op 757.5 ns/op 0 B/op 0 allocs/op 1.54
Benchmark_CORS_NewHandlerPreflightSingleOrigin - ns/op 1165 ns/op 757.5 ns/op 1.54
Benchmark_CORS_NewHandlerPreflightSingleOrigin - B/op 104 B/op 0 B/op +∞
Benchmark_CORS_NewHandlerPreflightSingleOrigin - allocs/op 5 allocs/op 0 allocs/op +∞
Benchmark_CORS_NewHandlerPreflightWildcard 1107 ns/op 104 B/op 5 allocs/op 691 ns/op 0 B/op 0 allocs/op 1.60
Benchmark_CORS_NewHandlerPreflightWildcard - ns/op 1107 ns/op 691 ns/op 1.60
Benchmark_CORS_NewHandlerPreflightWildcard - B/op 104 B/op 0 B/op +∞
Benchmark_CORS_NewHandlerPreflightWildcard - allocs/op 5 allocs/op 0 allocs/op +∞
Benchmark_Middleware_CSRF_Check - allocs/op 11 allocs/op 7 allocs/op 1.57
Benchmark_Middleware_CSRF_GenerateToken - B/op 510 B/op 326 B/op 1.56
Benchmark_Middleware_CSRF_GenerateToken - allocs/op 10 allocs/op 6 allocs/op 1.67

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.