go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/gae/impl/memory/memstore.go (about)

     1  // Copyright 2015 The LUCI Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package memory
    16  
    17  import (
    18  	"bytes"
    19  
    20  	"github.com/luci/gtreap"
    21  
    22  	"go.chromium.org/luci/common/data/treapstore"
    23  
    24  	"go.chromium.org/luci/gae/service/datastore"
    25  )
    26  
    27  type storeEntry struct {
    28  	key   []byte
    29  	value []byte
    30  }
    31  
    32  // storeEntryCompare is a gtreap.Compare function for *storeEntry.
    33  func storeEntryCompare(a, b any) int {
    34  	// TODO(dnj): Investigate optimizing this by removing the type assertions,
    35  	// either by explicitly tailoring gtreap / treapstore to use []byte or by
    36  	// optimizing via special-case interface.
    37  	return bytes.Compare(a.(*storeEntry).key, b.(*storeEntry).key)
    38  }
    39  
    40  func memStoreCollide(o, n memCollection, f func(k, ov, nv []byte)) {
    41  	var oldIter, newIter memIterator
    42  	if o != nil {
    43  		if !o.IsReadOnly() {
    44  			panic("old collection is r/w")
    45  		}
    46  		oldIter = o.Iterator(nil)
    47  	} else {
    48  		oldIter = nilIterator{}
    49  	}
    50  
    51  	if n != nil {
    52  		if !n.IsReadOnly() {
    53  			panic("new collection is r/w")
    54  		}
    55  		newIter = n.Iterator(nil)
    56  	} else {
    57  		newIter = nilIterator{}
    58  	}
    59  
    60  	l, r := oldIter.Next(), newIter.Next()
    61  	for {
    62  		switch {
    63  		case l == nil:
    64  			// No more "old" items, use up the rest of "new" and finish.
    65  			for r != nil {
    66  				f(r.key, nil, r.value)
    67  				r = newIter.Next()
    68  			}
    69  			return
    70  
    71  		case r == nil:
    72  			// No more "new" items, use up the rest of "old" and finish.
    73  			for l != nil {
    74  				f(l.key, l.value, nil)
    75  				l = oldIter.Next()
    76  			}
    77  			return
    78  
    79  		default:
    80  			switch bytes.Compare(l.key, r.key) {
    81  			case -1: // l < r
    82  				f(l.key, l.value, nil)
    83  				l = oldIter.Next()
    84  			case 0: // l == r
    85  				f(l.key, l.value, r.value)
    86  				l, r = oldIter.Next(), newIter.Next()
    87  			case 1: // l > r
    88  				f(r.key, nil, r.value)
    89  				r = newIter.Next()
    90  			}
    91  		}
    92  	}
    93  }
    94  
    95  // memStore is a generic interface modeled after treapstore.Store.
    96  type memStore interface {
    97  	datastore.TestingSnapshot
    98  
    99  	GetCollection(name string) memCollection
   100  	GetCollectionNames() []string
   101  	GetOrCreateCollection(name string) memCollection
   102  	Snapshot() memStore
   103  
   104  	IsReadOnly() bool
   105  }
   106  
   107  // memIterator is an iterator over a memStore's contents.
   108  type memIterator interface {
   109  	Next() *storeEntry
   110  }
   111  
   112  // memVisitor is a callback for ForEachItem.
   113  type memVisitor func(k, v []byte) bool
   114  
   115  // memCollection is a generic interface modeled after treapstore.Collection.
   116  type memCollection interface {
   117  	Name() string
   118  	Delete(k []byte)
   119  	Get(k []byte) []byte
   120  	MinItem() *storeEntry
   121  	Set(k, v []byte)
   122  	Iterator(pivot []byte) memIterator
   123  	ForEachItem(memVisitor)
   124  
   125  	IsReadOnly() bool
   126  }
   127  
   128  type memStoreImpl struct {
   129  	s *treapstore.Store
   130  }
   131  
   132  var _ memStore = (*memStoreImpl)(nil)
   133  
   134  func (*memStoreImpl) ImATestingSnapshot() {}
   135  
   136  func (ms *memStoreImpl) IsReadOnly() bool { return ms.s.IsReadOnly() }
   137  
   138  func newMemStore() memStore {
   139  	ret := memStore(&memStoreImpl{treapstore.New()})
   140  	if *logMemCollectionFolder != "" {
   141  		ret = wrapTracingMemStore(ret)
   142  	}
   143  	return ret
   144  }
   145  
   146  func (ms *memStoreImpl) Snapshot() memStore {
   147  	if ms.s.IsReadOnly() {
   148  		return ms
   149  	}
   150  	return &memStoreImpl{ms.s.Snapshot()}
   151  }
   152  
   153  func (ms *memStoreImpl) GetCollection(name string) memCollection {
   154  	coll := ms.s.GetCollection(name)
   155  	if coll == nil {
   156  		return nil
   157  	}
   158  	return &memCollectionImpl{coll}
   159  }
   160  
   161  func (ms *memStoreImpl) GetOrCreateCollection(name string) memCollection {
   162  	coll := ms.s.GetCollection(name)
   163  	if coll == nil {
   164  		coll = ms.s.CreateCollection(name, storeEntryCompare)
   165  	}
   166  	return &memCollectionImpl{coll}
   167  }
   168  
   169  func (ms *memStoreImpl) GetCollectionNames() []string { return ms.s.GetCollectionNames() }
   170  
   171  type memIteratorImpl struct {
   172  	base *gtreap.Iterator
   173  }
   174  
   175  func (it *memIteratorImpl) Next() *storeEntry {
   176  	v, ok := it.base.Next()
   177  	if !ok {
   178  		return nil
   179  	}
   180  	return v.(*storeEntry)
   181  }
   182  
   183  type memCollectionImpl struct {
   184  	c *treapstore.Collection
   185  }
   186  
   187  var _ memCollection = (*memCollectionImpl)(nil)
   188  
   189  func (mc *memCollectionImpl) Name() string     { return mc.c.Name() }
   190  func (mc *memCollectionImpl) IsReadOnly() bool { return mc.c.IsReadOnly() }
   191  
   192  func (mc *memCollectionImpl) Get(k []byte) []byte {
   193  	if ent := mc.c.Get(storeKey(k)); ent != nil {
   194  		return ent.(*storeEntry).value
   195  	}
   196  	return nil
   197  }
   198  
   199  func (mc *memCollectionImpl) MinItem() *storeEntry {
   200  	ent, _ := mc.c.Min().(*storeEntry)
   201  	return ent
   202  }
   203  
   204  func (mc *memCollectionImpl) Set(k, v []byte) { mc.c.Put(&storeEntry{k, v}) }
   205  func (mc *memCollectionImpl) Delete(k []byte) { mc.c.Delete(storeKey(k)) }
   206  
   207  func (mc *memCollectionImpl) Iterator(target []byte) memIterator {
   208  	if !mc.c.IsReadOnly() {
   209  		// We prevent this to ensure our internal logic, not because it's actually
   210  		// an invalid operation.
   211  		panic("attempting to get Iterator from r/w memCollection")
   212  	}
   213  	return &memIteratorImpl{mc.c.Iterator(storeKey(target))}
   214  }
   215  
   216  func (mc *memCollectionImpl) ForEachItem(fn memVisitor) {
   217  	mc.c.VisitAscend(storeKey(nil), func(it gtreap.Item) bool {
   218  		ent := it.(*storeEntry)
   219  		return fn(ent.key, ent.value)
   220  	})
   221  }
   222  
   223  func storeKey(k []byte) *storeEntry { return &storeEntry{k, nil} }
   224  
   225  // nilIterator is a memIterator that begins in a depleted state.
   226  type nilIterator struct{}
   227  
   228  func (it nilIterator) Next() *storeEntry { return nil }