1 package keystore 2 3 import ( 4 "errors" 5 "io" 6 "sort" 7 "sync" 8 9 "vimagination.zapto.org/byteio" 10 "vimagination.zapto.org/memio" 11 ) 12 13 // MemStore implements Store and does so entirely in memory. 14 type MemStore struct { 15 mu sync.RWMutex 16 data map[string]memio.Buffer 17 } 18 19 // NewMemStore creates a new memory-backed key-value store. 20 func NewMemStore() *MemStore { 21 ms := new(MemStore) 22 23 ms.init() 24 25 return ms 26 } 27 28 func (ms *MemStore) init() { 29 ms.data = make(map[string]memio.Buffer) 30 } 31 32 // Get retrieves the key data from memory. 33 func (ms *MemStore) Get(key string, r io.ReaderFrom) error { 34 d := ms.get(key) 35 if d == nil { 36 return ErrUnknownKey 37 } 38 39 _, err := r.ReadFrom(&d) 40 41 return err 42 } 43 44 // GetAll retrieves data for all of the keys given. Useful to reduce locking. 45 // Unknown Key errors are not returned, only errors from the ReaderFrom's. 46 func (ms *MemStore) GetAll(data map[string]io.ReaderFrom) error { 47 var err error 48 49 ms.mu.RLock() 50 51 for k, d := range data { 52 buf, ok := ms.data[k] 53 if !ok { 54 continue 55 } 56 57 if _, err = d.ReadFrom(&buf); err != nil { 58 return err 59 } 60 } 61 62 ms.mu.RUnlock() 63 64 return err 65 } 66 67 func (ms *MemStore) get(key string) memio.Buffer { 68 ms.mu.RLock() 69 d := ms.data[key] 70 ms.mu.RUnlock() 71 72 return d 73 } 74 75 // Set stores the key data in memory. 76 func (ms *MemStore) Set(key string, w io.WriterTo) error { 77 d := make(memio.Buffer, 0) 78 79 if _, err := w.WriteTo(&d); err != nil && !errors.Is(err, io.EOF) { 80 return err 81 } 82 83 ms.set(key, d) 84 85 return nil 86 } 87 88 // SetAll set data for all of the keys given. Useful to reduce locking. 89 // Will return the first error found, so may not set all data. 90 func (ms *MemStore) SetAll(data map[string]io.WriterTo) error { 91 var err error 92 93 ms.mu.Lock() 94 95 for k, d := range data { 96 var buf memio.Buffer 97 98 if _, err = d.WriteTo(&buf); err != nil { 99 break 100 } 101 102 ms.data[k] = buf 103 } 104 105 ms.mu.Unlock() 106 107 return err 108 } 109 110 func (ms *MemStore) set(key string, d memio.Buffer) { 111 ms.mu.Lock() 112 ms.data[key] = d 113 ms.mu.Unlock() 114 } 115 116 // Remove deletes the key data from memory. 117 func (ms *MemStore) Remove(key string) error { 118 ms.mu.Lock() 119 defer ms.mu.Unlock() 120 121 _, ok := ms.data[key] 122 if !ok { 123 return ErrUnknownKey 124 } 125 126 delete(ms.data, key) 127 128 return nil 129 } 130 131 // RemoveAll will attempt to remove all keys given. It does not return an error 132 // if a key doesn't exist. 133 func (ms *MemStore) RemoveAll(keys ...string) { 134 ms.mu.Lock() 135 136 for _, key := range keys { 137 delete(ms.data, key) 138 } 139 140 ms.mu.Unlock() 141 } 142 143 // WriteTo implements the io.WriterTo interface allowing a MemStore to be 144 // be stored in another Store. 145 func (ms *MemStore) WriteTo(w io.Writer) (int64, error) { 146 lw := byteio.StickyLittleEndianWriter{Writer: w} 147 148 ms.mu.RLock() 149 150 for key, value := range ms.data { 151 lw.WriteStringX(key) 152 lw.WriteUintX(uint64(len(value))) 153 lw.Write(value) 154 } 155 156 ms.mu.RUnlock() 157 158 return lw.Count, lw.Err 159 } 160 161 // ReadFrom implements the io.ReaderFrom interface allowing a MemStore to be 162 // be retrieved in another Store. 163 func (ms *MemStore) ReadFrom(r io.Reader) (int64, error) { 164 lr := byteio.StickyLittleEndianReader{Reader: r} 165 166 ms.mu.Lock() 167 168 for { 169 key := lr.ReadStringX() 170 171 if errors.Is(lr.Err, io.EOF) { 172 lr.Err = nil 173 174 break 175 } 176 177 buf := make(memio.Buffer, lr.ReadUintX()) 178 179 lr.Read(buf) 180 181 if lr.Err != nil { 182 if errors.Is(lr.Err, io.EOF) { 183 lr.Err = io.ErrUnexpectedEOF 184 } 185 186 break 187 } 188 189 ms.data[key] = buf 190 } 191 192 ms.mu.Unlock() 193 194 return lr.Count, lr.Err 195 } 196 197 // Keys returns a sorted slice of all of the keys. 198 func (ms *MemStore) Keys() []string { 199 ms.mu.RLock() 200 201 s := make([]string, 0, len(ms.data)) 202 203 for key := range ms.data { 204 s = append(s, key) 205 } 206 207 ms.mu.RUnlock() 208 209 sort.Strings(s) 210 211 return s 212 } 213 214 // Exists returns true when the key exists within the store. 215 func (ms *MemStore) Exists(key string) bool { 216 ms.mu.RLock() 217 _, ok := ms.data[key] 218 ms.mu.RUnlock() 219 220 return ok 221 } 222 223 // Rename moves data from an existing key to a new, unused key. 224 func (ms *MemStore) Rename(oldkey, newkey string) error { 225 ms.mu.Lock() 226 227 var err error 228 229 if d, ok := ms.data[oldkey]; !ok { 230 err = ErrUnknownKey 231 } else if _, ok = ms.data[newkey]; ok { 232 err = ErrKeyExists 233 } else { 234 ms.data[newkey] = d 235 236 delete(ms.data, oldkey) 237 } 238 239 ms.mu.Unlock() 240 241 return err 242 } 243