github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/dbnode/x/xio/segment_reader.go (about) 1 // Copyright (c) 2016 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 xio 22 23 import ( 24 "encoding/binary" 25 "io" 26 27 "github.com/m3db/m3/src/dbnode/ts" 28 "github.com/m3db/m3/src/x/pool" 29 ) 30 31 type segmentReader struct { 32 segment ts.Segment 33 lazyHead []byte 34 lazyTail []byte 35 si int 36 pool SegmentReaderPool 37 } 38 39 // NewSegmentReader creates a new segment reader along with a specified segment. 40 func NewSegmentReader(segment ts.Segment) SegmentReader { 41 return &segmentReader{segment: segment} 42 } 43 44 func (sr *segmentReader) Clone( 45 pool pool.CheckedBytesPool, 46 ) (SegmentReader, error) { 47 return NewSegmentReader(sr.segment.Clone(pool)), nil 48 } 49 50 func (sr *segmentReader) Read64() (word uint64, n byte, err error) { 51 sr.lazyInit() 52 53 var ( 54 headLen = len(sr.lazyHead) 55 res uint64 56 bytes byte 57 ) 58 59 if sr.si+8 <= headLen { 60 // NB: this compiles to a single 64 bit load followed by 61 // a BSWAPQ on amd64 gc 1.13 (https://godbolt.org/z/oTK1jx). 62 res = binary.BigEndian.Uint64(sr.lazyHead[sr.si:]) 63 sr.si += 8 64 return res, 8, nil 65 } 66 67 headTailLen := headLen + len(sr.lazyTail) 68 69 if sr.si < headLen { 70 for ; sr.si < headLen; sr.si++ { 71 res = (res << 8) | uint64(sr.lazyHead[sr.si]) 72 bytes++ 73 } 74 for ; sr.si < headTailLen && bytes < 8; sr.si++ { 75 res = (res << 8) | uint64(sr.lazyTail[sr.si-headLen]) 76 bytes++ 77 } 78 return res << (64 - 8*bytes), bytes, nil 79 } 80 81 if sr.si+8 <= headTailLen { 82 // NB: this compiles to a single 64 bit load followed by 83 // a BSWAPQ on amd64 gc 1.13 (https://godbolt.org/z/oTK1jx). 84 res = binary.BigEndian.Uint64(sr.lazyTail[sr.si-headLen:]) 85 sr.si += 8 86 return res, 8, nil 87 } 88 89 if sr.si >= headTailLen { 90 return 0, 0, io.EOF 91 } 92 93 for ; sr.si < headTailLen; sr.si++ { 94 res = (res << 8) | uint64(sr.lazyTail[sr.si-headLen]) 95 bytes++ 96 } 97 return res << (64 - 8*bytes), bytes, nil 98 } 99 100 func (sr *segmentReader) Peek64() (word uint64, n byte, err error) { 101 sr.lazyInit() 102 103 var ( 104 headLen = len(sr.lazyHead) 105 i = sr.si 106 res uint64 107 bytes byte 108 ) 109 110 if i+8 <= headLen { 111 // NB: this compiles to a single 64 bit load followed by 112 // a BSWAPQ on amd64 gc 1.13 (https://godbolt.org/z/oTK1jx). 113 res = binary.BigEndian.Uint64(sr.lazyHead[i:]) 114 return res, 8, nil 115 } 116 117 headTailLen := headLen + len(sr.lazyTail) 118 119 if i < headLen { 120 for ; i < headLen; i++ { 121 res = (res << 8) | uint64(sr.lazyHead[i]) 122 bytes++ 123 } 124 for ; i < headTailLen && bytes < 8; i++ { 125 res = (res << 8) | uint64(sr.lazyTail[i-headLen]) 126 bytes++ 127 } 128 return res << (64 - 8*bytes), bytes, nil 129 } 130 131 if i+8 <= headTailLen { 132 // NB: this compiles to a single 64 bit load followed by 133 // a BSWAPQ on amd64 gc 1.13 (https://godbolt.org/z/oTK1jx). 134 res = binary.BigEndian.Uint64(sr.lazyTail[i-headLen:]) 135 return res, 8, nil 136 } 137 138 if i >= headTailLen { 139 return 0, 0, io.EOF 140 } 141 142 for ; i < headTailLen; i++ { 143 res = (res << 8) | uint64(sr.lazyTail[i-headLen]) 144 bytes++ 145 } 146 return res << (64 - 8*bytes), bytes, nil 147 } 148 149 func (sr *segmentReader) Segment() (ts.Segment, error) { 150 return sr.segment, nil 151 } 152 153 func (sr *segmentReader) Reset(segment ts.Segment) { 154 sr.segment = segment 155 sr.si = 0 156 sr.lazyHead = sr.lazyHead[:0] 157 sr.lazyTail = sr.lazyTail[:0] 158 } 159 160 func (sr *segmentReader) Finalize() { 161 sr.segment.Finalize() 162 sr.lazyHead = nil 163 sr.lazyTail = nil 164 165 if pool := sr.pool; pool != nil { 166 pool.Put(sr) 167 } 168 } 169 170 func (sr *segmentReader) lazyInit() { 171 if b := sr.segment.Head; b != nil && len(sr.lazyHead) == 0 { 172 sr.lazyHead = b.Bytes() 173 } 174 if b := sr.segment.Tail; b != nil && len(sr.lazyTail) == 0 { 175 sr.lazyTail = b.Bytes() 176 } 177 }