services/allocator/allocatord: Add owner cache

Add a cache to make checking the ownership of an instance faster. This
is currently only used by the dashboard since it will benefit from it
the most.

Change-Id: I02de555b53c48e1ec55aa72b60f0f5ff8404b14f
diff --git a/services/allocator/allocatord/cache.go b/services/allocator/allocatord/cache.go
new file mode 100644
index 0000000..be7bc4a
--- /dev/null
+++ b/services/allocator/allocatord/cache.go
@@ -0,0 +1,40 @@
+// Copyright 2016 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+	"sync"
+
+	"github.com/golang/groupcache/lru"
+
+	"v.io/v23/verror"
+)
+
+var (
+	ownerCache      *lru.Cache
+	ownerCacheMutex sync.Mutex
+)
+
+func checkOwner(email, kName string) error {
+	ownerCacheMutex.Lock()
+	if ownerCache == nil {
+		ownerCache = lru.New(maxInstancesFlag)
+	} else if v, ok := ownerCache.Get(kName); ok {
+		ownerCacheMutex.Unlock()
+		if email != v {
+			return verror.New(verror.ErrNoExistOrNoAccess, nil)
+		}
+		return nil
+	}
+	ownerCacheMutex.Unlock()
+
+	if err := isOwnerOfInstance(email, kName); err != nil {
+		return err
+	}
+	ownerCacheMutex.Lock()
+	ownerCache.Add(kName, email)
+	ownerCacheMutex.Unlock()
+	return nil
+}
diff --git a/services/allocator/allocatord/dashboard.go b/services/allocator/allocatord/dashboard.go
index 8eb5aaa..19a6ed8 100644
--- a/services/allocator/allocatord/dashboard.go
+++ b/services/allocator/allocatord/dashboard.go
@@ -15,7 +15,6 @@
 
 	"google.golang.org/api/monitoring/v3"
 
-	"v.io/v23/verror"
 	"v.io/x/lib/gcm"
 )
 
@@ -55,15 +54,12 @@
 }
 
 func handleDashboard(ss *serverState, rs *requestState) error {
-	ctx := ss.ctx
 	instance := rs.r.FormValue(paramDashboardName)
 	if instance == "" {
 		return fmt.Errorf("parameter %q required for instance name", paramDashboardName)
 	}
-	if isOwner, err := isOwnerOfInstance(rs.email, kubeNameFromMountName(instance)); err != nil {
+	if err := checkOwner(rs.email, kubeNameFromMountName(instance)); err != nil {
 		return err
-	} else if !isOwner {
-		return verror.New(verror.ErrNoExistOrNoAccess, ctx)
 	}
 
 	tmplArgs := struct {
@@ -90,10 +86,8 @@
 	if mountedName == "" {
 		return fmt.Errorf("parameter %q required for instance name", paramDashboardName)
 	}
-	if isOwner, err := isOwnerOfInstance(rs.email, kubeNameFromMountName(mountedName)); err != nil {
+	if err := checkOwner(rs.email, kubeNameFromMountName(mountedName)); err != nil {
 		return err
-	} else if !isOwner {
-		return verror.New(verror.ErrNoExistOrNoAccess, ctx)
 	}
 
 	now := time.Now()
diff --git a/services/allocator/allocatord/service.go b/services/allocator/allocatord/service.go
index d673456..2036300 100644
--- a/services/allocator/allocatord/service.go
+++ b/services/allocator/allocatord/service.go
@@ -135,10 +135,8 @@
 func destroy(ctx *context.T, email, mName string) error {
 	kName := kubeNameFromMountName(mName)
 
-	if isOwner, err := isOwnerOfInstance(email, kName); err != nil {
+	if err := isOwnerOfInstance(email, kName); err != nil {
 		return err
-	} else if !isOwner {
-		return verror.New(verror.ErrNoExistOrNoAccess, ctx)
 	}
 
 	cfg, cleanup, err := createDeploymentConfig(ctx, email, kName, mName)
@@ -321,17 +319,17 @@
 	return instances, nil
 }
 
-func isOwnerOfInstance(email, kName string) (bool, error) {
+func isOwnerOfInstance(email, kName string) error {
 	instances, err := serverInstances(email)
 	if err != nil {
-		return false, err
+		return err
 	}
 	for _, i := range instances {
 		if i.name == kName {
-			return true, nil
+			return nil
 		}
 	}
-	return false, nil
+	return verror.New(verror.ErrNoExistOrNoAccess, nil)
 }
 
 func createPersistentDisk(ctx *context.T, name string) error {