-
Notifications
You must be signed in to change notification settings - Fork 25
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(GODT-2289): Use timestamp for UIDValidity
Use a epoch timestamp for uidvalidity starting from 1st of February 2023. This will ensure that the user will always have unique UIDValidities even if the connector data is erased/lost.
- Loading branch information
1 parent
2c64e59
commit 565039a
Showing
28 changed files
with
343 additions
and
185 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
package imap | ||
|
||
import ( | ||
"fmt" | ||
"sync/atomic" | ||
"time" | ||
) | ||
|
||
type UIDValidityGenerator interface { | ||
Generate() (UID, error) | ||
} | ||
|
||
type EpochUIDValidityGenerator struct { | ||
epochStart time.Time | ||
lastUID uint32 | ||
} | ||
|
||
func NewEpochUIDValidityGenerator(epochStart time.Time) *EpochUIDValidityGenerator { | ||
return &EpochUIDValidityGenerator{ | ||
epochStart: epochStart, | ||
} | ||
} | ||
|
||
func DefaultEpochUIDValidityGenerator() *EpochUIDValidityGenerator { | ||
return NewEpochUIDValidityGenerator(time.Date(2023, 2, 1, 0, 0, 0, 0, time.UTC)) | ||
} | ||
|
||
func (e *EpochUIDValidityGenerator) Generate() (UID, error) { | ||
timeStamp := uint64(time.Now().Sub(e.epochStart).Seconds()) | ||
if timeStamp > uint64(0xFFFFFFFF) { | ||
return 0, fmt.Errorf("failed to generate uid validity, interval exceeded maximum capacity") | ||
} | ||
|
||
timeStampU32 := uint32(timeStamp) | ||
|
||
// This loops is here to ensure that two successive calls to Generate that happen during the same second | ||
// can still generate unique values. To avoid waiting another second until the values are different, | ||
// we keep bumping the last generated value until it is greater than the last generated value. | ||
for { | ||
lastGenerated := atomic.LoadUint32(&e.lastUID) | ||
|
||
// Not enough time elapsed between the last time | ||
if lastGenerated >= timeStampU32 { | ||
if timeStampU32 == 0xFFFFFFFF { | ||
return 0, fmt.Errorf("failed to generate uid validity, interval exceeded maximum capacity") | ||
} | ||
|
||
timeStampU32 += 1 | ||
|
||
continue | ||
} | ||
|
||
if !atomic.CompareAndSwapUint32(&e.lastUID, lastGenerated, timeStampU32) { | ||
continue | ||
} | ||
|
||
return UID(timeStampU32), nil | ||
} | ||
} | ||
|
||
type IncrementalUIDValidityGenerator struct { | ||
counter uint32 | ||
} | ||
|
||
func (i *IncrementalUIDValidityGenerator) Generate() (UID, error) { | ||
return UID(atomic.AddUint32(&i.counter, 1)), nil | ||
} | ||
|
||
func (i *IncrementalUIDValidityGenerator) GetValue() UID { | ||
return UID(atomic.LoadUint32(&i.counter)) | ||
} | ||
|
||
func NewIncrementalUIDValidityGenerator() *IncrementalUIDValidityGenerator { | ||
return &IncrementalUIDValidityGenerator{} | ||
} | ||
|
||
type FixedUIDValidityGenerator struct { | ||
Value UID | ||
} | ||
|
||
func (f FixedUIDValidityGenerator) Generate() (UID, error) { | ||
return f.Value, nil | ||
} | ||
|
||
func NewFixedUIDValidityGenerator(value UID) *FixedUIDValidityGenerator { | ||
return &FixedUIDValidityGenerator{Value: value} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
package imap | ||
|
||
import ( | ||
"github.com/bradenaw/juniper/parallel" | ||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
"golang.org/x/exp/slices" | ||
"testing" | ||
"time" | ||
) | ||
|
||
func TestEpochUIDValidityGenerator_Generate(t *testing.T) { | ||
generator := DefaultEpochUIDValidityGenerator() | ||
|
||
const UIDCount = 10 | ||
|
||
var uids = make([]UID, UIDCount) | ||
|
||
for i := 0; i < UIDCount; i++ { | ||
uid, err := generator.Generate() | ||
require.NoError(t, err) | ||
|
||
uids[i] = uid | ||
} | ||
|
||
time.Sleep(10 * time.Second) | ||
|
||
uid, err := generator.Generate() | ||
require.NoError(t, err) | ||
|
||
for i := 0; i < UIDCount-1; i++ { | ||
assert.Less(t, uids[i], uids[i+1]) | ||
} | ||
|
||
assert.Greater(t, uid, uids[UIDCount-1]) | ||
} | ||
|
||
func TestEpochUIDValidityGenerator_GenerateParallel(t *testing.T) { | ||
generator := DefaultEpochUIDValidityGenerator() | ||
|
||
const UIDCount = 1000 | ||
|
||
var uids = make([]UID, UIDCount) | ||
|
||
parallel.Do(0, UIDCount, func(i int) { | ||
uid, err := generator.Generate() | ||
require.NoError(t, err) | ||
uids[i] = uid | ||
}) | ||
|
||
slices.Sort(uids) | ||
|
||
for i := 0; i < UIDCount-1; i++ { | ||
assert.Less(t, uids[i], uids[i+1]) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.