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  }