Merge pull request #65 from xStrom/txn-journal-lock

Fix race condition with transaction's cache update journaling
diff --git a/goon.go b/goon.go
index 66f9b13..0e32e21 100644
--- a/goon.go
+++ b/goon.go
@@ -59,6 +59,7 @@
 	cache         map[string]interface{}
 	cacheLock     sync.RWMutex // protect the cache from concurrent goroutines to speed up RPC access
 	inTransaction bool
+	txnCacheLock  sync.Mutex // protects toSet / toDelete / toDeleteMC
 	toSet         map[string]interface{}
 	toDelete      map[string]bool
 	toDeleteMC    map[string]bool
@@ -174,6 +175,8 @@
 	}, opts)
 
 	if err == nil {
+		ng.txnCacheLock.Lock()
+		defer ng.txnCacheLock.Unlock()
 		if len(ng.toDeleteMC) > 0 {
 			var memkeys []string
 			for k := range ng.toDeleteMC {
@@ -186,7 +189,6 @@
 		for k, v := range ng.toSet {
 			g.cache[k] = v
 		}
-
 		for k := range ng.toDelete {
 			delete(g.cache, k)
 		}
@@ -264,9 +266,11 @@
 				}
 				if g.inTransaction {
 					mk := MemcacheKey(rkeys[i])
+					g.txnCacheLock.Lock()
 					delete(g.toDelete, mk)
 					g.toSet[mk] = vi
 					g.toDeleteMC[mk] = true
+					g.txnCacheLock.Unlock()
 				} else {
 					g.putMemory(vi)
 				}
@@ -608,8 +612,10 @@
 		memkeys[i] = mk
 
 		if g.inTransaction {
+			g.txnCacheLock.Lock()
 			delete(g.toSet, mk)
 			g.toDelete[mk] = true
+			g.txnCacheLock.Unlock()
 		} else {
 			delete(g.cache, mk)
 		}
@@ -620,9 +626,11 @@
 	// where a concurrent request will fetch the not-yet-updated data from the datastore
 	// and populate memcache with it.
 	if g.inTransaction {
+		g.txnCacheLock.Lock()
 		for _, mk := range memkeys {
 			g.toDeleteMC[mk] = true
 		}
+		g.txnCacheLock.Unlock()
 	} else {
 		defer memcache.DeleteMulti(g.Context, memkeys)
 	}