]> granicus.if.org Git - postgresql/commitdiff
Make superuser.c maintain a simple one-entry cache holding the superuser
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 29 May 2005 20:38:06 +0000 (20:38 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 29 May 2005 20:38:06 +0000 (20:38 +0000)
status of the most recently queried userid.  Since the common pattern is
many successive queries about the same user (ie, the current user) this
can save a lot of syscache probes.

src/backend/utils/misc/superuser.c

index ee6cc397e3476e9f687a9689b2801bf8f6d19792..520dc470cdcef7e6cab563bdc86a3e8425b1466b 100644 (file)
@@ -2,7 +2,11 @@
  *
  * superuser.c
  *       The superuser() function.  Determines if user has superuser privilege.
- *       Also, a function to check for the owner (datdba) of a database.
+ *
+ * All code should use either of these two functions to find out
+ * whether a given user is a superuser, rather than examining
+ * pg_shadow.usesuper directly, so that the escape hatch built in for
+ * the single-user case works.
  *
  *
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/misc/superuser.c,v 1.30 2004/12/31 22:02:45 pgsql Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/misc/superuser.c,v 1.31 2005/05/29 20:38:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
-#include "access/heapam.h"
 #include "catalog/pg_shadow.h"
-#include "commands/dbcommands.h"
+#include "utils/inval.h"
 #include "utils/syscache.h"
 #include "miscadmin.h"
 
 
+/*
+ * In common cases the same userid (ie, the session or current ID) will
+ * be queried repeatedly.  So we maintain a simple one-entry cache for
+ * the status of the last requested userid.  The cache can be flushed
+ * at need by watching for cache update events on pg_shadow.
+ */
+static AclId   last_userid = 0;                /* 0 == cache not valid */
+static bool            last_userid_is_super = false;
+static bool            userid_callback_registered = false;
+
+static void UseridCallback(Datum arg, Oid relid);
+
+
 /*
  * The Postgres user running this command has Postgres superuser privileges
- *
- * All code should use either of these two functions to find out
- * whether a given user is a superuser, rather than evaluating
- * pg_shadow.usesuper directly, so that the escape hatch built in for
- * the single-user case works.
  */
 bool
 superuser(void)
@@ -38,16 +49,24 @@ superuser(void)
 }
 
 
+/*
+ * The specified userid has Postgres superuser privileges
+ */
 bool
 superuser_arg(AclId userid)
 {
-       bool            result = false;
+       bool            result;
        HeapTuple       utup;
 
+       /* Quick out for cache hit */
+       if (AclIdIsValid(last_userid) && last_userid == userid)
+               return last_userid_is_super;
+
        /* Special escape path in case you deleted all your users. */
        if (!IsUnderPostmaster && userid == BOOTSTRAP_USESYSID)
                return true;
 
+       /* OK, look up the information in pg_shadow */
        utup = SearchSysCache(SHADOWSYSID,
                                                  Int32GetDatum(userid),
                                                  0, 0, 0);
@@ -56,5 +75,35 @@ superuser_arg(AclId userid)
                result = ((Form_pg_shadow) GETSTRUCT(utup))->usesuper;
                ReleaseSysCache(utup);
        }
+       else
+       {
+               /* Report "not superuser" for invalid userids */
+               result = false;
+       }
+
+       /* If first time through, set up callback for cache flushes */
+       if (!userid_callback_registered)
+       {
+               CacheRegisterSyscacheCallback(SHADOWSYSID,
+                                                                         UseridCallback,
+                                                                         (Datum) 0);
+               userid_callback_registered = true;
+       }
+
+       /* Cache the result for next time */
+       last_userid = userid;
+       last_userid_is_super = result;
+
        return result;
 }
+
+/*
+ * UseridCallback
+ *             Syscache inval callback function
+ */
+static void
+UseridCallback(Datum arg, Oid relid)
+{
+       /* Invalidate our local cache in case user's superuserness changed */
+       last_userid = 0;
+}