Skip to content

Commit

Permalink
loader: use atomic.Value to store snapshot (#34)
Browse files Browse the repository at this point in the history
* loader: use atomic.Value to store snapshot

This eliminates the need to use a mutex.

```
benchmark                        old ns/op     new ns/op     delta
BenchmarkSnapsot-12              15.1          2.46          -83.71%
BenchmarkSnapsot_Parallel-12     36.6          0.51          -98.60%
```

* loader: fix spelling
  • Loading branch information
charlievieth authored Mar 11, 2020
1 parent 2c2ecd2 commit 7ddd2be
Show file tree
Hide file tree
Showing 2 changed files with 21 additions and 13 deletions.
18 changes: 5 additions & 13 deletions loader/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"path/filepath"
"strconv"
"strings"
"sync"
"sync/atomic"

"github.com/fsnotify/fsnotify"
"github.com/lyft/goruntime/snapshot"
Expand All @@ -33,23 +33,19 @@ func newLoaderStats(scope stats.Scope) loaderStats {

// Implementation of Loader that watches a symlink and reads from the filesystem.
type Loader struct {
currentSnapshot atomic.Value
watcher *fsnotify.Watcher
watchPath string
subdirectory string
currentSnapshot snapshot.IFace
nextSnapshot snapshot.IFace
updateLock sync.RWMutex
callbacks []chan<- int
stats loaderStats
ignoreDotfiles bool
}

func (l *Loader) Snapshot() snapshot.IFace {
// This could probably be done with an atomic pointer but the unsafe pointers the atomics
// take scared me so skipping for now.
l.updateLock.RLock()
defer l.updateLock.RUnlock()
return l.currentSnapshot
v, _ := l.currentSnapshot.Load().(snapshot.IFace)
return v
}

func (l *Loader) AddUpdateCallback(callback chan<- int) {
Expand All @@ -64,13 +60,9 @@ func (l *Loader) onRuntimeChanged() {
l.nextSnapshot = snapshot.New()
filepath.Walk(targetDir, l.walkDirectoryCallback)

// This could probably be done with an atomic pointer but the unsafe pointers the atomics
// take scared me so skipping for now.
l.stats.loadAttempts.Inc()
l.stats.numValues.Set(uint64(len(l.nextSnapshot.Entries())))
l.updateLock.Lock()
l.currentSnapshot = l.nextSnapshot
l.updateLock.Unlock()
l.currentSnapshot.Store(l.nextSnapshot)

l.nextSnapshot = nil
for _, callback := range l.callbacks {
Expand Down
16 changes: 16 additions & 0 deletions loader/loader_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,3 +190,19 @@ func TestDirectoryRefresher(t *testing.T) {
snapshot = loader.Snapshot()
assert.Equal("hello3", snapshot.Get("file2"))
}

func BenchmarkSnapshot(b *testing.B) {
var ll Loader
for i := 0; i < b.N; i++ {
ll.Snapshot()
}
}

func BenchmarkSnapshot_Parallel(b *testing.B) {
ll := new(Loader)
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
ll.Snapshot()
}
})
}

0 comments on commit 7ddd2be

Please sign in to comment.