github.com/pawelgaczynski/gain@v0.4.0-alpha.0.20230821120126-41f1e60a18da/pkg/buffer/magicring/ringbuffer.go (about) 1 // Copyright (c) 2023 Paweł Gaczyński 2 // Copyright (c) 2019 Chao yuepan, Andy Pan, Allen Xu 3 // 4 // Permission is hereby granted, free of charge, to any person obtaining a copy 5 // of this software and associated documentation files (the "Software"), to deal 6 // in the Software without restriction, including without limitation the rights 7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 // copies of the Software, and to permit persons to whom the Software is 9 // furnished to do so, subject to the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included in all 12 // copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 21 package magicring 22 23 import ( 24 "fmt" 25 "io" 26 "log" 27 "os" 28 "unsafe" 29 30 "github.com/pawelgaczynski/gain/pkg/errors" 31 "github.com/pawelgaczynski/gain/pkg/pool/virtualmem" 32 ) 33 34 var ( 35 DefaultMagicBufferSize = os.Getpagesize() 36 MinRead = 1024 37 ) 38 39 // RingBuffer is a circular buffer that implement io.ReaderWriter interface. 40 type RingBuffer struct { 41 vm *virtualmem.VirtualMem 42 43 Size int 44 r int // next position to read 45 w int // next position to write 46 isEmpty bool 47 } 48 49 func (rb *RingBuffer) ReadAddress() unsafe.Pointer { 50 return unsafe.Pointer(&rb.vm.Buf[rb.r]) 51 } 52 53 func (rb *RingBuffer) WriteAddress() unsafe.Pointer { 54 return unsafe.Pointer(&rb.vm.Buf[rb.w]) 55 } 56 57 func (rb *RingBuffer) Zeroes() { 58 for j := 0; j < rb.Size; j++ { 59 rb.vm.Buf[j] = 0 60 } 61 } 62 63 func (rb *RingBuffer) ReleaseBytes() { 64 virtualmem.Put(rb.vm) 65 } 66 67 func (rb *RingBuffer) Reset() { 68 rb.isEmpty = true 69 rb.r, rb.w = 0, 0 70 } 71 72 func (rb *RingBuffer) Read(buffer []byte) (int, error) { 73 if len(buffer) == 0 { 74 return 0, nil 75 } 76 77 if rb.isEmpty { 78 return 0, errors.ErrIsEmpty 79 } 80 81 bytesToWrite := rb.Buffered() 82 if bytesToWrite > len(buffer) { 83 bytesToWrite = len(buffer) 84 } 85 86 copy(buffer, rb.vm.Buf[rb.r:rb.r+bytesToWrite]) 87 88 rb.r = (rb.r + bytesToWrite) % rb.Size 89 if rb.r == rb.w { 90 rb.Reset() 91 } 92 93 return bytesToWrite, nil 94 } 95 96 func (rb *RingBuffer) Write(buffer []byte) (int, error) { 97 bytesToRead := len(buffer) 98 if bytesToRead == 0 { 99 return bytesToRead, nil 100 } 101 102 free := rb.Available() 103 if bytesToRead > free { 104 rb.Grow(rb.Size + bytesToRead - free) 105 } 106 107 copy(rb.vm.Buf[rb.w:], buffer) 108 rb.w = (rb.w + bytesToRead) % rb.Size 109 rb.isEmpty = false 110 111 return bytesToRead, nil 112 } 113 114 func (rb *RingBuffer) AdvanceWrite(bytesToAdvance int) { 115 if bytesToAdvance == 0 { 116 return 117 } 118 free := rb.Available() 119 rb.isEmpty = false 120 121 if bytesToAdvance > free { 122 log.Panicf("AdvanceWrite - bytesToAdvance (%d) is too large (free/size: %d/%d)", bytesToAdvance, free, rb.Size) 123 } 124 125 if rb.w+bytesToAdvance >= rb.Size { 126 m := rb.w + bytesToAdvance - rb.Size 127 rb.w = m 128 } else { 129 rb.w += bytesToAdvance 130 } 131 } 132 133 func (rb *RingBuffer) AdvanceRead(bytesToAdvance int) { 134 if bytesToAdvance == 0 { 135 return 136 } 137 138 buffered := rb.Buffered() 139 if bytesToAdvance > buffered { 140 log.Panic("n is too large: ", bytesToAdvance) 141 } 142 143 if rb.r+bytesToAdvance >= rb.Size { 144 m := rb.r + bytesToAdvance - rb.Size 145 rb.r = m 146 } else { 147 rb.r += bytesToAdvance 148 } 149 150 if rb.r == rb.w { 151 rb.Reset() 152 } 153 } 154 155 func (rb *RingBuffer) Grow(newCap int) { 156 newCap = virtualmem.AdjustBufferSize(newCap) 157 newBuf := virtualmem.Get(newCap) 158 oldLen := rb.Buffered() 159 _, _ = rb.Read(newBuf.Buf) 160 161 if rb.vm != nil && rb.vm.Buf != nil { 162 rb.ReleaseBytes() 163 } 164 rb.vm = newBuf 165 rb.r = 0 166 rb.w = oldLen 167 rb.Size = newCap 168 169 if rb.w > 0 { 170 rb.isEmpty = false 171 } 172 } 173 174 // Available returns the length of available bytes to write. 175 func (rb *RingBuffer) Available() int { 176 if rb.r == rb.w { 177 if rb.isEmpty { 178 return rb.Size 179 } 180 181 return 0 182 } 183 184 if rb.w < rb.r { 185 return rb.r - rb.w 186 } 187 188 return rb.Size - rb.w + rb.r 189 } 190 191 // Buffered returns the length of available bytes to read. 192 func (rb *RingBuffer) Buffered() int { 193 if rb.r == rb.w { 194 if rb.isEmpty { 195 return 0 196 } 197 198 return rb.Size 199 } 200 201 if rb.w > rb.r { 202 return rb.w - rb.r 203 } 204 205 return rb.Size - rb.r + rb.w 206 } 207 208 // IsFull tells if this ring-buffer is full. 209 func (rb *RingBuffer) IsFull() bool { 210 return rb.r == rb.w && !rb.isEmpty 211 } 212 213 // IsEmpty tells if this ring-buffer is empty. 214 func (rb *RingBuffer) IsEmpty() bool { 215 return rb.isEmpty 216 } 217 218 // Cap returns the size of the underlying buffer. 219 func (rb *RingBuffer) Cap() int { 220 return rb.Size 221 } 222 223 func (rb *RingBuffer) Next(nBytes int) ([]byte, error) { 224 bufferLen := rb.Buffered() 225 if nBytes > bufferLen { 226 return nil, io.ErrShortBuffer 227 } else if nBytes <= 0 { 228 nBytes = bufferLen 229 } 230 231 defer func() { 232 _ = rb.Discard(nBytes) 233 }() 234 235 return rb.vm.Buf[rb.r : rb.r+nBytes], nil 236 } 237 238 func (rb *RingBuffer) Peek(bytesToPeak int) []byte { 239 var buffer []byte 240 if rb.isEmpty { 241 return buffer 242 } 243 244 if bytesToPeak <= 0 { 245 return rb.peekAll() 246 } 247 248 bufferedBytes := rb.Buffered() // length of ring-buffer 249 if bufferedBytes > bytesToPeak { 250 bufferedBytes = bytesToPeak 251 } 252 253 return rb.vm.Buf[rb.r : rb.r+bufferedBytes] 254 } 255 256 func (rb *RingBuffer) peekAll() []byte { 257 var buffer []byte 258 if rb.isEmpty { 259 return buffer 260 } 261 262 return rb.vm.Buf[rb.r : rb.r+rb.Buffered()] 263 } 264 265 // Discard skips the next n bytes by advancing the read pointer. 266 func (rb *RingBuffer) Discard(bytesToDiscard int) int { 267 var discarded int 268 269 if bytesToDiscard == 0 { 270 return 0 271 } 272 273 discarded = rb.Buffered() 274 if bytesToDiscard < discarded { 275 rb.r = (rb.r + bytesToDiscard) % rb.Size 276 277 return bytesToDiscard 278 } 279 280 rb.Reset() 281 282 return discarded 283 } 284 285 // Bytes returns all available read bytes. It does not move the read pointer and only copy the available data. 286 func (rb *RingBuffer) Bytes() []byte { 287 if rb.isEmpty { 288 return nil 289 } 290 buffer := make([]byte, rb.Buffered()) 291 copy(buffer, rb.vm.Buf[rb.r:rb.r+rb.Buffered()]) 292 293 return buffer 294 } 295 296 func (rb *RingBuffer) WriteByte(c byte) error { 297 if rb.Available() < 1 { 298 rb.Grow(rb.Size + 1) 299 } 300 rb.vm.Buf[rb.w] = c 301 302 rb.w++ 303 if rb.w == rb.Size { 304 rb.w = 0 305 } 306 rb.isEmpty = false 307 308 return nil 309 } 310 311 // ReadByte reads and returns the next byte from the input or ErrIsEmpty. 312 func (rb *RingBuffer) ReadByte() (byte, error) { 313 if rb.isEmpty { 314 return 0, errors.ErrIsEmpty 315 } 316 byteRead := rb.vm.Buf[rb.r] 317 318 rb.r++ 319 if rb.r == rb.Size { 320 rb.r = 0 321 } 322 323 if rb.r == rb.w { 324 rb.Reset() 325 } 326 327 return byteRead, nil 328 } 329 330 func (rb *RingBuffer) GrowIfUnsufficientFreeSpace() { 331 if rb.Available() < MinRead { 332 rb.Grow(rb.Buffered() + MinRead) 333 } 334 } 335 336 // ReadFrom implements io.ReaderFrom. 337 func (rb *RingBuffer) ReadFrom(reader io.Reader) (int64, error) { 338 var ( 339 totalBytesRead int64 340 bytesRead int 341 err error 342 ) 343 344 for { 345 rb.GrowIfUnsufficientFreeSpace() 346 347 bytesRead, err = reader.Read(rb.vm.Buf[rb.w : rb.w+rb.Available()]) 348 if bytesRead < 0 { 349 log.Panic("RingBuffer.ReadFrom: reader returned negative count from Read") 350 } 351 rb.isEmpty = false 352 rb.w = (rb.w + bytesRead) % rb.Size 353 354 totalBytesRead += int64(bytesRead) 355 if err == io.EOF { 356 return totalBytesRead, nil 357 } 358 359 if err != nil { 360 return totalBytesRead, fmt.Errorf("reader Read error: %w", err) 361 } 362 } 363 } 364 365 // WriteTo implements io.WriterTo. 366 func (rb *RingBuffer) WriteTo(writer io.Writer) (int64, error) { 367 if rb.isEmpty { 368 return 0, errors.ErrIsEmpty 369 } 370 bufferedBytes := rb.Buffered() 371 372 bytesWritten, err := writer.Write(rb.vm.Buf[rb.r : rb.r+bufferedBytes]) 373 if bytesWritten > bufferedBytes { 374 log.Panicf("RingBuffer.WriteTo: invalid Write count [m > n | m: %d, n: %d]", bytesWritten, bufferedBytes) 375 } 376 377 rb.r = (rb.r + bytesWritten) % rb.Size 378 if rb.r == rb.w { 379 rb.Reset() 380 } 381 382 if err != nil { 383 return int64(bytesWritten), err 384 } 385 386 if !rb.isEmpty { 387 return int64(bytesWritten), io.ErrShortWrite 388 } 389 390 return int64(bytesWritten), nil 391 } 392 393 // New returns a new Buffer whose buffer has the given size. 394 func NewMagicBuffer(size int) *RingBuffer { 395 if size == 0 { 396 return &RingBuffer{isEmpty: true} 397 } 398 size = virtualmem.AdjustBufferSize(size) 399 buffer := &RingBuffer{ 400 vm: virtualmem.Get(size), 401 Size: size, 402 isEmpty: true, 403 } 404 405 return buffer 406 }