github.com/scottcagno/storage@v1.8.0/pkg/lsmt/binary/index.go (about)

     1  package binary
     2  
     3  import (
     4  	"encoding/binary"
     5  	"fmt"
     6  	"io"
     7  )
     8  
     9  // Index is a binary entry index
    10  type Index struct {
    11  	Key    []byte
    12  	Offset int64
    13  }
    14  
    15  // String is the stringer method for a *Index
    16  func (di *Index) String() string {
    17  	return fmt.Sprintf("index.key=%q, index.offset=%d", di.Key, di.Offset)
    18  }
    19  
    20  // EncodeIndex encodes and writes the provided entry index to w
    21  func EncodeIndex(w io.WriteSeeker, e *Index) (int64, error) {
    22  	// error check
    23  	if e == nil {
    24  		return -1, ErrBadEntry
    25  	}
    26  	// get the file pointer offset for the entry
    27  	offset, err := w.Seek(0, io.SeekCurrent)
    28  	if err != nil {
    29  		return -1, err
    30  	}
    31  	// make buffer
    32  	buf := make([]byte, 18)
    33  	// encode and write entry key length
    34  	binary.LittleEndian.PutUint64(buf[0:8], uint64(len(e.Key)))
    35  	_, err = w.Write(buf[0:8])
    36  	if err != nil {
    37  		return -1, err
    38  	}
    39  	// encode and write entry index data offset
    40  	binary.PutVarint(buf[8:18], e.Offset)
    41  	_, err = w.Write(buf[8:18])
    42  	if err != nil {
    43  		return -1, err
    44  	}
    45  	// write entry key
    46  	_, err = w.Write(e.Key)
    47  	if err != nil {
    48  		return -1, err
    49  	}
    50  	return offset, nil
    51  }
    52  
    53  // DecodeIndex reads and decodes the provided entry index from r
    54  func DecodeIndex(r io.Reader) (*Index, error) {
    55  	// make buffer
    56  	buf := make([]byte, 18)
    57  	// read entry key length
    58  	_, err := r.Read(buf[0:8])
    59  	if err != nil {
    60  		return nil, err
    61  	}
    62  	// read entry data offset
    63  	_, err = r.Read(buf[8:18])
    64  	if err != nil {
    65  		return nil, err
    66  	}
    67  	// decode key length
    68  	klen := binary.LittleEndian.Uint64(buf[0:8])
    69  	// decode data offset
    70  	off, _ := binary.Varint(buf[8:18])
    71  	// make entry index
    72  	e := &Index{
    73  		Key:    make([]byte, klen),
    74  		Offset: off,
    75  	}
    76  	// read key from data into entry key
    77  	_, err = r.Read(e.Key)
    78  	if err != nil {
    79  		return nil, err
    80  	}
    81  	// return entry
    82  	return e, nil
    83  }
    84  
    85  // DecodeIndexAt decodes the index at the provided offset using the provided reader
    86  func DecodeIndexAt(r io.ReaderAt, offset int64) (*Index, error) {
    87  	// make buffer
    88  	buf := make([]byte, 18)
    89  	// read entry key length
    90  	n, err := r.ReadAt(buf[0:8], offset)
    91  	if err != nil {
    92  		return nil, err
    93  	}
    94  	// update offset
    95  	offset += int64(n)
    96  	// read entry data offset
    97  	n, err = r.ReadAt(buf[8:18], offset)
    98  	if err != nil {
    99  		return nil, err
   100  	}
   101  	// update offset
   102  	offset += int64(n)
   103  	// decode key length
   104  	klen := binary.LittleEndian.Uint64(buf[0:8])
   105  	// decode data offset
   106  	off, _ := binary.Varint(buf[8:18])
   107  	// make entry index
   108  	e := &Index{
   109  		Key:    make([]byte, klen),
   110  		Offset: off,
   111  	}
   112  	// read key from data into entry key
   113  	n, err = r.ReadAt(e.Key, offset)
   114  	if err != nil {
   115  		return nil, err
   116  	}
   117  	// update offset
   118  	offset += int64(n)
   119  	// return entry
   120  	return e, nil
   121  }