mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-28 14:07:14 +00:00
serializer: Recognizer interface should take a buffer
The original intent of the Recognizer interface was to take a stream and peek into the contents. Over time all of the callers migrated to instead performing their own peek and then passing the buffer as a bytes.NewBuffer to the interface as a stream, which was then implemented as a read on the other side. This resulted in an excess buffer allocation in general decoder usage. Update the interface to take a []bytes slice and change all callers to stop creating buffered readers, then update the JSON serializer to check the buffer directly for "json-ness".
This commit is contained in:
parent
c241a237f9
commit
9f288610eb
@ -333,13 +333,12 @@ func (s *Serializer) Identifier() runtime.Identifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RecognizesData implements the RecognizingDecoder interface.
|
// RecognizesData implements the RecognizingDecoder interface.
|
||||||
func (s *Serializer) RecognizesData(peek io.Reader) (ok, unknown bool, err error) {
|
func (s *Serializer) RecognizesData(data []byte) (ok, unknown bool, err error) {
|
||||||
if s.options.Yaml {
|
if s.options.Yaml {
|
||||||
// we could potentially look for '---'
|
// we could potentially look for '---'
|
||||||
return false, true, nil
|
return false, true, nil
|
||||||
}
|
}
|
||||||
_, _, ok = utilyaml.GuessJSONStream(peek, 2048)
|
return utilyaml.IsJSONBuffer(data), false, nil
|
||||||
return ok, false, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Framer is the default JSON framing behavior, with newlines delimiting individual objects.
|
// Framer is the default JSON framing behavior, with newlines delimiting individual objects.
|
||||||
|
@ -120,7 +120,7 @@ func (s *Serializer) Decode(originalData []byte, gvk *schema.GroupVersionKind, i
|
|||||||
|
|
||||||
if intoUnknown, ok := into.(*runtime.Unknown); ok && intoUnknown != nil {
|
if intoUnknown, ok := into.(*runtime.Unknown); ok && intoUnknown != nil {
|
||||||
*intoUnknown = unk
|
*intoUnknown = unk
|
||||||
if ok, _, _ := s.RecognizesData(bytes.NewBuffer(unk.Raw)); ok {
|
if ok, _, _ := s.RecognizesData(unk.Raw); ok {
|
||||||
intoUnknown.ContentType = runtime.ContentTypeProtobuf
|
intoUnknown.ContentType = runtime.ContentTypeProtobuf
|
||||||
}
|
}
|
||||||
return intoUnknown, &actual, nil
|
return intoUnknown, &actual, nil
|
||||||
@ -245,19 +245,8 @@ func (s *Serializer) Identifier() runtime.Identifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RecognizesData implements the RecognizingDecoder interface.
|
// RecognizesData implements the RecognizingDecoder interface.
|
||||||
func (s *Serializer) RecognizesData(peek io.Reader) (bool, bool, error) {
|
func (s *Serializer) RecognizesData(data []byte) (bool, bool, error) {
|
||||||
prefix := make([]byte, 4)
|
return bytes.HasPrefix(data, s.prefix), false, nil
|
||||||
n, err := peek.Read(prefix)
|
|
||||||
if err != nil {
|
|
||||||
if err == io.EOF {
|
|
||||||
return false, false, nil
|
|
||||||
}
|
|
||||||
return false, false, err
|
|
||||||
}
|
|
||||||
if n != 4 {
|
|
||||||
return false, false, nil
|
|
||||||
}
|
|
||||||
return bytes.Equal(s.prefix, prefix), false, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// copyKindDefaults defaults dst to the value in src if dst does not have a value set.
|
// copyKindDefaults defaults dst to the value in src if dst does not have a value set.
|
||||||
|
@ -17,10 +17,7 @@ limitations under the License.
|
|||||||
package recognizer
|
package recognizer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
@ -35,7 +32,7 @@ type RecognizingDecoder interface {
|
|||||||
// provides) and may return unknown if the data provided is not sufficient to make a
|
// provides) and may return unknown if the data provided is not sufficient to make a
|
||||||
// a determination. When peek returns EOF that may mean the end of the input or the
|
// a determination. When peek returns EOF that may mean the end of the input or the
|
||||||
// end of buffered input - recognizers should return the best guess at that time.
|
// end of buffered input - recognizers should return the best guess at that time.
|
||||||
RecognizesData(peek io.Reader) (ok, unknown bool, err error)
|
RecognizesData(peek []byte) (ok, unknown bool, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDecoder creates a decoder that will attempt multiple decoders in an order defined
|
// NewDecoder creates a decoder that will attempt multiple decoders in an order defined
|
||||||
@ -57,16 +54,15 @@ type decoder struct {
|
|||||||
|
|
||||||
var _ RecognizingDecoder = &decoder{}
|
var _ RecognizingDecoder = &decoder{}
|
||||||
|
|
||||||
func (d *decoder) RecognizesData(peek io.Reader) (bool, bool, error) {
|
func (d *decoder) RecognizesData(data []byte) (bool, bool, error) {
|
||||||
var (
|
var (
|
||||||
lastErr error
|
lastErr error
|
||||||
anyUnknown bool
|
anyUnknown bool
|
||||||
)
|
)
|
||||||
data, _ := bufio.NewReaderSize(peek, 1024).Peek(1024)
|
|
||||||
for _, r := range d.decoders {
|
for _, r := range d.decoders {
|
||||||
switch t := r.(type) {
|
switch t := r.(type) {
|
||||||
case RecognizingDecoder:
|
case RecognizingDecoder:
|
||||||
ok, unknown, err := t.RecognizesData(bytes.NewBuffer(data))
|
ok, unknown, err := t.RecognizesData(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
lastErr = err
|
lastErr = err
|
||||||
continue
|
continue
|
||||||
@ -91,8 +87,7 @@ func (d *decoder) Decode(data []byte, gvk *schema.GroupVersionKind, into runtime
|
|||||||
for _, r := range d.decoders {
|
for _, r := range d.decoders {
|
||||||
switch t := r.(type) {
|
switch t := r.(type) {
|
||||||
case RecognizingDecoder:
|
case RecognizingDecoder:
|
||||||
buf := bytes.NewBuffer(data)
|
ok, unknown, err := t.RecognizesData(data)
|
||||||
ok, unknown, err := t.RecognizesData(buf)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
lastErr = err
|
lastErr = err
|
||||||
continue
|
continue
|
||||||
|
@ -92,7 +92,7 @@ func TestRecognize(t *testing.T) {
|
|||||||
{0x6b, 0x38, 0x73, 0x01},
|
{0x6b, 0x38, 0x73, 0x01},
|
||||||
}
|
}
|
||||||
for i, data := range ignores {
|
for i, data := range ignores {
|
||||||
if ok, _, err := s.RecognizesData(bytes.NewBuffer(data)); err != nil || ok {
|
if ok, _, err := s.RecognizesData(data); err != nil || ok {
|
||||||
t.Errorf("%d: should not recognize data: %v", i, err)
|
t.Errorf("%d: should not recognize data: %v", i, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -101,7 +101,7 @@ func TestRecognize(t *testing.T) {
|
|||||||
{0x6b, 0x38, 0x73, 0x00, 0x01},
|
{0x6b, 0x38, 0x73, 0x00, 0x01},
|
||||||
}
|
}
|
||||||
for i, data := range recognizes {
|
for i, data := range recognizes {
|
||||||
if ok, _, err := s.RecognizesData(bytes.NewBuffer(data)); err != nil || !ok {
|
if ok, _, err := s.RecognizesData(data); err != nil || !ok {
|
||||||
t.Errorf("%d: should recognize data: %v", i, err)
|
t.Errorf("%d: should recognize data: %v", i, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -197,7 +197,7 @@ func TestEncode(t *testing.T) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if ok, _, err := s.RecognizesData(bytes.NewBuffer(data)); !ok || err != nil {
|
if ok, _, err := s.RecognizesData(data); !ok || err != nil {
|
||||||
t.Errorf("%d: did not recognize data generated by call: %v", i, err)
|
t.Errorf("%d: did not recognize data generated by call: %v", i, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -343,6 +343,12 @@ func GuessJSONStream(r io.Reader, size int) (io.Reader, []byte, bool) {
|
|||||||
return buffer, b, hasJSONPrefix(b)
|
return buffer, b, hasJSONPrefix(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsJSONBuffer scans the provided buffer, looking
|
||||||
|
// for an open brace indicating this is JSON.
|
||||||
|
func IsJSONBuffer(buf []byte) bool {
|
||||||
|
return hasJSONPrefix(buf)
|
||||||
|
}
|
||||||
|
|
||||||
var jsonPrefix = []byte("{")
|
var jsonPrefix = []byte("{")
|
||||||
|
|
||||||
// hasJSONPrefix returns true if the provided buffer appears to start with
|
// hasJSONPrefix returns true if the provided buffer appears to start with
|
||||||
|
Loading…
Reference in New Issue
Block a user