Commit 3847874
authored
Wait for an in-flight replay before closing the log watcher (#1347)
## Motivation
When a replica shuts down, `PathChildrenCache.close()` cancels its
in-flight tasks with an interrupt.
If a replay was waiting on `delegate.execute(...)` at that moment, the
command had already been applied
to the local data but `lastReplayedRevision` was never advanced, because
it is updated only on the
success path. The replica is then left with local data ahead of
`<dataDir>/last_revision`, and the next
start-up replays the same revision again. Re-applying a command whose
effect is already in the local
data fails, so the replica enters read-only mode and needs a manual
re-sync.
```
[INFO ] [command-executor-shutdown] Closing the log watcher
[ERROR] [zookeeper-log-watcher-1-1] Failed to replay a log at revision N; entering read-only mode.
java.lang.InterruptedException
at java.base/java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:386)
at java.base/java.util.concurrent.CompletableFuture.get(CompletableFuture.java:2073)
at ...ZooKeeperCommandExecutor.replayLogs(ZooKeeperCommandExecutor.java:820)
at ...ZooKeeperCommandExecutor.childEvent(ZooKeeperCommandExecutor.java:885)
at ...PathChildrenCache.lambda$callListeners$1(PathChildrenCache.java:529)
```
## Modifications
- Wait for an in-flight replay before closing the log watcher, by
acquiring the same monitor that
`replayLogs()` holds. Releasing it is safe because `listenerInfo` is
already null, so a replay that
starts afterwards returns before executing anything.
- Move the log watcher shutdown ahead of `delegate.stop()`. The barrier
waits for a replay that is
itself waiting on the delegate, so the delegate must still be running.
This also matches the drain
that `shutdown(executor)` already performs for the command executor
threads.
`logWatcher.close()` still runs before `shutdown(logWatcherExecutor)`:
reversing the two would let
`PathChildrenCache` keep submitting to an already shut-down executor,
because `submitToExecutor()`
only guards on its own state, which flips in `close()`.
- Wait uninterruptibly for the replay result, as a safeguard on the line
where the failure occurred.
- Log the last replayed revision once the replay is drained.
Note this covers a graceful shutdown only. A `SIGKILL` between the local
apply and the progress update
leaves the same divergence; making the replay idempotent is a separate
topic.
## Result
- A replica that shuts down while replaying no longer leaves its local
data ahead of its recorded
replication progress, so it no longer enters read-only mode on the next
start-up.1 parent f8a443c commit 3847874
2 files changed
Lines changed: 74 additions & 3 deletions
File tree
- server/src
- main/java/com/linecorp/centraldogma/server/internal/replication
- test/java/com/linecorp/centraldogma/server/internal/replication
Lines changed: 12 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
680 | 680 | | |
681 | 681 | | |
682 | 682 | | |
| 683 | + | |
683 | 684 | | |
| 685 | + | |
684 | 686 | | |
685 | 687 | | |
686 | 688 | | |
687 | 689 | | |
688 | 690 | | |
689 | | - | |
690 | | - | |
| 691 | + | |
| 692 | + | |
| 693 | + | |
| 694 | + | |
| 695 | + | |
| 696 | + | |
| 697 | + | |
691 | 698 | | |
692 | 699 | | |
693 | 700 | | |
| |||
817 | 824 | | |
818 | 825 | | |
819 | 826 | | |
820 | | - | |
| 827 | + | |
| 828 | + | |
| 829 | + | |
821 | 830 | | |
822 | 831 | | |
823 | 832 | | |
| |||
Lines changed: 62 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
748 | 748 | | |
749 | 749 | | |
750 | 750 | | |
| 751 | + | |
| 752 | + | |
| 753 | + | |
| 754 | + | |
| 755 | + | |
| 756 | + | |
| 757 | + | |
| 758 | + | |
| 759 | + | |
| 760 | + | |
| 761 | + | |
| 762 | + | |
| 763 | + | |
| 764 | + | |
| 765 | + | |
| 766 | + | |
| 767 | + | |
| 768 | + | |
| 769 | + | |
| 770 | + | |
| 771 | + | |
| 772 | + | |
| 773 | + | |
| 774 | + | |
| 775 | + | |
| 776 | + | |
| 777 | + | |
| 778 | + | |
| 779 | + | |
| 780 | + | |
| 781 | + | |
| 782 | + | |
| 783 | + | |
| 784 | + | |
| 785 | + | |
| 786 | + | |
| 787 | + | |
| 788 | + | |
| 789 | + | |
| 790 | + | |
| 791 | + | |
| 792 | + | |
| 793 | + | |
| 794 | + | |
| 795 | + | |
| 796 | + | |
| 797 | + | |
| 798 | + | |
| 799 | + | |
| 800 | + | |
| 801 | + | |
| 802 | + | |
| 803 | + | |
| 804 | + | |
| 805 | + | |
| 806 | + | |
| 807 | + | |
| 808 | + | |
| 809 | + | |
| 810 | + | |
| 811 | + | |
| 812 | + | |
751 | 813 | | |
752 | 814 | | |
753 | 815 | | |
| |||
0 commit comments