github.com/cloudwego/hertz@v0.9.3/pkg/network/writer.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 network 18 19 import ( 20 "io" 21 "sync" 22 23 "github.com/bytedance/gopkg/lang/mcache" 24 ) 25 26 const size4K = 1024 * 4 27 28 type node struct { 29 data []byte 30 readOnly bool 31 } 32 33 var nodePool = sync.Pool{} 34 35 func init() { 36 nodePool.New = func() interface{} { 37 return &node{} 38 } 39 } 40 41 type networkWriter struct { 42 caches []*node 43 w io.Writer 44 } 45 46 func (w *networkWriter) release() { 47 for _, n := range w.caches { 48 if !n.readOnly { 49 mcache.Free(n.data) 50 } 51 n.data = nil 52 n.readOnly = false 53 nodePool.Put(n) 54 } 55 w.caches = w.caches[:0] 56 } 57 58 func (w *networkWriter) Malloc(length int) (buf []byte, err error) { 59 idx := len(w.caches) 60 if idx > 0 { 61 idx -= 1 62 inUse := len(w.caches[idx].data) 63 if !w.caches[idx].readOnly && cap(w.caches[idx].data)-inUse >= length { 64 end := inUse + length 65 w.caches[idx].data = w.caches[idx].data[:end] 66 return w.caches[idx].data[inUse:end], nil 67 } 68 } 69 buf = mcache.Malloc(length) 70 n := nodePool.Get().(*node) 71 n.data = buf 72 w.caches = append(w.caches, n) 73 return 74 } 75 76 func (w *networkWriter) WriteBinary(b []byte) (length int, err error) { 77 length = len(b) 78 if length < size4K { 79 buf, _ := w.Malloc(length) 80 copy(buf, b) 81 return 82 } 83 node := nodePool.Get().(*node) 84 node.readOnly = true 85 node.data = b 86 w.caches = append(w.caches, node) 87 return 88 } 89 90 func (w *networkWriter) Flush() (err error) { 91 for _, c := range w.caches { 92 _, err = w.w.Write(c.data) 93 if err != nil { 94 break 95 } 96 } 97 w.release() 98 return 99 } 100 101 func NewWriter(w io.Writer) Writer { 102 return &networkWriter{ 103 w: w, 104 } 105 } 106 107 type ExtWriter interface { 108 io.Writer 109 Flush() error 110 111 // Finalize will be called by framework before the writer is released. 112 // Implementations must guarantee that Finalize is safe for multiple calls. 113 Finalize() error 114 }