Skip to content

Commit 9df039a

Browse files
committed
Update README.md
1 parent 0535f9a commit 9df039a

File tree

4 files changed

+139
-13
lines changed

4 files changed

+139
-13
lines changed

CHANGELOG.md

+13-3
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,25 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
77

88
## [Unreleased]
99

10+
## [0.0.7] - 2022-11-9
11+
12+
### Added
13+
14+
- More thorough documentation for the Store
15+
16+
### Changed
17+
18+
### Fixed
19+
1020
## [0.0.6] - 2022-11-9
1121

1222
### Added
1323

1424
### Changed
1525

16-
- Optimized the Compact operation.
17-
- Removed unnecessary internal type conversions e.g. to `internal.entries.Index`.
18-
- Got rid of message passing in iterating over the index blocks
26+
- Optimized the Compact operation.
27+
- Removed unnecessary internal type conversions e.g. to `internal.entries.Index`.
28+
- Got rid of message passing in iterating over the index blocks
1929

2030
### Fixed
2131

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ A very simple and fast key-value pure-go store but persisting data to disk, with
66

77
This is the pure-golang version of the original [scdb](https://github.com/sopherapps/scdb)
88

9-
**scdb may not be production-ready yet. It works, quite well but it requires more vigorous testing.**
9+
**scdb may not be production-ready yet. It works, quite well but it requires more rigorous testing.**
1010

1111
## Purpose
1212

scdb/store.go

+46-9
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,16 @@ import (
1212
"time"
1313
)
1414

15-
// DefaultDbFile is the default name of the database file that contains all the key-value pairs
16-
const DefaultDbFile string = "dump.scdb"
15+
// defaultDbFile is the default name of the database file that contains all the key-value pairs
16+
const defaultDbFile string = "dump.scdb"
1717

18-
var ZeroU64 = internal.Uint64ToByteArray(0)
18+
var zeroU64 = internal.Uint64ToByteArray(0)
1919

20-
// Store is the public interface to the key-value store
21-
// that allows us to do operations like Set, Get, Delete, Clear and Compact
20+
// Store is a key-value store that persists key-value pairs to disk
21+
//
22+
// Store behaves like a HashMap that saves keys and value as byte arrays
23+
// on disk. It allows for specifying how long each key-value pair should be
24+
// kept for i.e. the time-to-live in seconds. If None is provided, they last indefinitely.
2225
type Store struct {
2326
bufferPool *buffers.BufferPool
2427
header *entries.DbFileHeader
@@ -27,14 +30,48 @@ type Store struct {
2730
isClosed bool
2831
}
2932

30-
// New creates a new Store at the given path, with the given `compactionInterval`
33+
// New creates a new Store at the given path
34+
// The Store has a number of configurations that are passed into this New function
35+
//
36+
// - `storePath` - required:
37+
// The path to a directory where scdb should store its data
38+
//
39+
// - `maxKeys` - default: 1 million:
40+
// The maximum number of key-value pairs to store in store
41+
//
42+
// - `redundantBlocks` - default: 1:
43+
// The store has an index to hold all the keys. This index is split
44+
// into a fixed number of blocks basing on the virtual memory page size
45+
// and the total number of keys to be held i.e. `max_keys`.
46+
// Sometimes, there may be hash collision errors as the store's
47+
// current stored keys approach `max_keys`. The closer it gets, the
48+
// more it becomes likely see those errors. Adding redundant blocks
49+
// helps mitigate this. Just be careful to not add too many (i.e. more than 2)
50+
// since the higher the number of these blocks, the slower the store becomes.
51+
//
52+
// - `poolCapacity` - default: 5:
53+
// The number of buffers to hold in memory as cache's for the store. Each buffer
54+
// has the size equal to the virtual memory's page size, usually 4096 bytes.
55+
// Increasing this number will speed this store up but of course, the machine
56+
// has a limited RAM. When this number increases to a value that clogs the RAM, performance
57+
// suddenly degrades, and keeps getting worse from there on.
58+
//
59+
// - `compactionInterval` - default 3600s (1 hour):
60+
// The interval at which the store is compacted to remove dangling
61+
// keys. Dangling keys result from either getting expired or being deleted.
62+
// When a `delete` operation is done, the actual key-value pair
63+
// is just marked as `deleted` but is not removed.
64+
// Something similar happens when a key-value is updated.
65+
// A new key-value pair is created and the old one is left unindexed.
66+
// Compaction is important because it reclaims this space and reduces the size
67+
// of the database file.
3168
func New(path string, maxKeys *uint64, redundantBlocks *uint16, poolCapacity *uint64, compactionInterval *uint32) (*Store, error) {
3269
err := os.MkdirAll(path, 0755)
3370
if err != nil {
3471
return nil, err
3572
}
3673

37-
dbFilePath := filepath.Join(path, DefaultDbFile)
74+
dbFilePath := filepath.Join(path, defaultDbFile)
3875
bufferPool, err := buffers.NewBufferPool(poolCapacity, dbFilePath, maxKeys, redundantBlocks, nil)
3976
if err != nil {
4077
return nil, err
@@ -133,7 +170,7 @@ func (s *Store) Get(k []byte) ([]byte, error) {
133170
return nil, err
134171
}
135172

136-
if bytes.Equal(kvOffsetInBytes, ZeroU64) {
173+
if bytes.Equal(kvOffsetInBytes, zeroU64) {
137174
continue
138175
}
139176

@@ -173,7 +210,7 @@ func (s *Store) Delete(k []byte) error {
173210
return err
174211
}
175212

176-
if bytes.Equal(kvOffsetInBytes, ZeroU64) {
213+
if bytes.Equal(kvOffsetInBytes, zeroU64) {
177214
continue
178215
}
179216

scdb/store_test.go

+79
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package scdb
33
import (
44
"fmt"
55
"github.com/stretchr/testify/assert"
6+
"log"
67
"os"
78
"path"
89
"runtime"
@@ -521,6 +522,84 @@ func BenchmarkStore_SetWithTtl(b *testing.B) {
521522

522523
}
523524

525+
func ExampleNew() {
526+
var maxKeys uint64 = 1_000_000
527+
var redundantBlocks uint16 = 1
528+
var poolCapacity uint64 = 10
529+
var compactionInterval uint32 = 1_800
530+
531+
store, err := New(
532+
"testdb",
533+
&maxKeys,
534+
&redundantBlocks,
535+
&poolCapacity,
536+
&compactionInterval)
537+
if err != nil {
538+
log.Fatalf("error opening store: %s", err)
539+
}
540+
defer func() {
541+
_ = store.Close()
542+
}()
543+
}
544+
545+
func ExampleStore_Set() {
546+
store, err := New("testdb", nil, nil, nil, nil)
547+
if err != nil {
548+
log.Fatalf("error opening store: %s", err)
549+
}
550+
defer func() {
551+
_ = store.Close()
552+
}()
553+
554+
err = store.Set([]byte("foo"), []byte("bar"), nil)
555+
if err != nil {
556+
log.Fatalf("error setting key value without ttl: %s", err)
557+
}
558+
559+
ttl := uint64(3_600)
560+
err = store.Set([]byte("fake"), []byte("bear"), &ttl)
561+
if err != nil {
562+
log.Fatalf("error setting key value with ttl: %s", err)
563+
}
564+
}
565+
566+
func ExampleStore_Get() {
567+
store, err := New("testdb", nil, nil, nil, nil)
568+
if err != nil {
569+
log.Fatalf("error opening store: %s", err)
570+
}
571+
defer func() {
572+
_ = store.Close()
573+
}()
574+
575+
err = store.Set([]byte("foo"), []byte("bar"), nil)
576+
if err != nil {
577+
log.Fatalf("error setting key value: %s", err)
578+
}
579+
580+
value, err := store.Get([]byte("foo"))
581+
if err != nil {
582+
log.Fatalf("error getting key: %s", err)
583+
}
584+
585+
fmt.Printf("%s", value)
586+
// Output: bar
587+
}
588+
func ExampleStore_Delete() {
589+
store, err := New("testdb", nil, nil, nil, nil)
590+
if err != nil {
591+
log.Fatalf("error opening store: %s", err)
592+
}
593+
defer func() {
594+
_ = store.Close()
595+
}()
596+
597+
err = store.Delete([]byte("foo"))
598+
if err != nil {
599+
log.Fatalf("error deleting key: %s", err)
600+
}
601+
}
602+
524603
// removeStore is a utility to remove the old store just before a given test is run
525604
func removeStore(t *testing.T, path string) {
526605
err := os.RemoveAll(path)

0 commit comments

Comments
 (0)