Skip to content

Commit

Permalink
feat: add copy
Browse files Browse the repository at this point in the history
  • Loading branch information
sujit-baniya committed Oct 24, 2023
1 parent 4e8e2b5 commit b0d87a3
Show file tree
Hide file tree
Showing 10 changed files with 228 additions and 40 deletions.
8 changes: 5 additions & 3 deletions context.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,8 @@ var defaultFormValue = func(ctx *Context, key string) []byte {
}

type Context struct {
// isCopy shows that whether it is a copy through ctx.Copy().
isCopy bool
conn network.Conn
Request protocol.Request
Response protocol.Response
Expand Down Expand Up @@ -775,8 +777,8 @@ func (ctx *Context) Copy() *Context {
conn: ctx.conn,
Params: ctx.Params,
}
ctx.Request.CopyTo(&cp.Request)
ctx.Response.CopyTo(&cp.Response)
ctx.Request.CopyToAndMark(&cp.Request)
ctx.Response.CopyToAndMark(&cp.Response)
cp.index = rConsts.AbortIndex
cp.handlers = nil
cp.Keys = map[string]interface{}{}
Expand Down Expand Up @@ -829,7 +831,7 @@ func (ctx *Context) ResetWithoutConn() {
ctx.index = -1
ctx.fullPath = ""
ctx.Keys = nil

ctx.isCopy = false
if ctx.finished != nil {
close(ctx.finished)
ctx.finished = nil
Expand Down
21 changes: 21 additions & 0 deletions examples/main.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,26 @@
package main

import (
"context"

"github.com/oarkflow/frame"
"github.com/oarkflow/frame/server"
)

func main() {
srv := server.New()
srv.GET("/", func(c context.Context, ctx *frame.Context) {
ctx.JSON(200, "Hello world")
})
srv.GET("/update", func(c context.Context, ctx *frame.Context) {
srv.GET("/", func(c context.Context, ctx *frame.Context) {
ctx.JSON(200, "Bye World")
})
})

srv.Spin()
}

/*func main() {
secret := "OdR4DlWhZk6osDd0qXLdVT88lHOvj14K"
v4 := paseto.NewPV4Local()
Expand Down
10 changes: 5 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ module github.com/oarkflow/frame
go 1.21.0

require (
github.com/bytedance/go-tagexpr/v2 v2.9.9
github.com/bytedance/go-tagexpr/v2 v2.9.11
github.com/bytedance/gopkg v0.0.0-20230728082804-614d0af6619b
github.com/c9s/goprocinfo v0.0.0-20210130143923-c95fcf8c64a8
github.com/cloudwego/netpoll v0.5.0
github.com/cloudwego/netpoll v0.5.1
github.com/golang-jwt/jwt/v4 v4.5.0
github.com/oarkflow/log v1.0.74
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee
Expand All @@ -21,14 +21,14 @@ require (
github.com/andeya/ameda v1.5.3 // indirect
github.com/andeya/goutil v1.0.1 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/protobuf v1.5.0 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/nyaruka/phonenumbers v1.1.8 // indirect
github.com/nyaruka/phonenumbers v1.0.55 // indirect
github.com/philhofer/fwd v1.1.2 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
github.com/shoenig/go-m1cpu v0.1.6 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect
github.com/yusufpapurcu/wmi v1.2.3 // indirect
Expand Down
18 changes: 7 additions & 11 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ github.com/andeya/ameda v1.5.3 h1:SvqnhQPZwwabS8HQTRGfJwWPl2w9ZIPInHAw9aE1Wlk=
github.com/andeya/ameda v1.5.3/go.mod h1:FQDHRe1I995v6GG+8aJ7UIUToEmbdTJn/U26NCPIgXQ=
github.com/andeya/goutil v1.0.1 h1:eiYwVyAnnK0dXU5FJsNjExkJW4exUGn/xefPt3k4eXg=
github.com/andeya/goutil v1.0.1/go.mod h1:jEG5/QnnhG7yGxwFUX6Q+JGMif7sjdHmmNVjn7nhJDo=
github.com/bytedance/go-tagexpr/v2 v2.9.9 h1:nawxXMVp7/Fba0lnDiZACj1hy0cMfqWg94OJN3KB7vQ=
github.com/bytedance/go-tagexpr/v2 v2.9.9/go.mod h1:UAyKh4ZRLBPGsyTRFZoPqTni1TlojMdOJXQnEIPCX84=
github.com/bytedance/go-tagexpr/v2 v2.9.11 h1:jJgmoDKPKacGl0llPYbYL/+/2N+Ng0vV0ipbnVssXHY=
github.com/bytedance/go-tagexpr/v2 v2.9.11/go.mod h1:UAyKh4ZRLBPGsyTRFZoPqTni1TlojMdOJXQnEIPCX84=
github.com/bytedance/gopkg v0.0.0-20220413063733-65bf48ffb3a7/go.mod h1:2ZlV9BaUH4+NXIBF0aMdKKAnHTzqH+iMU4KUjAbL23Q=
github.com/bytedance/gopkg v0.0.0-20230728082804-614d0af6619b h1:R6PWoQtxEMpWJPHnpci+9LgFxCS7iJCfOGBvCgZeTKI=
github.com/bytedance/gopkg v0.0.0-20230728082804-614d0af6619b/go.mod h1:FtQG3YbQG9L/91pbKSw787yBQPutC+457AvDW77fgUQ=
github.com/c9s/goprocinfo v0.0.0-20210130143923-c95fcf8c64a8 h1:SjZ2GvvOononHOpK84APFuMvxqsk3tEIaKH/z4Rpu3g=
github.com/c9s/goprocinfo v0.0.0-20210130143923-c95fcf8c64a8/go.mod h1:uEyr4WpAH4hio6LFriaPkL938XnrvLpNPmQHBdrmbIE=
github.com/cloudwego/netpoll v0.5.0 h1:oRrOp58cPCvK2QbMozZNDESvrxQaEHW2dCimmwH1lcU=
github.com/cloudwego/netpoll v0.5.0/go.mod h1:xVefXptcyheopwNDZjDPcfU6kIjZXZ4nY550k1yH9eQ=
github.com/cloudwego/netpoll v0.5.1 h1:zDUF7xF0C97I10fGlQFJ4jg65khZZMUvSu/TWX44Ohc=
github.com/cloudwego/netpoll v0.5.1/go.mod h1:xVefXptcyheopwNDZjDPcfU6kIjZXZ4nY550k1yH9eQ=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
Expand All @@ -19,18 +19,16 @@ github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiU
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/nyaruka/phonenumbers v1.0.55 h1:bj0nTO88Y68KeUQ/n3Lo2KgK7lM1hF7L9NFuwcCl3yg=
github.com/nyaruka/phonenumbers v1.0.55/go.mod h1:sDaTZ/KPX5f8qyV9qN+hIm+4ZBARJrupC6LuhshJq1U=
github.com/nyaruka/phonenumbers v1.1.8 h1:mjFu85FeoH2Wy18aOMUvxqi1GgAqiQSJsa/cCC5yu2s=
github.com/nyaruka/phonenumbers v1.1.8/go.mod h1:DC7jZd321FqUe+qWSNcHi10tyIyGNXGcNbfkPvdp1Vs=
github.com/oarkflow/log v1.0.74 h1:ZF+G7ZMO2bHRcNMVovqa3LwkzxsaQqhaFCe92Gwwhtg=
github.com/oarkflow/log v1.0.74/go.mod h1:GjB0Np5m9DXTwlS2fpkH5jDsiTMYhD60aG/9UegLNvw=
github.com/philhofer/fwd v1.1.2 h1:bnDivRJ1EWPjUIRXV5KfORO897HTbpFAQddBdE8t7Gw=
Expand Down Expand Up @@ -58,9 +56,8 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tinylib/msgp v1.1.8 h1:FCXC1xanKO4I8plpHGH2P7koL/RzZs12l/+r7vakfm0=
github.com/tinylib/msgp v1.1.8/go.mod h1:qkpG+2ldGg4xRFmx+jfTvZPxfGFhi64BcnL9vkCm/Tw=
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
Expand Down Expand Up @@ -120,7 +117,6 @@ golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
Expand Down
21 changes: 18 additions & 3 deletions pkg/protocol/args.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,11 @@ type argsScanner struct {

type Args struct {
noCopy nocopy.NoCopy //lint:ignore U1000 until noCopy is used

args []argsKV
buf []byte
// isCopy shows that whether it is a copy through ctx.Copy().
// Other APIs such as CopyTo do not need to handle this.
isCopy bool
args []argsKV
buf []byte
}

// Set sets 'key=value' argument.
Expand All @@ -75,6 +77,16 @@ func (a *Args) Set(key, value string) {
// Reset clears query args.
func (a *Args) Reset() {
a.args = a.args[:0]

// a.ParseBytes() will trigger reset, which is a process during lazy load(read scenario), so do not reset this flag.
// Args is not a recycle object so the risk of dirty data is relatively low even though we do not reset this field.
// a.isCopy = false
}

// CopyToAndMark copies all args to dst and mark the dst args as a copy.
func (a *Args) CopyToAndMark(dst *Args) {
dst.isCopy = true
a.CopyTo(dst)
}

// CopyTo copies all args to dst.
Expand Down Expand Up @@ -343,6 +355,9 @@ func peekArgStrExists(h []argsKV, k string) (string, bool) {
//
// The returned value is valid until the next call to Args methods.
func (a *Args) QueryString() []byte {
if a.isCopy {
return a.AppendBytes(nil)
}
a.buf = a.AppendBytes(a.buf[:0])
return a.buf
}
Expand Down
52 changes: 46 additions & 6 deletions pkg/protocol/header.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,9 @@ var (

type RequestHeader struct {
noCopy nocopy.NoCopy //lint:ignore U1000 until noCopy is used

// isCopy shows that whether it is a copy through ctx.Copy().
// Other APIs such as CopyTo do not need to handle this.
isCopy bool
disableNormalizing bool
connectionClose bool
noDefaultContentType bool
Expand Down Expand Up @@ -109,7 +111,9 @@ func (h *RequestHeader) SetRawHeaders(r []byte) {
// goroutines.
type ResponseHeader struct {
noCopy nocopy.NoCopy //lint:ignore U1000 until noCopy is used

// isCopy shows that whether it is a copy through ctx.Copy().
// Other APIs such as CopyTo do not need to handle this.
isCopy bool
disableNormalizing bool
connectionClose bool
noDefaultContentType bool
Expand Down Expand Up @@ -219,11 +223,15 @@ func (h *ResponseHeader) GetHeaders() []argsKV {
func (h *ResponseHeader) Reset() {
h.disableNormalizing = false
h.Trailer().disableNormalizing = false
h.noDefaultContentType = false
h.noDefaultDate = false
h.ResetSkipNormalize()
}

// CopyToAndMark copies all the headers to dst and mark the dst header as a copy.
func (h *ResponseHeader) CopyToAndMark(dst *ResponseHeader) {
dst.isCopy = true
h.CopyTo(dst)
}

// CopyTo copies all the headers to dst.
func (h *ResponseHeader) CopyTo(dst *ResponseHeader) {
dst.Reset()
Expand Down Expand Up @@ -434,6 +442,9 @@ func (h *RequestHeader) AppendBytes(dst []byte) []byte {
//
// The returned representation is valid until the next call to RequestHeader methods.
func (h *RequestHeader) Header() []byte {
if h.isCopy {
return h.AppendBytes(nil)
}
h.bufKV.value = h.AppendBytes(h.bufKV.value[:0])
return h.bufKV.value
}
Expand Down Expand Up @@ -497,6 +508,9 @@ func checkWriteHeaderCode(code int) {

func (h *ResponseHeader) ResetSkipNormalize() {
h.protocol = ""
h.isCopy = false
h.noDefaultContentType = false
h.noDefaultDate = false
h.connectionClose = false

h.statusCode = 0
Expand Down Expand Up @@ -630,6 +644,9 @@ func (h *ResponseHeader) DelBytes(key []byte) {
//
// The returned value is valid until the next call to ResponseHeader methods.
func (h *ResponseHeader) Header() []byte {
if h.isCopy {
return h.AppendBytes(nil)
}
h.bufKV.value = h.AppendBytes(h.bufKV.value[:0])
return h.bufKV.value
}
Expand Down Expand Up @@ -683,6 +700,9 @@ func (h *ResponseHeader) DelClientCookieBytes(key []byte) {
// Returned value is valid until the next call to ResponseHeader.
// Do not store references to returned value. Make copies instead.
func (h *ResponseHeader) Peek(key string) []byte {
if h.isCopy {
return h.peek(getHeaderKeyBytes(&argsKV{}, key, h.disableNormalizing))
}
k := getHeaderKeyBytes(&h.bufKV, key, h.disableNormalizing)
return h.peek(k)
}
Expand Down Expand Up @@ -729,6 +749,9 @@ func (h *ResponseHeader) peek(key []byte) []byte {
// Any future calls to the Peek* will modify the returned value.
// Do not store references to returned value. Use ResponseHeader.GetAll(key) instead.
func (h *ResponseHeader) PeekAll(key string) [][]byte {
if h.isCopy {
return h.peekAll(getHeaderKeyBytes(&argsKV{}, key, h.disableNormalizing))
}
k := getHeaderKeyBytes(&h.bufKV, key, h.disableNormalizing)
return h.peekAll(k)
}
Expand Down Expand Up @@ -771,6 +794,9 @@ func (h *ResponseHeader) peekAll(key []byte) [][]byte {
// Any future calls to the Peek* will modify the returned value.
// Do not store references to returned value. Use RequestHeader.GetAll(key) instead.
func (h *RequestHeader) PeekAll(key string) [][]byte {
if h.isCopy {
return h.peekAll(getHeaderKeyBytes(&argsKV{}, key, h.disableNormalizing))
}
k := getHeaderKeyBytes(&h.bufKV, key, h.disableNormalizing)
return h.peekAll(k)
}
Expand Down Expand Up @@ -1115,10 +1141,19 @@ func (h *RequestHeader) CopyTo(dst *RequestHeader) {
// Returned value is valid until the next call to RequestHeader.
// Do not store references to returned value. Make copies instead.
func (h *RequestHeader) Peek(key string) []byte {
if h.isCopy {
return h.peek(getHeaderKeyBytes(&argsKV{}, key, h.disableNormalizing))
}
k := getHeaderKeyBytes(&h.bufKV, key, h.disableNormalizing)
return h.peek(k)
}

// CopyToAndMark copies all the headers to dst and mark the dst header as a copy.
func (h *RequestHeader) CopyToAndMark(dst *RequestHeader) {
dst.isCopy = true
h.CopyTo(dst)
}

// SetMultipartFormBoundary sets the following Content-Type:
// 'multipart/form-data; boundary=...'
// where ... is substituted by the given boundary.
Expand Down Expand Up @@ -1412,6 +1447,7 @@ func (h *RequestHeader) SetCanonical(key, value []byte) {
}

func (h *RequestHeader) ResetSkipNormalize() {
h.isCopy = false
h.connectionClose = false
h.protocol = ""
h.noDefaultContentType = false
Expand Down Expand Up @@ -1528,8 +1564,12 @@ func (h *RequestHeader) VisitAll(f func(key, value []byte)) {

h.collectCookies()
if len(h.cookies) > 0 {
h.bufKV.value = appendRequestCookieBytes(h.bufKV.value[:0], h.cookies)
f(bytestr.StrCookie, h.bufKV.value)
if h.isCopy {
f(bytestr.StrCookie, appendRequestCookieBytes(nil, h.cookies))
} else {
h.bufKV.value = appendRequestCookieBytes(h.bufKV.value[:0], h.cookies)
f(bytestr.StrCookie, h.bufKV.value)
}
}
visitArgs(h.h, f)
if h.ConnectionClose() {
Expand Down
Loading

0 comments on commit b0d87a3

Please sign in to comment.