]> www.infradead.org Git - users/dhowells/kafs-utils.git/commitdiff
Provide a protection DB Name<->ID cache
authorDavid Howells <dhowells@redhat.com>
Wed, 14 May 2014 11:14:52 +0000 (12:14 +0100)
committerDavid Howells <dhowells@redhat.com>
Wed, 14 May 2014 11:14:52 +0000 (12:14 +0100)
Provide a protection DB Name<->ID cache to eliminate redundant lookups and to
reduce the number of NameToID and IDToName RPC calls made by consolidating
multiple requests into single calls.

Signed-off-by: David Howells <dhowells@redhat.com>
suite/commands/pts/delete.py
suite/commands/pts/listowned.py
suite/lib/cell.py
suite/lib/prcache.py [new file with mode: 0644]

index c49e42b7173213cd0fd3a9758a338a8bbffe65c8..c8859b79b7dcd5b78506966750d9ea050364d761 100644 (file)
@@ -53,30 +53,22 @@ Delete a Protection Database entry
 
 def main(params):
     cell = params["cell"]
+    prcache = cell.get_prcache(params)
 
     for name in params["nameorid"]:
-        try:
-            if name.isnumeric() or name[0] == "-" and name[1:].isnumeric():
-                uid = int(name)
-                verbose("ID ", uid, "\n")
-                # Convert the id to a name for message purposes - note that if
-                # the entry does not exist, this will just stringify the ID for
-                # us.
-                ret = cell.call_pt_server(params, kafs.PR_IDToName, [ uid ])
-                name = ret.nlist[0].prname
-            else:
-                verbose("Name ", name, "\n")
-                ret = cell.call_pt_server(params, kafs.PR_NameToID, [ name ])
-                uid = ret.ilist[0]
-                if uid == kafs.PR_ANONYMOUSID and name != "anonymous":
-                    error("User or group doesn't exist so couldn't look up id for " + name + "\n")
-                    if "force" not in params:
-                        break
-                    continue
+        prcache.precache_name_or_id(name)
 
-            verbose("Deleting user ", uid, " (", name, ")\n")
-            ret = cell.call_pt_server(params, kafs.PR_Delete, uid)
+    for name in params["nameorid"]:
+        uid = prcache.name_or_id_to_id(name)
+        if uid == None:
+            error("User or group doesn't exist so couldn't look up id for " + name + "\n")
+            if "force" not in params:
+                break
+            continue
 
+        try:
+            verbose("Deleting user ", uid, " (", prcache.id_to_name(uid), ")\n")
+            ret = cell.call_pt_server(params, kafs.PR_Delete, uid)
         except kafs.AbortPRNOENT:
             error("User or group doesn't exist deleting ", name, " (id ", uid, ")\n")
             if "force" not in params:
index d9d0cadfd7585ab4fb04e0096084a6c42eb67e32..f2a83faa2584dcb9ad2ea578fa17a3893a9b98b4 100644 (file)
@@ -53,37 +53,27 @@ Show the Protection Database groups owned by a user or group
 
 def main(params):
     cell = params["cell"]
+    prcache = cell.get_prcache(params)
 
     for name in params["nameorid"]:
-        try:
-            if name.isnumeric() or name[0] == "-" and name[1:].isnumeric():
-                uid = int(name)
-                verbose("ID ", uid, "\n")
-                # Convert the id to a name for message purposes - note that if
-                # the entry does not exist, this will just stringify the ID for
-                # us.
-                ret = cell.call_pt_server(params, kafs.PR_IDToName, [ uid ])
-                name = ret.nlist[0].prname
-            else:
-                verbose("Name ", name, "\n")
-                prname = kafs.prname()
-                prname.prname = name
-                ret = cell.call_pt_server(params, kafs.PR_NameToID, [ prname ])
-                uid = ret.ilist[0]
-                if uid == kafs.PR_ANONYMOUSID and name != "anonymous":
-                    error("User or group doesn't exist so couldn't look up id for " + name + "\n")
-                    if "force" not in params:
-                        break
-                    continue
+        prcache.precache_name_or_id(name)
+
+    results = []
+    for name in params["nameorid"]:
+        uid = prcache.name_or_id_to_id(name)
+        if uid == None:
+            error("User or group doesn't exist so couldn't look up id for " + name + "\n")
+            if "force" not in params:
+                break
+            continue
 
+        try:
             verbose("Listing entries owned by user ", uid, " (", name, ")\n")
             ret = cell.call_pt_server(params, kafs.PR_ListOwned, uid, 0)
-
-            output("Groups owned by ", name, " (id: ", uid, ") are:\n")
-            ret = cell.call_pt_server(params, kafs.PR_IDToName, ret.elist)
-
-            for i in ret.nlist:
-                output("  ", i.prname, "\n")
+            elist = ret.elist
+            for entry in elist:
+                prcache.precache_id(entry)
+            results.append((uid, elist))
 
         except kafs.AbortPRNOENT:
             error("User or group doesn't exist deleting ", name, " (id ", uid, ")\n")
@@ -93,3 +83,8 @@ def main(params):
             error("Permission denied deleting ", name, " (id: ", uid, ")\n")
             if "force" not in params:
                 break
+
+    for (uid, elist) in results:
+        output("Groups owned by ", prcache.id_to_name(uid), " (id: ", uid, ") are:\n")
+        for entry in elist:
+            output("  ", prcache.id_to_name(entry), "\n")
index 3e346214a4dfe2026fb7ac93e21c87cfc33f17e8..e38c4ad1da4f43e512f498e93c610e09b3853d5f 100644 (file)
@@ -24,6 +24,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 from afs import exception
 from afs.lib.vlserver import vlserver
 from afs.lib.server import ServerError
+from afs.lib.prcache import prcache
 from afs.lib.output import *
 import dns.resolver
 import linecache
@@ -53,6 +54,7 @@ class cell:
         self.__vlconn = None
         self.__ptserver_index = None
         self.__ptconn = None
+        self.__prcache = None
 
     def __repr__(self):
         return "<" + "AFS:" + self.__name + ">"
@@ -248,3 +250,9 @@ class cell:
                 verbose(e, "\n");
             self.__ptconn = None
             self.__ptserver_index += 1
+
+    # Get the prcache for this cell
+    def get_prcache(self, params):
+        if self.__prcache == None:
+            self.__prcache = prcache(params, self)
+        return self.__prcache
diff --git a/suite/lib/prcache.py b/suite/lib/prcache.py
new file mode 100644 (file)
index 0000000..d5f702d
--- /dev/null
@@ -0,0 +1,202 @@
+#
+# AFS Volume management toolkit: Protection DB ID<->Name cache
+# -*- coding: utf-8 -*-
+#
+
+__copyright__ = """
+Copyright (C) 2014 Red Hat, Inc. All Rights Reserved.
+Written by David Howells (dhowells@redhat.com)
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public Licence version 2 as
+published by the Free Software Foundation.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public Licence for more details.
+
+You should have received a copy of the GNU General Public Licence
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+"""
+
+from afs import exception
+from afs.lib.output import *
+import kafs
+
+class AFS_PR_Entry:
+    """Protection Database Name/ID mapping entry"""
+    def __init__(self, name, ugid):
+        self.__name = name
+        self.__id = ugid
+
+    def name(self):
+        return self.__name
+
+    def ugid(self):
+        return self.__id
+
+class prcache:
+    """Protection Database Name/ID mapping cache for a cell"""
+    def __init__(self, params, cell):
+        self.__params = params
+        self.__cell = cell
+        self.__name2id = dict()
+        self.__id2name = dict()
+        self.__names_to_lookup = []
+        self.__ids_to_lookup = []
+
+    ###########################################################################
+    #
+    # Do the pending names lookups
+    #
+    ###########################################################################
+    def do_look_up_pr_names(self):
+        if not self.__names_to_lookup:
+            return
+        names_to_lookup = self.__names_to_lookup
+        self.__names_to_lookup = []
+
+        # Convert name strings to appropriate structs
+        verbose("Do NameToID(")
+        name_arg_list = []
+        for i in names_to_lookup:
+            verbose_cont(i, ",")
+            prname = kafs.prname()
+            prname.prname = i
+            name_arg_list.append(prname)
+        verbose_cont(")\n")
+
+        ret = self.__cell.call_pt_server(self.__params, kafs.PR_NameToID, name_arg_list)
+        for i in range(0, len(names_to_lookup)):
+            name = names_to_lookup[i]
+            ugid = ret.ilist[i]
+            # Convert the name to an ID for message purposes - note that if the
+            # entry does not exist, this will return the anonymous ID
+            if ugid == kafs.PR_ANONYMOUSID and name != "anonymous":
+                entry = AFS_PR_Entry(name, None)
+            else:
+                entry = AFS_PR_Entry(name, ugid)
+                self.__id2name[ugid] = entry
+                if ugid in self.__ids_to_lookup:
+                    self.__ids_to_lookup.remove(ugid)
+            self.__name2id[name] = entry
+
+    ###########################################################################
+    #
+    # Do the pending ID lookups
+    #
+    ###########################################################################
+    def do_look_up_pr_ids(self):
+        if not self.__ids_to_lookup:
+            return
+        ids_to_lookup = self.__ids_to_lookup
+        self.__ids_to_lookup = []
+
+        verbose("Do IDToName(")
+        for i in ids_to_lookup:
+            verbose_cont(i, ",")
+        verbose_cont(")\n")
+
+        ret = self.__cell.call_pt_server(self.__params, kafs.PR_IDToName, ids_to_lookup)
+        nlist = ret.nlist
+        for i in range(0, len(ids_to_lookup)):
+            ugid = ids_to_lookup[i]
+            name = nlist[i].prname
+            # Convert the id to a name for message purposes - note that if
+            # the entry does not exist, this will just stringify the ID for
+            # us.
+            if name == str(ids_to_lookup[i]):
+                entry = AFS_PR_Entry(None, ugid)
+            else:
+                entry = AFS_PR_Entry(name, ugid)
+                self.__name2id[name] = entry
+                if name in self.__names_to_lookup:
+                    self.__names_to_lookup.remove(name)
+            self.__id2name[ugid] = entry
+
+    ###########################################################################
+    #
+    # Precache a name
+    #
+    ###########################################################################
+    def precache_name(self, name):
+        if name not in self.__names_to_lookup and name not in self.__name2id:
+            self.__names_to_lookup.append(name)
+
+    ###########################################################################
+    #
+    # Precache a ID
+    #
+    ###########################################################################
+    def precache_id(self, ugid):
+        if ugid not in self.__ids_to_lookup and ugid not in self.__id2name:
+            self.__ids_to_lookup.append(ugid)
+
+    ###########################################################################
+    #
+    # Precache a name or a stringified ID
+    #
+    ###########################################################################
+    def precache_name_or_id(self, name):
+        if name.isnumeric() or name[0] == "-" and name[1:].isnumeric():
+            self.precache_id(int(name))
+        else:
+            self.precache_name(name)
+
+    ###########################################################################
+    #
+    # Look up an ID by name
+    #
+    ###########################################################################
+    def name_to_id(self, name):
+        if name not in self.__name2id:
+            self.precache_name(name)
+            self.do_look_up_pr_names()
+        return self.__name2id[name].ugid()
+
+    ###########################################################################
+    #
+    # Look up an ID by name or stringified ID
+    #
+    ###########################################################################
+    def name_or_id_to_id(self, name):
+        if name.isnumeric() or name[0] == "-" and name[1:].isnumeric():
+            return int(name)
+        return self.name_to_id(name)
+
+    ###########################################################################
+    #
+    # Look up a name by ID
+    #
+    ###########################################################################
+    def id_to_name(self, ugid):
+        if ugid not in self.__id2name:
+            self.precache_id(ugid)
+            self.do_look_up_pr_ids()
+        return self.__id2name[ugid].name()
+
+    ###########################################################################
+    #
+    # Note that a name is unknown
+    #
+    ###########################################################################
+    def name_is_unknown(self, name):
+        if name in self.__names_to_lookup:
+            self.__names_to_lookup.remove(name)
+        if name not in self.__name2id:
+            entry = AFS_PR_Entry(name, None)
+            self.__name2id[name] = entry
+
+    ###########################################################################
+    #
+    # Note that an ID is unknown
+    #
+    ###########################################################################
+    def id_is_unknown(self, ugid):
+        if ugid in self.__ids_to_lookup:
+            self.__ids_to_lookup.remove(ugid)
+        if ugid not in self.__id2name:
+            entry = AFS_PR_Entry(None, ugid)
+            self.__id2name[ugid] = entry