t.order, err = openRecords(filepath.Join(t.dir, "tree.idx"), treeRecordBytes)
if err != nil {
- return err
+ return fmt.Errorf("open node order index: %w", err)
}
start := Position{}
if t.order.count == 0 {
err = t.removeLevels()
if err != nil {
- return err
+ return fmt.Errorf("remove empty level indexes: %w", err)
}
} else {
record, _, err := t.order.Read(t.order.count - 1)
if err != nil {
- return err
+ return fmt.Errorf("read last node order: %w", err)
}
// A crash can stop an add between the two index writes, so the
node, last := treeDecodeRecord(record)
err = t.writeLevel(node, last)
if err != nil {
- return err
+ return fmt.Errorf("restore last node level: %w", err)
}
start = Position{
}
}
- return t.journal.Scan(ctx, start, func(line []byte, place Position) error {
+ err = t.journal.Scan(ctx, start, func(line []byte, place Position) error {
var node Node
err := json.Unmarshal(line, &node)
err = t.check(node)
if err != nil {
- return err
+ return fmt.Errorf("validate scanned node: %w", err)
}
if nodeEnd(node.Level, node.Index) > total {
return fmt.Errorf("node (%d, %d) covers messages after the log", node.Level, node.Index)
}
- return t.addIndex(NodeKey{node.Level, node.Index}, place)
+ err = t.addIndex(NodeKey{node.Level, node.Index}, place)
+ if err != nil {
+ return fmt.Errorf("index scanned node: %w", err)
+ }
+
+ return nil
})
+ if err != nil {
+ return fmt.Errorf("scan node journal: %w", err)
+ }
+
+ return nil
}
// Close closes the files of the tree.
func (t *Tree) writeLevel(node NodeKey, place Position) error {
level, err := t.level(node.level)
if err != nil {
- return err
+ return fmt.Errorf("open node level index: %w", err)
}
record := make([]byte, positionBytes)
encodePosition(record, place)
- return level.Write(node.index, record)
+ err = level.Write(node.index, record)
+ if err != nil {
+ return fmt.Errorf("write node level record: %w", err)
+ }
+
+ return nil
}
// check makes sure that node is valid and can join the tree now.
built, err := t.Built(node.Level, node.Index)
if err != nil {
- return err
+ return fmt.Errorf("check target node: %w", err)
}
if built {
for _, index := range []int{2 * node.Index, 2*node.Index + 1} {
built, err = t.Built(node.Level-1, index)
if err != nil {
- return err
+ return fmt.Errorf("check child node: %w", err)
}
if !built {
err := t.order.Append(record)
if err != nil {
- return err
+ return fmt.Errorf("append node order: %w", err)
+ }
+
+ err = t.writeLevel(node, place)
+ if err != nil {
+ return fmt.Errorf("write indexed node level: %w", err)
}
- return t.writeLevel(node, place)
+ return nil
}
// level returns the index of level, and opens it at first use.
records, err := t.level(level)
if err != nil {
- return Position{}, false, err
+ return Position{}, false, fmt.Errorf("open node level index: %w", err)
}
record, found, err := records.Read(index)
if err != nil || !found {
- return Position{}, false, err
+ if err != nil {
+ return Position{}, false, fmt.Errorf("read node level record: %w", err)
+ }
+
+ return Position{}, false, nil
}
place := decodePosition(record)
err := t.check(node)
if err != nil {
- return err
+ return fmt.Errorf("validate node: %w", err)
}
line, err := json.Marshal(node)
func (t *Tree) Node(level, index int) (Node, bool, error) {
place, built, err := t.place(level, index)
if err != nil || !built {
- return Node{}, false, err
+ if err != nil {
+ return Node{}, false, fmt.Errorf("find node position: %w", err)
+ }
+
+ return Node{}, false, nil
}
line, err := t.journal.Read(place)