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 }