|
@@ -0,0 +1,70 @@
|
|
|
+package util
|
|
|
+
|
|
|
+import "sync/atomic"
|
|
|
+
|
|
|
+type StaleMode int
|
|
|
+
|
|
|
+const (
|
|
|
+ BothStale = iota
|
|
|
+ EitherStale
|
|
|
+ LeftStale
|
|
|
+ RightStale
|
|
|
+)
|
|
|
+
|
|
|
+type tracker struct {
|
|
|
+ leftCounter atomic.Int32
|
|
|
+ rightCounter atomic.Int32
|
|
|
+ leftTimedOutAt atomic.Int32
|
|
|
+ rightTimedOutAt atomic.Int32
|
|
|
+ staleFun func() bool
|
|
|
+}
|
|
|
+
|
|
|
+func newTracker(staleMode StaleMode) *tracker {
|
|
|
+ t := &tracker{}
|
|
|
+ switch staleMode {
|
|
|
+ case BothStale:
|
|
|
+ t.staleFun = t.bothStale
|
|
|
+ case EitherStale:
|
|
|
+ t.staleFun = t.eitherStale
|
|
|
+ case LeftStale:
|
|
|
+ t.staleFun = t.leftStale
|
|
|
+ case RightStale:
|
|
|
+ t.staleFun = t.rightStale
|
|
|
+ default:
|
|
|
+ panic("unsupported stale mode")
|
|
|
+ }
|
|
|
+ return t
|
|
|
+}
|
|
|
+
|
|
|
+func (t *tracker) notify(isLeft bool) {
|
|
|
+ if isLeft {
|
|
|
+ t.leftCounter.Add(1)
|
|
|
+ } else {
|
|
|
+ t.rightCounter.Add(1)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func (t *tracker) handleTimeout(isLeft bool) bool {
|
|
|
+ if isLeft {
|
|
|
+ t.leftTimedOutAt.Store(t.leftCounter.Load())
|
|
|
+ } else {
|
|
|
+ t.rightTimedOutAt.Store(t.rightCounter.Load())
|
|
|
+ }
|
|
|
+ return t.staleFun()
|
|
|
+}
|
|
|
+
|
|
|
+func (t *tracker) leftStale() bool {
|
|
|
+ return t.leftCounter.Load() == t.leftTimedOutAt.Load()
|
|
|
+}
|
|
|
+
|
|
|
+func (t *tracker) rightStale() bool {
|
|
|
+ return t.rightCounter.Load() == t.rightTimedOutAt.Load()
|
|
|
+}
|
|
|
+
|
|
|
+func (t *tracker) bothStale() bool {
|
|
|
+ return t.leftStale() && t.rightStale()
|
|
|
+}
|
|
|
+
|
|
|
+func (t *tracker) eitherStale() bool {
|
|
|
+ return t.leftStale() || t.rightStale()
|
|
|
+}
|