Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion posting/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -988,9 +988,14 @@ func (l *List) setMutationAfterCommit(startTs, commitTs uint64, pl *pb.PostingLi
}

if refresh {
// The committedEntries map may be aliased by other transactions' MutableLayer
// clones (see MutableLayer.clone), so we cannot mutate it in place. We do however
// copy the map by reference of its values: per the type's invariant (see comment
// above MutableLayer), committed entry *pb.PostingLists are treated as immutable
// once inserted, so a shallow copy is sufficient.
newMap := make(map[uint64]*pb.PostingList, l.mutationMap.len())
for k, v := range l.mutationMap.committedEntries {
newMap[k] = proto.Clone(v).(*pb.PostingList)
newMap[k] = v
}
newMap[commitTs] = pl
l.mutationMap.committedEntries = newMap
Expand Down
34 changes: 34 additions & 0 deletions posting/list_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1834,3 +1834,37 @@ func BenchmarkAddMutations(b *testing.B) {
}
}
}

// BenchmarkSetMutationAfterCommit exercises the commit hot path that builds a
// fresh committedEntries map. This is the path UpdateCachedKeys → updateItemInCache
// → setMutationAfterCommit(refresh=true) walks for every committed transaction
// against a cached List. Allocation behavior here directly drives GC pressure
// on heavily mutated lists.
func BenchmarkSetMutationAfterCommit(b *testing.B) {
for _, prior := range []int{1, 4, 32, 256} {
b.Run(fmt.Sprintf("priorEntries=%d", prior), func(b *testing.B) {
key := x.DataKey(x.AttrInRootNamespace("bench-commit"), uint64(prior))
l, err := GetNoStore(key, math.MaxUint64)
if err != nil {
b.Fatal(err)
}
l.mutationMap = newMutableLayer()
// Pre-populate committedEntries with `prior` versions to simulate a
// list that has been written many times.
for i := 0; i < prior; i++ {
pl := &pb.PostingList{
Postings: []*pb.Posting{{Uid: uint64(i + 1), Op: Set}},
}
l.mutationMap.committedEntries[uint64(i+1)] = pl
}
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
pl := &pb.PostingList{
Postings: []*pb.Posting{{Uid: uint64(i + 1000), Op: Set}},
}
l.setMutationAfterCommit(uint64(prior+i+1), uint64(prior+i+2), pl, true)
}
})
}
}
Loading