Skip to content

Commit 77ef5f8

Browse files
fix(GODT-1621): Fix race condition with temporary IDs
Currently it is possible to have temporary IDs for mailboxes and messages to become stale. It is possible, due to concurrency, that a session pushes an operation which still uses a temporary ID that is no longer valid. Rather than locking the entire queue and updating all the remaining entries, we now maintain two separate translation tables which are evicted via separate operations. This reduces the amount of time the queue spends in a locking state and also guarantees that by the time the removal of the temporary ID is processed by the operation queue no other operations exist that still refer to this temporary ID.
1 parent 253c01c commit 77ef5f8

14 files changed

Lines changed: 158 additions & 110 deletions

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ require (
1212
github.com/golang/mock v1.6.0
1313
github.com/google/uuid v1.3.0
1414
github.com/mattn/go-sqlite3 v1.14.10
15-
github.com/pkg/errors v0.9.1
1615
github.com/sirupsen/logrus v1.8.1
1716
github.com/stretchr/testify v1.7.1-0.20210427113832-6241f9ab9942
1817
golang.org/x/exp v0.0.0-20220518171630-0b5c67f07fdf
@@ -33,6 +32,7 @@ require (
3332
github.com/hashicorp/hcl/v2 v2.10.0 // indirect
3433
github.com/kr/pretty v0.3.0 // indirect
3534
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 // indirect
35+
github.com/pkg/errors v0.9.1 // indirect
3636
github.com/pmezard/go-difflib v1.0.0 // indirect
3737
github.com/rogpeppe/go-internal v1.8.0 // indirect
3838
github.com/zclconf/go-cty v1.8.0 // indirect

internal/backend/user_updates.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,10 @@ func (user *user) applyMailboxIDChanged(ctx context.Context, tx *ent.Tx, update
110110
return err
111111
}
112112

113+
if err := user.remote.FinishMailboxIDUpdate(update.OldID); err != nil {
114+
logrus.WithError(err).Errorf("Call to FinishMailboxIDUpdate() failed")
115+
}
116+
113117
return txUpdateMailboxID(ctx, tx, update.OldID, update.NewID)
114118
}
115119

@@ -208,6 +212,10 @@ func (user *user) applyMessageIDChanged(ctx context.Context, tx *ent.Tx, update
208212
return err
209213
}
210214

215+
if err := user.remote.FinishMessageIDUpdate(update.OldID); err != nil {
216+
logrus.WithError(err).Error("Call to FinishMessageIDUpdate() failed")
217+
}
218+
211219
if err := user.store.Update(update.OldID, update.NewID); err != nil {
212220
return err
213221
}

internal/remote/operation.go

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,6 @@ func (c *OperationBase) getConnMetadataID() ConnMetadataID {
2121
return c.MetadataID
2222
}
2323

24-
type mailboxOperation interface {
25-
setMailboxID(tempID, mailboxID string)
26-
}
27-
28-
type messageOperation interface {
29-
setMessageID(tempID, messageID string)
30-
}
31-
3224
// saveOps serializes the operation queue to a binary format to be serialized to disk.
3325
func saveOps(ops []operation) ([]byte, error) {
3426
buf := new(bytes.Buffer)

internal/remote/operation_mailbox_delete.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,4 @@ func (op *OpMailboxDelete) merge(other operation) (operation, bool) {
1515
return nil, false
1616
}
1717

18-
func (op *OpMailboxDelete) setMailboxID(tempID, mailboxID string) {
19-
if op.MBoxID == tempID {
20-
op.MBoxID = mailboxID
21-
}
22-
}
23-
2418
func (OpMailboxDelete) _isOperation() {}

internal/remote/operation_mailbox_update.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,4 @@ func (op *OpMailboxUpdate) merge(other operation) (operation, bool) {
1616
return nil, false
1717
}
1818

19-
func (op *OpMailboxUpdate) setMailboxID(tempID, mailboxID string) {
20-
if op.MBoxID == tempID {
21-
op.MBoxID = mailboxID
22-
}
23-
}
24-
2519
func (OpMailboxUpdate) _isOperation() {}

internal/remote/operation_message_add.go

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,4 @@ func (op *OpMessageAdd) merge(other operation) (operation, bool) {
2828
}
2929
}
3030

31-
func (op *OpMessageAdd) setMailboxID(tempID, mboxID string) {
32-
if op.MBoxID == tempID {
33-
op.MBoxID = mboxID
34-
}
35-
}
36-
37-
func (op *OpMessageAdd) setMessageID(tempID, messageID string) {
38-
for idx := range op.MessageIDs {
39-
if op.MessageIDs[idx] == tempID {
40-
op.MessageIDs[idx] = messageID
41-
}
42-
}
43-
}
44-
4531
func (OpMessageAdd) _isOperation() {}

internal/remote/operation_message_create.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,4 @@ func (op *OpMessageCreate) merge(other operation) (operation, bool) {
2424
return nil, false
2525
}
2626

27-
func (op *OpMessageCreate) setMailboxID(tempID, mailboxID string) {
28-
if op.MBoxID == tempID {
29-
op.MBoxID = mailboxID
30-
}
31-
}
32-
3327
func (OpMessageCreate) _isOperation() {}

internal/remote/operation_message_flagged.go

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,4 @@ func (op *OpMessageFlagged) merge(other operation) (operation, bool) {
2828
}
2929
}
3030

31-
func (op *OpMessageFlagged) setMessageID(tempID, messageID string) {
32-
for idx := range op.MessageIDs {
33-
if op.MessageIDs[idx] == tempID {
34-
op.MessageIDs[idx] = messageID
35-
}
36-
}
37-
}
38-
3931
func (OpMessageFlagged) _isOperation() {}

internal/remote/operation_message_remove.go

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,20 +28,6 @@ func (op *OpMessageRemove) merge(other operation) (operation, bool) {
2828
}
2929
}
3030

31-
func (op *OpMessageRemove) setMailboxID(tempID, mboxID string) {
32-
if op.MBoxID == tempID {
33-
op.MBoxID = mboxID
34-
}
35-
}
36-
37-
func (op *OpMessageRemove) setMessageID(tempID, messageID string) {
38-
for idx := range op.MessageIDs {
39-
if op.MessageIDs[idx] == tempID {
40-
op.MessageIDs[idx] = messageID
41-
}
42-
}
43-
}
44-
4531
func (op *OpMessageRemove) getConnMetadataID() ConnMetadataID {
4632
return op.MetadataID
4733
}

internal/remote/operation_message_seen.go

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,4 @@ func (op *OpMessageSeen) merge(other operation) (operation, bool) {
2828
}
2929
}
3030

31-
func (op *OpMessageSeen) setMessageID(tempID, messageID string) {
32-
for idx := range op.MessageIDs {
33-
if op.MessageIDs[idx] == tempID {
34-
op.MessageIDs[idx] = messageID
35-
}
36-
}
37-
}
38-
3931
func (OpMessageSeen) _isOperation() {}

0 commit comments

Comments
 (0)