Skip to content
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
6 changes: 6 additions & 0 deletions docs/changes/unreleased/2180-watch-receipt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
kind: fixed
title: Another computer taking a chat retires this window's send receipt before any reader is told
pr: 2180
surface: [chat, app]
---
32 changes: 21 additions & 11 deletions internal/syncsetup/drive.go
Original file line number Diff line number Diff line change
Expand Up @@ -613,17 +613,7 @@ func (d *Drive) CheckLease(ctx context.Context) error {
}
if err == nil && (v.Cell.Lease.Expires <= v.Now || v.Cell.Lease.Device != d.sync.Device.ID() || v.Cell.Lease.Fence != d.batcher.Fence()) {
if v.Cell.Lease.Device != d.sync.Device.ID() {
// Another computer holds the chat. Retire the hold at once so no
// new seal starts, wait for any seal already past Gate, and let the
// batcher keep unsent turns as a branch before the window names the
// new holder (#2091). The hold is retired quietly: becomeViewer
// announces the change once, with the viewer line already set.
d.mu.Lock()
d.lost = true
d.mu.Unlock()
d.sealMu.Lock()
d.sealMu.Unlock()
d.batcher.Displaced(ctx)
d.retireForAnotherHolder(ctx, held)
}
d.becomeViewer(cellsync.Superseded{By: v.Cell.Lease.Device})
} else if err == nil {
Expand All @@ -632,6 +622,26 @@ func (d *Drive) CheckLease(ctx context.Context) error {
return nil
}

// retireForAnotherHolder retires this writer's hold when CheckLease finds
// another computer holding the chat. It retires the hold at once so no new
// seal starts, waits for any seal already past Gate, and lets the batcher keep
// unsent turns as a branch before the window names the new holder (#2091).
// The send receipt goes before the
// batcher marks itself stale, because that mark already wakes renewal readers
// and none of them may still find a receipt for a hold another computer has.
// The hold is retired quietly: becomeViewer announces the change once.
func (d *Drive) retireForAnotherHolder(ctx context.Context, held sendLease) {
d.mu.Lock()
d.lost = true
d.mu.Unlock()
d.sealMu.Lock()
d.sealMu.Unlock()
if err := d.sync.forgetSendLease(d.cell.ID, held); err != nil {
d.notice(err.Error())
}
d.batcher.Displaced(ctx)
}

// sendLeaseSnapshot binds retirement to the receipt held before a relay reading,
// so an older reading cannot retire a receipt recorded by a later reacquisition.
func (d *Drive) sendLeaseSnapshot() sendLease {
Expand Down