Skip to content

Commit

Permalink
Snapshot-level allocator (#21)
Browse files Browse the repository at this point in the history
  • Loading branch information
outofforest authored Oct 4, 2024
1 parent d1d06b5 commit b584768
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 74 deletions.
93 changes: 55 additions & 38 deletions allocator.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,68 +36,85 @@ func (a *Allocator) Node(nodeAddress NodeAddress) []byte {
return a.data[uint64(nodeAddress)*a.config.NodeSize : uint64(nodeAddress+1)*a.config.NodeSize]
}

// Allocate allocates new node.
func (a *Allocator) Allocate() (NodeAddress, []byte) {
return a.allocate(a.zeroNode)
// Allocate allocates node and copies data into it.
func (a *Allocator) Allocate(copyFrom []byte) (NodeAddress, []byte) {
a.lastAllocatedNode++
node := a.Node(a.lastAllocatedNode)
copy(node, copyFrom)
return a.lastAllocatedNode, node
}

// Deallocate deallocates node.
func (a *Allocator) Deallocate(nodeAddress NodeAddress) {

}

// Copy allocates new node and copies content from existing one.
func (a *Allocator) Copy(data []byte) (NodeAddress, []byte) {
return a.allocate(data)
}

func (a *Allocator) allocate(copyFrom []byte) (NodeAddress, []byte) {
a.lastAllocatedNode++
node := a.Node(a.lastAllocatedNode)
copy(node, copyFrom)
return a.lastAllocatedNode, node
}

// NewDeallocator returns new deallocator.
func NewDeallocator(
// NewSnapshotAllocator returns snapshot-level allocator.
func NewSnapshotAllocator(
snapshotID SnapshotID,
allocator *Allocator,
deallocationLists *Space[SnapshotID, NodeAddress],
listNodeAllocator ListNodeAllocator,
) Deallocator {
return Deallocator{
) SnapshotAllocator {
return SnapshotAllocator{
snapshotID: snapshotID,
allocator: allocator,
deallocationLists: deallocationLists,
listNodeAllocator: listNodeAllocator,
dirtyNodes: map[NodeAddress]struct{}{},
}
}

// Deallocator tracks nodes to deallocate.
type Deallocator struct {
// SnapshotAllocator allocates memory on behalf of snapshot.
type SnapshotAllocator struct {
snapshotID SnapshotID
allocator *Allocator
deallocationLists *Space[SnapshotID, NodeAddress]
listNodeAllocator ListNodeAllocator

dirtyNodes map[NodeAddress]struct{}
}

// Allocate allocates new node.
func (sa SnapshotAllocator) Allocate() (NodeAddress, []byte) {
nodeAddress, node := sa.allocator.Allocate(sa.allocator.zeroNode)
sa.dirtyNodes[nodeAddress] = struct{}{}
return nodeAddress, node
}

// Deallocate adds node to the deallocation list.
func (d Deallocator) Deallocate(nodeAddress NodeAddress, srcSnapshotID SnapshotID) {
if srcSnapshotID == d.snapshotID {
// FIXME (wojciech): Deallocate immediately
// Copy allocates new node and copies content from existing one.
func (sa SnapshotAllocator) Copy(data []byte) (NodeAddress, []byte) {
nodeAddress, node := sa.allocator.Allocate(data)
sa.dirtyNodes[nodeAddress] = struct{}{}
return nodeAddress, node
}

// Deallocate marks node for deallocation.
func (sa SnapshotAllocator) Deallocate(nodeAddress NodeAddress, srcSnapshotID SnapshotID) {
if srcSnapshotID == sa.snapshotID {
sa.DeallocateImmediately(nodeAddress)
return
}

listNodeAddress, _ := d.deallocationLists.Get(srcSnapshotID)
listNodeAddress, _ := sa.deallocationLists.Get(srcSnapshotID)
list := NewList(ListConfig{
SnapshotID: d.snapshotID,
SnapshotID: sa.snapshotID,
Item: listNodeAddress,
NodeAllocator: d.listNodeAllocator,
Deallocator: d,
NodeAllocator: sa.listNodeAllocator,
Allocator: sa,
})
list.Add(nodeAddress)
if list.config.Item != listNodeAddress {
d.deallocationLists.Set(srcSnapshotID, list.config.Item)
sa.deallocationLists.Set(srcSnapshotID, list.config.Item)
}
}

// DeallocateImmediately dealocates node immediately.
func (sa SnapshotAllocator) DeallocateImmediately(nodeAddress NodeAddress) {
delete(sa.dirtyNodes, nodeAddress)
sa.allocator.Deallocate(nodeAddress)
}

// NewSpaceNodeAllocator creates new space node allocator.
func NewSpaceNodeAllocator[T comparable](allocator *Allocator) (SpaceNodeAllocator[T], error) {
headerSize := uint64(unsafe.Sizeof(SpaceNodeHeader{}))
Expand Down Expand Up @@ -154,14 +171,14 @@ func (na SpaceNodeAllocator[T]) Get(nodeAddress NodeAddress) ([]byte, SpaceNode[
}

// Allocate allocates new object.
func (na SpaceNodeAllocator[T]) Allocate() (NodeAddress, SpaceNode[T]) {
n, node := na.allocator.Allocate()
func (na SpaceNodeAllocator[T]) Allocate(allocator SnapshotAllocator) (NodeAddress, SpaceNode[T]) {
n, node := allocator.Allocate()
return n, na.project(node)
}

// Copy allocates copy of existing object.
func (na SpaceNodeAllocator[T]) Copy(data []byte) (NodeAddress, SpaceNode[T]) {
n, node := na.allocator.Copy(data)
func (na SpaceNodeAllocator[T]) Copy(allocator SnapshotAllocator, data []byte) (NodeAddress, SpaceNode[T]) {
n, node := allocator.Copy(data)
return n, na.project(node)
}

Expand Down Expand Up @@ -220,14 +237,14 @@ func (na ListNodeAllocator) Get(nodeAddress NodeAddress) ([]byte, ListNode) {
}

// Allocate allocates new object.
func (na ListNodeAllocator) Allocate() (NodeAddress, ListNode) {
n, node := na.allocator.Allocate()
func (na ListNodeAllocator) Allocate(allocator SnapshotAllocator) (NodeAddress, ListNode) {
n, node := allocator.Allocate()
return n, na.project(node)
}

// Copy allocates copy of existing object.
func (na ListNodeAllocator) Copy(data []byte) (NodeAddress, ListNode) {
n, node := na.allocator.Copy(data)
func (na ListNodeAllocator) Copy(allocator SnapshotAllocator, data []byte) (NodeAddress, ListNode) {
n, node := allocator.Copy(data)
return n, na.project(node)
}

Expand Down
28 changes: 13 additions & 15 deletions db.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ type Snapshot struct {
Snapshots *Space[SnapshotID, SnapshotInfo]
Spaces *Space[SpaceID, SpaceInfo]
SpacesToCommit map[SpaceID]SpaceToCommit
Deallocator Deallocator
Allocator SnapshotAllocator
}

// New creates new database.
Expand Down Expand Up @@ -106,18 +106,20 @@ func (db *DB) DeleteSnapshot(snapshotID SnapshotID) error {
State: lo.ToPtr(snapshotInfo.DeallocationRoot.State),
Item: lo.ToPtr(snapshotInfo.DeallocationRoot.Node),
},
PointerNodeAllocator: db.pointerNodeAllocator,
DataNodeAllocator: db.snapshotToNodeNodeAllocator,
})

nextDeallocationLists := NewSpace[SnapshotID, NodeAddress](SpaceConfig[SnapshotID, NodeAddress]{
SnapshotID: snapshotInfo.NextSnapshotID,
HashMod: &nextSnapshotInfo.DeallocationRoot.HashMod,
SpaceRoot: ParentInfo{
State: lo.ToPtr(nextSnapshotInfo.DeallocationRoot.State),
Item: lo.ToPtr(nextSnapshotInfo.DeallocationRoot.Node),
State: &nextSnapshotInfo.DeallocationRoot.State,
Item: &nextSnapshotInfo.DeallocationRoot.Node,
},
PointerNodeAllocator: db.pointerNodeAllocator,
DataNodeAllocator: db.snapshotToNodeNodeAllocator,
Deallocator: db.nextSnapshot.Deallocator,
Allocator: db.nextSnapshot.Allocator,
})

var startSnapshotID SnapshotID
Expand Down Expand Up @@ -159,11 +161,6 @@ func (db *DB) DeleteSnapshot(snapshotID SnapshotID) error {
}

nextSnapshotInfo.PreviousSnapshotID = snapshotInfo.PreviousSnapshotID
nextSnapshotInfo.DeallocationRoot = SpaceInfo{
State: *nextDeallocationLists.config.SpaceRoot.State,
Node: *nextDeallocationLists.config.SpaceRoot.Item,
HashMod: *nextDeallocationLists.config.HashMod,
}
db.nextSnapshot.Snapshots.Set(snapshotInfo.NextSnapshotID, nextSnapshotInfo)
}

Expand Down Expand Up @@ -223,8 +220,9 @@ func (db *DB) prepareNextSnapshot(singularityNode SingularityNode) error {
NextSnapshotID: snapshotID + 1,
}

deallocator := NewDeallocator(
allocator := NewSnapshotAllocator(
snapshotID,
db.config.Allocator,
NewSpace[SnapshotID, NodeAddress](SpaceConfig[SnapshotID, NodeAddress]{
SnapshotID: snapshotID,
HashMod: &snapshotInfo.DeallocationRoot.HashMod,
Expand All @@ -237,7 +235,7 @@ func (db *DB) prepareNextSnapshot(singularityNode SingularityNode) error {
}),
db.listNodeAllocator,
)
deallocator.deallocationLists.config.Deallocator = deallocator
allocator.deallocationLists.config.Allocator = allocator

snapshots := NewSpace[SnapshotID, SnapshotInfo](SpaceConfig[SnapshotID, SnapshotInfo]{
SnapshotID: snapshotID,
Expand All @@ -248,7 +246,7 @@ func (db *DB) prepareNextSnapshot(singularityNode SingularityNode) error {
},
PointerNodeAllocator: db.pointerNodeAllocator,
DataNodeAllocator: db.snapshotInfoNodeAllocator,
Deallocator: deallocator,
Allocator: allocator,
})

if singularityNode.SnapshotRoot.State != stateFree {
Expand Down Expand Up @@ -276,10 +274,10 @@ func (db *DB) prepareNextSnapshot(singularityNode SingularityNode) error {
},
PointerNodeAllocator: db.pointerNodeAllocator,
DataNodeAllocator: db.spaceInfoNodeAllocator,
Deallocator: deallocator,
Allocator: allocator,
}),
SpacesToCommit: map[SpaceID]SpaceToCommit{},
Deallocator: deallocator,
Allocator: allocator,
}

return nil
Expand Down Expand Up @@ -312,6 +310,6 @@ func GetSpace[K, V comparable](spaceID SpaceID, db *DB) (*Space[K, V], error) {
SpaceRoot: space.PInfo,
PointerNodeAllocator: db.pointerNodeAllocator,
DataNodeAllocator: dataNodeAllocator,
Deallocator: db.nextSnapshot.Deallocator,
Allocator: db.nextSnapshot.Allocator,
}), nil
}
17 changes: 8 additions & 9 deletions list.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ type ListConfig struct {
SnapshotID SnapshotID
Item NodeAddress
NodeAllocator ListNodeAllocator
Allocator *Allocator
Deallocator Deallocator
Allocator SnapshotAllocator
}

// NewList creates new list.
Expand All @@ -24,7 +23,7 @@ type List struct {
// Add adds address to the list.
func (l *List) Add(nodeAddress NodeAddress) {
if l.config.Item == 0 {
newNodeAddress, newNode := l.config.NodeAllocator.Allocate()
newNodeAddress, newNode := l.config.NodeAllocator.Allocate(l.config.Allocator)
newNode.Items[0] = nodeAddress
newNode.Header.SnapshotID = l.config.SnapshotID
newNode.Header.NumOfItems = 1
Expand All @@ -35,11 +34,11 @@ func (l *List) Add(nodeAddress NodeAddress) {
listNodeData, listNode := l.config.NodeAllocator.Get(l.config.Item)
if listNode.Header.NumOfItems+listNode.Header.NumOfSideLists < uint64(len(listNode.Items)) {
if listNode.Header.SnapshotID < l.config.SnapshotID {
newNodeAddress, newNode := l.config.NodeAllocator.Copy(listNodeData)
newNodeAddress, newNode := l.config.NodeAllocator.Copy(l.config.Allocator, listNodeData)
newNode.Header.SnapshotID = l.config.SnapshotID
oldNodeAddress := l.config.Item
l.config.Item = newNodeAddress
l.config.Allocator.Deallocate(oldNodeAddress)
l.config.Allocator.DeallocateImmediately(oldNodeAddress)
listNode = newNode
}

Expand All @@ -49,7 +48,7 @@ func (l *List) Add(nodeAddress NodeAddress) {
return
}

newNodeAddress, newNode := l.config.NodeAllocator.Allocate()
newNodeAddress, newNode := l.config.NodeAllocator.Allocate(l.config.Allocator)
newNode.Items[0] = nodeAddress
newNode.Items[len(newNode.Items)-1] = l.config.Item
newNode.Header.SnapshotID = l.config.SnapshotID
Expand All @@ -67,11 +66,11 @@ func (l *List) Attach(nodeAddress NodeAddress) {
listNodeData, listNode := l.config.NodeAllocator.Get(l.config.Item)
if listNode.Header.NumOfItems+listNode.Header.NumOfSideLists < uint64(len(listNode.Items)) {
if listNode.Header.SnapshotID < l.config.SnapshotID {
newNodeAddress, newNode := l.config.NodeAllocator.Copy(listNodeData)
newNodeAddress, newNode := l.config.NodeAllocator.Copy(l.config.Allocator, listNodeData)
newNode.Header.SnapshotID = l.config.SnapshotID
oldNodeAddress := l.config.Item
l.config.Item = newNodeAddress
l.config.Allocator.Deallocate(oldNodeAddress)
l.config.Allocator.DeallocateImmediately(oldNodeAddress)
listNode = newNode
}

Expand All @@ -81,7 +80,7 @@ func (l *List) Attach(nodeAddress NodeAddress) {
return
}

newNodeAddress, newNode := l.config.NodeAllocator.Allocate()
newNodeAddress, newNode := l.config.NodeAllocator.Allocate(l.config.Allocator)
newNode.Items[uint64(len(listNode.Items))-1] = l.config.Item
newNode.Items[uint64(len(listNode.Items))-2] = nodeAddress
newNode.Header.SnapshotID = l.config.SnapshotID
Expand Down
Loading

0 comments on commit b584768

Please sign in to comment.