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

HLC Parsing fixes #1724

Merged
merged 3 commits into from
Jan 30, 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
10 changes: 8 additions & 2 deletions e2e/newenemy/newenemy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,7 @@ func checkDataNoNewEnemy(ctx context.Context, t testing.TB, slowNodeID int, crdb
Updates: []*v1.RelationshipUpdate{blockusers[i]},
})
require.NoError(t, err)
t.Log("r1 token: ", r1.WrittenAt.Token)

// sleeping in between the writes seems to let cockroach clear out
// pending transactions in the background and has a better chance
Expand All @@ -373,6 +374,13 @@ func checkDataNoNewEnemy(ctx context.Context, t testing.TB, slowNodeID int, crdb
Updates: []*v1.RelationshipUpdate{allowlists[i]},
})
require.NoError(t, err)
t.Log("r2 token: ", r2.WrittenAt.Token)

z1, _ := zedtoken.DecodeRevision(r1.WrittenAt, revisions.CommonDecoder{Kind: revisions.HybridLogicalClock})
z2, _ := zedtoken.DecodeRevision(r2.WrittenAt, revisions.CommonDecoder{Kind: revisions.HybridLogicalClock})

t.Log("z1 revision: ", z1)
t.Log("z2 revision: ", z2)

canHas, err := spicedb[1].Client().V1().Permissions().CheckPermission(context.Background(), &v1.CheckPermissionRequest{
Consistency: &v1.Consistency{Requirement: &v1.Consistency_AtExactSnapshot{AtExactSnapshot: r2.WrittenAt}},
Expand All @@ -396,8 +404,6 @@ func checkDataNoNewEnemy(ctx context.Context, t testing.TB, slowNodeID int, crdb
ns2AllowlistLeader := getLeaderNodeForNamespace(ctx, crdb[2].Conn(), allowlists[i].Relationship.Subject.Object.ObjectType)

r1leader, r2leader := getLeaderNode(ctx, crdb[2].Conn(), blockusers[i].Relationship), getLeaderNode(ctx, crdb[2].Conn(), allowlists[i].Relationship)
z1, _ := zedtoken.DecodeRevision(r1.WrittenAt, revisions.CommonDecoder{Kind: revisions.HybridLogicalClock})
z2, _ := zedtoken.DecodeRevision(r2.WrittenAt, revisions.CommonDecoder{Kind: revisions.HybridLogicalClock})
t.Log(sleep, z1, z2, z1.GreaterThan(z2), r1leader, r2leader, ns1BlocklistLeader, ns1UserLeader, ns2ResourceLeader, ns2AllowlistLeader)

if z1.GreaterThan(z2) {
Expand Down
2 changes: 1 addition & 1 deletion internal/datastore/crdb/crdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -478,7 +478,7 @@ func readCRDBNow(ctx context.Context, reader pgxcommon.DBFuncQuerier) (datastore
return datastore.NoRevision, fmt.Errorf("unable to read timestamp: %w", err)
}

return revisions.NewForHLC(hlcNow), nil
return revisions.NewForHLC(hlcNow)
}

func readClusterTTLNanos(ctx context.Context, conn pgxcommon.DBFuncQuerier) (int64, error) {
Expand Down
2 changes: 1 addition & 1 deletion internal/datastore/crdb/stats.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,5 +105,5 @@ func updateCounter(ctx context.Context, tx pgx.Tx, change int64) (datastore.Revi
return datastore.NoRevision, fmt.Errorf("unable to executed upsert counter query: %w", err)
}

return revisions.NewForHLC(timestamp), nil
return revisions.NewForHLC(timestamp)
}
21 changes: 13 additions & 8 deletions internal/datastore/revisions/hlcrevision.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,14 @@ func parseHLCRevisionString(revisionStr string) (datastore.Revision, error) {
return datastore.NoRevision, fmt.Errorf("invalid revision string: %q", revisionStr)
}

logicalclock, err := strconv.ParseInt(pieces[1], 10, 32)
if err != nil {
return datastore.NoRevision, fmt.Errorf("invalid revision string: %q", revisionStr)
if len(pieces[1]) > logicalClockLength {
return datastore.NoRevision, spiceerrors.MustBugf("invalid revision string due to unexpected logical clock size (%d): %q", len(pieces[1]), revisionStr)
}

if len(pieces[1]) != logicalClockLength {
return datastore.NoRevision, spiceerrors.MustBugf("invalid revision string due to unexpected logical clock size (%d): %q", len(pieces[1]), revisionStr)
paddedLogicalClockStr := pieces[1] + strings.Repeat("0", logicalClockLength-len(pieces[1]))
logicalclock, err := strconv.ParseInt(paddedLogicalClockStr, 10, 32)
if err != nil {
return datastore.NoRevision, fmt.Errorf("invalid revision string: %q", revisionStr)
}

return HLCRevision{timestamp, uint32(logicalclock) + logicalClockOffset}, nil
Expand All @@ -73,9 +74,13 @@ func HLCRevisionFromString(revisionStr string) (HLCRevision, error) {
}

// NewForHLC creates a new revision for the given hybrid logical clock.
func NewForHLC(decimal decimal.Decimal) HLCRevision {
rev, _ := HLCRevisionFromString(decimal.String())
return rev
func NewForHLC(decimal decimal.Decimal) (HLCRevision, error) {
rev, err := HLCRevisionFromString(decimal.String())
if err != nil {
return zeroHLC, fmt.Errorf("invalid HLC decimal: %v (%s) => %w", decimal, decimal.String(), err)
}

return rev, nil
}

// NewHLCForTime creates a new revision for the given time.
Expand Down
20 changes: 19 additions & 1 deletion internal/datastore/revisions/hlcrevision_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,17 @@ func TestNewForHLC(t *testing.T) {
"-1",
"1.0000000023",
"1703283409994227985.0000000004",
"1703283409994227985.0000000040",
"1703283409994227985.0010000000",
}

for _, tc := range tcs {
t.Run(tc, func(t *testing.T) {
d, err := decimal.NewFromString(tc)
require.NoError(t, err)

rev := NewForHLC(d)
rev, err := NewForHLC(d)
require.NoError(t, err)
require.Equal(t, tc, rev.String())
})
}
Expand All @@ -40,6 +43,7 @@ func TestTimestampNanoSec(t *testing.T) {
"1.0000000023": 1,
"9223372036854775807.0000000002": 9223372036854775807,
"1703283409994227985.0000000004": 1703283409994227985,
"1703283409994227985.0000000040": 1703283409994227985,
}

for tc, nano := range tcs {
Expand All @@ -62,6 +66,11 @@ func TestInexactFloat64(t *testing.T) {
"1.0000000023": 1.0000000023,
"9223372036854775807.0000000002": 9223372036854775807.0000000002,
"1703283409994227985.0000000004": 1703283409994227985.0000000004,
"1703283409994227985.0000000040": 1703283409994227985.000000004,
"1703283409994227985.000000004": 1703283409994227985.000000004,
"1703283409994227985.0010": 1703283409994227985.001,
"1703283409994227985.0010000000": 1703283409994227985.001,
"1703283409994227985.001": 1703283409994227985.001,
}

for tc, floatValue := range tcs {
Expand Down Expand Up @@ -116,6 +125,15 @@ func TestHLCKeyEquals(t *testing.T) {
{
"1703283409994227985.0000000005", "1703283409994227985.0000000005", true,
},
{
"1703283409994227985.0000000050", "1703283409994227985.0000000050", true,
},
{
"1703283409994227985.0000000050", "1703283409994227985.0000000005", false,
},
{
"1703283409994227985.000000005", "1703283409994227985.0000000050", true,
},
}

for _, tc := range tcs {
Expand Down
22 changes: 17 additions & 5 deletions pkg/zedtoken/zedtoken_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,16 @@ var hlcDecodeTests = []struct {
expectError bool
}{
{
format: "V1 ZedToken",
token: "CAIaFQoTMTYyMTUzODE4OTAyODkyODAwMA==",
expectedRevision: revisions.NewForHLC(decimal.NewFromInt(1621538189028928000)),
expectError: false,
format: "V1 ZedToken",
token: "CAIaFQoTMTYyMTUzODE4OTAyODkyODAwMA==",
expectedRevision: func() datastore.Revision {
r, err := revisions.NewForHLC(decimal.NewFromInt(1621538189028928000))
if err != nil {
panic(err)
}
return r
}(),
expectError: false,
},
{
format: "V1 ZedToken",
Expand All @@ -179,7 +185,13 @@ var hlcDecodeTests = []struct {
if err != nil {
panic(err)
}
return revisions.NewForHLC(v)

r, err := revisions.NewForHLC(v)
if err != nil {
panic(err)
}

return r
})(),
expectError: false,
},
Expand Down
Loading