github.com/metacubex/gvisor@v0.0.0-20240320004321-933faba989ec/pkg/buffer/buffer.go (about)

     1  // Copyright 2022 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package buffer provides the implementation of a non-contiguous buffer that
    16  // is reference counted, pooled, and copy-on-write. It allows O(1) append,
    17  // and prepend operations.
    18  package buffer
    19  
    20  import (
    21  	"fmt"
    22  	"io"
    23  
    24  	"github.com/metacubex/gvisor/pkg/tcpip/checksum"
    25  )
    26  
    27  // Buffer is a non-linear buffer.
    28  //
    29  // +stateify savable
    30  type Buffer struct {
    31  	data ViewList `state:".([]byte)"`
    32  	size int64
    33  }
    34  
    35  func (b *Buffer) removeView(v *View) {
    36  	b.data.Remove(v)
    37  	v.Release()
    38  }
    39  
    40  // MakeWithData creates a new Buffer initialized with given data. This function
    41  // should be used with caution to avoid unnecessary []byte allocations. When in
    42  // doubt use NewWithView to maximize chunk reuse.
    43  func MakeWithData(b []byte) Buffer {
    44  	buf := Buffer{}
    45  	if len(b) == 0 {
    46  		return buf
    47  	}
    48  	v := NewViewWithData(b)
    49  	buf.Append(v)
    50  	return buf
    51  }
    52  
    53  // MakeWithView creates a new Buffer initialized with given view. This function
    54  // takes ownership of v.
    55  func MakeWithView(v *View) Buffer {
    56  	if v == nil {
    57  		return Buffer{}
    58  	}
    59  	b := Buffer{
    60  		size: int64(v.Size()),
    61  	}
    62  	if b.size == 0 {
    63  		v.Release()
    64  		return b
    65  	}
    66  	b.data.PushBack(v)
    67  	return b
    68  }
    69  
    70  // Release frees all resources held by b.
    71  func (b *Buffer) Release() {
    72  	for v := b.data.Front(); v != nil; v = b.data.Front() {
    73  		b.removeView(v)
    74  	}
    75  	b.size = 0
    76  }
    77  
    78  // TrimFront removes the first count bytes from the buffer.
    79  func (b *Buffer) TrimFront(count int64) {
    80  	if count >= b.size {
    81  		b.advanceRead(b.size)
    82  	} else {
    83  		b.advanceRead(count)
    84  	}
    85  }
    86  
    87  // ReadAt implements io.ReaderAt.ReadAt.
    88  func (b *Buffer) ReadAt(p []byte, offset int64) (int, error) {
    89  	var (
    90  		skipped int64
    91  		done    int64
    92  	)
    93  	for v := b.data.Front(); v != nil && done < int64(len(p)); v = v.Next() {
    94  		needToSkip := int(offset - skipped)
    95  		if sz := v.Size(); sz <= needToSkip {
    96  			skipped += int64(sz)
    97  			continue
    98  		}
    99  
   100  		// Actually read data.
   101  		n := copy(p[done:], v.AsSlice()[needToSkip:])
   102  		skipped += int64(needToSkip)
   103  		done += int64(n)
   104  	}
   105  	if int(done) < len(p) || offset+done == b.size {
   106  		return int(done), io.EOF
   107  	}
   108  	return int(done), nil
   109  }
   110  
   111  // advanceRead advances the Buffer's read index.
   112  //
   113  // Precondition: there must be sufficient bytes in the buffer.
   114  func (b *Buffer) advanceRead(count int64) {
   115  	for v := b.data.Front(); v != nil && count > 0; {
   116  		sz := int64(v.Size())
   117  		if sz > count {
   118  			// There is still data for reading.
   119  			v.TrimFront(int(count))
   120  			b.size -= count
   121  			count = 0
   122  			return
   123  		}
   124  
   125  		// Consume the whole view.
   126  		oldView := v
   127  		v = v.Next() // Iterate.
   128  		b.removeView(oldView)
   129  
   130  		// Update counts.
   131  		count -= sz
   132  		b.size -= sz
   133  	}
   134  	if count > 0 {
   135  		panic(fmt.Sprintf("advanceRead still has %d bytes remaining", count))
   136  	}
   137  }
   138  
   139  // Truncate truncates the Buffer to the given length.
   140  //
   141  // This will not grow the Buffer, only shrink it. If a length is passed that is
   142  // greater than the current size of the Buffer, then nothing will happen.
   143  //
   144  // Precondition: length must be >= 0.
   145  func (b *Buffer) Truncate(length int64) {
   146  	if length < 0 {
   147  		panic("negative length provided")
   148  	}
   149  	if length >= b.size {
   150  		return // Nothing to do.
   151  	}
   152  	for v := b.data.Back(); v != nil && b.size > length; v = b.data.Back() {
   153  		sz := int64(v.Size())
   154  		if after := b.size - sz; after < length {
   155  			// Truncate the buffer locally.
   156  			left := (length - after)
   157  			v.write = v.read + int(left)
   158  			b.size = length
   159  			break
   160  		}
   161  
   162  		// Drop the buffer completely; see above.
   163  		b.removeView(v)
   164  		b.size -= sz
   165  	}
   166  }
   167  
   168  // GrowTo grows the given Buffer to the number of bytes, which will be appended.
   169  // If zero is true, all these bytes will be zero. If zero is false, then this is
   170  // the caller's responsibility.
   171  //
   172  // Precondition: length must be >= 0.
   173  func (b *Buffer) GrowTo(length int64, zero bool) {
   174  	if length < 0 {
   175  		panic("negative length provided")
   176  	}
   177  	for b.size < length {
   178  		v := b.data.Back()
   179  
   180  		// Is there some space in the last buffer?
   181  		if v.Full() {
   182  			v = NewView(int(length - b.size))
   183  			b.data.PushBack(v)
   184  		}
   185  
   186  		// Write up to length bytes.
   187  		sz := v.AvailableSize()
   188  		if int64(sz) > length-b.size {
   189  			sz = int(length - b.size)
   190  		}
   191  
   192  		// Zero the written section; note that this pattern is
   193  		// specifically recognized and optimized by the compiler.
   194  		if zero {
   195  			for i := v.write; i < v.write+sz; i++ {
   196  				v.chunk.data[i] = 0
   197  			}
   198  		}
   199  
   200  		// Advance the index.
   201  		v.Grow(sz)
   202  		b.size += int64(sz)
   203  	}
   204  }
   205  
   206  // Prepend prepends the given data. Prepend takes ownership of src.
   207  func (b *Buffer) Prepend(src *View) error {
   208  	if src == nil {
   209  		return nil
   210  	}
   211  	if src.Size() == 0 {
   212  		src.Release()
   213  		return nil
   214  	}
   215  	// If the first buffer does not have room just prepend the view.
   216  	v := b.data.Front()
   217  	if v == nil || v.read == 0 {
   218  		b.prependOwned(src)
   219  		return nil
   220  	}
   221  
   222  	// If there's room at the front and we won't incur a copy by writing to this
   223  	// view, fill in the extra room first.
   224  	if !v.sharesChunk() {
   225  		avail := v.read
   226  		vStart := 0
   227  		srcStart := src.Size() - avail
   228  		if avail > src.Size() {
   229  			vStart = avail - src.Size()
   230  			srcStart = 0
   231  		}
   232  		// Save the write index and restore it after.
   233  		old := v.write
   234  		v.read = vStart
   235  		n, err := v.WriteAt(src.AsSlice()[srcStart:], 0)
   236  		if err != nil {
   237  			return fmt.Errorf("could not write to view during append: %w", err)
   238  		}
   239  		b.size += int64(n)
   240  		v.write = old
   241  		src.write = srcStart
   242  
   243  		// If there's no more to be written, then we're done.
   244  		if src.Size() == 0 {
   245  			src.Release()
   246  			return nil
   247  		}
   248  	}
   249  
   250  	// Otherwise, just prepend the view.
   251  	b.prependOwned(src)
   252  	return nil
   253  }
   254  
   255  // Append appends the given data. Append takes ownership of src.
   256  func (b *Buffer) Append(src *View) error {
   257  	if src == nil {
   258  		return nil
   259  	}
   260  	if src.Size() == 0 {
   261  		src.Release()
   262  		return nil
   263  	}
   264  	// If the last buffer is full, just append the view.
   265  	v := b.data.Back()
   266  	if v.Full() {
   267  		b.appendOwned(src)
   268  		return nil
   269  	}
   270  
   271  	// If a write won't incur a copy, then fill the back of the existing last
   272  	// chunk.
   273  	if !v.sharesChunk() {
   274  		writeSz := src.Size()
   275  		if src.Size() > v.AvailableSize() {
   276  			writeSz = v.AvailableSize()
   277  		}
   278  		done, err := v.Write(src.AsSlice()[:writeSz])
   279  		if err != nil {
   280  			return fmt.Errorf("could not write to view during append: %w", err)
   281  		}
   282  		src.TrimFront(done)
   283  		b.size += int64(done)
   284  		if src.Size() == 0 {
   285  			src.Release()
   286  			return nil
   287  		}
   288  	}
   289  
   290  	// If there is still data left just append the src.
   291  	b.appendOwned(src)
   292  	return nil
   293  }
   294  
   295  func (b *Buffer) appendOwned(v *View) {
   296  	b.data.PushBack(v)
   297  	b.size += int64(v.Size())
   298  }
   299  
   300  func (b *Buffer) prependOwned(v *View) {
   301  	b.data.PushFront(v)
   302  	b.size += int64(v.Size())
   303  }
   304  
   305  // PullUp makes the specified range contiguous and returns the backing memory.
   306  func (b *Buffer) PullUp(offset, length int) (View, bool) {
   307  	if length == 0 {
   308  		return View{}, true
   309  	}
   310  	tgt := Range{begin: offset, end: offset + length}
   311  	if tgt.Intersect(Range{end: int(b.size)}).Len() != length {
   312  		return View{}, false
   313  	}
   314  
   315  	curr := Range{}
   316  	v := b.data.Front()
   317  	for ; v != nil; v = v.Next() {
   318  		origLen := v.Size()
   319  		curr.end = curr.begin + origLen
   320  
   321  		if x := curr.Intersect(tgt); x.Len() == tgt.Len() {
   322  			// buf covers the whole requested target range.
   323  			sub := x.Offset(-curr.begin)
   324  			// Don't increment the reference count of the underlying chunk. Views
   325  			// returned by PullUp are explicitly unowned and read only
   326  			new := View{
   327  				read:  v.read + sub.begin,
   328  				write: v.read + sub.end,
   329  				chunk: v.chunk,
   330  			}
   331  			return new, true
   332  		} else if x.Len() > 0 {
   333  			// buf is pointing at the starting buffer we want to merge.
   334  			break
   335  		}
   336  
   337  		curr.begin += origLen
   338  	}
   339  
   340  	// Calculate the total merged length.
   341  	totLen := 0
   342  	for n := v; n != nil; n = n.Next() {
   343  		totLen += n.Size()
   344  		if curr.begin+totLen >= tgt.end {
   345  			break
   346  		}
   347  	}
   348  
   349  	// Merge the buffers.
   350  	merged := NewViewSize(totLen)
   351  	off := 0
   352  	for n := v; n != nil && off < totLen; {
   353  		merged.WriteAt(n.AsSlice(), off)
   354  		off += n.Size()
   355  
   356  		// Remove buffers except for the first one, which will be reused.
   357  		if n == v {
   358  			n = n.Next()
   359  		} else {
   360  			old := n
   361  			n = n.Next()
   362  			b.removeView(old)
   363  		}
   364  	}
   365  	// Make data the first buffer.
   366  	b.data.InsertBefore(v, merged)
   367  	b.removeView(v)
   368  
   369  	r := tgt.Offset(-curr.begin)
   370  	pulled := View{
   371  		read:  r.begin,
   372  		write: r.end,
   373  		chunk: merged.chunk,
   374  	}
   375  	return pulled, true
   376  }
   377  
   378  // Flatten returns a flattened copy of this data.
   379  //
   380  // This method should not be used in any performance-sensitive paths. It may
   381  // allocate a fresh byte slice sufficiently large to contain all the data in
   382  // the buffer. This is principally for debugging.
   383  //
   384  // N.B. Tee data still belongs to this Buffer, as if there is a single buffer
   385  // present, then it will be returned directly. This should be used for
   386  // temporary use only, and a reference to the given slice should not be held.
   387  func (b *Buffer) Flatten() []byte {
   388  	if v := b.data.Front(); v == nil {
   389  		return nil // No data at all.
   390  	}
   391  	data := make([]byte, 0, b.size) // Need to flatten.
   392  	for v := b.data.Front(); v != nil; v = v.Next() {
   393  		// Copy to the allocated slice.
   394  		data = append(data, v.AsSlice()...)
   395  	}
   396  	return data
   397  }
   398  
   399  // Size indicates the total amount of data available in this Buffer.
   400  func (b *Buffer) Size() int64 {
   401  	return b.size
   402  }
   403  
   404  // AsViewList returns the ViewList backing b. Users may not save or modify the
   405  // ViewList returned.
   406  func (b *Buffer) AsViewList() ViewList {
   407  	return b.data
   408  }
   409  
   410  // Clone creates a copy-on-write clone of b. The underlying chunks are shared
   411  // until they are written to.
   412  func (b *Buffer) Clone() Buffer {
   413  	other := Buffer{
   414  		size: b.size,
   415  	}
   416  	for v := b.data.Front(); v != nil; v = v.Next() {
   417  		newView := v.Clone()
   418  		other.data.PushBack(newView)
   419  	}
   420  	return other
   421  }
   422  
   423  // DeepClone creates a deep clone of b, copying data such that no bytes are
   424  // shared with any other Buffers.
   425  func (b *Buffer) DeepClone() Buffer {
   426  	newBuf := Buffer{}
   427  	buf := b.Clone()
   428  	reader := buf.AsBufferReader()
   429  	newBuf.WriteFromReader(&reader, b.size)
   430  	return newBuf
   431  }
   432  
   433  // Apply applies the given function across all valid data.
   434  func (b *Buffer) Apply(fn func(*View)) {
   435  	for v := b.data.Front(); v != nil; v = v.Next() {
   436  		d := v.Clone()
   437  		fn(d)
   438  		d.Release()
   439  	}
   440  }
   441  
   442  // SubApply applies fn to a given range of data in b. Any part of the range
   443  // outside of b is ignored.
   444  func (b *Buffer) SubApply(offset, length int, fn func(*View)) {
   445  	for v := b.data.Front(); length > 0 && v != nil; v = v.Next() {
   446  		if offset >= v.Size() {
   447  			offset -= v.Size()
   448  			continue
   449  		}
   450  		d := v.Clone()
   451  		if offset > 0 {
   452  			d.TrimFront(offset)
   453  			offset = 0
   454  		}
   455  		if length < d.Size() {
   456  			d.write = d.read + length
   457  		}
   458  		fn(d)
   459  		length -= d.Size()
   460  		d.Release()
   461  	}
   462  }
   463  
   464  // Checksum calculates a checksum over the buffer's payload starting at offset.
   465  func (b *Buffer) Checksum(offset int) uint16 {
   466  	if offset >= int(b.size) {
   467  		return 0
   468  	}
   469  	var v *View
   470  	for v = b.data.Front(); v != nil && offset >= v.Size(); v = v.Next() {
   471  		offset -= v.Size()
   472  	}
   473  
   474  	var cs checksum.Checksumer
   475  	cs.Add(v.AsSlice()[offset:])
   476  	for v = v.Next(); v != nil; v = v.Next() {
   477  		cs.Add(v.AsSlice())
   478  	}
   479  	return cs.Checksum()
   480  }
   481  
   482  // Merge merges the provided Buffer with this one.
   483  //
   484  // The other Buffer will be appended to v, and other will be empty after this
   485  // operation completes.
   486  func (b *Buffer) Merge(other *Buffer) {
   487  	b.data.PushBackList(&other.data)
   488  	other.data = ViewList{}
   489  
   490  	// Adjust sizes.
   491  	b.size += other.size
   492  	other.size = 0
   493  }
   494  
   495  // WriteFromReader writes to the buffer from an io.Reader. A maximum read size
   496  // of MaxChunkSize is enforced to prevent allocating views from the heap.
   497  func (b *Buffer) WriteFromReader(r io.Reader, count int64) (int64, error) {
   498  	var done int64
   499  	for done < count {
   500  		vsize := count - done
   501  		if vsize > MaxChunkSize {
   502  			vsize = MaxChunkSize
   503  		}
   504  		v := NewView(int(vsize))
   505  		lr := io.LimitedReader{R: r, N: vsize}
   506  		n, err := io.Copy(v, &lr)
   507  		b.Append(v)
   508  		done += n
   509  		if err == io.EOF {
   510  			break
   511  		}
   512  		if err != nil {
   513  			return done, err
   514  		}
   515  	}
   516  	return done, nil
   517  }
   518  
   519  // ReadToWriter reads from the buffer into an io.Writer.
   520  //
   521  // N.B. This does not consume the bytes read. TrimFront should
   522  // be called appropriately after this call in order to do so.
   523  func (b *Buffer) ReadToWriter(w io.Writer, count int64) (int64, error) {
   524  	bytesLeft := int(count)
   525  	for v := b.data.Front(); v != nil && bytesLeft > 0; v = v.Next() {
   526  		view := v.Clone()
   527  		if view.Size() > bytesLeft {
   528  			view.CapLength(bytesLeft)
   529  		}
   530  		n, err := io.Copy(w, view)
   531  		bytesLeft -= int(n)
   532  		view.Release()
   533  		if err != nil {
   534  			return count - int64(bytesLeft), err
   535  		}
   536  	}
   537  	return count - int64(bytesLeft), nil
   538  }
   539  
   540  // read implements the io.Reader interface. This method is used by BufferReader
   541  // to consume its underlying buffer. To perform io operations on buffers
   542  // directly, use ReadToWriter or WriteToReader.
   543  func (b *Buffer) read(p []byte) (int, error) {
   544  	if len(p) == 0 {
   545  		return 0, nil
   546  	}
   547  	if b.Size() == 0 {
   548  		return 0, io.EOF
   549  	}
   550  	done := 0
   551  	v := b.data.Front()
   552  	for v != nil && done < len(p) {
   553  		n, err := v.Read(p[done:])
   554  		done += n
   555  		next := v.Next()
   556  		if v.Size() == 0 {
   557  			b.removeView(v)
   558  		}
   559  		b.size -= int64(n)
   560  		if err != nil && err != io.EOF {
   561  			return done, err
   562  		}
   563  		v = next
   564  	}
   565  	return done, nil
   566  }
   567  
   568  // readByte implements the io.ByteReader interface. This method is used by
   569  // BufferReader to consume its underlying buffer. To perform io operations on
   570  // buffers directly, use ReadToWriter or WriteToReader.
   571  func (b *Buffer) readByte() (byte, error) {
   572  	if b.Size() == 0 {
   573  		return 0, io.EOF
   574  	}
   575  	v := b.data.Front()
   576  	bt := v.AsSlice()[0]
   577  	b.TrimFront(1)
   578  	return bt, nil
   579  }
   580  
   581  // AsBufferReader returns the Buffer as a BufferReader capable of io methods.
   582  // The new BufferReader takes ownership of b.
   583  func (b *Buffer) AsBufferReader() BufferReader {
   584  	return BufferReader{b}
   585  }
   586  
   587  // BufferReader implements io methods on Buffer. Users must call Close()
   588  // when finished with the buffer to free the underlying memory.
   589  type BufferReader struct {
   590  	b *Buffer
   591  }
   592  
   593  // Read implements the io.Reader interface.
   594  func (br *BufferReader) Read(p []byte) (int, error) {
   595  	return br.b.read(p)
   596  }
   597  
   598  // ReadByte implements the io.ByteReader interface.
   599  func (br *BufferReader) ReadByte() (byte, error) {
   600  	return br.b.readByte()
   601  }
   602  
   603  // Close implements the io.Closer interface.
   604  func (br *BufferReader) Close() {
   605  	br.b.Release()
   606  }
   607  
   608  // Len returns the number of bytes in the unread portion of the buffer.
   609  func (br *BufferReader) Len() int {
   610  	return int(br.b.Size())
   611  }
   612  
   613  // Range specifies a range of buffer.
   614  type Range struct {
   615  	begin int
   616  	end   int
   617  }
   618  
   619  // Intersect returns the intersection of x and y.
   620  func (x Range) Intersect(y Range) Range {
   621  	if x.begin < y.begin {
   622  		x.begin = y.begin
   623  	}
   624  	if x.end > y.end {
   625  		x.end = y.end
   626  	}
   627  	if x.begin >= x.end {
   628  		return Range{}
   629  	}
   630  	return x
   631  }
   632  
   633  // Offset returns x offset by off.
   634  func (x Range) Offset(off int) Range {
   635  	x.begin += off
   636  	x.end += off
   637  	return x
   638  }
   639  
   640  // Len returns the length of x.
   641  func (x Range) Len() int {
   642  	l := x.end - x.begin
   643  	if l < 0 {
   644  		l = 0
   645  	}
   646  	return l
   647  }