func (ind *indices) getNode(ref ast.Ref) *indicesNode { hashCode := ref.Hash() for entry := ind.table[hashCode]; entry != nil; entry = entry.next { if entry.key.Equal(ref) { return entry } } return nil }
// Drop removes the index for the reference. func (ind *indices) Drop(ref ast.Ref) { hashCode := ref.Hash() var prev *indicesNode for entry := ind.table[hashCode]; entry != nil; entry = entry.next { if entry.key.Equal(ref) { if prev == nil { ind.table[hashCode] = entry.next } else { prev.next = entry.next } return } } }
// BuildIndex causes the storage layer to create an index for the given // reference over the snapshot identified by the transaction. func (s *Storage) BuildIndex(ctx context.Context, txn Transaction, ref ast.Ref) error { path, err := NewPathForRef(ref.GroundPrefix()) if err != nil { return indexingNotSupportedError() } // TODO(tsandall): for now we prevent indexing against stores other than the // built-in. This will be revisited in the future. To determine the // reference touches an external store, we collect the ground portion of // the reference and see if it matches any mounts. for _, mount := range s.mounts { if path.HasPrefix(mount.path) || mount.path.HasPrefix(path) { return indexingNotSupportedError() } } return s.indices.Build(ctx, s.builtin, txn, ref) }
// Build initializes the references' index by walking the store for the reference and // creating the index that maps values to bindings. func (ind *indices) Build(ctx context.Context, store Store, txn Transaction, ref ast.Ref) error { index := newBindingIndex() ind.registerTriggers(store) err := iterStorage(ctx, store, txn, ref, ast.EmptyRef(), ast.NewValueMap(), func(bindings *ast.ValueMap, val interface{}) { index.Add(val, bindings) }) if err != nil { return err } hashCode := ref.Hash() head := ind.table[hashCode] entry := &indicesNode{ key: ref, val: index, next: head, } ind.table[hashCode] = entry return nil }