google.golang.org/grpc@v1.74.2/mem/buffer_slice.go (about) 1 /* 2 * 3 * Copyright 2024 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 package mem 20 21 import ( 22 "io" 23 ) 24 25 const ( 26 // 32 KiB is what io.Copy uses. 27 readAllBufSize = 32 * 1024 28 ) 29 30 // BufferSlice offers a means to represent data that spans one or more Buffer 31 // instances. A BufferSlice is meant to be immutable after creation, and methods 32 // like Ref create and return copies of the slice. This is why all methods have 33 // value receivers rather than pointer receivers. 34 // 35 // Note that any of the methods that read the underlying buffers such as Ref, 36 // Len or CopyTo etc., will panic if any underlying buffers have already been 37 // freed. It is recommended to not directly interact with any of the underlying 38 // buffers directly, rather such interactions should be mediated through the 39 // various methods on this type. 40 // 41 // By convention, any APIs that return (mem.BufferSlice, error) should reduce 42 // the burden on the caller by never returning a mem.BufferSlice that needs to 43 // be freed if the error is non-nil, unless explicitly stated. 44 type BufferSlice []Buffer 45 46 // Len returns the sum of the length of all the Buffers in this slice. 47 // 48 // # Warning 49 // 50 // Invoking the built-in len on a BufferSlice will return the number of buffers 51 // in the slice, and *not* the value returned by this function. 52 func (s BufferSlice) Len() int { 53 var length int 54 for _, b := range s { 55 length += b.Len() 56 } 57 return length 58 } 59 60 // Ref invokes Ref on each buffer in the slice. 61 func (s BufferSlice) Ref() { 62 for _, b := range s { 63 b.Ref() 64 } 65 } 66 67 // Free invokes Buffer.Free() on each Buffer in the slice. 68 func (s BufferSlice) Free() { 69 for _, b := range s { 70 b.Free() 71 } 72 } 73 74 // CopyTo copies each of the underlying Buffer's data into the given buffer, 75 // returning the number of bytes copied. Has the same semantics as the copy 76 // builtin in that it will copy as many bytes as it can, stopping when either dst 77 // is full or s runs out of data, returning the minimum of s.Len() and len(dst). 78 func (s BufferSlice) CopyTo(dst []byte) int { 79 off := 0 80 for _, b := range s { 81 off += copy(dst[off:], b.ReadOnlyData()) 82 } 83 return off 84 } 85 86 // Materialize concatenates all the underlying Buffer's data into a single 87 // contiguous buffer using CopyTo. 88 func (s BufferSlice) Materialize() []byte { 89 l := s.Len() 90 if l == 0 { 91 return nil 92 } 93 out := make([]byte, l) 94 s.CopyTo(out) 95 return out 96 } 97 98 // MaterializeToBuffer functions like Materialize except that it writes the data 99 // to a single Buffer pulled from the given BufferPool. 100 // 101 // As a special case, if the input BufferSlice only actually has one Buffer, this 102 // function simply increases the refcount before returning said Buffer. Freeing this 103 // buffer won't release it until the BufferSlice is itself released. 104 func (s BufferSlice) MaterializeToBuffer(pool BufferPool) Buffer { 105 if len(s) == 1 { 106 s[0].Ref() 107 return s[0] 108 } 109 sLen := s.Len() 110 if sLen == 0 { 111 return emptyBuffer{} 112 } 113 buf := pool.Get(sLen) 114 s.CopyTo(*buf) 115 return NewBuffer(buf, pool) 116 } 117 118 // Reader returns a new Reader for the input slice after taking references to 119 // each underlying buffer. 120 func (s BufferSlice) Reader() Reader { 121 s.Ref() 122 return &sliceReader{ 123 data: s, 124 len: s.Len(), 125 } 126 } 127 128 // Reader exposes a BufferSlice's data as an io.Reader, allowing it to interface 129 // with other parts systems. It also provides an additional convenience method 130 // Remaining(), which returns the number of unread bytes remaining in the slice. 131 // Buffers will be freed as they are read. 132 type Reader interface { 133 io.Reader 134 io.ByteReader 135 // Close frees the underlying BufferSlice and never returns an error. Subsequent 136 // calls to Read will return (0, io.EOF). 137 Close() error 138 // Remaining returns the number of unread bytes remaining in the slice. 139 Remaining() int 140 // Reset frees the currently held buffer slice and starts reading from the 141 // provided slice. This allows reusing the reader object. 142 Reset(s BufferSlice) 143 } 144 145 type sliceReader struct { 146 data BufferSlice 147 len int 148 // The index into data[0].ReadOnlyData(). 149 bufferIdx int 150 } 151 152 func (r *sliceReader) Remaining() int { 153 return r.len 154 } 155 156 func (r *sliceReader) Reset(s BufferSlice) { 157 r.data.Free() 158 s.Ref() 159 r.data = s 160 r.len = s.Len() 161 r.bufferIdx = 0 162 } 163 164 func (r *sliceReader) Close() error { 165 r.data.Free() 166 r.data = nil 167 r.len = 0 168 return nil 169 } 170 171 func (r *sliceReader) freeFirstBufferIfEmpty() bool { 172 if len(r.data) == 0 || r.bufferIdx != len(r.data[0].ReadOnlyData()) { 173 return false 174 } 175 176 r.data[0].Free() 177 r.data = r.data[1:] 178 r.bufferIdx = 0 179 return true 180 } 181 182 func (r *sliceReader) Read(buf []byte) (n int, _ error) { 183 if r.len == 0 { 184 return 0, io.EOF 185 } 186 187 for len(buf) != 0 && r.len != 0 { 188 // Copy as much as possible from the first Buffer in the slice into the 189 // given byte slice. 190 data := r.data[0].ReadOnlyData() 191 copied := copy(buf, data[r.bufferIdx:]) 192 r.len -= copied // Reduce len by the number of bytes copied. 193 r.bufferIdx += copied // Increment the buffer index. 194 n += copied // Increment the total number of bytes read. 195 buf = buf[copied:] // Shrink the given byte slice. 196 197 // If we have copied all the data from the first Buffer, free it and advance to 198 // the next in the slice. 199 r.freeFirstBufferIfEmpty() 200 } 201 202 return n, nil 203 } 204 205 func (r *sliceReader) ReadByte() (byte, error) { 206 if r.len == 0 { 207 return 0, io.EOF 208 } 209 210 // There may be any number of empty buffers in the slice, clear them all until a 211 // non-empty buffer is reached. This is guaranteed to exit since r.len is not 0. 212 for r.freeFirstBufferIfEmpty() { 213 } 214 215 b := r.data[0].ReadOnlyData()[r.bufferIdx] 216 r.len-- 217 r.bufferIdx++ 218 // Free the first buffer in the slice if the last byte was read 219 r.freeFirstBufferIfEmpty() 220 return b, nil 221 } 222 223 var _ io.Writer = (*writer)(nil) 224 225 type writer struct { 226 buffers *BufferSlice 227 pool BufferPool 228 } 229 230 func (w *writer) Write(p []byte) (n int, err error) { 231 b := Copy(p, w.pool) 232 *w.buffers = append(*w.buffers, b) 233 return b.Len(), nil 234 } 235 236 // NewWriter wraps the given BufferSlice and BufferPool to implement the 237 // io.Writer interface. Every call to Write copies the contents of the given 238 // buffer into a new Buffer pulled from the given pool and the Buffer is 239 // added to the given BufferSlice. 240 func NewWriter(buffers *BufferSlice, pool BufferPool) io.Writer { 241 return &writer{buffers: buffers, pool: pool} 242 } 243 244 // ReadAll reads from r until an error or EOF and returns the data it read. 245 // A successful call returns err == nil, not err == EOF. Because ReadAll is 246 // defined to read from src until EOF, it does not treat an EOF from Read 247 // as an error to be reported. 248 // 249 // Important: A failed call returns a non-nil error and may also return 250 // partially read buffers. It is the responsibility of the caller to free the 251 // BufferSlice returned, or its memory will not be reused. 252 func ReadAll(r io.Reader, pool BufferPool) (BufferSlice, error) { 253 var result BufferSlice 254 if wt, ok := r.(io.WriterTo); ok { 255 // This is more optimal since wt knows the size of chunks it wants to 256 // write and, hence, we can allocate buffers of an optimal size to fit 257 // them. E.g. might be a single big chunk, and we wouldn't chop it 258 // into pieces. 259 w := NewWriter(&result, pool) 260 _, err := wt.WriteTo(w) 261 return result, err 262 } 263 nextBuffer: 264 for { 265 buf := pool.Get(readAllBufSize) 266 // We asked for 32KiB but may have been given a bigger buffer. 267 // Use all of it if that's the case. 268 *buf = (*buf)[:cap(*buf)] 269 usedCap := 0 270 for { 271 n, err := r.Read((*buf)[usedCap:]) 272 usedCap += n 273 if err != nil { 274 if usedCap == 0 { 275 // Nothing in this buf, put it back 276 pool.Put(buf) 277 } else { 278 *buf = (*buf)[:usedCap] 279 result = append(result, NewBuffer(buf, pool)) 280 } 281 if err == io.EOF { 282 err = nil 283 } 284 return result, err 285 } 286 if len(*buf) == usedCap { 287 result = append(result, NewBuffer(buf, pool)) 288 continue nextBuffer 289 } 290 } 291 } 292 }