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 }