Skip to content

Commit

Permalink
Simplify deallocation list operations
Browse files Browse the repository at this point in the history
  • Loading branch information
outofforest committed Dec 2, 2024
1 parent f7b2ce5 commit 38d0d0b
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 96 deletions.
57 changes: 17 additions & 40 deletions db.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"unsafe"

"github.com/pkg/errors"
"github.com/samber/lo"

"github.com/outofforest/parallel"
"github.com/outofforest/photon"
Expand Down Expand Up @@ -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]()
Expand All @@ -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,
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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)
Expand All @@ -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 {
Expand Down Expand Up @@ -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
}

Expand Down
102 changes: 46 additions & 56 deletions list/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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 {
Expand All @@ -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])
}
Expand Down

0 comments on commit 38d0d0b

Please sign in to comment.