commit f2cc13a668caf474b5d5806c7f1adbbe4ce28524
parent 73600a98c556ff2da24a90f556188b676eaaff31
Author: Francois Parquet <francois.parquet@gmail.com>
Date: Thu, 20 Dec 2018 17:31:23 +0800
Merge pull request #93 from francoispqt/update/optimize-alloc-marshal
create new buffer before releasing only when using marshal syntax
Diffstat:
12 files changed, 66 insertions(+), 22 deletions(-)
diff --git a/encode.go b/encode.go
@@ -34,7 +34,12 @@ func MarshalJSONArray(v MarshalerJSONArray) ([]byte, error) {
enc.writeByte('[')
v.(MarshalerJSONArray).MarshalJSONArray(enc)
enc.writeByte(']')
- defer enc.Release()
+
+ defer func() {
+ enc.buf = make([]byte, 0, 512)
+ enc.Release()
+ }()
+
return enc.buf, nil
}
@@ -61,7 +66,12 @@ func MarshalJSONArray(v MarshalerJSONArray) ([]byte, error) {
func MarshalJSONObject(v MarshalerJSONObject) ([]byte, error) {
enc := BorrowEncoder(nil)
enc.grow(512)
- defer enc.Release()
+
+ defer func() {
+ enc.buf = make([]byte, 0, 512)
+ enc.Release()
+ }()
+
return enc.encodeObject(v)
}
@@ -91,6 +101,11 @@ func marshal(v interface{}, any bool) ([]byte, error) {
err error
)
+ defer func() {
+ enc.buf = make([]byte, 0, 512)
+ enc.Release()
+ }()
+
buf, err = func() ([]byte, error) {
switch vt := v.(type) {
case MarshalerJSONObject:
@@ -133,8 +148,6 @@ func marshal(v interface{}, any bool) ([]byte, error) {
return nil, InvalidMarshalError(fmt.Sprintf(invalidMarshalErrorMsg, vt))
}
}()
-
- enc.Release()
return buf, err
}
diff --git a/encode_bool_test.go b/encode_bool_test.go
@@ -43,7 +43,7 @@ func TestEncoderBoolErrors(t *testing.T) {
t.Run("pool-error", func(t *testing.T) {
builder := &strings.Builder{}
enc := BorrowEncoder(builder)
- enc.Release()
+ enc.isPooled = 1
defer func() {
err := recover()
assert.NotNil(t, err, "err shouldnt be nil")
diff --git a/encode_embedded_json_test.go b/encode_embedded_json_test.go
@@ -124,7 +124,7 @@ func TestEncodingEmbeddedJSON(t *testing.T) {
t.Run("pool-error", func(t *testing.T) {
v := EmbeddedJSON([]byte(`"test"`))
enc := BorrowEncoder(nil)
- enc.Release()
+ enc.isPooled = 1
defer func() {
err := recover()
assert.NotNil(t, err, "err shouldnt be nil")
diff --git a/encode_interface_test.go b/encode_interface_test.go
@@ -153,7 +153,7 @@ func TestEncoderInterfaceEncodeAPI(t *testing.T) {
v := ""
w := TestWriterError("")
enc := BorrowEncoder(w)
- enc.Release()
+ enc.isPooled = 1
defer func() {
err := recover()
assert.NotNil(t, err, "err should not be nil")
diff --git a/encode_number_test.go b/encode_number_test.go
@@ -73,7 +73,7 @@ func TestEncoderNumberEncodeAPIErrors(t *testing.T) {
t.Run("encode-int-pool-error", func(t *testing.T) {
builder := &strings.Builder{}
enc := NewEncoder(builder)
- enc.Release()
+ enc.isPooled = 1
defer func() {
err := recover()
assert.NotNil(t, err, "err should not be nil")
@@ -92,7 +92,7 @@ func TestEncoderNumberEncodeAPIErrors(t *testing.T) {
t.Run("encode-int64-pool-error", func(t *testing.T) {
builder := &strings.Builder{}
enc := NewEncoder(builder)
- enc.Release()
+ enc.isPooled = 1
defer func() {
err := recover()
assert.NotNil(t, err, "err should not be nil")
@@ -112,7 +112,7 @@ func TestEncoderNumberEncodeAPIErrors(t *testing.T) {
t.Run("encode-uint64-pool-error", func(t *testing.T) {
builder := &strings.Builder{}
enc := NewEncoder(builder)
- enc.Release()
+ enc.isPooled = 1
defer func() {
err := recover()
assert.NotNil(t, err, "err should not be nil")
@@ -132,7 +132,7 @@ func TestEncoderNumberEncodeAPIErrors(t *testing.T) {
t.Run("encode-float64-pool-error", func(t *testing.T) {
builder := &strings.Builder{}
enc := NewEncoder(builder)
- enc.Release()
+ enc.isPooled = 1
defer func() {
err := recover()
assert.NotNil(t, err, "err should not be nil")
@@ -151,7 +151,7 @@ func TestEncoderNumberEncodeAPIErrors(t *testing.T) {
t.Run("encode-float32-pool-error", func(t *testing.T) {
builder := &strings.Builder{}
enc := NewEncoder(builder)
- enc.Release()
+ enc.isPooled = 1
defer func() {
err := recover()
assert.NotNil(t, err, "err should not be nil")
diff --git a/encode_object.go b/encode_object.go
@@ -44,7 +44,7 @@ func (enc *Encoder) EncodeObjectKeys(v MarshalerJSONObject, keys []string) error
}
func (enc *Encoder) encodeObject(v MarshalerJSONObject) ([]byte, error) {
- enc.grow(500)
+ enc.grow(512)
enc.writeByte('{')
if !v.IsNil() {
v.MarshalJSONObject(enc)
diff --git a/encode_object_test.go b/encode_object_test.go
@@ -417,7 +417,7 @@ func TestEncoderObjectEncodeAPIError(t *testing.T) {
t.Run("pool-error", func(t *testing.T) {
v := &TestEncoding{}
enc := BorrowEncoder(nil)
- enc.Release()
+ enc.isPooled = 1
defer func() {
err := recover()
assert.NotNil(t, err, "err shouldnt be nil")
@@ -608,7 +608,7 @@ func TestEncodeObjectWithKeys(t *testing.T) {
t.Run("pool-error", func(t *testing.T) {
v := &TestEncoding{}
enc := BorrowEncoder(nil)
- enc.Release()
+ enc.isPooled = 1
defer func() {
err := recover()
assert.NotNil(t, err, "err shouldnt be nil")
diff --git a/encode_pool.go b/encode_pool.go
@@ -35,7 +35,7 @@ func NewEncoder(w io.Writer) *Encoder {
func BorrowEncoder(w io.Writer) *Encoder {
enc := encPool.Get().(*Encoder)
enc.w = w
- enc.buf = make([]byte, 0, 512)
+ enc.buf = enc.buf[:0]
enc.isPooled = 0
enc.err = nil
enc.hasKeys = false
diff --git a/encode_pool_test.go b/encode_pool_test.go
@@ -1 +1,32 @@
package gojay
+
+import (
+ "fmt"
+ "log"
+ "strconv"
+ "testing"
+ "time"
+)
+
+func TestConcurrencyMarshal(t *testing.T) {
+ var f = func(num int, t *testing.T) {
+ for {
+ b, err := Marshal(num)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ s := string(b)
+ if n, err := strconv.Atoi(s); err != nil || n != num {
+ t.Error(fmt.Errorf(
+ "caught race: %v %v", s, num,
+ ))
+ }
+ }
+ }
+
+ for i := 0; i < 100; i++ {
+ go f(i, t)
+ }
+ time.Sleep(2 * time.Second)
+}
diff --git a/encode_sqlnull_test.go b/encode_sqlnull_test.go
@@ -51,7 +51,7 @@ func TestEncoceSQLNullString(t *testing.T) {
func(t *testing.T) {
builder := &strings.Builder{}
enc := NewEncoder(builder)
- enc.Release()
+ enc.isPooled = 1
defer func() {
err := recover()
assert.NotNil(t, err, "err should not be nil")
@@ -329,7 +329,7 @@ func TestEncoceSQLNullInt64(t *testing.T) {
func(t *testing.T) {
builder := &strings.Builder{}
enc := NewEncoder(builder)
- enc.Release()
+ enc.isPooled = 1
defer func() {
err := recover()
assert.NotNil(t, err, "err should not be nil")
@@ -606,7 +606,7 @@ func TestEncoceSQLNullFloat64(t *testing.T) {
func(t *testing.T) {
builder := &strings.Builder{}
enc := NewEncoder(builder)
- enc.Release()
+ enc.isPooled = 1
defer func() {
err := recover()
assert.NotNil(t, err, "err should not be nil")
@@ -884,7 +884,7 @@ func TestEncoceSQLNullBool(t *testing.T) {
func(t *testing.T) {
builder := &strings.Builder{}
enc := NewEncoder(builder)
- enc.Release()
+ enc.isPooled = 1
defer func() {
err := recover()
assert.NotNil(t, err, "err should not be nil")
diff --git a/encode_string_test.go b/encode_string_test.go
@@ -122,7 +122,7 @@ func TestEncoderStringEncodeAPIErrors(t *testing.T) {
t.Run("pool-error", func(t *testing.T) {
v := ""
enc := BorrowEncoder(nil)
- enc.Release()
+ enc.isPooled = 1
defer func() {
err := recover()
assert.NotNil(t, err, "err shouldnt be nil")
diff --git a/encode_time_test.go b/encode_time_test.go
@@ -41,7 +41,7 @@ func TestEncodeTime(t *testing.T) {
t.Run("encode-time-pool-error", func(t *testing.T) {
builder := &strings.Builder{}
enc := NewEncoder(builder)
- enc.Release()
+ enc.isPooled = 1
defer func() {
err := recover()
assert.NotNil(t, err, "err should not be nil")