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  }