From d71b5e13d9aff54e295d4bc0fb7a28f43e531a25 Mon Sep 17 00:00:00 2001 From: David Howells Date: Wed, 14 May 2014 12:14:52 +0100 Subject: [PATCH] Provide a protection DB Name<->ID cache 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 --- suite/commands/pts/delete.py | 32 ++--- suite/commands/pts/listowned.py | 47 ++++---- suite/lib/cell.py | 8 ++ suite/lib/prcache.py | 202 ++++++++++++++++++++++++++++++++ 4 files changed, 243 insertions(+), 46 deletions(-) create mode 100644 suite/lib/prcache.py diff --git a/suite/commands/pts/delete.py b/suite/commands/pts/delete.py index c49e42b..c8859b7 100644 --- a/suite/commands/pts/delete.py +++ b/suite/commands/pts/delete.py @@ -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: diff --git a/suite/commands/pts/listowned.py b/suite/commands/pts/listowned.py index d9d0cad..f2a83fa 100644 --- a/suite/commands/pts/listowned.py +++ b/suite/commands/pts/listowned.py @@ -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") diff --git a/suite/lib/cell.py b/suite/lib/cell.py index 3e34621..e38c4ad 100644 --- a/suite/lib/cell.py +++ b/suite/lib/cell.py @@ -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 index 0000000..d5f702d --- /dev/null +++ b/suite/lib/prcache.py @@ -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 -- 2.49.0