(stack []common.Pgid, visited map[common.Pgid]struct{}, callback func(page *common.Page, stack []common.Pgid) error)
| 22 | } |
| 23 | |
| 24 | func (n XRay) traverse(stack []common.Pgid, visited map[common.Pgid]struct{}, callback func(page *common.Page, stack []common.Pgid) error) error { |
| 25 | pgid := stack[len(stack)-1] |
| 26 | if _, ok := visited[pgid]; ok { |
| 27 | return fmt.Errorf("cycle detected at page %d (stack %v)", pgid, stack) |
| 28 | } |
| 29 | visited[pgid] = struct{}{} |
| 30 | |
| 31 | p, data, err := guts_cli.ReadPage(n.path, uint64(pgid)) |
| 32 | if err != nil { |
| 33 | return fmt.Errorf("failed reading page (stack %v): %w", stack, err) |
| 34 | } |
| 35 | err = callback(p, stack) |
| 36 | if err != nil { |
| 37 | return fmt.Errorf("failed callback for page (stack %v): %w", stack, err) |
| 38 | } |
| 39 | switch p.Typ() { |
| 40 | case "meta": |
| 41 | { |
| 42 | m := common.LoadPageMeta(data) |
| 43 | r := m.RootBucket().RootPage() |
| 44 | return n.traverse(append(stack, r), visited, callback) |
| 45 | } |
| 46 | case "branch": |
| 47 | { |
| 48 | for i := uint16(0); i < p.Count(); i++ { |
| 49 | bpe := p.BranchPageElement(i) |
| 50 | if err := n.traverse(append(stack, bpe.Pgid()), visited, callback); err != nil { |
| 51 | return err |
| 52 | } |
| 53 | } |
| 54 | } |
| 55 | case "leaf": |
| 56 | for i := uint16(0); i < p.Count(); i++ { |
| 57 | lpe := p.LeafPageElement(i) |
| 58 | if lpe.IsBucketEntry() { |
| 59 | pgid := lpe.Bucket().RootPage() |
| 60 | if pgid > 0 { |
| 61 | if err := n.traverse(append(stack, pgid), visited, callback); err != nil { |
| 62 | return err |
| 63 | } |
| 64 | } else { |
| 65 | inlinePage := lpe.Bucket().InlinePage(lpe.Value()) |
| 66 | if err := callback(inlinePage, stack); err != nil { |
| 67 | return fmt.Errorf("failed callback for inline page (stack %v): %w", stack, err) |
| 68 | } |
| 69 | } |
| 70 | } |
| 71 | } |
| 72 | case "freelist": |
| 73 | return nil |
| 74 | // Free does not have children. |
| 75 | } |
| 76 | return nil |
| 77 | } |
| 78 | |
| 79 | // FindPathsToKey finds all paths from root to the page that contains the given key. |
| 80 | // As it traverses multiple buckets, so in theory there might be multiple keys with the given name. |
no test coverage detected