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

     1  package binary
     2  
     3  import (
     4  	"encoding/binary"
     5  	"fmt"
     6  	"io"
     7  	"math"
     8  )
     9  
    10  // Entry is a key-value data entry
    11  type Entry struct {
    12  	Key   []byte
    13  	Value []byte
    14  }
    15  
    16  // CheckSize take a maximum key and maximum value size and
    17  // checks to ensure the entry key and value do not exceed
    18  // the specified max sizes. It returns a nil error if all
    19  // is okay, otherwise ErrKeyTooLarge or ErrValueTooLarge
    20  func (de *Entry) CheckSize(maxKeySize, maxValueSize uint) error {
    21  	if ks := uint(len(de.Key)); ks > maxKeySize || ks > math.MaxUint64 {
    22  		return ErrKeyTooLarge
    23  	}
    24  	if vs := uint(len(de.Value)); vs > maxValueSize || vs > math.MaxUint64 {
    25  		return ErrValueTooLarge
    26  	}
    27  	return nil
    28  }
    29  
    30  // String is the stringer method for a *Entry
    31  func (de *Entry) String() string {
    32  	return fmt.Sprintf("entry.key=%q, entry.value=%q", de.Key, de.Value)
    33  }
    34  
    35  // Size returns the approximate size of the entry in bytes
    36  func (de *Entry) Size() int {
    37  	return len(de.Key) + len(de.Value) + 24
    38  
    39  }
    40  
    41  // EncodeEntry writes the provided entry to the writer provided
    42  func EncodeEntry(w io.WriteSeeker, e *Entry) (int64, error) {
    43  	// error check
    44  	if e == nil {
    45  		return -1, ErrBadEntry
    46  	}
    47  	// get the file pointer offset for the entry
    48  	offset, err := w.Seek(0, io.SeekCurrent)
    49  	if err != nil {
    50  		return -1, err
    51  	}
    52  	// make buffer
    53  	buf := make([]byte, 16)
    54  	// encode and write entry key length
    55  	binary.LittleEndian.PutUint64(buf[0:8], uint64(len(e.Key)))
    56  	_, err = w.Write(buf[0:8])
    57  	if err != nil {
    58  		return -1, err
    59  	}
    60  	// encode and write entry value length
    61  	binary.LittleEndian.PutUint64(buf[8:16], uint64(len(e.Value)))
    62  	_, err = w.Write(buf[8:16])
    63  	if err != nil {
    64  		return -1, err
    65  	}
    66  	// write entry key
    67  	_, err = w.Write(e.Key)
    68  	if err != nil {
    69  		return -1, err
    70  	}
    71  	// write entry value
    72  	_, err = w.Write(e.Value)
    73  	if err != nil {
    74  		return -1, err
    75  	}
    76  	return offset, nil
    77  }
    78  
    79  // DecodeEntry encodes the next entry from the reader provided
    80  func DecodeEntry(r io.Reader) (*Entry, error) {
    81  	// make buffer
    82  	buf := make([]byte, 16)
    83  	// read entry key length
    84  	_, err := r.Read(buf[0:8])
    85  	if err != nil {
    86  		return nil, err
    87  	}
    88  	// read entry value length
    89  	_, err = r.Read(buf[8:16])
    90  	if err != nil {
    91  		return nil, err
    92  	}
    93  	// decode key length
    94  	klen := binary.LittleEndian.Uint64(buf[0:8])
    95  	// decode value length
    96  	vlen := binary.LittleEndian.Uint64(buf[8:16])
    97  	// make entry to read data into
    98  	e := &Entry{
    99  		Key:   make([]byte, klen),
   100  		Value: make([]byte, vlen),
   101  	}
   102  	// read key from data into entry key
   103  	_, err = r.Read(e.Key)
   104  	if err != nil {
   105  		return nil, err
   106  	}
   107  	// read value key from data into entry value
   108  	_, err = r.Read(e.Value)
   109  	if err != nil {
   110  		return nil, err
   111  	}
   112  	// return entry
   113  	return e, nil
   114  }
   115  
   116  // DecodeEntryAt decodes the entry from the reader provided at the offset provided
   117  func DecodeEntryAt(r io.ReaderAt, offset int64) (*Entry, error) {
   118  	// make buffer
   119  	buf := make([]byte, 16)
   120  	// read entry key length
   121  	n, err := r.ReadAt(buf[0:8], offset)
   122  	if err != nil {
   123  		return nil, err
   124  	}
   125  	// update offset
   126  	offset += int64(n)
   127  	// read entry value length
   128  	n, err = r.ReadAt(buf[8:16], offset)
   129  	if err != nil {
   130  		return nil, err
   131  	}
   132  	// update offset for reading key data a bit below
   133  	offset += int64(n)
   134  	// decode key length
   135  	klen := binary.LittleEndian.Uint64(buf[0:8])
   136  	// decode value length
   137  	vlen := binary.LittleEndian.Uint64(buf[8:16])
   138  	// make entry to read data into
   139  	e := &Entry{
   140  		Key:   make([]byte, klen),
   141  		Value: make([]byte, vlen),
   142  	}
   143  	// read key from data into entry key
   144  	n, err = r.ReadAt(e.Key, offset)
   145  	if err != nil {
   146  		return nil, err
   147  	}
   148  	// update offset
   149  	offset += int64(n)
   150  	// read value key from data into entry value
   151  	n, err = r.ReadAt(e.Value, offset)
   152  	if err != nil {
   153  		return nil, err
   154  	}
   155  	// update offset
   156  	offset += int64(n)
   157  	// return entry
   158  	return e, nil
   159  }