mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-01 07:47:56 +00:00
Reuse gob.Encoder and Decoder in DeepCopy
This commit is contained in:
parent
d577db9987
commit
f95cc2b8f2
@ -20,24 +20,49 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"encoding/gob"
|
"encoding/gob"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DeepCopy makes a deep copy of source. Won't work for any private fields!
|
// pool is a pool of copiers
|
||||||
// For nil slices, will return 0-length slices. These are equivilent in
|
var pool = sync.Pool{
|
||||||
// basically every way except for the way that reflect.DeepEqual checks.
|
New: func() interface{} { return newGobCopier() },
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeepCopy makes a deep copy of source or returns an error.
|
||||||
func DeepCopy(source interface{}) (interface{}, error) {
|
func DeepCopy(source interface{}) (interface{}, error) {
|
||||||
v := reflect.New(reflect.TypeOf(source))
|
v := reflect.New(reflect.TypeOf(source))
|
||||||
|
|
||||||
buff := &bytes.Buffer{}
|
c := pool.Get().(gobCopier)
|
||||||
enc := gob.NewEncoder(buff)
|
defer pool.Put(c)
|
||||||
dec := gob.NewDecoder(buff)
|
if err := c.CopyInto(v.Interface(), source); err != nil {
|
||||||
err := enc.Encode(source)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
err = dec.Decode(v.Interface())
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return v.Elem().Interface(), nil
|
return v.Elem().Interface(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// gobCopier provides a copy mechanism for objects using Gob.
|
||||||
|
// This object is not safe for multiple threads because buffer
|
||||||
|
// is shared.
|
||||||
|
type gobCopier struct {
|
||||||
|
enc *gob.Encoder
|
||||||
|
dec *gob.Decoder
|
||||||
|
}
|
||||||
|
|
||||||
|
func newGobCopier() gobCopier {
|
||||||
|
buf := &bytes.Buffer{}
|
||||||
|
return gobCopier{
|
||||||
|
enc: gob.NewEncoder(buf),
|
||||||
|
dec: gob.NewDecoder(buf),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *gobCopier) CopyInto(dst, src interface{}) error {
|
||||||
|
if err := c.enc.Encode(src); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := c.dec.Decode(dst); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||||||
package conversion
|
package conversion
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math/rand"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@ -106,3 +107,37 @@ func TestDeepCopyPointerSeparate(t *testing.T) {
|
|||||||
t.Errorf("deep copy wasn't deep: %#q %#q", x, y)
|
t.Errorf("deep copy wasn't deep: %#q %#q", x, y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var result interface{}
|
||||||
|
|
||||||
|
func BenchmarkDeepCopy(b *testing.B) {
|
||||||
|
table := []interface{}{
|
||||||
|
map[string]string{},
|
||||||
|
int(5),
|
||||||
|
"hello world",
|
||||||
|
struct {
|
||||||
|
A, B, C struct {
|
||||||
|
D map[string]int
|
||||||
|
}
|
||||||
|
X []int
|
||||||
|
Y []byte
|
||||||
|
}{},
|
||||||
|
}
|
||||||
|
|
||||||
|
f := fuzz.New().RandSource(rand.NewSource(1)).NilChance(.5).NumElements(0, 100)
|
||||||
|
for i := range table {
|
||||||
|
out := table[i]
|
||||||
|
obj := reflect.New(reflect.TypeOf(out)).Interface()
|
||||||
|
f.Fuzz(obj)
|
||||||
|
table[i] = obj
|
||||||
|
}
|
||||||
|
|
||||||
|
b.ResetTimer()
|
||||||
|
var r interface{}
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
for j := range table {
|
||||||
|
r, _ = DeepCopy(table[j])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result = r
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user