2022-02-16 16:16:29 +05:00
|
|
|
package zkv
|
2022-02-16 16:08:20 +05:00
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
2022-12-05 21:26:54 +05:00
|
|
|
"crypto/sha256"
|
2022-02-16 16:08:20 +05:00
|
|
|
"encoding/binary"
|
2022-02-16 16:38:50 +05:00
|
|
|
"encoding/gob"
|
2022-02-16 16:08:20 +05:00
|
|
|
"io"
|
|
|
|
)
|
|
|
|
|
|
|
|
type RecordType uint8
|
|
|
|
|
|
|
|
const (
|
|
|
|
RecordTypeSet RecordType = iota + 1
|
|
|
|
RecordTypeDelete
|
|
|
|
)
|
|
|
|
|
|
|
|
type Record struct {
|
2022-12-02 20:32:09 +05:00
|
|
|
Type RecordType
|
2022-12-02 21:37:34 +05:00
|
|
|
KeyHash [28]byte
|
2022-12-02 20:32:09 +05:00
|
|
|
ValueBytes []byte
|
2022-02-16 16:08:20 +05:00
|
|
|
}
|
|
|
|
|
2022-12-05 21:26:54 +05:00
|
|
|
func newRecordBytes(recordType RecordType, keyHash [sha256.Size224]byte, valueBytes []byte) (*Record, error) {
|
|
|
|
record := &Record{
|
|
|
|
Type: recordType,
|
|
|
|
KeyHash: keyHash,
|
|
|
|
ValueBytes: valueBytes}
|
|
|
|
|
|
|
|
return record, nil
|
|
|
|
}
|
|
|
|
|
2022-02-16 16:08:20 +05:00
|
|
|
func newRecord(recordType RecordType, key, value interface{}) (*Record, error) {
|
2022-12-05 21:26:54 +05:00
|
|
|
keyHash, err := hashInterface(key)
|
2022-02-16 16:08:20 +05:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
valueBytes, err := encode(value)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2022-12-05 21:26:54 +05:00
|
|
|
return newRecordBytes(recordType, keyHash, valueBytes)
|
2022-02-16 16:08:20 +05:00
|
|
|
}
|
|
|
|
|
|
|
|
func (r *Record) Marshal() ([]byte, error) {
|
|
|
|
buf := new(bytes.Buffer)
|
|
|
|
|
2022-02-16 16:38:50 +05:00
|
|
|
err := gob.NewEncoder(buf).Encode(r)
|
2022-02-16 16:08:20 +05:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
buf2 := new(bytes.Buffer)
|
|
|
|
|
|
|
|
err = binary.Write(buf2, binary.LittleEndian, int64(buf.Len()))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return append(buf2.Bytes(), buf.Bytes()...), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func readRecord(r io.Reader) (n int64, record *Record, err error) {
|
|
|
|
var recordBytesLen int64
|
|
|
|
err = binary.Read(r, binary.LittleEndian, &recordBytesLen)
|
|
|
|
if err != nil {
|
|
|
|
return 0, nil, err // TODO: вместо нуля должно быть реальное кол-во считанных байт
|
|
|
|
}
|
|
|
|
|
|
|
|
recordBytes := make([]byte, int(recordBytesLen))
|
|
|
|
|
|
|
|
_, err = io.ReadAtLeast(r, recordBytes, int(recordBytesLen))
|
|
|
|
if err != nil {
|
|
|
|
return 0, nil, err // TODO: вместо нуля должно быть реальное кол-во считанных байт
|
|
|
|
}
|
|
|
|
|
2022-02-16 16:38:50 +05:00
|
|
|
err = gob.NewDecoder(bytes.NewReader(recordBytes)).Decode(&record)
|
2022-02-16 16:08:20 +05:00
|
|
|
if err != nil {
|
|
|
|
return 0, nil, err // TODO: вместо нуля должно быть реальное кол-во считанных байт
|
|
|
|
}
|
|
|
|
|
|
|
|
return recordBytesLen + 8, record, nil
|
|
|
|
}
|