Skip to content

Commit

Permalink
Optimize memory usage by reordering fields (#299)
Browse files Browse the repository at this point in the history
* Optimize memory alignment by reordering fields

* Remove betteralign from Makefile - we'll take care of this manually
  • Loading branch information
EwenQuim authored Jan 8, 2025
1 parent 15430da commit ade61ca
Show file tree
Hide file tree
Showing 14 changed files with 73 additions and 59 deletions.
6 changes: 6 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ linters-settings:
locale: "US"
error: true

govet:
enable-all: true
disable:
- shadow
- fieldalignment

gofumpt:
extra-rules: true
staticcheck:
Expand Down
18 changes: 10 additions & 8 deletions ctx.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,19 +124,21 @@ func NewNetHTTPContext[B any](route BaseRoute, w http.ResponseWriter, r *http.Re
// has a Body. The Body type parameter represents the expected data type
// from http.Request.Body. Please do not use a pointer as a type parameter.
type netHttpContext[Body any] struct {
internal.CommonContext[Body]
Res http.ResponseWriter

body *Body // Cache the body in request context, because it is not possible to read an HTTP request body multiple times.
fs fs.FS

Req *http.Request
Res http.ResponseWriter
body *Body // Cache the body in request context, because it is not possible to read an HTTP request body multiple times.

fs fs.FS
Req *http.Request
templates *template.Template

readOptions readOptions
serializer Sender
errorSerializer ErrorSender

internal.CommonContext[Body]

readOptions readOptions
}

var (
Expand All @@ -153,8 +155,8 @@ func (c netHttpContext[B]) SetStatus(code int) {

// readOptions are options for reading the request body.
type readOptions struct {
DisallowUnknownFields bool
MaxBodySize int64
DisallowUnknownFields bool
LogBody bool
}

Expand Down Expand Up @@ -322,7 +324,7 @@ func body[B any](c netHttpContext[B]) (B, error) {
body, err = readJSON[B](c.Req.Context(), c.Req.Body, c.readOptions)
}

c.Res.Header().Add("Server-Timing", Timing{"deserialize", time.Since(timeDeserialize), "controller > deserialize"}.String())
c.Res.Header().Add("Server-Timing", Timing{"deserialize", "controller > deserialize", time.Since(timeDeserialize)}.String())

return body, err
}
4 changes: 2 additions & 2 deletions default_middlewares.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@ var defaultLoggingConfig = LoggingConfig{
// override the default request ID generator (UUID) with a custom one that
// appends the current Unix time in nanoseconds for response logs
type LoggingConfig struct {
// Optional custom request ID generator
RequestIDFunc func() string
// If true, request logging is disabled
DisableRequest bool
// If true, response logging is disabled
DisableResponse bool
// Optional custom request ID generator
RequestIDFunc func() string
}

func (l *LoggingConfig) Disabled() bool {
Expand Down
4 changes: 2 additions & 2 deletions engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,14 @@ type Engine struct {
}

type OpenAPIConfig struct {
// Local path to save the OpenAPI JSON spec
JSONFilePath string
// If true, the server will not serve nor generate any OpenAPI resources
Disabled bool
// If true, the engine will not print messages
DisableMessages bool
// If true, the engine will not save the OpenAPI JSON spec locally
DisableLocalSave bool
// Local path to save the OpenAPI JSON spec
JSONFilePath string
// Pretty prints the OpenAPI spec with proper JSON indentation
PrettyFormatJSON bool
}
Expand Down
6 changes: 3 additions & 3 deletions errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,18 @@ type HTTPError struct {
Type string `json:"type,omitempty" xml:"type,omitempty" description:"URL of the error type. Can be used to lookup the error in a documentation"`
// Short title of the error
Title string `json:"title,omitempty" xml:"title,omitempty" description:"Short title of the error"`
// HTTP status code. If using a different type than [HTTPError], for example [BadRequestError], this will be automatically overridden after Fuego error handling.
Status int `json:"status,omitempty" xml:"status,omitempty" description:"HTTP status code" example:"403"`
// Human readable error message
Detail string `json:"detail,omitempty" xml:"detail,omitempty" description:"Human readable error message"`
Instance string `json:"instance,omitempty" xml:"instance,omitempty"`
Errors []ErrorItem `json:"errors,omitempty" xml:"errors,omitempty"`
// HTTP status code. If using a different type than [HTTPError], for example [BadRequestError], this will be automatically overridden after Fuego error handling.
Status int `json:"status,omitempty" xml:"status,omitempty" description:"HTTP status code" example:"403"`
}

type ErrorItem struct {
More map[string]any `json:"more,omitempty" xml:"more,omitempty" description:"Additional information about the error"`
Name string `json:"name" xml:"name" description:"For example, name of the parameter that caused the error"`
Reason string `json:"reason" xml:"reason" description:"Human readable error message"`
More map[string]any `json:"more,omitempty" xml:"more,omitempty" description:"Additional information about the error"`
}

func (e HTTPError) Error() string {
Expand Down
6 changes: 3 additions & 3 deletions html.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,11 @@ type H map[string]any

// StdRenderer renders a template using the standard library templating engine.
type StdRenderer struct {
templateToExecute string
templates *template.Template
layoutsGlobs []string
fs fs.FS
data any
templates *template.Template
templateToExecute string
layoutsGlobs []string
}

var _ CtxRenderer = StdRenderer{}
Expand Down
2 changes: 1 addition & 1 deletion internal/common_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,10 +139,10 @@ func (e QueryParamNotFoundError) Error() string {
}

type QueryParamInvalidTypeError struct {
Err error
ParamName string
ParamValue string
ExpectedType string
Err error
}

func (e QueryParamInvalidTypeError) Error() string {
Expand Down
4 changes: 2 additions & 2 deletions openapi_operations.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func (o *OpenAPI) buildOpenapi3Response(description string, response Response) *

// openAPIResponse describes a response error in the OpenAPI spec.
type openAPIResponse struct {
Response
Code int
Description string
Response
Code int
}
4 changes: 2 additions & 2 deletions option.go
Original file line number Diff line number Diff line change
Expand Up @@ -332,10 +332,10 @@ func OptionAddError(code int, description string, errorType ...any) func(*BaseRo
// Response represents a fuego.Response that can be used
// when setting custom response types on routes
type Response struct {
// content-type of the response i.e application/json
ContentTypes []string
// user provided type
Type any
// content-type of the response i.e application/json
ContentTypes []string
}

// AddResponse adds a response to a route by status code
Expand Down
2 changes: 1 addition & 1 deletion perf.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import (
// Used in the Server-Timing header.
type Timing struct {
Name string
Dur time.Duration
Desc string
Dur time.Duration
}

// String returns a string representation of a Timing, as defined in https://www.w3.org/TR/server-timing/#the-server-timing-header-field
Expand Down
19 changes: 12 additions & 7 deletions route.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,31 +40,36 @@ func NewBaseRoute(method, path string, handler any, openapi *OpenAPI, options ..
// BaseRoute is the base struct for all routes in Fuego.
// It contains the OpenAPI operation and other metadata.
type BaseRoute struct {
// handler executed for this route
Handler http.Handler

// OpenAPI operation
Operation *openapi3.Operation

// Ref to the whole OpenAPI spec. Be careful when changing directly its value directly.
OpenAPI *OpenAPI

Params map[string]OpenAPIParam

// HTTP method (GET, POST, PUT, PATCH, DELETE)
Method string

// URL path. Will be prefixed by the base path of the server and the group path if any
Path string

// namespace and name of the function to execute
FullName string
Params map[string]OpenAPIParam
Middlewares []func(http.Handler) http.Handler
FullName string

// Content types accepted for the request body. If nil, all content types (*/*) are accepted.
AcceptedContentTypes []string

// If true, the route will not be documented in the OpenAPI spec
Hidden bool
Middlewares []func(http.Handler) http.Handler

// Default status code for the response
DefaultStatusCode int

// Ref to the whole OpenAPI spec. Be careful when changing directly its value directly.
OpenAPI *OpenAPI
// If true, the route will not be documented in the OpenAPI spec
Hidden bool

// Override the default description
overrideDescription bool
Expand Down
2 changes: 1 addition & 1 deletion security.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ func (security Security) ValidateToken(token string) (*jwt.Token, error) {
}

type AutoAuthConfig struct {
Enabled bool
VerifyUserInfo func(user, password string) (jwt.Claims, error) // Must check the username and password, and return the claims
Enabled bool
}

type contextKey string
Expand Down
8 changes: 4 additions & 4 deletions serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ func Flow[B, T any](s *Engine, ctx ContextFlowable[B], controller func(c Context
}

timeController := time.Now()
ctx.SetHeader("Server-Timing", Timing{"fuegoReqInit", timeController.Sub(timeCtxInit), ""}.String())
ctx.SetHeader("Server-Timing", Timing{"fuegoReqInit", "", timeController.Sub(timeCtxInit)}.String())

// CONTROLLER
ans, err := controller(ctx)
Expand All @@ -138,7 +138,7 @@ func Flow[B, T any](s *Engine, ctx ContextFlowable[B], controller func(c Context
ctx.SerializeError(err)
return
}
ctx.SetHeader("Server-Timing", Timing{"controller", time.Since(timeController), ""}.String())
ctx.SetHeader("Server-Timing", Timing{"controller", "", time.Since(timeController)}.String())

ctx.SetDefaultStatusCode()

Expand All @@ -155,13 +155,13 @@ func Flow[B, T any](s *Engine, ctx ContextFlowable[B], controller func(c Context
return
}
timeAfterTransformOut := time.Now()
ctx.SetHeader("Server-Timing", Timing{"transformOut", timeAfterTransformOut.Sub(timeTransformOut), "transformOut"}.String())
ctx.SetHeader("Server-Timing", Timing{"transformOut", "transformOut", timeAfterTransformOut.Sub(timeTransformOut)}.String())

// SERIALIZATION
err = ctx.Serialize(ans)
if err != nil {
err = s.ErrorHandler(err)
ctx.SerializeError(err)
}
ctx.SetHeader("Server-Timing", Timing{"serialize", time.Since(timeAfterTransformOut), ""}.String())
ctx.SetHeader("Server-Timing", Timing{"serialize", "", time.Since(timeAfterTransformOut)}.String())
}
47 changes: 24 additions & 23 deletions server.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ import (
)

type OpenAPIServerConfig struct {
// If true, the server will not serve the Swagger UI
DisableSwaggerUI bool
// URL to serve the swagger UI
SwaggerURL string
// Handler to serve the OpenAPI UI from spec URL
UIHandler func(specURL string) http.Handler
// URL to serve the swagger UI
SwaggerURL string
// URL to serve the OpenAPI JSON spec
SpecURL string
// If true, the server will not serve the Swagger UI
DisableSwaggerUI bool
}

var defaultOpenAPIServerConfig = OpenAPIServerConfig{
Expand All @@ -46,42 +46,43 @@ type Server struct {
// For example, it allows OPTIONS /foo even if it is not declared (only GET /foo is declared).
corsMiddleware func(http.Handler) http.Handler

// routeOptions is used to store the options
// that will be applied of the route.
routeOptions []func(*BaseRoute)

middlewares []func(http.Handler) http.Handler

disableStartupMessages bool
disableAutoGroupTags bool
basePath string // Base path of the group

*Engine

listener net.Listener

Security Security

autoAuth AutoAuthConfig
fs fs.FS
template *template.Template // TODO: use preparsed templates

// If true, the server will return an error if the request body contains unknown fields. Useful for quick debugging in development.
DisallowUnknownFields bool
maxBodySize int64

// Custom serializer that overrides the default one.
Serialize Sender
// Used to serialize the error response. Defaults to [SendError].
SerializeError ErrorSender

startTime time.Time

Security Security

autoAuth AutoAuthConfig
fs fs.FS

// Base path of the group
basePath string

loggingConfig LoggingConfig

OpenAPIServerConfig OpenAPIServerConfig

isTLS bool
// routeOptions is used to store the options
// that will be applied of the route.
routeOptions []func(*BaseRoute)

middlewares []func(http.Handler) http.Handler

maxBodySize int64
// If true, the server will return an error if the request body contains unknown fields. Useful for quick debugging in development.
DisallowUnknownFields bool
disableStartupMessages bool
disableAutoGroupTags bool
isTLS bool
}

// NewServer creates a new server with the given options.
Expand Down

0 comments on commit ade61ca

Please sign in to comment.