46 lines
1.5 KiB
Go
46 lines
1.5 KiB
Go
package internal
|
|
|
|
import (
|
|
"fmt"
|
|
"sync/atomic"
|
|
)
|
|
|
|
// NodePointer is a pointer to a Node, which may be either in-memory, on-disk or both.
|
|
type NodePointer struct {
|
|
mem atomic.Pointer[MemNode]
|
|
// changeset *Changeset // commented to satisfy linter, will uncomment in a future PR when we wire it up
|
|
fileIdx uint32 // absolute index in file, 1-based, zero means we don't have an offset
|
|
id NodeID
|
|
}
|
|
|
|
// NewNodePointer creates a new NodePointer pointing to the given in-memory node.
|
|
func NewNodePointer(memNode *MemNode) *NodePointer {
|
|
n := &NodePointer{}
|
|
n.mem.Store(memNode)
|
|
return n
|
|
}
|
|
|
|
// Resolve resolves the NodePointer to a Node, loading from memory or disk as necessary
|
|
// as well as a Pin which MUST be unpinned after the caller is done using the node.
|
|
// Resolve will ALWAYS return a valid Pin even if there is an error. For clarity and
|
|
// consistency it is recommended to introduce a defer pin.Unpin() immediately after
|
|
// calling Resolve and BEFORE checking the error return value like this:
|
|
//
|
|
// node, pin, err := nodePointer.Resolve()
|
|
// defer pin.Unpin()
|
|
// if err != nil {
|
|
// // handle error
|
|
// }
|
|
func (p *NodePointer) Resolve() (Node, Pin, error) {
|
|
mem := p.mem.Load()
|
|
if mem != nil {
|
|
return mem, NoopPin{}, nil
|
|
}
|
|
return nil, NoopPin{}, fmt.Errorf("node not in memory and on-disk loading will be implemented in a future PR")
|
|
}
|
|
|
|
// String implements the fmt.Stringer interface.
|
|
func (p *NodePointer) String() string {
|
|
return fmt.Sprintf("NodePointer{id: %s, fileIdx: %d}", p.id.String(), p.fileIdx)
|
|
}
|