Skip to content

Commit

Permalink
Return errors from allocators (#22)
Browse files Browse the repository at this point in the history
  • Loading branch information
outofforest authored Oct 4, 2024
1 parent b584768 commit 670ba08
Show file tree
Hide file tree
Showing 5 changed files with 182 additions and 84 deletions.
77 changes: 53 additions & 24 deletions allocator.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,14 @@ func (a *Allocator) Node(nodeAddress NodeAddress) []byte {
}

// Allocate allocates node and copies data into it.
func (a *Allocator) Allocate(copyFrom []byte) (NodeAddress, []byte) {
func (a *Allocator) Allocate(copyFrom []byte) (NodeAddress, []byte, error) {
a.lastAllocatedNode++
if a.lastAllocatedNode >= NodeAddress(len(a.data)) {
return 0, nil, errors.New("out of space")
}
node := a.Node(a.lastAllocatedNode)
copy(node, copyFrom)
return a.lastAllocatedNode, node
return a.lastAllocatedNode, node, nil
}

// Deallocate deallocates node.
Expand Down Expand Up @@ -76,24 +79,32 @@ type SnapshotAllocator struct {
}

// Allocate allocates new node.
func (sa SnapshotAllocator) Allocate() (NodeAddress, []byte) {
nodeAddress, node := sa.allocator.Allocate(sa.allocator.zeroNode)
func (sa SnapshotAllocator) Allocate() (NodeAddress, []byte, error) {
nodeAddress, node, err := sa.allocator.Allocate(sa.allocator.zeroNode)
if err != nil {
return 0, nil, err
}

sa.dirtyNodes[nodeAddress] = struct{}{}
return nodeAddress, node
return nodeAddress, node, nil
}

// Copy allocates new node and copies content from existing one.
func (sa SnapshotAllocator) Copy(data []byte) (NodeAddress, []byte) {
nodeAddress, node := sa.allocator.Allocate(data)
func (sa SnapshotAllocator) Copy(data []byte) (NodeAddress, []byte, error) {
nodeAddress, node, err := sa.allocator.Allocate(data)
if err != nil {
return 0, nil, err
}

sa.dirtyNodes[nodeAddress] = struct{}{}
return nodeAddress, node
return nodeAddress, node, nil
}

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

listNodeAddress, _ := sa.deallocationLists.Get(srcSnapshotID)
Expand All @@ -103,10 +114,16 @@ func (sa SnapshotAllocator) Deallocate(nodeAddress NodeAddress, srcSnapshotID Sn
NodeAllocator: sa.listNodeAllocator,
Allocator: sa,
})
list.Add(nodeAddress)
if err := list.Add(nodeAddress); err != nil {
return err
}
if list.config.Item != listNodeAddress {
sa.deallocationLists.Set(srcSnapshotID, list.config.Item)
if err := sa.deallocationLists.Set(srcSnapshotID, list.config.Item); err != nil {
return err
}
}

return nil
}

// DeallocateImmediately dealocates node immediately.
Expand Down Expand Up @@ -171,15 +188,21 @@ func (na SpaceNodeAllocator[T]) Get(nodeAddress NodeAddress) ([]byte, SpaceNode[
}

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

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

// Index returns element index based on hash.
Expand Down Expand Up @@ -237,15 +260,21 @@ func (na ListNodeAllocator) Get(nodeAddress NodeAddress) ([]byte, ListNode) {
}

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

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

func (na ListNodeAllocator) project(node []byte) ListNode {
Expand Down
30 changes: 22 additions & 8 deletions db.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,9 @@ func (db *DB) DeleteSnapshot(snapshotID SnapshotID) error {
NodeAllocator: db.listNodeAllocator,
})
list.Deallocate(db.config.Allocator)
nextDeallocationLists.Delete(sID)
if err := nextDeallocationLists.Delete(sID); err != nil {
return err
}
}

// FIXME (wojciech): Iterate over space instead
Expand All @@ -154,14 +156,20 @@ func (db *DB) DeleteSnapshot(snapshotID SnapshotID) error {
nextList := NewList(ListConfig{
Item: nextListNodeAddress,
})
nextList.Attach(listNodeAddress)
if err := nextList.Attach(listNodeAddress); err != nil {
return err
}
if nextList.config.Item != nextListNodeAddress {
nextDeallocationLists.Set(sID, nextList.config.Item)
if err := nextDeallocationLists.Set(sID, nextList.config.Item); err != nil {
return err
}
}
}

nextSnapshotInfo.PreviousSnapshotID = snapshotInfo.PreviousSnapshotID
db.nextSnapshot.Snapshots.Set(snapshotInfo.NextSnapshotID, nextSnapshotInfo)
if err := db.nextSnapshot.Snapshots.Set(snapshotInfo.NextSnapshotID, nextSnapshotInfo); err != nil {
return err
}
}

if snapshotInfo.PreviousSnapshotID > db.nextSnapshot.SingularityNode.FirstSnapshotID {
Expand All @@ -170,7 +178,9 @@ func (db *DB) DeleteSnapshot(snapshotID SnapshotID) error {
return errors.Errorf("snapshot %d does not exist", snapshotID)
}
previousSnapshotInfo.NextSnapshotID = snapshotInfo.NextSnapshotID
db.nextSnapshot.Snapshots.Set(snapshotInfo.PreviousSnapshotID, previousSnapshotInfo)
if err := db.nextSnapshot.Snapshots.Set(snapshotInfo.PreviousSnapshotID, previousSnapshotInfo); err != nil {
return err
}
}

if snapshotID == db.nextSnapshot.SingularityNode.FirstSnapshotID {
Expand All @@ -195,14 +205,18 @@ func (db *DB) Commit() error {
if *spaceToCommit.PInfo.State == stateFree || *spaceToCommit.PInfo.Item == spaceToCommit.OriginalItem {
continue
}
db.nextSnapshot.Spaces.Set(spaceID, SpaceInfo{
if err := db.nextSnapshot.Spaces.Set(spaceID, SpaceInfo{
HashMod: *spaceToCommit.HashMod,
State: *spaceToCommit.PInfo.State,
Node: *spaceToCommit.PInfo.Item,
})
}); err != nil {
return err
}
}

db.nextSnapshot.Snapshots.Set(db.nextSnapshot.SnapshotID, *db.nextSnapshot.SnapshotInfo)
if err := db.nextSnapshot.Snapshots.Set(db.nextSnapshot.SnapshotID, *db.nextSnapshot.SnapshotInfo); err != nil {
return err
}

*photon.FromBytes[SingularityNode](db.config.Allocator.Node(0)) = *db.nextSnapshot.SingularityNode

Expand Down
38 changes: 23 additions & 15 deletions db_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,15 @@ var collisions = [][]int{
}

func newDB(t *testing.T) *DB {
requireT := require.New(t)

db, err := New(Config{
Allocator: NewAllocator(AllocatorConfig{
TotalSize: 10 * 1024 * 1024,
NodeSize: 512,
}),
})
require.NoError(t, err)
requireT.NoError(err)
return db
}

Expand All @@ -47,51 +49,57 @@ func TestCollisions(t *testing.T) {
}

func TestSet(t *testing.T) {
requireT := require.New(t)

db := newDB(t)

space, err := GetSpace[int, int](spaceID, db)
require.NoError(t, err)
requireT.NoError(err)

for i := range 10 {
space.Set(i, i)
requireT.NoError(space.Set(i, i))
}

require.Equal(t, []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, collect(space))
requireT.Equal([]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, collect(space))
}

func TestSetCollisions(t *testing.T) {
requireT := require.New(t)

db := newDB(t)

space, err := GetSpace[int, int](spaceID, db)
require.NoError(t, err)
requireT.NoError(err)

allValues := make([]int, 0, len(collisions)*len(collisions[0]))

for _, set := range collisions {
for _, i := range set {
allValues = append(allValues, i)
space.Set(i, i)
requireT.NoError(space.Set(i, i))
}
}

sort.Ints(allValues)

require.Equal(t, allValues, collect(space))
requireT.Equal(allValues, collect(space))
}

func TestGetCollisions(t *testing.T) {
requireT := require.New(t)

db := newDB(t)

space, err := GetSpace[int, int](spaceID, db)
require.NoError(t, err)
requireT.NoError(err)

inserted := make([]int, 0, len(collisions)*len(collisions[0]))
read := make([]int, 0, len(collisions)*len(collisions[0]))

for _, set := range collisions {
for _, i := range set {
inserted = append(inserted, i)
space.Set(i, i)
requireT.NoError(space.Set(i, i))
}
}

Expand All @@ -106,7 +114,7 @@ func TestGetCollisions(t *testing.T) {
sort.Ints(inserted)
sort.Ints(read)

require.Equal(t, inserted, read)
requireT.Equal(inserted, read)
}

func TestSetOnNext(t *testing.T) {
Expand All @@ -118,7 +126,7 @@ func TestSetOnNext(t *testing.T) {
requireT.NoError(err)

for i := range 10 {
space1.Set(i, i)
requireT.NoError(space1.Set(i, i))
}

requireT.NoError(db.Commit())
Expand All @@ -127,7 +135,7 @@ func TestSetOnNext(t *testing.T) {
requireT.NoError(err)

for i := range 5 {
space2.Set(i, i+10)
requireT.NoError(space2.Set(i, i+10))
}

requireT.Equal([]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, collect(space1))
Expand All @@ -143,7 +151,7 @@ func TestGet(t *testing.T) {
requireT.NoError(err)

for i := range 10 {
space.Set(i, i)
requireT.NoError(space.Set(i, i))
}
for i := range 10 {
v, exists := space.Get(i)
Expand All @@ -161,7 +169,7 @@ func TestReplace(t *testing.T) {
requireT.NoError(err)

for i := range 10 {
space1.Set(i, i)
requireT.NoError(space1.Set(i, i))
}

requireT.NoError(db.Commit())
Expand All @@ -170,7 +178,7 @@ func TestReplace(t *testing.T) {
requireT.NoError(err)

for i, j := 0, 10; i < 5; i, j = i+1, j+1 {
space2.Set(i, j)
requireT.NoError(space2.Set(i, j))
}

for i := range 10 {
Expand Down
Loading

0 comments on commit 670ba08

Please sign in to comment.