mirror of
https://github.com/pgsty/minio.git
synced 2026-07-21 21:20:23 +03:00
Improve object reuse for grid messages (#18940)
Allow internal types to support a `Recycler` interface, which will allow for sharing of common types across handlers. This means that all `grid.MSS` (and similar) objects are shared across in a common pool instead of a per-handler pool. Add internal request reuse of internal types. Add for safe (pointerless) types explicitly. Only log params for internal types. Doing Sprint(obj) is just a bit too messy.
This commit is contained in:
+94
-3
@@ -27,6 +27,14 @@ import (
|
||||
"github.com/tinylib/msgp/msgp"
|
||||
)
|
||||
|
||||
// Recycler will override the internal reuse in typed handlers.
|
||||
// When this is supported, the handler will not do internal pooling of objects,
|
||||
// call Recycle() when the object is no longer needed.
|
||||
// The recycler should handle nil pointers.
|
||||
type Recycler interface {
|
||||
Recycle()
|
||||
}
|
||||
|
||||
// MSS is a map[string]string that can be serialized.
|
||||
// It is not very efficient, but it is only used for easy parameter passing.
|
||||
type MSS map[string]string
|
||||
@@ -39,6 +47,14 @@ func (m *MSS) Get(key string) string {
|
||||
return (*m)[key]
|
||||
}
|
||||
|
||||
// Set a key, value pair.
|
||||
func (m *MSS) Set(key, value string) {
|
||||
if m == nil {
|
||||
*m = mssPool.Get().(map[string]string)
|
||||
}
|
||||
(*m)[key] = value
|
||||
}
|
||||
|
||||
// UnmarshalMsg deserializes m from the provided byte slice and returns the
|
||||
// remainder of bytes.
|
||||
func (m *MSS) UnmarshalMsg(bts []byte) (o []byte, err error) {
|
||||
@@ -111,7 +127,10 @@ func (m *MSS) Msgsize() int {
|
||||
|
||||
// NewMSS returns a new MSS.
|
||||
func NewMSS() *MSS {
|
||||
m := MSS(make(map[string]string))
|
||||
m := MSS(mssPool.Get().(map[string]string))
|
||||
for k := range m {
|
||||
delete(m, k)
|
||||
}
|
||||
return &m
|
||||
}
|
||||
|
||||
@@ -121,6 +140,20 @@ func NewMSSWith(m map[string]string) *MSS {
|
||||
return &m2
|
||||
}
|
||||
|
||||
var mssPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return make(map[string]string, 5)
|
||||
},
|
||||
}
|
||||
|
||||
// Recycle the underlying map.
|
||||
func (m *MSS) Recycle() {
|
||||
if m != nil && *m != nil {
|
||||
mssPool.Put(map[string]string(*m))
|
||||
*m = nil
|
||||
}
|
||||
}
|
||||
|
||||
// ToQuery constructs a URL query string from the MSS, including "?" if there are any keys.
|
||||
func (m MSS) ToQuery() string {
|
||||
if len(m) == 0 {
|
||||
@@ -147,17 +180,36 @@ func (m MSS) ToQuery() string {
|
||||
}
|
||||
|
||||
// NewBytes returns a new Bytes.
|
||||
// A slice is preallocated.
|
||||
func NewBytes() *Bytes {
|
||||
b := Bytes(GetByteBuffer()[:0])
|
||||
return &b
|
||||
}
|
||||
|
||||
// NewBytesWith returns a new Bytes with the provided content.
|
||||
// When sent as a parameter, the caller gives up ownership of the byte slice.
|
||||
// When returned as response, the handler also gives up ownership of the byte slice.
|
||||
func NewBytesWith(b []byte) *Bytes {
|
||||
bb := Bytes(b)
|
||||
return &bb
|
||||
}
|
||||
|
||||
// NewBytesWithCopyOf returns a new byte slice with a copy of the provided content.
|
||||
func NewBytesWithCopyOf(b []byte) *Bytes {
|
||||
if b == nil {
|
||||
bb := Bytes(nil)
|
||||
return &bb
|
||||
}
|
||||
if len(b) < maxBufferSize {
|
||||
bb := NewBytes()
|
||||
*bb = append(*bb, b...)
|
||||
return bb
|
||||
}
|
||||
bb := Bytes(make([]byte, len(b)))
|
||||
copy(bb, b)
|
||||
return &bb
|
||||
}
|
||||
|
||||
// Bytes provides a byte slice that can be serialized.
|
||||
type Bytes []byte
|
||||
|
||||
@@ -168,6 +220,9 @@ func (b *Bytes) UnmarshalMsg(bytes []byte) ([]byte, error) {
|
||||
return bytes, errors.New("Bytes: UnmarshalMsg on nil pointer")
|
||||
}
|
||||
if bytes, err := msgp.ReadNilBytes(bytes); err == nil {
|
||||
if *b != nil {
|
||||
PutByteBuffer(*b)
|
||||
}
|
||||
*b = nil
|
||||
return bytes, nil
|
||||
}
|
||||
@@ -179,7 +234,16 @@ func (b *Bytes) UnmarshalMsg(bytes []byte) ([]byte, error) {
|
||||
*b = (*b)[:len(val)]
|
||||
copy(*b, val)
|
||||
} else {
|
||||
*b = append(make([]byte, 0, len(val)), val...)
|
||||
if cap(*b) == 0 && len(val) <= maxBufferSize {
|
||||
PutByteBuffer(*b)
|
||||
*b = GetByteBuffer()[:0]
|
||||
} else {
|
||||
PutByteBuffer(*b)
|
||||
*b = make([]byte, 0, len(val))
|
||||
}
|
||||
in := *b
|
||||
in = append(in[:0], val...)
|
||||
*b = in
|
||||
}
|
||||
return bytes, nil
|
||||
}
|
||||
@@ -202,7 +266,8 @@ func (b *Bytes) Msgsize() int {
|
||||
|
||||
// Recycle puts the Bytes back into the pool.
|
||||
func (b *Bytes) Recycle() {
|
||||
if *b != nil {
|
||||
if b != nil && *b != nil {
|
||||
*b = (*b)[:0]
|
||||
PutByteBuffer(*b)
|
||||
*b = nil
|
||||
}
|
||||
@@ -329,3 +394,29 @@ func (u URLValues) Msgsize() (s int) {
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// NoPayload is a type that can be used for handlers that do not use a payload.
|
||||
type NoPayload struct{}
|
||||
|
||||
// Msgsize returns 0.
|
||||
func (p NoPayload) Msgsize() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
// UnmarshalMsg satisfies the interface, but is a no-op.
|
||||
func (NoPayload) UnmarshalMsg(bytes []byte) ([]byte, error) {
|
||||
return bytes, nil
|
||||
}
|
||||
|
||||
// MarshalMsg satisfies the interface, but is a no-op.
|
||||
func (NoPayload) MarshalMsg(bytes []byte) ([]byte, error) {
|
||||
return bytes, nil
|
||||
}
|
||||
|
||||
// NewNoPayload returns an empty NoPayload struct.
|
||||
func NewNoPayload() NoPayload {
|
||||
return NoPayload{}
|
||||
}
|
||||
|
||||
// Recycle is a no-op.
|
||||
func (NoPayload) Recycle() {}
|
||||
|
||||
Reference in New Issue
Block a user