gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/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  	"gvisor.dev/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.
   193  		if zero {
   194  			clear(v.chunk.data[v.write : v.write+sz])
   195  		}
   196  
   197  		// Advance the index.
   198  		v.Grow(sz)
   199  		b.size += int64(sz)
   200  	}
   201  }
   202  
   203  // Prepend prepends the given data. Prepend takes ownership of src.
   204  func (b *Buffer) Prepend(src *View) error {
   205  	if src == nil {
   206  		return nil
   207  	}
   208  	if src.Size() == 0 {
   209  		src.Release()
   210  		return nil
   211  	}
   212  	// If the first buffer does not have room just prepend the view.
   213  	v := b.data.Front()
   214  	if v == nil || v.read == 0 {
   215  		b.prependOwned(src)
   216  		return nil
   217  	}
   218  
   219  	// If there's room at the front and we won't incur a copy by writing to this
   220  	// view, fill in the extra room first.
   221  	if !v.sharesChunk() {
   222  		avail := v.read
   223  		vStart := 0
   224  		srcStart := src.Size() - avail
   225  		if avail > src.Size() {
   226  			vStart = avail - src.Size()
   227  			srcStart = 0
   228  		}
   229  		// Save the write index and restore it after.
   230  		old := v.write
   231  		v.read = vStart
   232  		n, err := v.WriteAt(src.AsSlice()[srcStart:], 0)
   233  		if err != nil {
   234  			return fmt.Errorf("could not write to view during append: %w", err)
   235  		}
   236  		b.size += int64(n)
   237  		v.write = old
   238  		src.write = srcStart
   239  
   240  		// If there's no more to be written, then we're done.
   241  		if src.Size() == 0 {
   242  			src.Release()
   243  			return nil
   244  		}
   245  	}
   246  
   247  	// Otherwise, just prepend the view.
   248  	b.prependOwned(src)
   249  	return nil
   250  }
   251  
   252  // Append appends the given data. Append takes ownership of src.
   253  func (b *Buffer) Append(src *View) error {
   254  	if src == nil {
   255  		return nil
   256  	}
   257  	if src.Size() == 0 {
   258  		src.Release()
   259  		return nil
   260  	}
   261  	// If the last buffer is full, just append the view.
   262  	v := b.data.Back()
   263  	if v.Full() {
   264  		b.appendOwned(src)
   265  		return nil
   266  	}
   267  
   268  	// If a write won't incur a copy, then fill the back of the existing last
   269  	// chunk.
   270  	if !v.sharesChunk() {
   271  		writeSz := src.Size()
   272  		if src.Size() > v.AvailableSize() {
   273  			writeSz = v.AvailableSize()
   274  		}
   275  		done, err := v.Write(src.AsSlice()[:writeSz])
   276  		if err != nil {
   277  			return fmt.Errorf("could not write to view during append: %w", err)
   278  		}
   279  		src.TrimFront(done)
   280  		b.size += int64(done)
   281  		if src.Size() == 0 {
   282  			src.Release()
   283  			return nil
   284  		}
   285  	}
   286  
   287  	// If there is still data left just append the src.
   288  	b.appendOwned(src)
   289  	return nil
   290  }
   291  
   292  func (b *Buffer) appendOwned(v *View) {
   293  	b.data.PushBack(v)
   294  	b.size += int64(v.Size())
   295  }
   296  
   297  func (b *Buffer) prependOwned(v *View) {
   298  	b.data.PushFront(v)
   299  	b.size += int64(v.Size())
   300  }
   301  
   302  // PullUp makes the specified range contiguous and returns the backing memory.
   303  func (b *Buffer) PullUp(offset, length int) (View, bool) {
   304  	if length == 0 {
   305  		return View{}, true
   306  	}
   307  	tgt := Range{begin: offset, end: offset + length}
   308  	if tgt.Intersect(Range{end: int(b.size)}).Len() != length {
   309  		return View{}, false
   310  	}
   311  
   312  	curr := Range{}
   313  	v := b.data.Front()
   314  	for ; v != nil; v = v.Next() {
   315  		origLen := v.Size()
   316  		curr.end = curr.begin + origLen
   317  
   318  		if x := curr.Intersect(tgt); x.Len() == tgt.Len() {
   319  			// buf covers the whole requested target range.
   320  			sub := x.Offset(-curr.begin)
   321  			// Don't increment the reference count of the underlying chunk. Views
   322  			// returned by PullUp are explicitly unowned and read only
   323  			new := View{
   324  				read:  v.read + sub.begin,
   325  				write: v.read + sub.end,
   326  				chunk: v.chunk,
   327  			}
   328  			return new, true
   329  		} else if x.Len() > 0 {
   330  			// buf is pointing at the starting buffer we want to merge.
   331  			break
   332  		}
   333  
   334  		curr.begin += origLen
   335  	}
   336  
   337  	// Calculate the total merged length.
   338  	totLen := 0
   339  	for n := v; n != nil; n = n.Next() {
   340  		totLen += n.Size()
   341  		if curr.begin+totLen >= tgt.end {
   342  			break
   343  		}
   344  	}
   345  
   346  	// Merge the buffers.
   347  	merged := NewViewSize(totLen)
   348  	off := 0
   349  	for n := v; n != nil && off < totLen; {
   350  		merged.WriteAt(n.AsSlice(), off)
   351  		off += n.Size()
   352  
   353  		// Remove buffers except for the first one, which will be reused.
   354  		if n == v {
   355  			n = n.Next()
   356  		} else {
   357  			old := n
   358  			n = n.Next()
   359  			b.removeView(old)
   360  		}
   361  	}
   362  	// Make data the first buffer.
   363  	b.data.InsertBefore(v, merged)
   364  	b.removeView(v)
   365  
   366  	r := tgt.Offset(-curr.begin)
   367  	pulled := View{
   368  		read:  r.begin,
   369  		write: r.end,
   370  		chunk: merged.chunk,
   371  	}
   372  	return pulled, true
   373  }
   374  
   375  // Flatten returns a flattened copy of this data.
   376  //
   377  // This method should not be used in any performance-sensitive paths. It may
   378  // allocate a fresh byte slice sufficiently large to contain all the data in
   379  // the buffer. This is principally for debugging.
   380  //
   381  // N.B. Tee data still belongs to this Buffer, as if there is a single buffer
   382  // present, then it will be returned directly. This should be used for
   383  // temporary use only, and a reference to the given slice should not be held.
   384  func (b *Buffer) Flatten() []byte {
   385  	if v := b.data.Front(); v == nil {
   386  		return nil // No data at all.
   387  	}
   388  	data := make([]byte, 0, b.size) // Need to flatten.
   389  	for v := b.data.Front(); v != nil; v = v.Next() {
   390  		// Copy to the allocated slice.
   391  		data = append(data, v.AsSlice()...)
   392  	}
   393  	return data
   394  }
   395  
   396  // Size indicates the total amount of data available in this Buffer.
   397  func (b *Buffer) Size() int64 {
   398  	return b.size
   399  }
   400  
   401  // AsViewList returns the ViewList backing b. Users may not save or modify the
   402  // ViewList returned.
   403  func (b *Buffer) AsViewList() ViewList {
   404  	return b.data
   405  }
   406  
   407  // Clone creates a copy-on-write clone of b. The underlying chunks are shared
   408  // until they are written to.
   409  func (b *Buffer) Clone() Buffer {
   410  	other := Buffer{
   411  		size: b.size,
   412  	}
   413  	for v := b.data.Front(); v != nil; v = v.Next() {
   414  		newView := v.Clone()
   415  		other.data.PushBack(newView)
   416  	}
   417  	return other
   418  }
   419  
   420  // DeepClone creates a deep clone of b, copying data such that no bytes are
   421  // shared with any other Buffers.
   422  func (b *Buffer) DeepClone() Buffer {
   423  	newBuf := Buffer{}
   424  	buf := b.Clone()
   425  	reader := buf.AsBufferReader()
   426  	newBuf.WriteFromReader(&reader, b.size)
   427  	return newBuf
   428  }
   429  
   430  // Apply applies the given function across all valid data.
   431  func (b *Buffer) Apply(fn func(*View)) {
   432  	for v := b.data.Front(); v != nil; v = v.Next() {
   433  		d := v.Clone()
   434  		fn(d)
   435  		d.Release()
   436  	}
   437  }
   438  
   439  // SubApply applies fn to a given range of data in b. Any part of the range
   440  // outside of b is ignored.
   441  func (b *Buffer) SubApply(offset, length int, fn func(*View)) {
   442  	for v := b.data.Front(); length > 0 && v != nil; v = v.Next() {
   443  		if offset >= v.Size() {
   444  			offset -= v.Size()
   445  			continue
   446  		}
   447  		d := v.Clone()
   448  		if offset > 0 {
   449  			d.TrimFront(offset)
   450  			offset = 0
   451  		}
   452  		if length < d.Size() {
   453  			d.write = d.read + length
   454  		}
   455  		fn(d)
   456  		length -= d.Size()
   457  		d.Release()
   458  	}
   459  }
   460  
   461  // Checksum calculates a checksum over the buffer's payload starting at offset.
   462  func (b *Buffer) Checksum(offset int) uint16 {
   463  	if offset >= int(b.size) {
   464  		return 0
   465  	}
   466  	var v *View
   467  	for v = b.data.Front(); v != nil && offset >= v.Size(); v = v.Next() {
   468  		offset -= v.Size()
   469  	}
   470  
   471  	var cs checksum.Checksumer
   472  	cs.Add(v.AsSlice()[offset:])
   473  	for v = v.Next(); v != nil; v = v.Next() {
   474  		cs.Add(v.AsSlice())
   475  	}
   476  	return cs.Checksum()
   477  }
   478  
   479  // Merge merges the provided Buffer with this one.
   480  //
   481  // The other Buffer will be appended to v, and other will be empty after this
   482  // operation completes.
   483  func (b *Buffer) Merge(other *Buffer) {
   484  	b.data.PushBackList(&other.data)
   485  	other.data = ViewList{}
   486  
   487  	// Adjust sizes.
   488  	b.size += other.size
   489  	other.size = 0
   490  }
   491  
   492  // WriteFromReader writes to the buffer from an io.Reader. A maximum read size
   493  // of MaxChunkSize is enforced to prevent allocating views from the heap.
   494  func (b *Buffer) WriteFromReader(r io.Reader, count int64) (int64, error) {
   495  	return b.WriteFromReaderAndLimitedReader(r, count, nil)
   496  }
   497  
   498  // WriteFromReaderAndLimitedReader is the same as WriteFromReader, but
   499  // optimized to avoid allocations if a LimitedReader is passed in.
   500  //
   501  // This function clobbers the values of lr.
   502  func (b *Buffer) WriteFromReaderAndLimitedReader(r io.Reader, count int64, lr *io.LimitedReader) (int64, error) {
   503  	if lr == nil {
   504  		lr = &io.LimitedReader{}
   505  	}
   506  
   507  	var done int64
   508  	for done < count {
   509  		vsize := count - done
   510  		if vsize > MaxChunkSize {
   511  			vsize = MaxChunkSize
   512  		}
   513  		v := NewView(int(vsize))
   514  		lr.R = r
   515  		lr.N = vsize
   516  		n, err := io.Copy(v, lr)
   517  		b.Append(v)
   518  		done += n
   519  		if err == io.EOF {
   520  			break
   521  		}
   522  		if err != nil {
   523  			return done, err
   524  		}
   525  	}
   526  	return done, nil
   527  }
   528  
   529  // ReadToWriter reads from the buffer into an io.Writer.
   530  //
   531  // N.B. This does not consume the bytes read. TrimFront should
   532  // be called appropriately after this call in order to do so.
   533  func (b *Buffer) ReadToWriter(w io.Writer, count int64) (int64, error) {
   534  	bytesLeft := int(count)
   535  	for v := b.data.Front(); v != nil && bytesLeft > 0; v = v.Next() {
   536  		view := v.Clone()
   537  		if view.Size() > bytesLeft {
   538  			view.CapLength(bytesLeft)
   539  		}
   540  		n, err := io.Copy(w, view)
   541  		bytesLeft -= int(n)
   542  		view.Release()
   543  		if err != nil {
   544  			return count - int64(bytesLeft), err
   545  		}
   546  	}
   547  	return count - int64(bytesLeft), nil
   548  }
   549  
   550  // read implements the io.Reader interface. This method is used by BufferReader
   551  // to consume its underlying buffer. To perform io operations on buffers
   552  // directly, use ReadToWriter or WriteToReader.
   553  func (b *Buffer) read(p []byte) (int, error) {
   554  	if len(p) == 0 {
   555  		return 0, nil
   556  	}
   557  	if b.Size() == 0 {
   558  		return 0, io.EOF
   559  	}
   560  	done := 0
   561  	v := b.data.Front()
   562  	for v != nil && done < len(p) {
   563  		n, err := v.Read(p[done:])
   564  		done += n
   565  		next := v.Next()
   566  		if v.Size() == 0 {
   567  			b.removeView(v)
   568  		}
   569  		b.size -= int64(n)
   570  		if err != nil && err != io.EOF {
   571  			return done, err
   572  		}
   573  		v = next
   574  	}
   575  	return done, nil
   576  }
   577  
   578  // readByte implements the io.ByteReader interface. This method is used by
   579  // BufferReader to consume its underlying buffer. To perform io operations on
   580  // buffers directly, use ReadToWriter or WriteToReader.
   581  func (b *Buffer) readByte() (byte, error) {
   582  	if b.Size() == 0 {
   583  		return 0, io.EOF
   584  	}
   585  	v := b.data.Front()
   586  	bt := v.AsSlice()[0]
   587  	b.TrimFront(1)
   588  	return bt, nil
   589  }
   590  
   591  // AsBufferReader returns the Buffer as a BufferReader capable of io methods.
   592  // The new BufferReader takes ownership of b.
   593  func (b *Buffer) AsBufferReader() BufferReader {
   594  	return BufferReader{b}
   595  }
   596  
   597  // BufferReader implements io methods on Buffer. Users must call Close()
   598  // when finished with the buffer to free the underlying memory.
   599  type BufferReader struct {
   600  	b *Buffer
   601  }
   602  
   603  // Read implements the io.Reader interface.
   604  func (br *BufferReader) Read(p []byte) (int, error) {
   605  	return br.b.read(p)
   606  }
   607  
   608  // ReadByte implements the io.ByteReader interface.
   609  func (br *BufferReader) ReadByte() (byte, error) {
   610  	return br.b.readByte()
   611  }
   612  
   613  // Close implements the io.Closer interface.
   614  func (br *BufferReader) Close() {
   615  	br.b.Release()
   616  }
   617  
   618  // Len returns the number of bytes in the unread portion of the buffer.
   619  func (br *BufferReader) Len() int {
   620  	return int(br.b.Size())
   621  }
   622  
   623  // Range specifies a range of buffer.
   624  type Range struct {
   625  	begin int
   626  	end   int
   627  }
   628  
   629  // Intersect returns the intersection of x and y.
   630  func (x Range) Intersect(y Range) Range {
   631  	if x.begin < y.begin {
   632  		x.begin = y.begin
   633  	}
   634  	if x.end > y.end {
   635  		x.end = y.end
   636  	}
   637  	if x.begin >= x.end {
   638  		return Range{}
   639  	}
   640  	return x
   641  }
   642  
   643  // Offset returns x offset by off.
   644  func (x Range) Offset(off int) Range {
   645  	x.begin += off
   646  	x.end += off
   647  	return x
   648  }
   649  
   650  // Len returns the length of x.
   651  func (x Range) Len() int {
   652  	l := x.end - x.begin
   653  	if l < 0 {
   654  		l = 0
   655  	}
   656  	return l
   657  }