diff --git a/bson/default_value_encoders.go b/bson/default_value_encoders.go index 38cb953151..07e7c89e47 100644 --- a/bson/default_value_encoders.go +++ b/bson/default_value_encoders.go @@ -17,7 +17,11 @@ import ( "go.mongodb.org/mongo-driver/x/bsonx/bsoncore" ) -var bvwPool = NewValueWriterPool() +var bvwPool = sync.Pool{ + New: func() interface{} { + return new(valueWriter) + }, +} var errInvalidValue = errors.New("cannot encode invalid element") @@ -511,7 +515,9 @@ func codeWithScopeEncodeValue(ec EncodeContext, vw ValueWriter, val reflect.Valu defer sliceWriterPool.Put(sw) *sw = (*sw)[:0] - scopeVW := bvwPool.Get(sw) + scopeVW := bvwPool.Get().(*valueWriter) + scopeVW.reset(scopeVW.buf[:0]) + scopeVW.w = sw defer bvwPool.Put(scopeVW) encoder, err := ec.LookupEncoder(reflect.TypeOf(cws.Scope)) diff --git a/bson/marshal.go b/bson/marshal.go index 8e30d608cb..5d3407f162 100644 --- a/bson/marshal.go +++ b/bson/marshal.go @@ -96,8 +96,26 @@ func MarshalValue(val interface{}) (Type, []byte, error) { // Deprecated: Using a custom registry to marshal individual BSON values will not be supported in Go // Driver 2.0. func MarshalValueWithRegistry(r *Registry, val interface{}) (Type, []byte, error) { - sw := sliceWriter(make([]byte, 0)) - vw := bvwPool.Get(&sw).(*valueWriter) + sw := bufPool.Get().(*bytes.Buffer) + defer func() { + // Proper usage of a sync.Pool requires each entry to have approximately + // the same memory cost. To obtain this property when the stored type + // contains a variably-sized buffer, we add a hard limit on the maximum + // buffer to place back in the pool. We limit the size to 16MiB because + // that's the maximum wire message size supported by any current MongoDB + // server. + // + // Comment based on + // https://cs.opensource.google/go/go/+/refs/tags/go1.19:src/fmt/print.go;l=147 + // + // Recycle byte slices that are smaller than 16MiB and at least half + // occupied. + if sw.Cap() < 16*1024*1024 && sw.Cap()/2 < sw.Len() { + bufPool.Put(sw) + } + }() + sw.Reset() + vw := NewValueWriter(sw).(*valueWriter) vwFlusher, err := vw.WriteDocumentElement("") if err != nil { return 0, nil, err @@ -107,7 +125,7 @@ func MarshalValueWithRegistry(r *Registry, val interface{}) (Type, []byte, error enc := encPool.Get().(*Encoder) defer encPool.Put(enc) enc.Reset(vwFlusher) - enc.ec = EncodeContext{Registry: r} + enc.SetRegistry(r) if err := enc.Encode(val); err != nil { return 0, nil, err } @@ -118,7 +136,8 @@ func MarshalValueWithRegistry(r *Registry, val interface{}) (Type, []byte, error if err := vw.Flush(); err != nil { return 0, nil, err } - return Type(sw[0]), sw[2:], nil + buf := sw.Bytes() + return Type(buf[0]), buf[2:], nil } // MarshalExtJSON returns the extended JSON encoding of val. diff --git a/bson/value_writer.go b/bson/value_writer.go index 1d2bbf8fdf..82ece3a7ae 100644 --- a/bson/value_writer.go +++ b/bson/value_writer.go @@ -33,53 +33,6 @@ func putValueWriter(vw *valueWriter) { } } -// ValueWriterPool is a pool for BSON ValueWriters. -// -// Deprecated: ValueWriterPool will not be supported in Go Driver 2.0. -type ValueWriterPool struct { - pool sync.Pool -} - -// NewValueWriterPool creates a new pool for ValueWriter instances that write to BSON. -// -// Deprecated: ValueWriterPool will not be supported in Go Driver 2.0. -func NewValueWriterPool() *ValueWriterPool { - return &ValueWriterPool{ - pool: sync.Pool{ - New: func() interface{} { - return new(valueWriter) - }, - }, - } -} - -// Get retrieves a BSON ValueWriter from the pool and resets it to use w as the destination. -// -// Deprecated: ValueWriterPool will not be supported in Go Driver 2.0. -func (bvwp *ValueWriterPool) Get(w io.Writer) ValueWriter { - vw := bvwp.pool.Get().(*valueWriter) - - // TODO: Having to call reset here with the same buffer doesn't really make sense. - vw.reset(vw.buf) - vw.buf = vw.buf[:0] - vw.w = w - return vw -} - -// Put inserts a ValueWriter into the pool. If the ValueWriter is not a BSON ValueWriter, nothing -// happens and ok will be false. -// -// Deprecated: ValueWriterPool will not be supported in Go Driver 2.0. -func (bvwp *ValueWriterPool) Put(vw ValueWriter) (ok bool) { - bvw, ok := vw.(*valueWriter) - if !ok { - return false - } - - bvwp.pool.Put(bvw) - return true -} - // This is here so that during testing we can change it and not require // allocating a 4GB slice. var maxSize = math.MaxInt32 diff --git a/mongo/mongo.go b/mongo/mongo.go index 7ba0dff24e..0da198c8de 100644 --- a/mongo/mongo.go +++ b/mongo/mongo.go @@ -52,9 +52,6 @@ func (me MarshalError) Error() string { // } type Pipeline []bson.D -// bvwPool is a pool of BSON value writers. BSON value writers -var bvwPool = bson.NewValueWriterPool() - // getEncoder takes a writer, BSON options, and a BSON registry and returns a properly configured // bson.Encoder that writes to the given writer. func getEncoder( @@ -62,7 +59,7 @@ func getEncoder( opts *options.BSONOptions, reg *bson.Registry, ) (*bson.Encoder, error) { - vw := bvwPool.Get(w) + vw := bson.NewValueWriter(w) enc := bson.NewEncoder(vw) if opts != nil {