Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Return errors from allocators #22

Merged
merged 1 commit into from
Oct 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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