From 3f18d5890e4f8acb7cd3a65579617b55e87951d2 Mon Sep 17 00:00:00 2001
From: Sean Young <sean.young@monax.io>
Date: Fri, 6 Apr 2018 11:19:03 +0100
Subject: [PATCH] Fix locking issues in name cache

Avoid concurrent duplicate calls to backend.GetNameEntry(). This avoids
duplicate work but holds a write lock for the duration.

Ensure we unlock in error path in Sync.

Signed-off-by: Sean Young <sean.young@monax.io>
---
 execution/namereg_cache.go | 23 ++++++++++++++---------
 1 file changed, 14 insertions(+), 9 deletions(-)

diff --git a/execution/namereg_cache.go b/execution/namereg_cache.go
index f941b9f9..5cb0c63a 100644
--- a/execution/namereg_cache.go
+++ b/execution/namereg_cache.go
@@ -109,11 +109,13 @@ func (cache *NameRegCache) Sync(state NameRegWriter) error {
 		if nameInfo.removed {
 			err := state.RemoveNameRegEntry(name)
 			if err != nil {
+				nameInfo.RUnlock()
 				return err
 			}
 		} else if nameInfo.updated {
 			err := state.UpdateNameRegEntry(nameInfo.entry)
 			if err != nil {
+				nameInfo.RUnlock()
 				return err
 			}
 		}
@@ -150,16 +152,19 @@ func (cache *NameRegCache) get(name string) (*nameInfo, error) {
 	nmeInfo := cache.names[name]
 	cache.RUnlock()
 	if nmeInfo == nil {
-		entry, err := cache.backend.GetNameRegEntry(name)
-		if err != nil {
-			return nil, err
-		}
-		nmeInfo = &nameInfo{
-			entry: entry,
-		}
 		cache.Lock()
-		cache.names[name] = nmeInfo
-		cache.Unlock()
+		defer cache.Unlock()
+		nmeInfo = cache.names[name]
+		if nmeInfo == nil {
+			entry, err := cache.backend.GetNameRegEntry(name)
+			if err != nil {
+				return nil, err
+			}
+			nmeInfo = &nameInfo{
+				entry: entry,
+			}
+			cache.names[name] = nmeInfo
+		}
 	}
 	return nmeInfo, nil
 }
-- 
GitLab