-
Notifications
You must be signed in to change notification settings - Fork 508
/
filekeyvaluestore.go
170 lines (153 loc) · 4.27 KB
/
filekeyvaluestore.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
/*
Copyright SecureKey Technologies Inc. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package keyvaluestore
import (
"io/ioutil"
"os"
"path/filepath"
"github.com/hyperledger/fabric-sdk-go/pkg/common/providers/core"
"github.com/pkg/errors"
)
const (
newDirMode = 0700
newFileMode = 0600
)
// KeySerializer converts a key to a unique fila path
type KeySerializer func(key interface{}) (string, error)
// Marshaller marshals a value into a byte array
type Marshaller func(value interface{}) ([]byte, error)
// Unmarshaller unmarshals a value from a byte array
type Unmarshaller func(value []byte) (interface{}, error)
// FileKeyValueStore stores each value into a separate file.
// KeySerializer maps a key to a unique file path (raletive to the store path)
// ValueSerializer and ValueDeserializer serializes/de-serializes a value
// to and from a byte array that is stored in the path derived from the key.
type FileKeyValueStore struct {
path string
keySerializer KeySerializer
marshaller Marshaller
unmarshaller Unmarshaller
}
// FileKeyValueStoreOptions allow overriding store defaults
type FileKeyValueStoreOptions struct {
// Store path, mandatory
Path string
// Optional. If not provided, default key serializer is used.
KeySerializer KeySerializer
// Optional. If not provided, default Marshaller is used.
Marshaller Marshaller
// Optional. If not provided, default Unmarshaller is used.
Unmarshaller Unmarshaller
}
// Default Marshaller
func defaultMarshaller(value interface{}) ([]byte, error) {
if value == nil {
return nil, nil
}
valueBytes, ok := value.([]byte)
if !ok {
return nil, errors.New("converting value to byte array failed")
}
return valueBytes, nil
}
// Default Unmarshaller
func defaultUnmarshaller(value []byte) (interface{}, error) {
return value, nil
}
// GetPath returns the store path
func (fkvs *FileKeyValueStore) GetPath() string {
return fkvs.path
}
// New creates a new instance of FileKeyValueStore using provided options
func New(opts *FileKeyValueStoreOptions) (*FileKeyValueStore, error) {
if opts == nil {
return nil, errors.New("FileKeyValueStoreOptions is nil")
}
if opts.Path == "" {
return nil, errors.New("FileKeyValueStore path is empty")
}
if opts.KeySerializer == nil {
// Default key serializer
opts.KeySerializer = func(key interface{}) (string, error) {
keyString, ok := key.(string)
if !ok {
return "", errors.New("converting key to string failed")
}
return filepath.Join(opts.Path, keyString), nil
}
}
if opts.Marshaller == nil {
opts.Marshaller = defaultMarshaller
}
if opts.Unmarshaller == nil {
opts.Unmarshaller = defaultUnmarshaller
}
return &FileKeyValueStore{
path: opts.Path,
keySerializer: opts.KeySerializer,
marshaller: opts.Marshaller,
unmarshaller: opts.Unmarshaller,
}, nil
}
// Load returns the value stored in the store for a key.
// If a value for the key was not found, returns (nil, ErrNotFound)
func (fkvs *FileKeyValueStore) Load(key interface{}) (interface{}, error) {
file, err := fkvs.keySerializer(key)
if err != nil {
return nil, err
}
if _, err1 := os.Stat(file); os.IsNotExist(err1) {
return nil, core.ErrKeyValueNotFound
}
bytes, err := ioutil.ReadFile(file) // nolint: gas
if err != nil {
return nil, err
}
if bytes == nil {
return nil, core.ErrKeyValueNotFound
}
return fkvs.unmarshaller(bytes)
}
// Store sets the value for the key.
func (fkvs *FileKeyValueStore) Store(key interface{}, value interface{}) error {
if key == nil {
return errors.New("key is nil")
}
if value == nil {
return errors.New("value is nil")
}
file, err := fkvs.keySerializer(key)
if err != nil {
return err
}
valueBytes, err := fkvs.marshaller(value)
if err != nil {
return err
}
err = os.MkdirAll(filepath.Dir(file), newDirMode)
if err != nil {
return err
}
return ioutil.WriteFile(file, valueBytes, newFileMode)
}
// Delete deletes the value for a key.
func (fkvs *FileKeyValueStore) Delete(key interface{}) error {
if key == nil {
return errors.New("key is nil")
}
file, err := fkvs.keySerializer(key)
if err != nil {
return err
}
_, err = os.Stat(file)
if err != nil {
if !os.IsNotExist(err) {
return errors.Wrapf(err, "stat dir failed")
}
// Doesn't exist, OK
return nil
}
return os.Remove(file)
}