runMutation goes through all the edges and applies them.
(ctx context.Context, edge *pb.DirectedEdge, txn *posting.Txn)
| 57 | |
| 58 | // runMutation goes through all the edges and applies them. |
| 59 | func runMutation(ctx context.Context, edge *pb.DirectedEdge, txn *posting.Txn) error { |
| 60 | ctx = schema.GetWriteContext(ctx) |
| 61 | |
| 62 | // We shouldn't check whether this Alpha serves this predicate or not. Membership information |
| 63 | // isn't consistent across the entire cluster. We should just apply whatever is given to us. |
| 64 | su, ok := schema.State().Get(ctx, edge.Attr) |
| 65 | if edge.Op != pb.DirectedEdge_DEL { |
| 66 | if !ok { |
| 67 | return errors.Errorf("runMutation: Unable to find schema for %s", edge.Attr) |
| 68 | } |
| 69 | } |
| 70 | |
| 71 | if isDeletePredicateEdge(edge) { |
| 72 | return errors.New("We should never reach here") |
| 73 | } |
| 74 | |
| 75 | // Once mutation comes via raft we do best effort conversion |
| 76 | // Type check is done before proposing mutation, in case schema is not |
| 77 | // present, some invalid entries might be written initially |
| 78 | if err := ValidateAndConvert(edge, &su); err != nil { |
| 79 | return err |
| 80 | } |
| 81 | |
| 82 | key := x.DataKey(edge.Attr, edge.Entity) |
| 83 | // The following is a performance optimization which allows us to not read a posting list from |
| 84 | // disk. We calculate this based on how AddMutationWithIndex works. The general idea is that if |
| 85 | // we're not using the read posting list, we don't need to retrieve it. We need the posting list |
| 86 | // if we're doing count index or delete operation. For scalar predicates, we just get the last item merged. |
| 87 | // In other cases, we can just create a posting list facade in memory and use it to store the delta in Badger. |
| 88 | // Later, the rollup operation would consolidate all these deltas into a posting list. |
| 89 | isList := su.GetList() |
| 90 | var getFn func(key []byte) (*posting.List, error) |
| 91 | switch { |
| 92 | case len(edge.Lang) == 0 && !isList: |
| 93 | // Scalar Predicates, without lang |
| 94 | getFn = txn.GetScalarList |
| 95 | case len(edge.Lang) > 0 || su.GetCount(): |
| 96 | // Language or Count Index |
| 97 | getFn = txn.Get |
| 98 | case edge.Op == pb.DirectedEdge_DEL: |
| 99 | // Covers various delete cases to keep things simple. |
| 100 | getFn = txn.Get |
| 101 | default: |
| 102 | // Only count index needs to be read. For other indexes on list, we don't need to read any data. |
| 103 | // For indexes on scalar prediactes, only the last element needs to be left. |
| 104 | // Delete cases covered above. |
| 105 | getFn = txn.GetFromDelta |
| 106 | } |
| 107 | |
| 108 | t := time.Now() |
| 109 | plist, err := getFn(key) |
| 110 | if dur := time.Since(t); dur > time.Millisecond { |
| 111 | span := trace.SpanFromContext(ctx) |
| 112 | span.AddEvent("Slow GetLru", trace.WithAttributes( |
| 113 | attribute.Bool("slow-get", true), |
| 114 | attribute.String("duration", dur.String()))) |
| 115 | } |
| 116 | if err != nil { |
searching dependent graphs…