github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/dbnode/persist/fs/read_decode_stream.go (about) 1 // Copyright (c) 2017 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package fs 22 23 import ( 24 "bytes" 25 "fmt" 26 "io" 27 28 "github.com/m3db/m3/src/dbnode/digest" 29 "github.com/m3db/m3/src/dbnode/persist/fs/msgpack" 30 ) 31 32 type dataFileSetReaderDecoderStream interface { 33 msgpack.ByteDecoderStream 34 35 // reader returns the underlying reader with access to the 36 // incremental computed digest 37 reader() digest.ReaderWithDigest 38 } 39 40 type readerDecoderStream struct { 41 bytesReader *bytes.Reader 42 readerWithDigest digest.ReaderWithDigest 43 backingBytes []byte 44 buf [64]byte 45 lastReadByte int 46 unreadByte int 47 } 48 49 func newReaderDecoderStream() dataFileSetReaderDecoderStream { 50 return &readerDecoderStream{ 51 readerWithDigest: digest.NewReaderWithDigest(nil), 52 bytesReader: bytes.NewReader(nil), 53 } 54 } 55 56 func (s *readerDecoderStream) reader() digest.ReaderWithDigest { 57 return s.readerWithDigest 58 } 59 60 func (s *readerDecoderStream) Reset(d []byte) { 61 s.bytesReader.Reset(d) 62 s.readerWithDigest.Reset(s.bytesReader) 63 s.backingBytes = d 64 s.lastReadByte = -1 65 s.unreadByte = -1 66 } 67 68 func (s *readerDecoderStream) Read(p []byte) (int, error) { 69 if len(p) == 0 { 70 return 0, nil 71 } 72 73 ref := p 74 75 var numUnreadByte int 76 if s.unreadByte >= 0 { 77 p[0] = byte(s.unreadByte) 78 p = p[1:] 79 s.unreadByte = -1 80 numUnreadByte = 1 81 } 82 n, err := s.readerWithDigest.Read(p) 83 n += numUnreadByte 84 if n > 0 { 85 s.lastReadByte = int(ref[n-1]) 86 } 87 if err == io.EOF && n > 0 { 88 return n, nil // return EOF next time, might be returning last byte still 89 } 90 return n, err 91 } 92 93 func (s *readerDecoderStream) ReadByte() (byte, error) { 94 if s.unreadByte >= 0 { 95 r := byte(s.unreadByte) 96 s.unreadByte = -1 97 return r, nil 98 } 99 n, err := s.readerWithDigest.Read(s.buf[:1]) 100 if n > 0 { 101 s.lastReadByte = int(s.buf[0]) 102 } 103 return s.buf[0], err 104 } 105 106 func (s *readerDecoderStream) UnreadByte() error { 107 if s.lastReadByte < 0 { 108 return fmt.Errorf("no previous read byte or already unread byte") 109 } 110 s.unreadByte = s.lastReadByte 111 s.lastReadByte = -1 112 return nil 113 } 114 115 func (s *readerDecoderStream) Bytes() []byte { 116 return s.backingBytes 117 } 118 119 func (s *readerDecoderStream) Skip(length int64) error { 120 // NB(r): This ensures the reader with digest is always read 121 // from start to end, i.e. to calculate digest properly. 122 remaining := length 123 for { 124 readEnd := int64(len(s.buf)) 125 if remaining < readEnd { 126 readEnd = remaining 127 } 128 n, err := s.Read(s.buf[:readEnd]) 129 if err != nil { 130 return err 131 } 132 remaining -= int64(n) 133 if remaining < 0 { 134 return fmt.Errorf("skipped too far, remaining is: %d", remaining) 135 } 136 if remaining == 0 { 137 return nil 138 } 139 } 140 } 141 142 func (s *readerDecoderStream) Remaining() int64 { 143 var unreadBytes int64 144 if s.unreadByte != -1 { 145 unreadBytes = 1 146 } 147 return int64(s.bytesReader.Len()) + unreadBytes 148 } 149 150 func (s *readerDecoderStream) Offset() int { 151 return len(s.backingBytes) - int(s.Remaining()) 152 }