Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[TT-12965] Fix/improve ctx allocation with clone #6855

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 1 addition & 18 deletions apidef/oas/oas.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@ import (
"fmt"
"strings"

"github.com/TykTechnologies/tyk/config"

"github.com/getkin/kin-openapi/openapi3"

"github.com/TykTechnologies/tyk/apidef"
"github.com/TykTechnologies/tyk/config"
)

const (
Expand Down Expand Up @@ -203,22 +202,6 @@ func (s *OAS) RemoveTykExtension() {
delete(s.Extensions, ExtensionTykAPIGateway)
}

// Clone creates a deep copy of the OAS object and returns a new instance.
func (s *OAS) Clone() (*OAS, error) {
oasInBytes, err := json.Marshal(s)
if err != nil {
return nil, err
}

var retOAS OAS
_ = json.Unmarshal(oasInBytes, &retOAS)

// convert Tyk extension from map to struct
retOAS.GetTykExtension()

return &retOAS, nil
}

func (s *OAS) getTykAuthentication() (authentication *Authentication) {
if s.GetTykExtension() != nil {
authentication = s.GetTykExtension().Server.Authentication
Expand Down
48 changes: 0 additions & 48 deletions apidef/oas/oas_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -794,54 +794,6 @@ func TestOAS_MarshalJSON(t *testing.T) {
})
}

func TestOAS_Clone(t *testing.T) {
s := &OAS{}
s.SetTykExtension(&XTykAPIGateway{Info: Info{
Name: "my-api",
}})

clonedOAS, err := s.Clone()
assert.NoError(t, err)
assert.Equal(t, s, clonedOAS)

s.GetTykExtension().Info.Name = "my-api-modified"
assert.NotEqual(t, s, clonedOAS)

t.Run("marshal error", func(t *testing.T) {
s.Extensions["weird extension"] = make(chan int)
_, err = s.Clone()
assert.ErrorContains(t, err, "unsupported type: chan int")
})
}

func BenchmarkOAS_Clone(b *testing.B) {
oas := &OAS{
T: openapi3.T{
Info: &openapi3.Info{
Title: "my-oas-doc",
},
Paths: map[string]*openapi3.PathItem{
"/get": {
Get: &openapi3.Operation{
Responses: openapi3.Responses{
"200": &openapi3.ResponseRef{
Value: &openapi3.Response{
Description: getStrPointer("some example endpoint"),
},
},
},
},
},
},
},
}

for i := 0; i < b.N; i++ {
_, err := oas.Clone()
assert.NoError(b, err)
}
}

func TestMigrateAndFillOAS(t *testing.T) {
var api apidef.APIDefinition
api.SetDisabledFlags()
Expand Down
51 changes: 19 additions & 32 deletions ctx/ctx.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,15 @@ import (
"encoding/json"
"net/http"

"github.com/TykTechnologies/tyk/internal/httputil"

"github.com/TykTechnologies/tyk/apidef"
"github.com/TykTechnologies/tyk/apidef/oas"

"github.com/TykTechnologies/tyk/config"

"github.com/TykTechnologies/tyk/apidef"
logger "github.com/TykTechnologies/tyk/log"
"github.com/TykTechnologies/tyk/internal/httputil"
"github.com/TykTechnologies/tyk/internal/reflect"
"github.com/TykTechnologies/tyk/storage"
"github.com/TykTechnologies/tyk/user"

logger "github.com/TykTechnologies/tyk/log"
)

type Key uint
Expand Down Expand Up @@ -57,7 +56,6 @@ const (
)

func ctxSetSession(r *http.Request, s *user.SessionState, scheduleUpdate bool, hashKey bool) {

if s == nil {
panic("setting a nil context SessionData")
}
Expand All @@ -84,7 +82,10 @@ func ctxSetSession(r *http.Request, s *user.SessionState, scheduleUpdate bool, h

func GetAuthToken(r *http.Request) string {
if v := r.Context().Value(AuthToken); v != nil {
return v.(string)
value, ok := v.(string)
if ok {
return value
}
}
return ""
}
Expand Down Expand Up @@ -114,45 +115,31 @@ func SetSession(r *http.Request, s *user.SessionState, scheduleUpdate bool, hash
}
}

// SetDefinition sets an API definition object to the request context.
func SetDefinition(r *http.Request, s *apidef.APIDefinition) {
ctx := r.Context()
ctx = context.WithValue(ctx, Definition, s)
httputil.SetContext(r, ctx)
}

// GetDefinition will return a deep copy of the API definition valid for the request.
func GetDefinition(r *http.Request) *apidef.APIDefinition {
if v := r.Context().Value(Definition); v != nil {
if val, ok := v.(*apidef.APIDefinition); ok {
return val
} else {
logger.Get().Warning("APIDefinition struct differ from the gateway version, trying to unmarshal.")
def := apidef.APIDefinition{}
b, _ := json.Marshal(v)
e := json.Unmarshal(b, &def)
if e == nil {
return &def
}
return reflect.Clone(val)
}
}

return nil
}

// GetOASDefinition returns a deep copy of the OAS definition of the called API.
// GetOASDefinition will return a deep copy of the OAS API definition valid for the request.
func GetOASDefinition(r *http.Request) *oas.OAS {
v := r.Context().Value(OASDefinition)
if v == nil {
return nil
}

val, ok := v.(*oas.OAS)
if !ok {
return nil
}

ret, err := val.Clone()
if err != nil {
logger.Get().WithError(err).Error("Cloning OAS object in the request context")
if v := r.Context().Value(OASDefinition); v != nil {
if val, ok := v.(*oas.OAS); ok {
return reflect.Clone(val)
}
}

return ret
return nil
}
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ require (
github.com/go-redis/redismock/v9 v9.2.0
github.com/goccy/go-json v0.10.4
github.com/google/go-cmp v0.6.0
github.com/huandu/go-clone/generic v1.7.2
github.com/nats-io/nats.go v1.38.0
github.com/newrelic/go-agent/v3 v3.35.1
github.com/newrelic/go-agent/v3/integrations/nrgorilla v1.2.2
Expand Down Expand Up @@ -185,6 +186,7 @@ require (
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/hashicorp/raft v1.7.1 // indirect
github.com/hashicorp/serf v0.10.1 // indirect
github.com/huandu/go-clone v1.6.0 // indirect
github.com/huandu/xstrings v1.5.0 // indirect
github.com/iancoleman/strcase v0.3.0 // indirect
github.com/imdario/mergo v0.3.13 // indirect
Expand Down
6 changes: 6 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,12 @@ github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfE
github.com/hashicorp/vault/api v1.15.0 h1:O24FYQCWwhwKnF7CuSqP30S51rTV7vz1iACXE/pj5DA=
github.com/hashicorp/vault/api v1.15.0/go.mod h1:+5YTO09JGn0u+b6ySD/LLVf8WkJCPLAL2Vkmrn2+CM8=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/huandu/go-assert v1.1.5 h1:fjemmA7sSfYHJD7CUqs9qTwwfdNAx7/j2/ZlHXzNB3c=
github.com/huandu/go-assert v1.1.5/go.mod h1:yOLvuqZwmcHIC5rIzrBhT7D3Q9c3GFnd0JrPVhn/06U=
github.com/huandu/go-clone v1.6.0 h1:HMo5uvg4wgfiy5FoGOqlFLQED/VGRm2D9Pi8g1FXPGc=
github.com/huandu/go-clone v1.6.0/go.mod h1:ReGivhG6op3GYr+UY3lS6mxjKp7MIGTknuU5TbTVaXE=
github.com/huandu/go-clone/generic v1.7.2 h1:47pQphxs1Xc9cVADjOHN+Bm5D0hNagwH9UXErbxgVKA=
github.com/huandu/go-clone/generic v1.7.2/go.mod h1:xgd9ZebcMsBWWcBx5mVMCoqMX24gLWr5lQicr+nVXNs=
github.com/huandu/xstrings v1.2.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI=
github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
Expand Down
11 changes: 11 additions & 0 deletions internal/reflect/clone.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package reflect

import (
clone "github.com/huandu/go-clone/generic"
)

// Clone is a hacky way to wrap the generic declaration.
// Using `var Clone = clone.Clone` is not allowed.
func Clone[T any](t T) T {
return clone.Clone[T](t)
}
Loading