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

Adds created and modified timestamps #30

Merged
merged 2 commits into from
Sep 30, 2023
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
2 changes: 2 additions & 0 deletions honu.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
pb "github.com/rotationalio/honu/object"
opts "github.com/rotationalio/honu/options"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/timestamppb"
)

// DB is a Honu embedded database.
Expand Down Expand Up @@ -274,6 +275,7 @@ func (db *DB) Put(key, value []byte, options ...opts.Option) (_ *pb.Object, err
obj = &pb.Object{
Key: key,
Namespace: cfg.Namespace,
Created: timestamppb.Now(),
}
} else {
return nil, err
Expand Down
2 changes: 2 additions & 0 deletions honu_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ func TestLevelDBInteractions(t *testing.T) {
require.NoError(t, err)
require.Equal(t, uint64(1), obj.Version.Version)
require.False(t, obj.Tombstone())
require.NotEmpty(t, obj.Created)
require.False(t, obj.Created.AsTime().IsZero())

// Delete the version from the database and ensure you
// are not able to get the deleted version
Expand Down
20 changes: 19 additions & 1 deletion object/object.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
package object

import (
"time"

"google.golang.org/protobuf/types/known/timestamppb"
)

var VersionZero = Version{}

// Tombstone returns true if the version of the object is a Tombstone (for a deleted object)
Expand All @@ -10,6 +16,17 @@ func (o *Object) Tombstone() bool {
return o.Version.Tombstone
}

func (o *Object) CreatedAt() time.Time {
return o.Created.AsTime()
}

func (o *Object) ModifiedAt() time.Time {
if o.Version == nil {
panic("object improperly initialized without version")
}
return o.Version.Modified.AsTime()
}

// IsZero determines if the version is zero valued (e.g. the PID and Version are zero).
// Note that zero-valuation does not check parent or region.
func (v *Version) IsZero() bool {
Expand Down Expand Up @@ -102,13 +119,14 @@ func (v *Version) Skips(other *Version) bool {
return v.IsLater(other) && !v.Concurrent(other) && !v.LinearFrom(other)
}

//Copies the child's attributes before updating to the parent.
// Copies the child's attributes before updating to the parent.
func (v *Version) Clone() *Version {
parent := &Version{
Pid: v.Pid,
Version: v.Version,
Region: v.Region,
Tombstone: v.Tombstone,
Modified: timestamppb.New(v.Modified.AsTime()),
}
return parent
}
97 changes: 64 additions & 33 deletions object/object.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 0 additions & 2 deletions proto/buf.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
version: v1
name: buf.build/rotational/honudb
deps:
- buf.build/googleapis/googleapis
breaking:
use:
- FILE
Expand Down
39 changes: 24 additions & 15 deletions proto/object/v1/object.proto
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
syntax = "proto3";

package honu.object.v1;

import "google/protobuf/timestamp.proto";

option go_package = "github.com/rotationalio/honu/object";

// An Object is a generic representation of a replicated piece of data. At the top level
Expand All @@ -16,22 +19,28 @@ option go_package = "github.com/rotationalio/honu/object";
// Additionally, it is recommended that a history table be maintained locally so that
// Object versions can be rolled back to previous states where necessary.
message Object {
// The object metadata that must be populated on both VersionVectors and Updates
bytes key = 1; // A unique key/id that represents the object across the namespace of the object type
string namespace = 2; // The namespace of the object, used to disambiguate keys or different object types
Version version = 3; // A version vector representing this objects current or latest version
string region = 4; // The region code where the data originated
string owner = 5; // The replica that created the object (identified as "pid:name" if name exists)

// The object data that is only populated on Updates.
bytes data = 10;
// The object metadata that must be populated on both VersionVectors and Updates
bytes key = 1; // A unique key/id that represents the object across the namespace of the object type
string namespace = 2; // The namespace of the object, used to disambiguate keys or different object types
Version version = 3; // A version vector representing this objects current or latest version
string region = 4; // The region code where the data originated
string owner = 5; // The replica that created the object (identified as "pid:name" if name exists)

// The object data that is only populated on Updates.
bytes data = 10;

// The timestamp that the object was created (modified timestamps are on versions).
google.protobuf.Timestamp created = 15;
}

// Implements a geo-distributed version as a Lamport Scalar
message Version {
uint64 pid = 1; // Process ID - used to deconflict ties in the version number.
uint64 version = 2; // Montonically increasing version number.
string region = 3; // The region where the change occurred to track multi-region handling.
Version parent = 4; // In order to get a complete version history, identify the predessor; for compact data transfer parent should not be defined in parent version.
bool tombstone = 5; // Set to true in order to mark the object as deleted
}
uint64 pid = 1; // Process ID - used to deconflict ties in the version number.
uint64 version = 2; // Montonically increasing version number.
string region = 3; // The region where the change occurred to track multi-region handling.
Version parent = 4; // In order to get a complete version history, identify the predessor; for compact data transfer parent should not be defined in parent version.
bool tombstone = 5; // Set to true in order to mark the object as deleted

// The timestamp that the version was created (e.g. the last modified date).
google.protobuf.Timestamp modified = 15;
}
4 changes: 3 additions & 1 deletion versions.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (

"github.com/rotationalio/honu/config"
pb "github.com/rotationalio/honu/object"
"google.golang.org/protobuf/types/known/timestamppb"
)

// NewVersionManager creates a new manager for handling lamport scalar versions.
Expand Down Expand Up @@ -83,10 +84,11 @@ func (v VersionManager) Delete(meta *pb.Object) error {
return nil
}

//Assigns the attributes of the passed versionManager to the object.
// Assigns the attributes of the passed versionManager to the object.
func (v VersionManager) updateVersion(meta *pb.Object, delete_version bool) {
meta.Version.Pid = v.PID
meta.Version.Version++
meta.Version.Region = v.Region
meta.Version.Tombstone = delete_version
meta.Version.Modified = timestamppb.Now()
}
8 changes: 8 additions & 0 deletions versions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ func TestVersionManager(t *testing.T) {
require.Equal(t, vers1.Region, obj.Version.Region)
require.Empty(t, obj.Version.Parent)
require.False(t, obj.Tombstone())
require.NotEmpty(t, obj.Version.Modified)
require.False(t, obj.Version.Modified.AsTime().IsZero())

// Create a new remote versioner
conf.PID = 13
Expand Down Expand Up @@ -96,6 +98,8 @@ func TestVersionManager(t *testing.T) {
require.Equal(t, uint64(1), obj.Version.Parent.Version)
require.Equal(t, vers1.Region, obj.Version.Parent.Region)
require.False(t, obj.Tombstone())
require.NotEmpty(t, obj.Version.Modified)
require.False(t, obj.Version.Modified.AsTime().IsZero())

// Test Delete - creating a tombstone
require.NoError(t, vers1.Delete(obj))
Expand Down Expand Up @@ -130,6 +134,8 @@ func TestVersionManager(t *testing.T) {
require.Equal(t, uint64(2), obj.Version.Parent.Version)
require.Equal(t, vers2.Region, obj.Version.Parent.Region)
require.True(t, obj.Tombstone())
require.NotEmpty(t, obj.Version.Modified)
require.False(t, obj.Version.Modified.AsTime().IsZero())

// Cannot delete a deleted object
require.Error(t, vers1.Delete(obj))
Expand Down Expand Up @@ -174,4 +180,6 @@ func TestVersionManager(t *testing.T) {
require.Equal(t, uint64(3), obj.Version.Parent.Version)
require.Equal(t, vers1.Region, obj.Version.Parent.Region)
require.False(t, obj.Tombstone())
require.NotEmpty(t, obj.Version.Modified)
require.False(t, obj.Version.Modified.AsTime().IsZero())
}
Loading