kythe.io@v0.0.68-0.20240422202219-7225dbc01741/kythe/go/storage/inmemory/inmemory.go (about) 1 /* 2 * Copyright 2014 The Kythe Authors. All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 // Package inmemory provides a in-memory implementation of graphstore.Service 18 // and keyvalue.DB. 19 package inmemory // import "kythe.io/kythe/go/storage/inmemory" 20 21 import ( 22 "context" 23 "fmt" 24 "io" 25 "sort" 26 "strings" 27 "sync" 28 29 "kythe.io/kythe/go/services/graphstore" 30 "kythe.io/kythe/go/storage/keyvalue" 31 "kythe.io/kythe/go/util/compare" 32 33 "google.golang.org/protobuf/proto" 34 35 spb "kythe.io/kythe/proto/storage_go_proto" 36 ) 37 38 // GraphStore implements the graphstore.Service interface. A zero of this type 39 // is ready for use, and is safe for access by concurrent goroutines. 40 type GraphStore struct { 41 mu sync.RWMutex 42 entries []*spb.Entry 43 } 44 45 // Close implements io.Closer. It never returns an error. 46 func (*GraphStore) Close(ctx context.Context) error { return nil } 47 48 // Write implements part of the graphstore.Service interface. 49 func (s *GraphStore) Write(ctx context.Context, req *spb.WriteRequest) error { 50 s.mu.Lock() 51 defer s.mu.Unlock() 52 for _, u := range req.Update { 53 s.insert(proto.Clone(&spb.Entry{ 54 Source: req.Source, 55 EdgeKind: u.EdgeKind, 56 Target: u.Target, 57 FactName: u.FactName, 58 FactValue: u.FactValue, 59 }).(*spb.Entry)) 60 } 61 return nil 62 } 63 64 func (s *GraphStore) insert(e *spb.Entry) { 65 i := sort.Search(len(s.entries), func(i int) bool { 66 return compare.Entries(e, s.entries[i]) == compare.LT 67 }) 68 if i == len(s.entries) { 69 s.entries = append(s.entries, e) 70 } else if i < len(s.entries) && compare.EntriesEqual(e, s.entries[i]) { 71 s.entries[i] = e 72 } else if i == 0 { 73 s.entries = append([]*spb.Entry{e}, s.entries...) 74 } else { 75 s.entries = append(s.entries[:i], append([]*spb.Entry{e}, s.entries[i:]...)...) 76 } 77 } 78 79 // Read implements part of the graphstore.Service interface. 80 func (s *GraphStore) Read(ctx context.Context, req *spb.ReadRequest, f graphstore.EntryFunc) error { 81 s.mu.RLock() 82 defer s.mu.RUnlock() 83 start := sort.Search(len(s.entries), func(i int) bool { 84 comp := compare.VNames(s.entries[i].Source, req.Source) 85 return comp != compare.LT && (comp == compare.GT || req.EdgeKind == "*" || s.entries[i].EdgeKind >= req.EdgeKind) 86 }) 87 end := sort.Search(len(s.entries), func(i int) bool { 88 comp := compare.VNames(s.entries[i].Source, req.Source) 89 return comp == compare.GT || (comp != compare.LT && req.EdgeKind != "*" && s.entries[i].EdgeKind > req.EdgeKind) 90 }) 91 for i := start; i < end; i++ { 92 if err := f(s.entries[i]); err == io.EOF { 93 return nil 94 } else if err != nil { 95 return err 96 } 97 } 98 return nil 99 } 100 101 // Scan implements part of the graphstore.Service interface. 102 func (s *GraphStore) Scan(ctx context.Context, req *spb.ScanRequest, f graphstore.EntryFunc) error { 103 s.mu.RLock() 104 defer s.mu.RUnlock() 105 106 for _, e := range s.entries { 107 if !graphstore.EntryMatchesScan(req, e) { 108 continue 109 } else if err := f(e); err == io.EOF { 110 return nil 111 } else if err != nil { 112 return err 113 } 114 } 115 return nil 116 } 117 118 // NewKeyValueDB returns a keyvalue.DB backed by an in-memory data structure. 119 func NewKeyValueDB() *KeyValueDB { 120 return &KeyValueDB{ 121 db: make(map[string][]byte), 122 } 123 } 124 125 // KeyValueDB implements the keyvalue.DB interface backed by an in-memory map. 126 type KeyValueDB struct { 127 mu sync.RWMutex 128 db map[string][]byte 129 keys []string 130 } 131 132 var _ keyvalue.DB = &KeyValueDB{} 133 134 // Get implements part of the keyvalue.DB interface. 135 func (k *KeyValueDB) Get(ctx context.Context, key []byte, opts *keyvalue.Options) ([]byte, error) { 136 k.mu.RLock() 137 defer k.mu.RUnlock() 138 val, ok := k.db[string(key)] 139 if !ok { 140 return nil, io.EOF 141 } 142 return val, nil 143 } 144 145 type kvPrefixIterator struct { 146 db *KeyValueDB 147 prefix string 148 idx int 149 } 150 151 // Next implements part of the keyvalue.Iterator interface. 152 func (p *kvPrefixIterator) Next() (key, val []byte, err error) { 153 if p.idx >= len(p.db.keys) || !strings.HasPrefix(p.db.keys[p.idx], p.prefix) { 154 return nil, nil, io.EOF 155 } 156 157 k := p.db.keys[p.idx] 158 v := p.db.db[k] 159 p.idx++ 160 return []byte(k), []byte(v), nil 161 } 162 163 // Seek implements part of the keyvalue.Iterator interface. 164 func (p *kvPrefixIterator) Seek(k []byte) error { 165 s := string(k) 166 i := sort.Search(len(p.db.keys), func(i int) bool { return strings.Compare(p.db.keys[i], s) >= 0 }) 167 if i < p.idx { 168 return fmt.Errorf("given key before current iterator position: %q", k) 169 } 170 p.idx = i 171 return nil 172 } 173 174 // Close implements part of the keyvalue.Iterator interface. 175 func (p *kvPrefixIterator) Close() error { 176 p.db.mu.RUnlock() 177 return nil 178 } 179 180 // ScanPrefix implements part of the keyvalue.DB interface. 181 func (k *KeyValueDB) ScanPrefix(ctx context.Context, prefix []byte, opts *keyvalue.Options) (keyvalue.Iterator, error) { 182 k.mu.RLock() 183 p := string(prefix) 184 i := sort.Search(len(k.keys), func(i int) bool { return strings.Compare(k.keys[i], p) >= 0 }) 185 return &kvPrefixIterator{k, p, i}, nil 186 } 187 188 type kvRangeIterator struct { 189 db *KeyValueDB 190 end *string 191 idx int 192 } 193 194 // Next implements part of the keyvalue.Iterator interface. 195 func (p *kvRangeIterator) Next() (key, val []byte, err error) { 196 if p.idx >= len(p.db.keys) || (p.end != nil && strings.Compare(p.db.keys[p.idx], *p.end) >= 0) { 197 return nil, nil, io.EOF 198 } 199 200 k := p.db.keys[p.idx] 201 v := p.db.db[k] 202 p.idx++ 203 return []byte(k), []byte(v), nil 204 } 205 206 // Seek implements part of the keyvalue.Iterator interface. 207 func (p *kvRangeIterator) Seek(k []byte) error { 208 s := string(k) 209 i := sort.Search(len(p.db.keys), func(i int) bool { return strings.Compare(p.db.keys[i], s) >= 0 }) 210 if i < p.idx { 211 return fmt.Errorf("given key before current iterator position: %q", k) 212 } 213 p.idx = i 214 return nil 215 } 216 217 // Close implements part of the keyvalue.Iterator interface. 218 func (p *kvRangeIterator) Close() error { 219 p.db.mu.RUnlock() 220 return nil 221 } 222 223 // ScanRange implements part of the keyvalue.DB interface. 224 func (k *KeyValueDB) ScanRange(ctx context.Context, r *keyvalue.Range, opts *keyvalue.Options) (keyvalue.Iterator, error) { 225 k.mu.RLock() 226 var start int 227 if r != nil && len(r.Start) != 0 { 228 s := string(r.Start) 229 start = sort.Search(len(k.keys), func(i int) bool { return strings.Compare(k.keys[i], s) >= 0 }) 230 } 231 var end *string 232 if r != nil && r.End != nil { 233 e := string(r.End) 234 end = &e 235 } 236 return &kvRangeIterator{k, end, start}, nil 237 } 238 239 type kvWriter struct{ db *KeyValueDB } 240 241 // Write implements part of the keyvalue.Writer interface. 242 func (w kvWriter) Write(key, val []byte) error { 243 k := string(key) 244 i := sort.Search(len(w.db.keys), func(i int) bool { return strings.Compare(w.db.keys[i], k) >= 0 }) 245 if i == len(w.db.keys) { 246 w.db.keys = append(w.db.keys, k) 247 } else if w.db.keys[i] != k { 248 w.db.keys = append(w.db.keys[:i], append([]string{k}, w.db.keys[i:]...)...) 249 } 250 w.db.db[k] = val 251 return nil 252 } 253 254 // Close implements part of the keyvalue.Writer interface. 255 func (w kvWriter) Close() error { 256 w.db.mu.Unlock() 257 return nil 258 } 259 260 // Writer implements part of the keyvalue.DB interface. 261 func (k *KeyValueDB) Writer(ctx context.Context) (keyvalue.Writer, error) { 262 k.mu.Lock() 263 return kvWriter{k}, nil 264 } 265 266 // NewSnapshot implements part of the keyvalue.DB interface. 267 func (k *KeyValueDB) NewSnapshot(ctx context.Context) keyvalue.Snapshot { return nil } 268 269 // Close implements part of the keyvalue.DB interface. 270 func (k *KeyValueDB) Close(context.Context) error { return nil }