99 "os"
1010 "sync"
1111 "time"
12+
13+ "github.com/valyala/bytebufferpool"
1214)
1315
1416const (
@@ -30,30 +32,8 @@ type globalMemoryCache struct {
3032
3133var (
3234 memoryUsageCache = & globalMemoryCache {}
33- spooledPool = sync.Pool {
34- New : func () any {
35- b := make ([]byte , 0 , InitialBufferSize )
36- return & b
37- },
38- }
3935)
4036
41- // Get a zero-length slice backed by a pooled array (cap == InitialBufferSize).
42- func getPooledBuf () []byte {
43- p := spooledPool .Get ().(* []byte )
44- return (* p )[:0 ]
45- }
46-
47- // Return a slice to the pool without retaining large arrays.
48- // IMPORTANT: do NOT pass &s.buf directly; copy a header first.
49- func putPooledBuf (b []byte ) {
50- if cap (b ) == 0 || cap (b ) > InitialBufferSize {
51- return // don't retain big arrays
52- }
53- h := b [:0 ] // fresh header decoupled from callers
54- spooledPool .Put (& h ) // pointer-like -> SA6002 satisfied
55- }
56-
5737// ReaderAt is the interface for ReadAt - read at position, without moving pointer.
5838type ReaderAt interface {
5939 ReadAt (p []byte , off int64 ) (n int , err error )
@@ -70,7 +50,7 @@ type ReadSeekCloser interface {
7050// spooledTempFile writes to memory (or to disk if
7151// over MaxInMemorySize) and deletes the file on Close
7252type spooledTempFile struct {
73- buf [] byte // Use []byte instead of bytes.Buffer
53+ buf * bytebufferpool. ByteBuffer
7454 mem * bytes.Reader // Reader for in-memory data
7555 file * os.File
7656 filePrefix string
@@ -118,7 +98,7 @@ func NewSpooledTempFile(filePrefix string, tempDir string, threshold int, fullOn
11898 return & spooledTempFile {
11999 filePrefix : filePrefix ,
120100 tempDir : tempDir ,
121- buf : getPooledBuf (),
101+ buf : bytebufferpool . Get (),
122102 maxInMemorySize : threshold ,
123103 fullOnDisk : fullOnDisk ,
124104 maxRAMUsageFraction : maxRAMUsageFraction ,
@@ -142,7 +122,7 @@ func (s *spooledTempFile) prepareRead() error {
142122 return nil
143123 }
144124
145- s .mem = bytes .NewReader (s .buf ) // Create a reader from the []byte slice
125+ s .mem = bytes .NewReader (s .buf . Bytes ())
146126 return nil
147127}
148128
@@ -154,7 +134,7 @@ func (s *spooledTempFile) Len() int {
154134 }
155135 return int (fi .Size ())
156136 }
157- return len ( s .buf ) // Return the length of the []byte slice
137+ return s .buf . Len ()
158138}
159139
160140func (s * spooledTempFile ) Read (p []byte ) (n int , err error ) {
@@ -196,6 +176,7 @@ func (s *spooledTempFile) Write(p []byte) (n int, err error) {
196176 if s .closed {
197177 return 0 , io .EOF
198178 }
179+
199180 if s .reading {
200181 panic ("write after read" )
201182 }
@@ -205,27 +186,26 @@ func (s *spooledTempFile) Write(p []byte) (n int, err error) {
205186 }
206187
207188 aboveRAMThreshold := s .isSystemMemoryUsageHigh ()
208- if aboveRAMThreshold || s .fullOnDisk || (len ( s .buf )+ len (p ) > s .maxInMemorySize ) {
189+ if aboveRAMThreshold || s .fullOnDisk || (s .buf . Len ( )+ len (p ) > s .maxInMemorySize ) {
209190 // Switch to file if we haven't already
210191 s .file , err = os .CreateTemp (s .tempDir , s .filePrefix + "-" )
211192 if err != nil {
212193 return 0 , err
213194 }
214195
215196 // Copy what we already had in the buffer
216- _ , err = s .file . Write (s .buf )
197+ _ , err = s .buf . WriteTo (s .file )
217198 if err != nil {
218199 s .file .Close ()
219200 s .file = nil
220201 return 0 , err
221202 }
222203
223204 // Release the buffer back to the pool
224- if s .buf != nil && cap ( s . buf ) <= InitialBufferSize && cap ( s . buf ) > 0 {
225- putPooledBuf (s .buf )
205+ if s .buf != nil {
206+ bytebufferpool . Put (s .buf )
226207 }
227208 s .buf = nil
228- s .mem = nil // Discard the bytes.Reader
229209
230210 // Write incoming bytes directly to file
231211 n , err = s .file .Write (p )
@@ -237,36 +217,22 @@ func (s *spooledTempFile) Write(p []byte) (n int, err error) {
237217 return n , nil
238218 }
239219
240- // Grow the buffer if necessary, but never exceed MaxInMemorySize
241- if len (s .buf )+ len (p ) > cap (s .buf ) {
242- newCap := min (len (s .buf )+ len (p ), s .maxInMemorySize )
243-
244- // Allocate a new buffer with the increased capacity
245- newBuf := make ([]byte , len (s .buf ), newCap )
246- copy (newBuf , s .buf )
247-
248- // Release the old buffer to the pool
249- if s .buf != nil && cap (s .buf ) <= InitialBufferSize && cap (s .buf ) > 0 {
250- putPooledBuf (s .buf )
251- }
252- s .buf = newBuf
253- s .mem = nil // Discard the old bytes.Reader
254- }
255-
256220 // Append data to the buffer
257- s .buf = append ( s . buf , p ... )
221+ s .buf . Write ( p )
258222 return len (p ), nil
259223}
260224
261225func (s * spooledTempFile ) Close () error {
262226 s .closed = true
263- s .mem = nil
227+
228+ if s .mem != nil {
229+ s .mem .Reset ([]byte {})
230+ s .mem = nil
231+ }
264232
265233 // Release the buffer back to the pool
266234 if s .buf != nil {
267- if cap (s .buf ) <= InitialBufferSize && cap (s .buf ) > 0 {
268- putPooledBuf (s .buf )
269- }
235+ bytebufferpool .Put (s .buf )
270236 s .buf = nil
271237 }
272238
0 commit comments