From 38d0d0bc971ec89e84483e4b9af581f8a9dc9046 Mon Sep 17 00:00:00 2001 From: Wojciech Malota-Wojcik Date: Mon, 2 Dec 2024 08:09:54 +0100 Subject: [PATCH] Simplify deallocation list operations --- db.go | 57 +++++++++------------------- list/list.go | 102 +++++++++++++++++++++++---------------------------- 2 files changed, 63 insertions(+), 96 deletions(-) diff --git a/db.go b/db.go index b8f1c3d..b719b76 100644 --- a/db.go +++ b/db.go @@ -9,6 +9,7 @@ import ( "unsafe" "github.com/pkg/errors" + "github.com/samber/lo" "github.com/outofforest/parallel" "github.com/outofforest/photon" @@ -41,12 +42,6 @@ type SpaceToCommit struct { OriginalPointer types.Pointer } -// ListToCommit contains cached deallocation list. -type ListToCommit struct { - List *list.List - Root types.NodeAddress -} - // New creates new database. func New(config Config) (*DB, error) { snapshotInfoNodeAssistant, err := space.NewDataNodeAssistant[types.SnapshotID, types.SnapshotInfo]() @@ -67,7 +62,7 @@ func New(config Config) (*DB, error) { singularityNode: photon.FromPointer[types.SingularityNode](config.State.Node(0)), snapshotInfoNodeAssistant: snapshotInfoNodeAssistant, snapshotToNodeNodeAssistant: snapshotToNodeNodeAssistant, - deallocationListsToCommit: map[types.SnapshotID]*ListToCommit{}, + deallocationListsToCommit: map[types.SnapshotID]*types.NodeAddress{}, queue: queue, queueReader: queueReader, } @@ -111,7 +106,7 @@ type DB struct { snapshotInfoNodeAssistant *space.DataNodeAssistant[types.SnapshotID, types.SnapshotInfo] snapshotToNodeNodeAssistant *space.DataNodeAssistant[types.SnapshotID, types.NodeAddress] - deallocationListsToCommit map[types.SnapshotID]*ListToCommit + deallocationListsToCommit map[types.SnapshotID]*types.NodeAddress queueReader *pipeline.Reader queue *pipeline.Pipeline @@ -381,27 +376,23 @@ func (db *DB) deleteSnapshot( if err != nil { return err } - listNodeAddress, err := deallocationListValue.Value(snapshotID, tx, walRecorder, allocator, deallocationHashBuff, + listRootAddress, err := deallocationListValue.Value(snapshotID, tx, walRecorder, allocator, deallocationHashBuff, deallocationHashMatches) if err != nil { return err } - list := list.New(list.Config{ - Root: listNodeAddress, - State: db.config.State, - }) + originalListRootAddress := listRootAddress - listRoot, err := list.Attach(nextDeallocSnapshot.Value, allocator) - if err != nil { + if err := list.Attach(&listRootAddress, nextDeallocSnapshot.Value, db.config.State, allocator); err != nil { return err } - if listRoot != listNodeAddress { + if listRootAddress != originalListRootAddress { if err := deallocationListValue.Set( snapshotID, tx, walRecorder, allocator, - listRoot, + listRootAddress, deallocationHashBuff, deallocationHashMatches, ); err != nil { @@ -489,7 +480,7 @@ func (db *DB) commit( sort.Slice(lists, func(i, j int) bool { return lists[i] < lists[j] }) for _, snapshotID := range lists { - l := db.deallocationListsToCommit[snapshotID] + listRootAddress := db.deallocationListsToCommit[snapshotID] var deallocationListValue space.Entry[types.SnapshotID, types.NodeAddress] err := db.deallocationLists.Find(&deallocationListValue, commitSnapshotID, tx, walRecorder, allocator, snapshotID, space.StageData, deallocationHashBuff, deallocationHashMatches) @@ -507,20 +498,17 @@ func (db *DB) commit( if err != nil { return err } - listRoot, err := l.List.Attach(v, allocator) - if err != nil { + + if err := list.Attach(listRootAddress, v, db.config.State, allocator); err != nil { return err } - if listRoot != l.Root { - l.Root = listRoot - } } if err := deallocationListValue.Set( commitSnapshotID, tx, walRecorder, allocator, - l.Root, + *listRootAddress, deallocationHashBuff, deallocationHashMatches, ); err != nil { @@ -1085,26 +1073,15 @@ func (db *DB) deallocateNode( return nil } - l, exists := db.deallocationListsToCommit[nodeSnapshotID] - if !exists { - l = &ListToCommit{ - List: list.New(list.Config{ - State: db.config.State, - }), - } - db.deallocationListsToCommit[nodeSnapshotID] = l + listRoot := db.deallocationListsToCommit[nodeSnapshotID] + if listRoot == nil { + listRoot = lo.ToPtr[types.NodeAddress](0) + db.deallocationListsToCommit[nodeSnapshotID] = listRoot } - - listRoot, err := l.List.Add( - nodeAddress, - allocator, - ) - if err != nil { + if err := list.Add(listRoot, nodeAddress, db.config.State, allocator); err != nil { return err } - l.Root = listRoot - return nil } diff --git a/list/list.go b/list/list.go index 42214cd..fd53182 100644 --- a/list/list.go +++ b/list/list.go @@ -7,119 +7,109 @@ import ( "github.com/outofforest/quantum/types" ) -// Config stores list configuration. -type Config struct { - Root types.NodeAddress - State *alloc.State -} - -// New creates new list. -func New(config Config) *List { - return &List{ - config: config, - } -} - -// List represents the list of node addresses. -type List struct { - config Config -} - // Add adds address to the list. -func (l *List) Add(nodeAddress types.NodeAddress, allocator *alloc.Allocator) (types.NodeAddress, error) { - if l.config.Root == 0 { - newNodeAddress, err := allocator.Allocate() +func Add( + listRoot *types.NodeAddress, + nodeAddress types.NodeAddress, + state *alloc.State, + allocator *alloc.Allocator, +) error { + if *listRoot == 0 { + var err error + *listRoot, err = allocator.Allocate() if err != nil { - return 0, err + return err } - node := ProjectNode(l.config.State.Node(newNodeAddress)) + node := ProjectNode(state.Node(*listRoot)) node.Slots[0] = nodeAddress node.NumOfPointerAddresses = 1 // This is needed because list nodes are not zeroed. node.NumOfSideListAddresses = 0 - l.config.Root = newNodeAddress - - return l.config.Root, nil + return nil } - node := ProjectNode(l.config.State.Node(l.config.Root)) + node := ProjectNode(state.Node(*listRoot)) if node.NumOfPointerAddresses+node.NumOfSideListAddresses < NumOfAddresses { node.Slots[node.NumOfPointerAddresses] = nodeAddress node.NumOfPointerAddresses++ - return l.config.Root, nil + return nil } newNodeAddress, err := allocator.Allocate() if err != nil { - return 0, err + return err } - node = ProjectNode(l.config.State.Node(newNodeAddress)) + node = ProjectNode(state.Node(newNodeAddress)) node.Slots[0] = nodeAddress - node.Slots[NumOfAddresses-1] = l.config.Root + node.Slots[NumOfAddresses-1] = *listRoot node.NumOfPointerAddresses = 1 node.NumOfSideListAddresses = 1 - l.config.Root = newNodeAddress + *listRoot = newNodeAddress - return l.config.Root, nil + return nil } // Attach attaches another list. -func (l *List) Attach(listAddress types.NodeAddress, allocator *alloc.Allocator) (types.NodeAddress, error) { - if l.config.Root == 0 { - newNodeAddress, err := allocator.Allocate() +func Attach( + listRoot *types.NodeAddress, + listAddress types.NodeAddress, + state *alloc.State, + allocator *alloc.Allocator, +) error { + if *listRoot == 0 { + var err error + *listRoot, err = allocator.Allocate() if err != nil { - return 0, err + return err } - node := ProjectNode(l.config.State.Node(newNodeAddress)) + node := ProjectNode(state.Node(*listRoot)) node.Slots[NumOfAddresses-1] = listAddress node.NumOfSideListAddresses = 1 // This is needed because list nodes are not zeroed. node.NumOfPointerAddresses = 0 - l.config.Root = newNodeAddress - - return l.config.Root, nil + return nil } - node := ProjectNode(l.config.State.Node(l.config.Root)) + node := ProjectNode(state.Node(*listRoot)) if node.NumOfPointerAddresses+node.NumOfSideListAddresses < NumOfAddresses { node.NumOfSideListAddresses++ node.Slots[NumOfAddresses-node.NumOfSideListAddresses] = listAddress - return l.config.Root, nil + return nil } newNodeAddress, err := allocator.Allocate() if err != nil { - return 0, err + return err } - node = ProjectNode(l.config.State.Node(newNodeAddress)) + node = ProjectNode(state.Node(newNodeAddress)) - node.Slots[NumOfAddresses-2] = l.config.Root + node.Slots[NumOfAddresses-2] = *listRoot node.Slots[NumOfAddresses-1] = listAddress node.NumOfSideListAddresses = 2 // This is needed because list nodes are not zeroed. node.NumOfPointerAddresses = 0 - l.config.Root = newNodeAddress + *listRoot = newNodeAddress - return l.config.Root, nil + return nil } // Iterator iterates over items in the list. -func (l *List) Iterator() func(func(types.NodeAddress) bool) { +func Iterator(listRoot types.NodeAddress, state *alloc.State) func(func(types.NodeAddress) bool) { return func(yield func(types.NodeAddress) bool) { - if l.config.Root == 0 { + if listRoot == 0 { return } - stack := []types.NodeAddress{l.config.Root} + stack := []types.NodeAddress{listRoot} for { if len(stack) == 0 { return @@ -128,7 +118,7 @@ func (l *List) Iterator() func(func(types.NodeAddress) bool) { volatileAddress := stack[len(stack)-1] stack = stack[:len(stack)-1] - node := ProjectNode(l.config.State.Node(volatileAddress)) + node := ProjectNode(state.Node(volatileAddress)) for i := range node.NumOfPointerAddresses { if !yield(node.Slots[i]) { return @@ -143,13 +133,13 @@ func (l *List) Iterator() func(func(types.NodeAddress) bool) { } // Nodes returns list of nodes used by the list. -func (l *List) Nodes() []types.NodeAddress { - if l.config.Root == 0 { +func Nodes(listRoot types.NodeAddress, state *alloc.State) []types.NodeAddress { + if listRoot == 0 { return nil } nodes := []types.NodeAddress{} - stack := []types.NodeAddress{l.config.Root} + stack := []types.NodeAddress{listRoot} for { if len(stack) == 0 { @@ -164,7 +154,7 @@ func (l *List) Nodes() []types.NodeAddress { stack = stack[:len(stack)-1] nodes = append(nodes, volatileAddress) - node := ProjectNode(l.config.State.Node(volatileAddress)) + node := ProjectNode(state.Node(volatileAddress)) for i, j := uint16(0), NumOfAddresses-1; i < node.NumOfSideListAddresses; i, j = i+1, j-1 { stack = append(stack, node.Slots[j]) }