Skip to content

Commit d201799

Browse files
authored
fix(cache): Estimate size of posting lists (#9515)
**Description** The maximum cost of the Ristretto cache is set to a number of megabytes, but when inserting a posting list item into the cache, the cost is set to 1. Because of this the cache only grows and no items get evicted. This results in high memory consumption, especially with the new UID cache (see #9513). This PR introduces a cost function which estimates the memory size of each item. For more details see predictable-labs#6. Credits to @darkcoderrises for the implementation. The default cache size is changed from 1024 to 4096, to reflect the more accurate cost estimation. See below for how the size of the cache relates to the occupied memory by the Dgrpah process, when this PR is applied. size-mb=1024 Dgraph process occupies up to 3.7 GiB of memory heap: ``` 344.49MB 30.34% 30.34% 407.26MB 35.87% github.com/hypermodeinc/dgraph/v25/posting.(*List).calculateUids 130.37MB 11.48% 41.83% 130.37MB 11.48% github.com/dgraph-io/ristretto/v2.newCmRow 83.20MB 7.33% 49.15% 83.20MB 7.33% github.com/dgraph-io/badger/v4/skl.newArena 69.50MB 6.12% 55.28% 69.50MB 6.12% github.com/hypermodeinc/dgraph/v25/posting.(*List).Uids.func1 65.16MB 5.74% 61.02% 65.16MB 5.74% github.com/dgraph-io/ristretto/v2/z.(*Bloom).Size 53.27MB 4.69% 65.71% 53.27MB 4.69% github.com/hypermodeinc/dgraph/v25/posting.(*List).calculateUids.func1 ``` size-mb=2048 Dgraph process occupies up to 5.4 GiB of memory heap: ``` 637.07MB 33.68% 33.68% 699.33MB 36.97% github.com/hypermodeinc/dgraph/v25/posting.(*List).calculateUids 260.63MB 13.78% 47.46% 260.63MB 13.78% github.com/dgraph-io/ristretto/v2.newCmRow 130.04MB 6.88% 54.34% 130.04MB 6.88% github.com/dgraph-io/ristretto/v2/z.(*Bloom).Size 99.01MB 5.23% 59.57% 99.01MB 5.23% github.com/hypermodeinc/dgraph/v25/posting.(*List).Uids.func1 89.89MB 4.75% 64.32% 89.89MB 4.75% github.com/dgraph-io/ristretto/v2.(*lockedMap[go.shape.*uint8]).Set 83.20MB 4.40% 68.72% 83.20MB 4.40% github.com/dgraph-io/badger/v4/skl.newArena ``` size-mb=4096 Dgraph process occupies up to 8.4 GiB of memory heap: ``` 1343.44MB 41.61% 41.61% 1404.71MB 43.51% github.com/hypermodeinc/dgraph/v25/posting.(*List).calculateUids 520.15MB 16.11% 57.72% 520.15MB 16.11% github.com/dgraph-io/ristretto/v2.newCmRow 260MB 8.05% 65.77% 260MB 8.05% github.com/dgraph-io/ristretto/v2/z.(*Bloom).Size 136.70MB 4.23% 70.01% 136.70MB 4.23% github.com/dgraph-io/ristretto/v2.(*lockedMap[go.shape.*uint8]).Set 106.51MB 3.30% 73.31% 106.51MB 3.30% reflect.New 83.20MB 2.58% 75.88% 83.20MB 2.58% github.com/dgraph-io/badger/v4/skl.newArena ``` size-mb=8192 Dgraph process occupies up to 13.3 GiB of memory heap: ``` 2539.78MB 45.10% 45.10% 2601.10MB 46.19% github.com/hypermodeinc/dgraph/v25/posting.(*List).calculateUids 1040.01MB 18.47% 63.56% 1040.01MB 18.47% github.com/dgraph-io/ristretto/v2.newCmRow 520MB 9.23% 72.80% 520MB 9.23% github.com/dgraph-io/ristretto/v2/z.(*Bloom).Size 223.52MB 3.97% 76.77% 223.52MB 3.97% reflect.New 157.97MB 2.81% 79.57% 157.97MB 2.81% github.com/dgraph-io/ristretto/v2.(*lockedMap[go.shape.*uint8]).Set 136.01MB 2.42% 81.99% 259.03MB 4.60% github.com/hypermodeinc/dgraph/v25/posting.copyList ``` Closes #9513
1 parent c5b88b5 commit d201799

File tree

3 files changed

+99
-4
lines changed

3 files changed

+99
-4
lines changed

posting/mvcc.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,7 @@ func (c *Cache) set(key []byte, i *CachePL) {
370370
return
371371
}
372372
c.numCacheSave.Add(1)
373-
c.data.Set(key, i, 1)
373+
c.data.Set(key, i, 0)
374374
}
375375

376376
func (c *Cache) del(key []byte) {
@@ -508,14 +508,18 @@ func initMemoryLayer(cacheSize int64, removeOnUpdate bool) *MemoryLayer {
508508
ml.removeOnUpdate = removeOnUpdate
509509
ml.statsHolder = NewStatsHolder()
510510
if cacheSize > 0 {
511-
cache, err := ristretto.NewCache[[]byte, *CachePL](&ristretto.Config[[]byte, *CachePL]{
511+
cache, err := ristretto.NewCache(&ristretto.Config[[]byte, *CachePL]{
512512
// Use 5% of cache memory for storing counters.
513513
NumCounters: int64(float64(cacheSize) * 0.05 * 2),
514514
MaxCost: int64(float64(cacheSize) * 0.95),
515515
BufferItems: 16,
516516
Metrics: true,
517517
Cost: func(val *CachePL) int64 {
518-
return 1
518+
itemSize := int64(8)
519+
if val.list != nil {
520+
itemSize += int64(val.list.ApproximateSize())
521+
}
522+
return itemSize
519523
},
520524
ShouldUpdate: func(cur, prev *CachePL) bool {
521525
return !(cur.list != nil && prev.list != nil && prev.list.maxTs > cur.list.maxTs)

posting/size.go

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,97 @@ import (
1616

1717
const sizeOfBucket = 144
1818

19+
func (l *List) ApproximateSize() uint64 {
20+
if l == nil {
21+
return 0
22+
}
23+
24+
l.RLock()
25+
defer l.RUnlock()
26+
27+
var size uint64 = 4*8 + // safe mutex consists of 4 words.
28+
1*8 + // plist pointer consists of 1 word.
29+
1*8 + // mutation map pointer consists of 1 word.
30+
2*8 + // minTs and maxTs take 1 word each.
31+
3*8 + // array take 3 words. so key array is 3 words.
32+
3*8 + // array take 3 words. so cache array is 3 words.
33+
1*8 // So far 11 words, in order to round the slab we're adding one more word.
34+
// so far basic struct layout has been calculated.
35+
36+
// add byte array memory
37+
size += uint64(cap(l.key)) + uint64(cap(l.cache))
38+
39+
size += approxPostingListSize(l.plist)
40+
41+
if l.mutationMap != nil {
42+
size += l.mutationMap.ApproximateSize()
43+
}
44+
45+
return size
46+
}
47+
48+
func approxPostingListSize(list *pb.PostingList) uint64 {
49+
if list == nil {
50+
return 0
51+
}
52+
53+
var size uint64 = 1*8 + // Pack consists of 1 word.
54+
3*8 + // Postings array consists of 3 words.
55+
1*8 + // CommitTs consists of 1 word.
56+
3*8 // Splits array consists of 3 words.
57+
58+
// add pack size.
59+
size += calculatePackSize(list.Pack)
60+
61+
// Each entry take one word.
62+
// Adding each entry reference allocation.
63+
size += uint64(cap(list.Postings)) * 8
64+
for _, p := range list.Postings {
65+
// add the size of each posting.
66+
size += calculatePostingSize(p) * uint64(cap(list.Postings))
67+
break
68+
}
69+
70+
// Each entry take one word.
71+
// Adding each entry size.
72+
size += uint64(cap(list.Splits)) * 8
73+
74+
return size
75+
}
76+
77+
func (m *MutableLayer) ApproximateSize() uint64 {
78+
if m == nil {
79+
return 0
80+
}
81+
82+
var size uint64 = 2*8 + // committedEntries and currentEntries take 2 words each.
83+
1*8 + // readTs takes 1 word.
84+
1*8 + // deleteAllMarker takes 1 word.
85+
1*8 + // committedUids takes 1 word.
86+
1*8 + // committedUidsTime takes 1 word.
87+
1*8 + // length takes 1 word.
88+
1*8 + // lastEntry takes 1 word.
89+
1*8 + // committedUidsTime takes 1 word.
90+
1*8 + // isUidsCalculated takes 1 word.
91+
1*8 // calculatedUids takes 1 word.
92+
// so far basic struct layout has been calculated.
93+
94+
// Add each entry size of committedEntries.
95+
size += uint64(len(m.committedEntries)) * 8
96+
for _, v := range m.committedUids {
97+
size += calculatePostingSize(v) * uint64(len(m.committedEntries))
98+
break
99+
}
100+
101+
size += approxPostingListSize(m.currentEntries)
102+
size += approxPostingListSize(m.lastEntry)
103+
104+
size += uint64(len(m.currentUids)) * 8
105+
size += uint64(cap(m.calculatedUids)) * 8
106+
107+
return size
108+
}
109+
19110
// DeepSize computes the memory taken by a Posting List
20111
func (l *List) DeepSize() uint64 {
21112
if l == nil {

worker/server_state.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ const (
4141
ZeroLimitsDefaults = `uid-lease=0; refill-interval=30s; disable-admin-http=false;`
4242
GraphQLDefaults = `introspection=true; debug=false; extensions=true; poll-interval=1s; ` +
4343
`lambda-url=;`
44-
CacheDefaults = `size-mb=1024; percentage=40,40,20; remove-on-update=false`
44+
CacheDefaults = `size-mb=4096; percentage=40,40,20; remove-on-update=false`
4545
FeatureFlagsDefaults = `normalize-compatibility-mode=; enable-detailed-metrics=false`
4646
)
4747

0 commit comments

Comments
 (0)