github.com/zuoyebang/bitalosdb@v1.1.1-0.20240516111551-79a8c4d8ce20/bithash/reader.go (about) 1 // Copyright 2021 The Bitalosdb author(hustxrb@163.com) and other contributors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package bithash 16 17 import ( 18 "bytes" 19 "encoding/binary" 20 "io" 21 "os" 22 "runtime/debug" 23 24 "github.com/cockroachdb/errors" 25 "github.com/zuoyebang/bitalosdb/internal/bytepools" 26 27 "github.com/zuoyebang/bitalosdb/internal/bindex" 28 "github.com/zuoyebang/bitalosdb/internal/vfs" 29 ) 30 31 type ReadableFile interface { 32 io.ReaderAt 33 io.Closer 34 Stat() (os.FileInfo, error) 35 } 36 37 type Reader struct { 38 b *Bithash 39 file ReadableFile 40 fs vfs.FS 41 filename string 42 fileNum FileNum 43 err error 44 footer footer 45 indexHashBH BlockHandle 46 indexHash *bindex.HashIndex 47 conflictBH BlockHandle 48 conflictBuf []byte 49 dataBH BlockHandle 50 dataBlock block2Reader 51 readOnly bool 52 } 53 54 type ReaderOption interface { 55 readerApply(*Reader) 56 } 57 58 type FileReopenOpt struct { 59 fs vfs.FS 60 filename string 61 fileNum FileNum 62 readOnly bool 63 } 64 65 func (f FileReopenOpt) readerApply(r *Reader) { 66 if r.fs == nil { 67 r.fs = f.fs 68 r.filename = f.filename 69 r.fileNum = f.fileNum 70 r.readOnly = f.readOnly 71 } 72 } 73 74 func NewReader(b *Bithash, f ReadableFile, extraOpts ...ReaderOption) (r *Reader, err error) { 75 r = &Reader{ 76 b: b, 77 file: f, 78 indexHash: bindex.NewHashIndex(false), 79 } 80 81 defer func() { 82 if c := recover(); c != nil { 83 r.err = errors.Errorf("bithash: NewReader panic file:%s err:%v stack:%s", r.filename, c, string(debug.Stack())) 84 err = r.Close() 85 r = nil 86 } 87 }() 88 89 if f == nil { 90 r.err = ErrBhNewReaderNoFile 91 return nil, r.Close() 92 } 93 94 for _, opt := range extraOpts { 95 opt.readerApply(r) 96 } 97 98 r.footer, err = readTableFooter(f) 99 if err != nil { 100 r.err = err 101 return nil, r.Close() 102 } 103 104 err = r.readMeta() 105 if err != nil { 106 r.err = err 107 return nil, r.Close() 108 } 109 110 if err = r.readIndexHash(); err != nil { 111 r.err = err 112 return nil, r.Close() 113 } 114 115 return r, nil 116 } 117 118 func (r *Reader) readMeta() (err error) { 119 buf := make([]byte, r.footer.metaBH.Length) 120 if _, err = r.file.ReadAt(buf, int64(r.footer.metaBH.Offset)); err != nil { 121 return err 122 } 123 124 iter, err := newBlockIter(bytes.Compare, buf) 125 if err != nil { 126 return err 127 } 128 defer iter.Close() 129 130 var bhCounter int 131 for k, v := iter.First(); iter.Valid(); k, v = iter.Next() { 132 if bytes.Equal(k.UserKey, []byte(MetaIndexHashBH)) { 133 r.indexHashBH = decodeBlockHandle(v) 134 bhCounter++ 135 continue 136 } 137 if bytes.Equal(k.UserKey, []byte(MetaConflictBH)) { 138 r.conflictBH = decodeBlockHandle(v) 139 bhCounter++ 140 continue 141 } 142 if bytes.Equal(k.UserKey, []byte(MetaDataBH)) { 143 r.dataBH = decodeBlockHandle(v) 144 bhCounter++ 145 continue 146 } 147 } 148 149 if bhCounter != blockHandleSum { 150 return errors.Errorf("bithash: read meta blockHandleSum mismatch file:%s", r.filename) 151 } 152 153 if r.conflictBH.Length > 0 { 154 r.conflictBuf = make([]byte, r.conflictBH.Length) 155 if _, err = r.file.ReadAt(r.conflictBuf, int64(r.conflictBH.Offset)); err != nil { 156 return err 157 } 158 } 159 160 return nil 161 } 162 163 func (r *Reader) readIndexHash() (err error) { 164 indexHashBH := make([]byte, r.indexHashBH.Length) 165 if _, err = r.file.ReadAt(indexHashBH, int64(r.indexHashBH.Offset)); err != nil { 166 return err 167 } 168 169 iter, err := newBlockIter(bytes.Compare, indexHashBH) 170 if err != nil { 171 return err 172 } 173 defer iter.Close() 174 175 for k, v := iter.First(); iter.Valid(); k, v = iter.Next() { 176 if bytes.Equal(k.UserKey, []byte(IndexHashData)) { 177 if !r.indexHash.SetReader(v) { 178 return ErrBhHashIndexReadFail 179 } 180 } 181 } 182 183 return nil 184 } 185 186 func (r *Reader) Close() error { 187 if r.err != nil { 188 if r.file != nil { 189 r.file.Close() 190 r.file = nil 191 } 192 return r.err 193 } 194 195 if r.file != nil { 196 r.err = r.file.Close() 197 r.file = nil 198 if r.err != nil { 199 return r.err 200 } 201 } 202 203 r.indexHash.Finish() 204 205 r.err = ErrBhReaderClosed 206 207 return nil 208 } 209 210 func (r *Reader) Get(key []byte, khash uint32) ([]byte, func(), error) { 211 vint, ok := r.indexHash.Get64(khash) 212 if !ok { 213 return nil, nil, ErrBhNotFound 214 } 215 216 var buf [blockHandleLen]byte 217 binary.LittleEndian.PutUint64(buf[:], vint) 218 bh := decodeBlockHandle(buf[:]) 219 220 if r.conflictBH.Length != 0 && bh.Offset >= r.conflictBH.Offset && bh.Length <= r.conflictBH.Length { 221 conflictBH, err := r.readConflict(key) 222 if err != nil { 223 return nil, nil, err 224 } 225 if conflictBH.Length == 0 && conflictBH.Offset == 0 { 226 return nil, nil, ErrBhIllegalBlockLength 227 } 228 bh = conflictBH 229 } 230 231 return r.readData(bh) 232 } 233 234 func (r *Reader) readData(bh BlockHandle) ([]byte, func(), error) { 235 if bh.Length <= 0 { 236 return nil, nil, ErrBhIllegalBlockLength 237 } 238 239 var err error 240 var v []byte 241 var n int 242 243 buf, closer := bytepools.ReaderBytePools.GetBytePool(int(bh.Length)) 244 defer func() { 245 if err != nil { 246 closer() 247 } 248 }() 249 250 length := int(bh.Length) 251 buf = buf[:length] 252 n, err = r.file.ReadAt(buf, int64(bh.Offset)) 253 if err != nil { 254 return nil, nil, err 255 } 256 if n != length { 257 err = ErrBhReadAtIncomplete 258 return nil, nil, err 259 } 260 261 _, val, _ := r.dataBlock.readRecord(buf) 262 if val == nil { 263 err = ErrBhReadRecordNil 264 return nil, nil, err 265 } 266 267 v, err = r.b.compressor.Decode(nil, val) 268 if err != nil { 269 return nil, nil, err 270 } 271 272 return v, closer, nil 273 } 274 275 func (r *Reader) readConflict(key []byte) (BlockHandle, error) { 276 bh := BlockHandle{} 277 278 iter, err := newBlockIter(bytes.Compare, r.conflictBuf) 279 if err != nil { 280 return bh, err 281 } 282 defer iter.Close() 283 284 ik, iv := iter.SeekGE(key) 285 if iter.Valid() && bytes.Equal(ik.UserKey, key) { 286 bh = decodeBlockHandle(iv) 287 } 288 289 return bh, nil 290 }