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 }