diff --git a/goatherd.go b/goatherd.go index 29c9a2f4452f1c4b2de18f7a9d659a81a4c6e55b..cc02fccff683d71af28f2057864376e2d4d0ba0e 100644 --- a/goatherd.go +++ b/goatherd.go @@ -259,14 +259,17 @@ func handle_conn(db *sql.DB, conn net.Conn) { } log.Printf("%v: %v", name, result) - // name exists, get or create its lock + // name exists, so we can get or create its lock, double-checked locking style + // NOTE: the read lock is important to synchronize with the mutex initiali- + // zation, not just the map itself (i.e. a reader might observe a non- + // zeroed mutex if we used a concurrent map without a temporary variable + // and further memory barriers) faildelay.RLock() delay, exists := faildelay.userlocks[name] faildelay.RUnlock() if !exists { debugf("[%v] not yet in faildelay.userlocks", remote) - // no atomic upgrade with sync.RWMutex, so we have to do the lookup again faildelay.Lock() delay, exists = faildelay.userlocks[name] if !exists {