mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-30 15:05:27 +00:00
Reuse gob.Encoder and Decoder in DeepCopy
This commit is contained in:
parent
d577db9987
commit
f95cc2b8f2
@ -20,24 +20,49 @@ import (
|
||||
"bytes"
|
||||
"encoding/gob"
|
||||
"reflect"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// DeepCopy makes a deep copy of source. Won't work for any private fields!
|
||||
// For nil slices, will return 0-length slices. These are equivilent in
|
||||
// basically every way except for the way that reflect.DeepEqual checks.
|
||||
// pool is a pool of copiers
|
||||
var pool = sync.Pool{
|
||||
New: func() interface{} { return newGobCopier() },
|
||||
}
|
||||
|
||||
// DeepCopy makes a deep copy of source or returns an error.
|
||||
func DeepCopy(source interface{}) (interface{}, error) {
|
||||
v := reflect.New(reflect.TypeOf(source))
|
||||
|
||||
buff := &bytes.Buffer{}
|
||||
enc := gob.NewEncoder(buff)
|
||||
dec := gob.NewDecoder(buff)
|
||||
err := enc.Encode(source)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = dec.Decode(v.Interface())
|
||||
if err != nil {
|
||||
c := pool.Get().(gobCopier)
|
||||
defer pool.Put(c)
|
||||
if err := c.CopyInto(v.Interface(), source); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
@ -106,3 +107,37 @@ func TestDeepCopyPointerSeparate(t *testing.T) {
|
||||
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