mirror of
https://github.com/nxshock/zkv.git
synced 2024-11-27 11:21:02 +05:00
New version
* Simplify internal structures * Update minimal Go version * Add Delete() function
This commit is contained in:
parent
5c459416b1
commit
4ec53665af
5
errors.go
Normal file
5
errors.go
Normal file
@ -0,0 +1,5 @@
|
||||
package zkv
|
||||
|
||||
import "errors"
|
||||
|
||||
var ErrNotExists = errors.New("not exists")
|
10
go.mod
10
go.mod
@ -1,14 +1,14 @@
|
||||
module github.com/nxshock/zkv
|
||||
|
||||
go 1.17
|
||||
go 1.19
|
||||
|
||||
require (
|
||||
github.com/klauspost/compress v1.14.2
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/klauspost/compress v1.15.12
|
||||
github.com/stretchr/testify v1.8.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
18
go.sum
18
go.sum
@ -1,13 +1,19 @@
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/klauspost/compress v1.14.2 h1:S0OHlFk/Gbon/yauFJ4FfJJF5V0fc5HbBTJazi28pRw=
|
||||
github.com/klauspost/compress v1.14.2/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/klauspost/compress v1.15.12 h1:YClS/PImqYbn+UILDnqxQCZ3RehC9N318SU3kElDUEM=
|
||||
github.com/klauspost/compress v1.15.12/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
@ -15,10 +15,9 @@ const (
|
||||
)
|
||||
|
||||
type Record struct {
|
||||
Type RecordType `json:"t"`
|
||||
KeyHash []byte `json:"h"`
|
||||
KeyBytes []byte `json:"k,omitempty"` // optional
|
||||
ValueBytes []byte `json:"v"`
|
||||
Type RecordType
|
||||
KeyHash []byte
|
||||
ValueBytes []byte
|
||||
}
|
||||
|
||||
func newRecord(recordType RecordType, key, value interface{}) (*Record, error) {
|
||||
@ -35,7 +34,6 @@ func newRecord(recordType RecordType, key, value interface{}) (*Record, error) {
|
||||
record := &Record{
|
||||
Type: recordType,
|
||||
KeyHash: hashBytes(keyBytes),
|
||||
KeyBytes: keyBytes,
|
||||
ValueBytes: valueBytes}
|
||||
|
||||
return record, nil
|
||||
|
3
utils.go
3
utils.go
@ -5,7 +5,6 @@ import (
|
||||
"crypto/sha256"
|
||||
"encoding/gob"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
func encode(value interface{}) ([]byte, error) {
|
||||
@ -39,7 +38,7 @@ func skip(r io.Reader, count int64) (err error) {
|
||||
case io.Seeker:
|
||||
_, err = r.Seek(count, io.SeekCurrent)
|
||||
default:
|
||||
_, err = io.CopyN(ioutil.Discard, r, count)
|
||||
_, err = io.CopyN(io.Discard, r, count)
|
||||
}
|
||||
|
||||
return err
|
||||
|
46
zkv.go
46
zkv.go
@ -3,7 +3,6 @@ package zkv
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
@ -12,10 +11,6 @@ import (
|
||||
"github.com/klauspost/compress/zstd"
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
SaveKeys bool
|
||||
}
|
||||
|
||||
type Database struct {
|
||||
dataOffset map[string]int64
|
||||
file *os.File
|
||||
@ -23,8 +18,6 @@ type Database struct {
|
||||
filePath string
|
||||
offset int64
|
||||
|
||||
options Options
|
||||
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
@ -49,10 +42,6 @@ func (db *Database) Set(key, value interface{}) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if !db.options.SaveKeys {
|
||||
record.KeyBytes = nil
|
||||
}
|
||||
|
||||
b, err := record.Marshal()
|
||||
if err != nil {
|
||||
return err
|
||||
@ -81,7 +70,7 @@ func (db *Database) Get(key, value interface{}) error {
|
||||
|
||||
offset, exists := db.dataOffset[string(hashToFind)]
|
||||
if !exists {
|
||||
return errors.New("not exists") // TODO: заменить на константную ошибку
|
||||
return ErrNotExists
|
||||
}
|
||||
|
||||
readF, err := os.Open(db.filePath)
|
||||
@ -106,7 +95,7 @@ func (db *Database) Get(key, value interface{}) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if bytes.Compare(record.KeyHash, hashToFind) != 0 {
|
||||
if !bytes.Equal(record.KeyHash, hashToFind) {
|
||||
return fmt.Errorf("wrong hash on this offset: expected %s, got %s", base64.StdEncoding.EncodeToString(hashToFind), base64.StdEncoding.EncodeToString(record.KeyHash)) // TODO: заменить на константную ошибку
|
||||
}
|
||||
|
||||
@ -168,3 +157,34 @@ func Open(filePath string) (*Database, error) {
|
||||
|
||||
return database, nil
|
||||
}
|
||||
|
||||
func (db *Database) Delete(key interface{}) error {
|
||||
db.mu.Lock()
|
||||
defer db.mu.Unlock()
|
||||
|
||||
keyHash, err := hashInterface(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
record := &Record{
|
||||
Type: RecordTypeDelete,
|
||||
KeyHash: keyHash,
|
||||
}
|
||||
|
||||
b, err := record.Marshal()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
delete(db.dataOffset, string(record.KeyHash))
|
||||
|
||||
_, err = db.compressor.Write(b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
db.offset += int64(len(b))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
41
zkv_test.go
41
zkv_test.go
@ -77,3 +77,44 @@ func TestSmallWrites(t *testing.T) {
|
||||
err = db.Close()
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestDeleteBasic(t *testing.T) {
|
||||
const filePath = "TestDeleteBasic.zkv"
|
||||
const recordCount = 100
|
||||
defer os.Remove(filePath)
|
||||
|
||||
db, err := Open(filePath)
|
||||
assert.NoError(t, err)
|
||||
|
||||
for i := 1; i <= recordCount; i++ {
|
||||
err = db.Set(i, i)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
assert.Len(t, db.dataOffset, recordCount)
|
||||
|
||||
err = db.Delete(50)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Len(t, db.dataOffset, recordCount-1)
|
||||
var value int
|
||||
err = db.Get(50, &value)
|
||||
assert.Equal(t, 0, value)
|
||||
assert.ErrorIs(t, err, ErrNotExists)
|
||||
|
||||
err = db.Close()
|
||||
assert.NoError(t, err)
|
||||
|
||||
// try to read
|
||||
db, err = Open(filePath)
|
||||
assert.NoError(t, err)
|
||||
|
||||
assert.Len(t, db.dataOffset, recordCount-1)
|
||||
value = 0
|
||||
err = db.Get(50, &value)
|
||||
assert.Equal(t, 0, value)
|
||||
assert.ErrorIs(t, err, ErrNotExists)
|
||||
|
||||
err = db.Close()
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user