github.com/rbisecke/kafka-go@v0.4.27/protocol/buffer.go (about) 1 package protocol 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 "math" 8 "sync" 9 "sync/atomic" 10 ) 11 12 // Bytes is an interface implemented by types that represent immutable 13 // sequences of bytes. 14 // 15 // Bytes values are used to abstract the location where record keys and 16 // values are read from (e.g. in-memory buffers, network sockets, files). 17 // 18 // The Close method should be called to release resources held by the object 19 // when the program is done with it. 20 // 21 // Bytes values are generally not safe to use concurrently from multiple 22 // goroutines. 23 type Bytes interface { 24 io.ReadCloser 25 // Returns the number of bytes remaining to be read from the payload. 26 Len() int 27 } 28 29 // NewBytes constructs a Bytes value from b. 30 // 31 // The returned value references b, it does not make a copy of the backing 32 // array. 33 // 34 // If b is nil, nil is returned to represent a null BYTES value in the kafka 35 // protocol. 36 func NewBytes(b []byte) Bytes { 37 if b == nil { 38 return nil 39 } 40 r := new(bytesReader) 41 r.Reset(b) 42 return r 43 } 44 45 // ReadAll is similar to ioutil.ReadAll, but it takes advantage of knowing the 46 // length of b to minimize the memory footprint. 47 // 48 // The function returns a nil slice if b is nil. 49 func ReadAll(b Bytes) ([]byte, error) { 50 if b == nil { 51 return nil, nil 52 } 53 s := make([]byte, b.Len()) 54 _, err := io.ReadFull(b, s) 55 return s, err 56 } 57 58 type bytesReader struct{ bytes.Reader } 59 60 func (*bytesReader) Close() error { return nil } 61 62 type refCount uintptr 63 64 func (rc *refCount) ref() { atomic.AddUintptr((*uintptr)(rc), 1) } 65 66 func (rc *refCount) unref(onZero func()) { 67 if atomic.AddUintptr((*uintptr)(rc), ^uintptr(0)) == 0 { 68 onZero() 69 } 70 } 71 72 const ( 73 // Size of the memory buffer for a single page. We use a farily 74 // large size here (64 KiB) because batches exchanged with kafka 75 // tend to be multiple kilobytes in size, sometimes hundreds. 76 // Using large pages amortizes the overhead of the page metadata 77 // and algorithms to manage the pages. 78 pageSize = 65536 79 ) 80 81 type page struct { 82 refc refCount 83 offset int64 84 length int 85 buffer *[pageSize]byte 86 } 87 88 func newPage(offset int64) *page { 89 p, _ := pagePool.Get().(*page) 90 if p != nil { 91 p.offset = offset 92 p.length = 0 93 p.ref() 94 } else { 95 p = &page{ 96 refc: 1, 97 offset: offset, 98 buffer: &[pageSize]byte{}, 99 } 100 } 101 return p 102 } 103 104 func (p *page) ref() { p.refc.ref() } 105 106 func (p *page) unref() { p.refc.unref(func() { pagePool.Put(p) }) } 107 108 func (p *page) slice(begin, end int64) []byte { 109 i, j := begin-p.offset, end-p.offset 110 111 if i < 0 { 112 i = 0 113 } else if i > pageSize { 114 i = pageSize 115 } 116 117 if j < 0 { 118 j = 0 119 } else if j > pageSize { 120 j = pageSize 121 } 122 123 if i < j { 124 return p.buffer[i:j] 125 } 126 127 return nil 128 } 129 130 func (p *page) Cap() int { return pageSize } 131 132 func (p *page) Len() int { return p.length } 133 134 func (p *page) Size() int64 { return int64(p.length) } 135 136 func (p *page) Truncate(n int) { 137 if n < p.length { 138 p.length = n 139 } 140 } 141 142 func (p *page) ReadAt(b []byte, off int64) (int, error) { 143 if off -= p.offset; off < 0 || off > pageSize { 144 panic("offset out of range") 145 } 146 if off > int64(p.length) { 147 return 0, nil 148 } 149 return copy(b, p.buffer[off:p.length]), nil 150 } 151 152 func (p *page) ReadFrom(r io.Reader) (int64, error) { 153 n, err := io.ReadFull(r, p.buffer[p.length:]) 154 if err == io.EOF || err == io.ErrUnexpectedEOF { 155 err = nil 156 } 157 p.length += n 158 return int64(n), err 159 } 160 161 func (p *page) WriteAt(b []byte, off int64) (int, error) { 162 if off -= p.offset; off < 0 || off > pageSize { 163 panic("offset out of range") 164 } 165 n := copy(p.buffer[off:], b) 166 if end := int(off) + n; end > p.length { 167 p.length = end 168 } 169 return n, nil 170 } 171 172 func (p *page) Write(b []byte) (int, error) { 173 return p.WriteAt(b, p.offset+int64(p.length)) 174 } 175 176 var ( 177 _ io.ReaderAt = (*page)(nil) 178 _ io.ReaderFrom = (*page)(nil) 179 _ io.Writer = (*page)(nil) 180 _ io.WriterAt = (*page)(nil) 181 ) 182 183 type pageBuffer struct { 184 refc refCount 185 pages contiguousPages 186 length int 187 cursor int 188 } 189 190 func newPageBuffer() *pageBuffer { 191 b, _ := pageBufferPool.Get().(*pageBuffer) 192 if b != nil { 193 b.cursor = 0 194 b.refc.ref() 195 } else { 196 b = &pageBuffer{ 197 refc: 1, 198 pages: make(contiguousPages, 0, 16), 199 } 200 } 201 return b 202 } 203 204 func (pb *pageBuffer) refTo(ref *pageRef, begin, end int64) { 205 length := end - begin 206 207 if length > math.MaxUint32 { 208 panic("reference to contiguous buffer pages exceeds the maximum size of 4 GB") 209 } 210 211 ref.pages = append(ref.buffer[:0], pb.pages.slice(begin, end)...) 212 ref.pages.ref() 213 ref.offset = begin 214 ref.length = uint32(length) 215 } 216 217 func (pb *pageBuffer) ref(begin, end int64) *pageRef { 218 ref := new(pageRef) 219 pb.refTo(ref, begin, end) 220 return ref 221 } 222 223 func (pb *pageBuffer) unref() { 224 pb.refc.unref(func() { 225 pb.pages.unref() 226 pb.pages.clear() 227 pb.pages = pb.pages[:0] 228 pb.length = 0 229 pageBufferPool.Put(pb) 230 }) 231 } 232 233 func (pb *pageBuffer) newPage() *page { 234 return newPage(int64(pb.length)) 235 } 236 237 func (pb *pageBuffer) Close() error { 238 return nil 239 } 240 241 func (pb *pageBuffer) Len() int { 242 return pb.length - pb.cursor 243 } 244 245 func (pb *pageBuffer) Size() int64 { 246 return int64(pb.length) 247 } 248 249 func (pb *pageBuffer) Discard(n int) (int, error) { 250 remain := pb.length - pb.cursor 251 if remain < n { 252 n = remain 253 } 254 pb.cursor += n 255 return n, nil 256 } 257 258 func (pb *pageBuffer) Truncate(n int) { 259 if n < pb.length { 260 pb.length = n 261 262 if n < pb.cursor { 263 pb.cursor = n 264 } 265 266 for i := range pb.pages { 267 if p := pb.pages[i]; p.length <= n { 268 n -= p.length 269 } else { 270 if n > 0 { 271 pb.pages[i].Truncate(n) 272 i++ 273 } 274 pb.pages[i:].unref() 275 pb.pages[i:].clear() 276 pb.pages = pb.pages[:i] 277 break 278 } 279 } 280 } 281 } 282 283 func (pb *pageBuffer) Seek(offset int64, whence int) (int64, error) { 284 c, err := seek(int64(pb.cursor), int64(pb.length), offset, whence) 285 if err != nil { 286 return -1, err 287 } 288 pb.cursor = int(c) 289 return c, nil 290 } 291 292 func (pb *pageBuffer) ReadByte() (byte, error) { 293 b := [1]byte{} 294 _, err := pb.Read(b[:]) 295 return b[0], err 296 } 297 298 func (pb *pageBuffer) Read(b []byte) (int, error) { 299 if pb.cursor >= pb.length { 300 return 0, io.EOF 301 } 302 n, err := pb.ReadAt(b, int64(pb.cursor)) 303 pb.cursor += n 304 return n, err 305 } 306 307 func (pb *pageBuffer) ReadAt(b []byte, off int64) (int, error) { 308 return pb.pages.ReadAt(b, off) 309 } 310 311 func (pb *pageBuffer) ReadFrom(r io.Reader) (int64, error) { 312 if len(pb.pages) == 0 { 313 pb.pages = append(pb.pages, pb.newPage()) 314 } 315 316 rn := int64(0) 317 318 for { 319 tail := pb.pages[len(pb.pages)-1] 320 free := tail.Cap() - tail.Len() 321 322 if free == 0 { 323 tail = pb.newPage() 324 free = pageSize 325 pb.pages = append(pb.pages, tail) 326 } 327 328 n, err := tail.ReadFrom(r) 329 pb.length += int(n) 330 rn += n 331 if n < int64(free) { 332 return rn, err 333 } 334 } 335 } 336 337 func (pb *pageBuffer) WriteString(s string) (int, error) { 338 return pb.Write([]byte(s)) 339 } 340 341 func (pb *pageBuffer) Write(b []byte) (int, error) { 342 wn := len(b) 343 if wn == 0 { 344 return 0, nil 345 } 346 347 if len(pb.pages) == 0 { 348 pb.pages = append(pb.pages, pb.newPage()) 349 } 350 351 for len(b) != 0 { 352 tail := pb.pages[len(pb.pages)-1] 353 free := tail.Cap() - tail.Len() 354 355 if len(b) <= free { 356 tail.Write(b) 357 pb.length += len(b) 358 break 359 } 360 361 tail.Write(b[:free]) 362 b = b[free:] 363 364 pb.length += free 365 pb.pages = append(pb.pages, pb.newPage()) 366 } 367 368 return wn, nil 369 } 370 371 func (pb *pageBuffer) WriteAt(b []byte, off int64) (int, error) { 372 n, err := pb.pages.WriteAt(b, off) 373 if err != nil { 374 return n, err 375 } 376 if n < len(b) { 377 pb.Write(b[n:]) 378 } 379 return len(b), nil 380 } 381 382 func (pb *pageBuffer) WriteTo(w io.Writer) (int64, error) { 383 var wn int 384 var err error 385 pb.pages.scan(int64(pb.cursor), int64(pb.length), func(b []byte) bool { 386 var n int 387 n, err = w.Write(b) 388 wn += n 389 return err == nil 390 }) 391 pb.cursor += wn 392 return int64(wn), err 393 } 394 395 var ( 396 _ io.ReaderAt = (*pageBuffer)(nil) 397 _ io.ReaderFrom = (*pageBuffer)(nil) 398 _ io.StringWriter = (*pageBuffer)(nil) 399 _ io.Writer = (*pageBuffer)(nil) 400 _ io.WriterAt = (*pageBuffer)(nil) 401 _ io.WriterTo = (*pageBuffer)(nil) 402 403 pagePool sync.Pool 404 pageBufferPool sync.Pool 405 ) 406 407 type contiguousPages []*page 408 409 func (pages contiguousPages) ref() { 410 for _, p := range pages { 411 p.ref() 412 } 413 } 414 415 func (pages contiguousPages) unref() { 416 for _, p := range pages { 417 p.unref() 418 } 419 } 420 421 func (pages contiguousPages) clear() { 422 for i := range pages { 423 pages[i] = nil 424 } 425 } 426 427 func (pages contiguousPages) ReadAt(b []byte, off int64) (int, error) { 428 rn := 0 429 430 for _, p := range pages.slice(off, off+int64(len(b))) { 431 n, _ := p.ReadAt(b, off) 432 b = b[n:] 433 rn += n 434 off += int64(n) 435 } 436 437 return rn, nil 438 } 439 440 func (pages contiguousPages) WriteAt(b []byte, off int64) (int, error) { 441 wn := 0 442 443 for _, p := range pages.slice(off, off+int64(len(b))) { 444 n, _ := p.WriteAt(b, off) 445 b = b[n:] 446 wn += n 447 off += int64(n) 448 } 449 450 return wn, nil 451 } 452 453 func (pages contiguousPages) slice(begin, end int64) contiguousPages { 454 i := pages.indexOf(begin) 455 j := pages.indexOf(end) 456 if j < len(pages) { 457 j++ 458 } 459 return pages[i:j] 460 } 461 462 func (pages contiguousPages) indexOf(offset int64) int { 463 if len(pages) == 0 { 464 return 0 465 } 466 return int((offset - pages[0].offset) / pageSize) 467 } 468 469 func (pages contiguousPages) scan(begin, end int64, f func([]byte) bool) { 470 for _, p := range pages.slice(begin, end) { 471 if !f(p.slice(begin, end)) { 472 break 473 } 474 } 475 } 476 477 var ( 478 _ io.ReaderAt = contiguousPages{} 479 _ io.WriterAt = contiguousPages{} 480 ) 481 482 type pageRef struct { 483 buffer [2]*page 484 pages contiguousPages 485 offset int64 486 cursor int64 487 length uint32 488 once uint32 489 } 490 491 func (ref *pageRef) unref() { 492 if atomic.CompareAndSwapUint32(&ref.once, 0, 1) { 493 ref.pages.unref() 494 ref.pages.clear() 495 ref.pages = nil 496 ref.offset = 0 497 ref.cursor = 0 498 ref.length = 0 499 } 500 } 501 502 func (ref *pageRef) Len() int { return int(ref.Size() - ref.cursor) } 503 504 func (ref *pageRef) Size() int64 { return int64(ref.length) } 505 506 func (ref *pageRef) Close() error { ref.unref(); return nil } 507 508 func (ref *pageRef) String() string { 509 return fmt.Sprintf("[offset=%d cursor=%d length=%d]", ref.offset, ref.cursor, ref.length) 510 } 511 512 func (ref *pageRef) Seek(offset int64, whence int) (int64, error) { 513 c, err := seek(ref.cursor, int64(ref.length), offset, whence) 514 if err != nil { 515 return -1, err 516 } 517 ref.cursor = c 518 return c, nil 519 } 520 521 func (ref *pageRef) ReadByte() (byte, error) { 522 var c byte 523 var ok bool 524 ref.scan(ref.cursor, func(b []byte) bool { 525 c, ok = b[0], true 526 return false 527 }) 528 if ok { 529 ref.cursor++ 530 } else { 531 return 0, io.EOF 532 } 533 return c, nil 534 } 535 536 func (ref *pageRef) Read(b []byte) (int, error) { 537 if ref.cursor >= int64(ref.length) { 538 return 0, io.EOF 539 } 540 n, err := ref.ReadAt(b, ref.cursor) 541 ref.cursor += int64(n) 542 return n, err 543 } 544 545 func (ref *pageRef) ReadAt(b []byte, off int64) (int, error) { 546 limit := ref.offset + int64(ref.length) 547 off += ref.offset 548 549 if off >= limit { 550 return 0, io.EOF 551 } 552 553 if off+int64(len(b)) > limit { 554 b = b[:limit-off] 555 } 556 557 if len(b) == 0 { 558 return 0, nil 559 } 560 561 n, err := ref.pages.ReadAt(b, off) 562 if n == 0 && err == nil { 563 err = io.EOF 564 } 565 return n, err 566 } 567 568 func (ref *pageRef) WriteTo(w io.Writer) (wn int64, err error) { 569 ref.scan(ref.cursor, func(b []byte) bool { 570 var n int 571 n, err = w.Write(b) 572 wn += int64(n) 573 return err == nil 574 }) 575 ref.cursor += wn 576 return 577 } 578 579 func (ref *pageRef) scan(off int64, f func([]byte) bool) { 580 begin := ref.offset + off 581 end := ref.offset + int64(ref.length) 582 ref.pages.scan(begin, end, f) 583 } 584 585 var ( 586 _ io.Closer = (*pageRef)(nil) 587 _ io.Seeker = (*pageRef)(nil) 588 _ io.Reader = (*pageRef)(nil) 589 _ io.ReaderAt = (*pageRef)(nil) 590 _ io.WriterTo = (*pageRef)(nil) 591 ) 592 593 type pageRefAllocator struct { 594 refs []pageRef 595 head int 596 size int 597 } 598 599 func (a *pageRefAllocator) newPageRef() *pageRef { 600 if a.head == len(a.refs) { 601 a.refs = make([]pageRef, a.size) 602 a.head = 0 603 } 604 ref := &a.refs[a.head] 605 a.head++ 606 return ref 607 } 608 609 func unref(x interface{}) { 610 if r, _ := x.(interface{ unref() }); r != nil { 611 r.unref() 612 } 613 } 614 615 func seek(cursor, limit, offset int64, whence int) (int64, error) { 616 switch whence { 617 case io.SeekStart: 618 // absolute offset 619 case io.SeekCurrent: 620 offset = cursor + offset 621 case io.SeekEnd: 622 offset = limit - offset 623 default: 624 return -1, fmt.Errorf("seek: invalid whence value: %d", whence) 625 } 626 if offset < 0 { 627 offset = 0 628 } 629 if offset > limit { 630 offset = limit 631 } 632 return offset, nil 633 } 634 635 func closeBytes(b Bytes) { 636 if b != nil { 637 b.Close() 638 } 639 } 640 641 func resetBytes(b Bytes) { 642 if r, _ := b.(interface{ Reset() }); r != nil { 643 r.Reset() 644 } 645 }