Skip to content

Commit 3fb6d31

Browse files
authored
feat: implement parent pointer tree recovery (#3390)
1 parent dfd129c commit 3fb6d31

File tree

2 files changed

+69
-0
lines changed

2 files changed

+69
-0
lines changed

pkg/phlaredb/symdb/stacktrace_tree.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,37 @@ func (t *parentPointerTree) Nodes() []Node {
186186
return dst
187187
}
188188

189+
func (t *parentPointerTree) toStacktraceTree() *stacktraceTree {
190+
l := int32(len(t.nodes))
191+
x := stacktraceTree{nodes: make([]node, l)}
192+
x.nodes[0] = node{
193+
p: sentinel,
194+
fc: sentinel,
195+
ns: sentinel,
196+
}
197+
lc := make([]int32, len(t.nodes))
198+
var s int32
199+
for i := int32(1); i < l; i++ {
200+
n := t.nodes[i]
201+
x.nodes[i] = node{
202+
p: n.p,
203+
r: n.r,
204+
fc: sentinel,
205+
ns: sentinel,
206+
}
207+
// Swap the last child of the parent with self.
208+
// If this is the first child, update the parent.
209+
// Otherwise, update the sibling.
210+
s, lc[n.p] = lc[n.p], i
211+
if s == 0 {
212+
x.nodes[n.p].fc = i
213+
} else {
214+
x.nodes[s].ns = i
215+
}
216+
}
217+
return &x
218+
}
219+
189220
// ReadFrom decodes parent pointer tree from the reader.
190221
// The tree must have enough nodes.
191222
func (t *parentPointerTree) ReadFrom(r io.Reader) (int64, error) {

pkg/phlaredb/symdb/stacktrace_tree_test.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,44 @@ func Test_stacktrace_tree_pprof_locations(t *testing.T) {
164164
}
165165
}
166166

167+
// The test is helpful for debugging.
168+
func Test_parentPointerTree_toStacktraceTree(t *testing.T) {
169+
x := newStacktraceTree(10)
170+
for _, stack := range [][]uint64{
171+
{5, 4, 3, 2, 1},
172+
{6, 4, 3, 2, 1},
173+
{4, 3, 2, 1},
174+
{3, 2, 1},
175+
{4, 2, 1},
176+
{7, 2, 1},
177+
{2, 1},
178+
{1},
179+
} {
180+
x.insert(stack)
181+
}
182+
assertRestoredStacktraceTree(t, x)
183+
}
184+
185+
func Test_parentPointerTree_toStacktraceTree_profile(t *testing.T) {
186+
p, err := pprof.OpenFile("testdata/profile.pb.gz")
187+
require.NoError(t, err)
188+
x := newStacktraceTree(defaultStacktraceTreeSize)
189+
for _, s := range p.Sample {
190+
x.insert(s.LocationId)
191+
}
192+
assertRestoredStacktraceTree(t, x)
193+
}
194+
195+
func assertRestoredStacktraceTree(t *testing.T, x *stacktraceTree) {
196+
var b bytes.Buffer
197+
_, _ = x.WriteTo(&b)
198+
ppt := newParentPointerTree(x.len())
199+
_, err := ppt.ReadFrom(bytes.NewBuffer(b.Bytes()))
200+
require.NoError(t, err)
201+
restored := ppt.toStacktraceTree()
202+
assert.Equal(t, x.nodes, restored.nodes)
203+
}
204+
167205
func Benchmark_stacktrace_tree_insert(b *testing.B) {
168206
p, err := pprof.OpenFile("testdata/profile.pb.gz")
169207
require.NoError(b, err)

0 commit comments

Comments
 (0)