Skip to content

Commit

Permalink
refactor(sync): get rid of RWMutex and TryLock
Browse files Browse the repository at this point in the history
  • Loading branch information
tzdybal committed Jul 4, 2023
1 parent a1322fc commit ce00a07
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 8 deletions.
2 changes: 1 addition & 1 deletion sync/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ func NewSyncer[H header.Header](
return &Syncer[H]{
sub: sub,
store: syncStore[H]{Store: store},
getter: syncGetter[H]{Getter: getter},
getter: *newSyncGetter(getter),
triggerSync: make(chan struct{}, 1), // should be buffered
Params: &params,
}, nil
Expand Down
24 changes: 17 additions & 7 deletions sync/sync_getter.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,32 +10,36 @@ import (

// syncGetter is a Getter wrapper that ensure only one Head call happens at the time
type syncGetter[H header.Header] struct {
getterLk sync.RWMutex
getterLk sync.Mutex
getterCond *sync.Cond
isGetterLk atomic.Bool
header.Getter[H]
}

func newSyncGetter[H header.Header](g header.Getter[H]) *syncGetter[H] {
getter := syncGetter[H]{Getter: g}
getter.getterCond = sync.NewCond(&getter.getterLk)
return &getter
}

// Lock locks the getter for single user.
// Reports 'true' if the lock was held by the current routine.
// Does not require unlocking on 'false'.
func (se *syncGetter[H]) Lock() bool {
// the lock construction here ensures only one routine is freed at a time
// while others wait via Rlock
locked := se.getterLk.TryLock()
locked := se.isGetterLk.CompareAndSwap(false, true)
if !locked {
se.getterLk.RLock()
defer se.getterLk.RUnlock()
return false
se.await()
}
se.isGetterLk.Store(locked)
return locked
}

// Unlock unlocks the getter.
func (se *syncGetter[H]) Unlock() {
se.checkLock("Unlock without preceding Lock on syncGetter")
se.getterLk.Unlock()
se.isGetterLk.Store(false)
se.getterCond.Broadcast()
}

// Head must be called with held Lock.
Expand All @@ -50,3 +54,9 @@ func (se *syncGetter[H]) checkLock(msg string) {
panic(msg)
}
}

func (se *syncGetter[H]) await() {
se.getterLk.Lock()
se.getterCond.Wait()
se.getterLk.Unlock()
}
1 change: 1 addition & 0 deletions sync/sync_getter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ func TestSyncGetterHead(t *testing.T) {

fex := &fakeGetter[*headertest.DummyHeader]{}
sex := &syncGetter[*headertest.DummyHeader]{Getter: fex}
sex.getterCond = sync.NewCond(&sex.getterLk)

var wg sync.WaitGroup
for i := 0; i < 100; i++ {
Expand Down

0 comments on commit ce00a07

Please sign in to comment.