From 073dae2be2878ac1d8113930579c6459cd4acc92 Mon Sep 17 00:00:00 2001
From: Lukas Braun <lukas.braun@fau.de>
Date: Fri, 27 Jan 2017 21:13:03 +0100
Subject: [PATCH] comment on userlocks synchronization

---
 goatherd.go | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/goatherd.go b/goatherd.go
index 29c9a2f..cc02fcc 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 {
-- 
GitLab