github.com/cloudwego/hertz@v0.9.3/pkg/network/standard/buffer.go (about)

     1  /*
     2   * Copyright 2022 CloudWeGo Authors
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package standard
    18  
    19  import (
    20  	"sync"
    21  
    22  	"github.com/bytedance/gopkg/lang/mcache"
    23  )
    24  
    25  var bufferPool = sync.Pool{}
    26  
    27  func init() {
    28  	bufferPool.New = func() interface{} {
    29  		return &linkBufferNode{}
    30  	}
    31  }
    32  
    33  type linkBufferNode struct {
    34  	buf      []byte          // buffer
    35  	off      int             // read-offset
    36  	malloc   int             // write-offset
    37  	next     *linkBufferNode // the next node of the linked buffer
    38  	readOnly bool            // whether this node is a read only node
    39  }
    40  
    41  type linkBuffer struct {
    42  	// The release head
    43  	head *linkBufferNode
    44  	// The read pointer to point current read node
    45  	// There is no need to save current write node
    46  	read *linkBufferNode
    47  	// Tail node
    48  	write *linkBufferNode
    49  	len   int
    50  }
    51  
    52  func (l *linkBuffer) release() {
    53  	for l.head != nil {
    54  		node := l.head
    55  		l.head = l.head.next
    56  		node.Release()
    57  	}
    58  }
    59  
    60  // newBufferNode creates a new node with buffer size
    61  func newBufferNode(size int) *linkBufferNode {
    62  	buf := bufferPool.Get().(*linkBufferNode)
    63  	buf.buf = malloc(size, size)
    64  	return buf
    65  }
    66  
    67  // Reset resets this node.
    68  //
    69  // NOTE: Reset won't recycle the buffer of node.
    70  func (b *linkBufferNode) Reset() {
    71  	b.buf = b.buf[:0]
    72  	b.off, b.malloc = 0, 0
    73  	b.readOnly = false
    74  }
    75  
    76  // Len calculates the data size of this node.
    77  func (b *linkBufferNode) Len() int {
    78  	return b.malloc - b.off
    79  }
    80  
    81  func (b *linkBufferNode) recyclable() bool {
    82  	return cap(b.buf) <= block8k && !b.readOnly
    83  }
    84  
    85  // Cap returns the capacity of the node buffer
    86  func (b *linkBufferNode) Cap() int {
    87  	return cap(b.buf) - b.malloc
    88  }
    89  
    90  // Release will recycle the buffer of node
    91  func (b *linkBufferNode) Release() {
    92  	if !b.readOnly {
    93  		free(b.buf)
    94  	}
    95  	b.readOnly = false
    96  	b.buf = nil
    97  	b.next = nil
    98  	b.malloc, b.off = 0, 0
    99  	bufferPool.Put(b)
   100  }
   101  
   102  // malloc limits the cap of the buffer from mcache.
   103  func malloc(size, capacity int) []byte {
   104  	if capacity > mallocMax {
   105  		return make([]byte, size, capacity)
   106  	}
   107  	return mcache.Malloc(size, capacity)
   108  }
   109  
   110  // free limits the cap of the buffer from mcache.
   111  func free(buf []byte) {
   112  	if cap(buf) > mallocMax {
   113  		return
   114  	}
   115  	mcache.Free(buf)
   116  }