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 }