github.com/nikandfor/tlog@v0.21.5-0.20231108111739-3ef89426a96d/tlio/writers.go (about) 1 package tlio 2 3 import ( 4 "bytes" 5 "io" 6 "sync/atomic" 7 "testing" 8 9 "github.com/nikandfor/errors" 10 11 "github.com/nikandfor/tlog" 12 "github.com/nikandfor/tlog/tlwire" 13 ) 14 15 type ( 16 MultiWriter []io.Writer 17 18 ReWriter struct { 19 io.Writer 20 io.Closer 21 22 Open func(io.Writer, error) (io.Writer, error) 23 } 24 25 // DeLabels removes repeating Labels from events. 26 DeLabels struct { 27 io.Writer 28 29 d tlwire.Decoder 30 e tlwire.Encoder 31 32 b, ls []byte 33 } 34 35 TailWriter struct { 36 io.Writer 37 n int 38 39 i int 40 buf [][]byte 41 } 42 43 HeadWriter struct { 44 io.Writer 45 N int 46 } 47 48 // CountingIODiscard discards data but counts writes and bytes. 49 // It's safe to use simultaneously (atomic operations are used). 50 CountingIODiscard struct { 51 Bytes, Writes atomic.Int64 52 } 53 54 WriterFunc func(p []byte) (int, error) 55 56 // base interfaces 57 58 Flusher interface { 59 Flush() error 60 } 61 62 FlusherNoError interface { 63 Flush() 64 } 65 66 NopCloser struct { 67 io.Reader 68 io.Writer 69 } 70 71 WriteCloser struct { 72 io.Writer 73 io.Closer 74 } 75 76 WriteFlusher struct { 77 io.Writer 78 Flusher 79 } 80 81 wrapFlusher struct { 82 FlusherNoError 83 } 84 ) 85 86 func NewMultiWriter(ws ...io.Writer) (w MultiWriter) { 87 return w.Append(ws...) 88 } 89 90 func (w MultiWriter) Append(ws ...io.Writer) MultiWriter { 91 w = make(MultiWriter, 0, len(ws)) 92 93 for _, s := range ws { 94 if s == nil { 95 continue 96 } 97 98 if tee, ok := s.(MultiWriter); ok { 99 w = append(w, tee...) 100 } else { 101 w = append(w, s) 102 } 103 } 104 105 return w 106 } 107 108 func (w MultiWriter) Write(p []byte) (n int, err error) { 109 for i, w := range w { 110 m, e := w.Write(p) 111 112 if i == 0 { 113 n = m 114 } 115 116 if err == nil { 117 err = e 118 } 119 } 120 121 return 122 } 123 124 func (w MultiWriter) Close() (err error) { 125 for _, w := range w { 126 c, ok := w.(io.Closer) 127 if !ok { 128 continue 129 } 130 131 e := c.Close() 132 if err == nil { 133 err = e 134 } 135 } 136 137 return 138 } 139 140 func (NopCloser) Close() error { return nil } 141 142 func (c NopCloser) Fd() uintptr { 143 return Fd(c.Writer) 144 } 145 146 func (w *CountingIODiscard) ReportDisk(b *testing.B) { 147 b.ReportMetric(float64(w.Bytes.Load())/float64(b.N), "disk_B/op") 148 } 149 150 func (w *CountingIODiscard) Write(p []byte) (int, error) { 151 w.Writes.Add(1) 152 w.Bytes.Add(int64(len(p))) 153 154 return len(p), nil 155 } 156 157 func NewReWriter(open func(io.Writer, error) (io.Writer, error)) *ReWriter { 158 return &ReWriter{ 159 Open: open, 160 } 161 } 162 163 func (w *ReWriter) Write(p []byte) (n int, err error) { 164 if w.Writer != nil { 165 n, err = w.Writer.Write(p) 166 if err == nil { 167 return n, nil 168 } 169 } 170 171 err = w.open() 172 if err != nil { 173 return 174 } 175 176 n, err = w.Writer.Write(p) 177 if err != nil { 178 return 179 } 180 181 return 182 } 183 184 func (w *ReWriter) open() (err error) { 185 w.Writer, err = w.Open(w.Writer, err) 186 if err != nil { 187 return errors.Wrap(err, "open") 188 } 189 190 w.Closer, _ = w.Writer.(io.Closer) 191 192 return nil 193 } 194 195 func (w *ReWriter) Close() error { 196 if w.Closer == nil { 197 return nil 198 } 199 200 return w.Closer.Close() 201 } 202 203 func NewDeLabels(w io.Writer) *DeLabels { 204 return &DeLabels{ 205 Writer: w, 206 } 207 } 208 209 func (w *DeLabels) Write(p []byte) (i int, err error) { 210 tag, els, i := w.d.Tag(p, i) 211 if tag != tlwire.Map { 212 return i, errors.New("map expected") 213 } 214 215 gst := i 216 217 var st int 218 var sub int64 219 for el := 0; els == -1 || el < int(els); el++ { 220 if els == -1 && w.d.Break(p, &i) { 221 break 222 } 223 224 st = i 225 226 _, i = w.d.Bytes(p, i) 227 _, sub, i = w.d.SkipTag(p, i) 228 229 if sub == tlog.WireLabel { 230 break 231 } 232 } 233 234 if !bytes.Equal(w.ls, p[st:i]) { 235 w.ls = append(w.ls[:0], p[st:i]...) 236 237 return w.Writer.Write(p) 238 } 239 240 w.b = w.b[:0] 241 242 if els != -1 { 243 w.b = w.e.AppendMap(w.b, int(els-1)) 244 } else { 245 gst = 0 246 } 247 248 w.b = append(w.b, p[gst:st]...) 249 w.b = append(w.b, p[i:]...) 250 251 i, err = w.Writer.Write(w.b) 252 if err != nil { 253 return i, err 254 } 255 256 return len(p), nil 257 } 258 259 func (w *DeLabels) Unwrap() interface{} { 260 return w.Writer 261 } 262 263 func NewTailWriter(w io.Writer, n int) *TailWriter { 264 return &TailWriter{ 265 Writer: w, 266 n: n, 267 buf: make([][]byte, n), 268 } 269 } 270 271 func (w *TailWriter) Write(p []byte) (n int, err error) { 272 i := w.i % w.n 273 w.buf[i] = append(w.buf[i][:0], p...) 274 275 w.i++ 276 277 return len(p), nil 278 } 279 280 func (w *TailWriter) Flush() (err error) { 281 for i := w.i; i < w.i+w.n; i++ { 282 b := w.buf[i%w.n] 283 284 if len(b) == 0 { 285 continue 286 } 287 288 _, err = w.Writer.Write(b) 289 if err != nil { 290 return err 291 } 292 293 w.buf[i%w.n] = b[:0] 294 } 295 296 if f, ok := w.Writer.(Flusher); ok { 297 return f.Flush() 298 } 299 300 return nil 301 } 302 303 func (w *TailWriter) Unwrap() interface{} { 304 return w.Writer 305 } 306 307 func NewHeadWriter(w io.Writer, n int) *HeadWriter { 308 return &HeadWriter{ 309 Writer: w, 310 N: n, 311 } 312 } 313 314 func (w *HeadWriter) Write(p []byte) (int, error) { 315 if w.N > 0 { 316 w.N-- 317 318 return w.Writer.Write(p) 319 } 320 321 return len(p), nil 322 } 323 324 func (w *HeadWriter) Unwrap() interface{} { 325 return w.Writer 326 } 327 328 func (w WriterFunc) Write(p []byte) (int, error) { return w(p) } 329 330 func WrapFlusherNoError(f FlusherNoError) Flusher { 331 return wrapFlusher{FlusherNoError: f} 332 } 333 334 func (f wrapFlusher) Flush() error { 335 f.FlusherNoError.Flush() 336 return nil 337 } 338 339 func Fd(f interface{}) uintptr { 340 const ffff = ^uintptr(0) 341 342 if f == nil { 343 return ffff 344 } 345 346 switch f := f.(type) { 347 case interface{ Fd() uintptr }: 348 return f.Fd() 349 case interface{ Fd() int }: 350 return uintptr(f.Fd()) 351 } 352 353 return ffff 354 }