In pg_dump, use simplehash.h to look up dumpable objects by OID.
authorTom Lane <[email protected]>
Fri, 22 Oct 2021 21:19:03 +0000 (17:19 -0400)
committerTom Lane <[email protected]>
Fri, 22 Oct 2021 21:19:03 +0000 (17:19 -0400)
Create a hash table that indexes dumpable objects by CatalogId
(that is, catalog OID + object OID).  Use this to replace the
former catalogIdMap array, as well as various other single-
catalog index arrays, and also the extension membership map.

In principle this should be faster for databases with many objects,
since lookups are now O(1) not O(log N).  However, it seems that these
lookups are pretty much negligible in context, so that no overall
performance change can be measured.  But having only one lookup
data structure to maintain makes the code simpler and more flexible,
so let's do it anyway.

Discussion: https://postgr.es/m/2595220.1634855245@sss.pgh.pa.us

src/bin/pg_dump/common.c
src/bin/pg_dump/pg_backup.h
src/bin/pg_dump/pg_dump.c
src/bin/pg_dump/pg_dump.h

index 1f24e796651ff0fcd322c493c7bc1ba2e62056a3..0170fe036fa691d62b25dd135e3eca96de0f0694 100644 (file)
 #include <ctype.h>
 
 #include "catalog/pg_class_d.h"
+#include "catalog/pg_collation_d.h"
+#include "catalog/pg_extension_d.h"
+#include "catalog/pg_namespace_d.h"
+#include "catalog/pg_operator_d.h"
+#include "catalog/pg_proc_d.h"
+#include "catalog/pg_publication_d.h"
+#include "catalog/pg_type_d.h"
+#include "common/hashfn.h"
 #include "fe_utils/string_utils.h"
 #include "pg_backup_archiver.h"
 #include "pg_backup_utils.h"
@@ -31,54 +39,54 @@ static int  allocedDumpIds = 0;
 static DumpId lastDumpId = 0;  /* Note: 0 is InvalidDumpId */
 
 /*
- * Variables for mapping CatalogId to DumpableObject
- */
-static bool catalogIdMapValid = false;
-static DumpableObject **catalogIdMap = NULL;
-static int     numCatalogIds = 0;
-
-/*
- * These variables are static to avoid the notational cruft of having to pass
- * them into findTableByOid() and friends.  For each of these arrays, we build
- * a sorted-by-OID index array immediately after the objects are fetched,
- * and then we use binary search in findTableByOid() and friends.  (qsort'ing
- * the object arrays themselves would be simpler, but it doesn't work because
- * pg_dump.c may have already established pointers between items.)
+ * Infrastructure for mapping CatalogId to DumpableObject
+ *
+ * We use a hash table generated by simplehash.h.  That infrastructure
+ * requires all the hash table entries to be the same size, and it also
+ * expects that it can move them around when resizing the table.  So we
+ * cannot make the DumpableObjects be elements of the hash table directly;
+ * instead, the hash table elements contain pointers to DumpableObjects.
+ *
+ * It turns out to be convenient to also use this data structure to map
+ * CatalogIds to owning extensions, if any.  Since extension membership
+ * data is read before creating most DumpableObjects, either one of dobj
+ * and ext could be NULL.
  */
-static DumpableObject **tblinfoindex;
-static DumpableObject **typinfoindex;
-static DumpableObject **funinfoindex;
-static DumpableObject **oprinfoindex;
-static DumpableObject **collinfoindex;
-static DumpableObject **nspinfoindex;
-static DumpableObject **extinfoindex;
-static DumpableObject **pubinfoindex;
-static int     numTables;
-static int     numTypes;
-static int     numFuncs;
-static int     numOperators;
-static int     numCollations;
-static int     numNamespaces;
-static int     numExtensions;
-static int     numPublications;
-
-/* This is an array of object identities, not actual DumpableObjects */
-static ExtensionMemberId *extmembers;
-static int     numextmembers;
+typedef struct _catalogIdMapEntry
+{
+       CatalogId       catId;                  /* the indexed CatalogId */
+       uint32          status;                 /* hash status */
+       uint32          hashval;                /* hash code for the CatalogId */
+       DumpableObject *dobj;           /* the associated DumpableObject, if any */
+       ExtensionInfo *ext;                     /* owning extension, if any */
+} CatalogIdMapEntry;
+
+#define SH_PREFIX              catalogid
+#define SH_ELEMENT_TYPE        CatalogIdMapEntry
+#define SH_KEY_TYPE            CatalogId
+#define        SH_KEY                  catId
+#define SH_HASH_KEY(tb, key)   hash_bytes((const unsigned char *) &(key), sizeof(CatalogId))
+#define SH_EQUAL(tb, a, b)             ((a).oid == (b).oid && (a).tableoid == (b).tableoid)
+#define SH_STORE_HASH
+#define SH_GET_HASH(tb, a) (a)->hashval
+#define        SH_SCOPE                static inline
+#define SH_RAW_ALLOCATOR       pg_malloc0
+#define SH_DECLARE
+#define SH_DEFINE
+#include "lib/simplehash.h"
+
+#define CATALOGIDHASH_INITIAL_SIZE     10000
+
+static catalogid_hash *catalogIdHash = NULL;
 
 static void flagInhTables(Archive *fout, TableInfo *tbinfo, int numTables,
                                                  InhInfo *inhinfo, int numInherits);
 static void flagInhIndexes(Archive *fout, TableInfo *tblinfo, int numTables);
 static void flagInhAttrs(DumpOptions *dopt, TableInfo *tblinfo, int numTables);
-static DumpableObject **buildIndexArray(void *objArray, int numObjs,
-                                                                               Size objSize);
-static int     DOCatalogIdCompare(const void *p1, const void *p2);
-static int     ExtensionMemberIdCompare(const void *p1, const void *p2);
 static void findParentsByOid(TableInfo *self,
                                                         InhInfo *inhinfo, int numInherits);
 static int     strInArray(const char *pattern, char **arr, int arr_size);
-static IndxInfo *findIndexByOid(Oid oid, DumpableObject **idxinfoindex,
-                                                               int numIndexes);
+static IndxInfo *findIndexByOid(Oid oid);
 
 
 /*
@@ -89,14 +97,16 @@ TableInfo *
 getSchemaData(Archive *fout, int *numTablesPtr)
 {
        TableInfo  *tblinfo;
-       TypeInfo   *typinfo;
-       FuncInfo   *funinfo;
-       OprInfo    *oprinfo;
-       CollInfo   *collinfo;
-       NamespaceInfo *nspinfo;
        ExtensionInfo *extinfo;
-       PublicationInfo *pubinfo;
        InhInfo    *inhinfo;
+       int                     numTables;
+       int                     numTypes;
+       int                     numFuncs;
+       int                     numOperators;
+       int                     numCollations;
+       int                     numNamespaces;
+       int                     numExtensions;
+       int                     numPublications;
        int                     numAggregates;
        int                     numInherits;
        int                     numRules;
@@ -123,14 +133,12 @@ getSchemaData(Archive *fout, int *numTablesPtr)
         */
        pg_log_info("reading extensions");
        extinfo = getExtensions(fout, &numExtensions);
-       extinfoindex = buildIndexArray(extinfo, numExtensions, sizeof(ExtensionInfo));
 
        pg_log_info("identifying extension members");
        getExtensionMembership(fout, extinfo, numExtensions);
 
        pg_log_info("reading schemas");
-       nspinfo = getNamespaces(fout, &numNamespaces);
-       nspinfoindex = buildIndexArray(nspinfo, numNamespaces, sizeof(NamespaceInfo));
+       (void) getNamespaces(fout, &numNamespaces);
 
        /*
         * getTables should be done as soon as possible, so as to minimize the
@@ -140,19 +148,15 @@ getSchemaData(Archive *fout, int *numTablesPtr)
         */
        pg_log_info("reading user-defined tables");
        tblinfo = getTables(fout, &numTables);
-       tblinfoindex = buildIndexArray(tblinfo, numTables, sizeof(TableInfo));
 
-       /* Do this after we've built tblinfoindex */
        getOwnedSeqs(fout, tblinfo, numTables);
 
        pg_log_info("reading user-defined functions");
-       funinfo = getFuncs(fout, &numFuncs);
-       funinfoindex = buildIndexArray(funinfo, numFuncs, sizeof(FuncInfo));
+       (void) getFuncs(fout, &numFuncs);
 
        /* this must be after getTables and getFuncs */
        pg_log_info("reading user-defined types");
-       typinfo = getTypes(fout, &numTypes);
-       typinfoindex = buildIndexArray(typinfo, numTypes, sizeof(TypeInfo));
+       (void) getTypes(fout, &numTypes);
 
        /* this must be after getFuncs, too */
        pg_log_info("reading procedural languages");
@@ -162,8 +166,7 @@ getSchemaData(Archive *fout, int *numTablesPtr)
        getAggregates(fout, &numAggregates);
 
        pg_log_info("reading user-defined operators");
-       oprinfo = getOperators(fout, &numOperators);
-       oprinfoindex = buildIndexArray(oprinfo, numOperators, sizeof(OprInfo));
+       (void) getOperators(fout, &numOperators);
 
        pg_log_info("reading user-defined access methods");
        getAccessMethods(fout, &numAccessMethods);
@@ -196,8 +199,7 @@ getSchemaData(Archive *fout, int *numTablesPtr)
        getDefaultACLs(fout, &numDefaultACLs);
 
        pg_log_info("reading user-defined collations");
-       collinfo = getCollations(fout, &numCollations);
-       collinfoindex = buildIndexArray(collinfo, numCollations, sizeof(CollInfo));
+       (void) getCollations(fout, &numCollations);
 
        pg_log_info("reading user-defined conversions");
        getConversions(fout, &numConversions);
@@ -250,9 +252,7 @@ getSchemaData(Archive *fout, int *numTablesPtr)
        getPolicies(fout, tblinfo, numTables);
 
        pg_log_info("reading publications");
-       pubinfo = getPublications(fout, &numPublications);
-       pubinfoindex = buildIndexArray(pubinfo, numPublications,
-                                                                  sizeof(PublicationInfo));
+       (void) getPublications(fout, &numPublications);
 
        pg_log_info("reading publication membership");
        getPublicationTables(fout, tblinfo, numTables);
@@ -375,34 +375,15 @@ flagInhIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
        int                     i,
                                j,
                                k;
-       DumpableObject ***parentIndexArray;
-
-       parentIndexArray = (DumpableObject ***)
-               pg_malloc0(getMaxDumpId() * sizeof(DumpableObject **));
 
        for (i = 0; i < numTables; i++)
        {
-               TableInfo  *parenttbl;
                IndexAttachInfo *attachinfo;
 
                if (!tblinfo[i].ispartition || tblinfo[i].numParents == 0)
                        continue;
 
                Assert(tblinfo[i].numParents == 1);
-               parenttbl = tblinfo[i].parents[0];
-
-               /*
-                * We need access to each parent table's index list, but there is no
-                * index to cover them outside of this function.  To avoid having to
-                * sort every parent table's indexes each time we come across each of
-                * its partitions, create an indexed array for each parent the first
-                * time it is required.
-                */
-               if (parentIndexArray[parenttbl->dobj.dumpId] == NULL)
-                       parentIndexArray[parenttbl->dobj.dumpId] =
-                               buildIndexArray(parenttbl->indexes,
-                                                               parenttbl->numIndexes,
-                                                               sizeof(IndxInfo));
 
                attachinfo = (IndexAttachInfo *)
                        pg_malloc0(tblinfo[i].numIndexes * sizeof(IndexAttachInfo));
@@ -414,9 +395,7 @@ flagInhIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
                        if (index->parentidx == 0)
                                continue;
 
-                       parentidx = findIndexByOid(index->parentidx,
-                                                                          parentIndexArray[parenttbl->dobj.dumpId],
-                                                                          parenttbl->numIndexes);
+                       parentidx = findIndexByOid(index->parentidx);
                        if (parentidx == NULL)
                                continue;
 
@@ -457,11 +436,6 @@ flagInhIndexes(Archive *fout, TableInfo tblinfo[], int numTables)
                        k++;
                }
        }
-
-       for (i = 0; i < numTables; i++)
-               if (parentIndexArray[i])
-                       pg_free(parentIndexArray[i]);
-       pg_free(parentIndexArray);
 }
 
 /* flagInhAttrs -
@@ -596,7 +570,7 @@ flagInhAttrs(DumpOptions *dopt, TableInfo *tblinfo, int numTables)
 /*
  * AssignDumpId
  *             Given a newly-created dumpable object, assign a dump ID,
- *             and enter the object into the lookup table.
+ *             and enter the object into the lookup tables.
  *
  * The caller is expected to have filled in objType and catId,
  * but not any of the other standard fields of a DumpableObject.
@@ -615,6 +589,7 @@ AssignDumpId(DumpableObject *dobj)
        dobj->nDeps = 0;
        dobj->allocDeps = 0;
 
+       /* Add object to dumpIdMap[], enlarging that array if need be */
        while (dobj->dumpId >= allocedDumpIds)
        {
                int                     newAlloc;
@@ -637,8 +612,25 @@ AssignDumpId(DumpableObject *dobj)
        }
        dumpIdMap[dobj->dumpId] = dobj;
 
-       /* mark catalogIdMap invalid, but don't rebuild it yet */
-       catalogIdMapValid = false;
+       /* If it has a valid CatalogId, enter it into the hash table */
+       if (OidIsValid(dobj->catId.tableoid))
+       {
+               CatalogIdMapEntry *entry;
+               bool            found;
+
+               /* Initialize CatalogId hash table if not done yet */
+               if (catalogIdHash == NULL)
+                       catalogIdHash = catalogid_create(CATALOGIDHASH_INITIAL_SIZE, NULL);
+
+               entry = catalogid_insert(catalogIdHash, dobj->catId, &found);
+               if (!found)
+               {
+                       entry->dobj = NULL;
+                       entry->ext = NULL;
+               }
+               Assert(entry->dobj == NULL);
+               entry->dobj = dobj;
+       }
 }
 
 /*
@@ -679,140 +671,19 @@ findObjectByDumpId(DumpId dumpId)
  * Find a DumpableObject by catalog ID
  *
  * Returns NULL for unknown ID
- *
- * We use binary search in a sorted list that is built on first call.
- * If AssignDumpId() and findObjectByCatalogId() calls were freely intermixed,
- * the code would work, but possibly be very slow.  In the current usage
- * pattern that does not happen, indeed we build the list at most twice.
  */
 DumpableObject *
 findObjectByCatalogId(CatalogId catalogId)
 {
-       DumpableObject **low;
-       DumpableObject **high;
+       CatalogIdMapEntry *entry;
 
-       if (!catalogIdMapValid)
-       {
-               if (catalogIdMap)
-                       free(catalogIdMap);
-               getDumpableObjects(&catalogIdMap, &numCatalogIds);
-               if (numCatalogIds > 1)
-                       qsort((void *) catalogIdMap, numCatalogIds,
-                                 sizeof(DumpableObject *), DOCatalogIdCompare);
-               catalogIdMapValid = true;
-       }
+       if (catalogIdHash == NULL)
+               return NULL;                    /* no objects exist yet */
 
-       /*
-        * We could use bsearch() here, but the notational cruft of calling
-        * bsearch is nearly as bad as doing it ourselves; and the generalized
-        * bsearch function is noticeably slower as well.
-        */
-       if (numCatalogIds <= 0)
+       entry = catalogid_lookup(catalogIdHash, catalogId);
+       if (entry == NULL)
                return NULL;
-       low = catalogIdMap;
-       high = catalogIdMap + (numCatalogIds - 1);
-       while (low <= high)
-       {
-               DumpableObject **middle;
-               int                     difference;
-
-               middle = low + (high - low) / 2;
-               /* comparison must match DOCatalogIdCompare, below */
-               difference = oidcmp((*middle)->catId.oid, catalogId.oid);
-               if (difference == 0)
-                       difference = oidcmp((*middle)->catId.tableoid, catalogId.tableoid);
-               if (difference == 0)
-                       return *middle;
-               else if (difference < 0)
-                       low = middle + 1;
-               else
-                       high = middle - 1;
-       }
-       return NULL;
-}
-
-/*
- * Find a DumpableObject by OID, in a pre-sorted array of one type of object
- *
- * Returns NULL for unknown OID
- */
-static DumpableObject *
-findObjectByOid(Oid oid, DumpableObject **indexArray, int numObjs)
-{
-       DumpableObject **low;
-       DumpableObject **high;
-
-       /*
-        * This is the same as findObjectByCatalogId except we assume we need not
-        * look at table OID because the objects are all the same type.
-        *
-        * We could use bsearch() here, but the notational cruft of calling
-        * bsearch is nearly as bad as doing it ourselves; and the generalized
-        * bsearch function is noticeably slower as well.
-        */
-       if (numObjs <= 0)
-               return NULL;
-       low = indexArray;
-       high = indexArray + (numObjs - 1);
-       while (low <= high)
-       {
-               DumpableObject **middle;
-               int                     difference;
-
-               middle = low + (high - low) / 2;
-               difference = oidcmp((*middle)->catId.oid, oid);
-               if (difference == 0)
-                       return *middle;
-               else if (difference < 0)
-                       low = middle + 1;
-               else
-                       high = middle - 1;
-       }
-       return NULL;
-}
-
-/*
- * Build an index array of DumpableObject pointers, sorted by OID
- */
-static DumpableObject **
-buildIndexArray(void *objArray, int numObjs, Size objSize)
-{
-       DumpableObject **ptrs;
-       int                     i;
-
-       if (numObjs <= 0)
-               return NULL;
-
-       ptrs = (DumpableObject **) pg_malloc(numObjs * sizeof(DumpableObject *));
-       for (i = 0; i < numObjs; i++)
-               ptrs[i] = (DumpableObject *) ((char *) objArray + i * objSize);
-
-       /* We can use DOCatalogIdCompare to sort since its first key is OID */
-       if (numObjs > 1)
-               qsort((void *) ptrs, numObjs, sizeof(DumpableObject *),
-                         DOCatalogIdCompare);
-
-       return ptrs;
-}
-
-/*
- * qsort comparator for pointers to DumpableObjects
- */
-static int
-DOCatalogIdCompare(const void *p1, const void *p2)
-{
-       const DumpableObject *obj1 = *(DumpableObject *const *) p1;
-       const DumpableObject *obj2 = *(DumpableObject *const *) p2;
-       int                     cmpval;
-
-       /*
-        * Compare OID first since it's usually unique, whereas there will only be
-        * a few distinct values of tableoid.
-        */
-       cmpval = oidcmp(obj1->catId.oid, obj2->catId.oid);
-       if (cmpval == 0)
-               cmpval = oidcmp(obj1->catId.tableoid, obj2->catId.tableoid);
-       return cmpval;
+       return entry->dobj;
 }
 
 /*
@@ -886,119 +757,191 @@ removeObjectDependency(DumpableObject *dobj, DumpId refId)
 
 /*
  * findTableByOid
- *       finds the entry (in tblinfo) of the table with the given oid
+ *       finds the DumpableObject for the table with the given oid
  *       returns NULL if not found
  */
 TableInfo *
 findTableByOid(Oid oid)
 {
-       return (TableInfo *) findObjectByOid(oid, tblinfoindex, numTables);
+       CatalogId       catId;
+       DumpableObject *dobj;
+
+       catId.tableoid = RelationRelationId;
+       catId.oid = oid;
+       dobj = findObjectByCatalogId(catId);
+       Assert(dobj == NULL || dobj->objType == DO_TABLE);
+       return (TableInfo *) dobj;
+}
+
+/*
+ * findIndexByOid
+ *       finds the DumpableObject for the index with the given oid
+ *       returns NULL if not found
+ */
+static IndxInfo *
+findIndexByOid(Oid oid)
+{
+       CatalogId       catId;
+       DumpableObject *dobj;
+
+       catId.tableoid = RelationRelationId;
+       catId.oid = oid;
+       dobj = findObjectByCatalogId(catId);
+       Assert(dobj == NULL || dobj->objType == DO_INDEX);
+       return (IndxInfo *) dobj;
 }
 
 /*
  * findTypeByOid
- *       finds the entry (in typinfo) of the type with the given oid
+ *       finds the DumpableObject for the type with the given oid
  *       returns NULL if not found
  */
 TypeInfo *
 findTypeByOid(Oid oid)
 {
-       return (TypeInfo *) findObjectByOid(oid, typinfoindex, numTypes);
+       CatalogId       catId;
+       DumpableObject *dobj;
+
+       catId.tableoid = TypeRelationId;
+       catId.oid = oid;
+       dobj = findObjectByCatalogId(catId);
+       Assert(dobj == NULL ||
+                  dobj->objType == DO_TYPE || dobj->objType == DO_DUMMY_TYPE);
+       return (TypeInfo *) dobj;
 }
 
 /*
  * findFuncByOid
- *       finds the entry (in funinfo) of the function with the given oid
+ *       finds the DumpableObject for the function with the given oid
  *       returns NULL if not found
  */
 FuncInfo *
 findFuncByOid(Oid oid)
 {
-       return (FuncInfo *) findObjectByOid(oid, funinfoindex, numFuncs);
+       CatalogId       catId;
+       DumpableObject *dobj;
+
+       catId.tableoid = ProcedureRelationId;
+       catId.oid = oid;
+       dobj = findObjectByCatalogId(catId);
+       Assert(dobj == NULL || dobj->objType == DO_FUNC);
+       return (FuncInfo *) dobj;
 }
 
 /*
  * findOprByOid
- *       finds the entry (in oprinfo) of the operator with the given oid
+ *       finds the DumpableObject for the operator with the given oid
  *       returns NULL if not found
  */
 OprInfo *
 findOprByOid(Oid oid)
 {
-       return (OprInfo *) findObjectByOid(oid, oprinfoindex, numOperators);
+       CatalogId       catId;
+       DumpableObject *dobj;
+
+       catId.tableoid = OperatorRelationId;
+       catId.oid = oid;
+       dobj = findObjectByCatalogId(catId);
+       Assert(dobj == NULL || dobj->objType == DO_OPERATOR);
+       return (OprInfo *) dobj;
 }
 
 /*
  * findCollationByOid
- *       finds the entry (in collinfo) of the collation with the given oid
+ *       finds the DumpableObject for the collation with the given oid
  *       returns NULL if not found
  */
 CollInfo *
 findCollationByOid(Oid oid)
 {
-       return (CollInfo *) findObjectByOid(oid, collinfoindex, numCollations);
+       CatalogId       catId;
+       DumpableObject *dobj;
+
+       catId.tableoid = CollationRelationId;
+       catId.oid = oid;
+       dobj = findObjectByCatalogId(catId);
+       Assert(dobj == NULL || dobj->objType == DO_COLLATION);
+       return (CollInfo *) dobj;
 }
 
 /*
  * findNamespaceByOid
- *       finds the entry (in nspinfo) of the namespace with the given oid
+ *       finds the DumpableObject for the namespace with the given oid
  *       returns NULL if not found
  */
 NamespaceInfo *
 findNamespaceByOid(Oid oid)
 {
-       return (NamespaceInfo *) findObjectByOid(oid, nspinfoindex, numNamespaces);
+       CatalogId       catId;
+       DumpableObject *dobj;
+
+       catId.tableoid = NamespaceRelationId;
+       catId.oid = oid;
+       dobj = findObjectByCatalogId(catId);
+       Assert(dobj == NULL || dobj->objType == DO_NAMESPACE);
+       return (NamespaceInfo *) dobj;
 }
 
 /*
  * findExtensionByOid
- *       finds the entry (in extinfo) of the extension with the given oid
+ *       finds the DumpableObject for the extension with the given oid
  *       returns NULL if not found
  */
 ExtensionInfo *
 findExtensionByOid(Oid oid)
 {
-       return (ExtensionInfo *) findObjectByOid(oid, extinfoindex, numExtensions);
+       CatalogId       catId;
+       DumpableObject *dobj;
+
+       catId.tableoid = ExtensionRelationId;
+       catId.oid = oid;
+       dobj = findObjectByCatalogId(catId);
+       Assert(dobj == NULL || dobj->objType == DO_EXTENSION);
+       return (ExtensionInfo *) dobj;
 }
 
 /*
  * findPublicationByOid
- *       finds the entry (in pubinfo) of the publication with the given oid
+ *       finds the DumpableObject for the publication with the given oid
  *       returns NULL if not found
  */
 PublicationInfo *
 findPublicationByOid(Oid oid)
 {
-       return (PublicationInfo *) findObjectByOid(oid, pubinfoindex, numPublications);
+       CatalogId       catId;
+       DumpableObject *dobj;
+
+       catId.tableoid = PublicationRelationId;
+       catId.oid = oid;
+       dobj = findObjectByCatalogId(catId);
+       Assert(dobj == NULL || dobj->objType == DO_PUBLICATION);
+       return (PublicationInfo *) dobj;
 }
 
-/*
- * findIndexByOid
- *             find the entry of the index with the given oid
- *
- * This one's signature is different from the previous ones because we lack a
- * global array of all indexes, so caller must pass their array as argument.
- */
-static IndxInfo *
-findIndexByOid(Oid oid, DumpableObject **idxinfoindex, int numIndexes)
-{
-       return (IndxInfo *) findObjectByOid(oid, idxinfoindex, numIndexes);
-}
 
 /*
- * setExtensionMembership
- *       accept and save data about which objects belong to extensions
+ * recordExtensionMembership
+ *       Record that the object identified by the given catalog ID
+ *       belongs to the given extension
  */
 void
-setExtensionMembership(ExtensionMemberId *extmems, int nextmems)
+recordExtensionMembership(CatalogId catId, ExtensionInfo *ext)
 {
-       /* Sort array in preparation for binary searches */
-       if (nextmems > 1)
-               qsort((void *) extmems, nextmems, sizeof(ExtensionMemberId),
-                         ExtensionMemberIdCompare);
-       /* And save */
-       extmembers = extmems;
-       numextmembers = nextmems;
+       CatalogIdMapEntry *entry;
+       bool            found;
+
+       /* CatalogId hash table must exist, if we have an ExtensionInfo */
+       Assert(catalogIdHash != NULL);
+
+       /* Add reference to CatalogId hash */
+       entry = catalogid_insert(catalogIdHash, catId, &found);
+       if (!found)
+       {
+               entry->dobj = NULL;
+               entry->ext = NULL;
+       }
+       Assert(entry->ext == NULL);
+       entry->ext = ext;
 }
 
 /*
@@ -1008,56 +951,15 @@ setExtensionMembership(ExtensionMemberId *extmems, int nextmems)
 ExtensionInfo *
 findOwningExtension(CatalogId catalogId)
 {
-       ExtensionMemberId *low;
-       ExtensionMemberId *high;
+       CatalogIdMapEntry *entry;
 
-       /*
-        * We could use bsearch() here, but the notational cruft of calling
-        * bsearch is nearly as bad as doing it ourselves; and the generalized
-        * bsearch function is noticeably slower as well.
-        */
-       if (numextmembers <= 0)
-               return NULL;
-       low = extmembers;
-       high = extmembers + (numextmembers - 1);
-       while (low <= high)
-       {
-               ExtensionMemberId *middle;
-               int                     difference;
-
-               middle = low + (high - low) / 2;
-               /* comparison must match ExtensionMemberIdCompare, below */
-               difference = oidcmp(middle->catId.oid, catalogId.oid);
-               if (difference == 0)
-                       difference = oidcmp(middle->catId.tableoid, catalogId.tableoid);
-               if (difference == 0)
-                       return middle->ext;
-               else if (difference < 0)
-                       low = middle + 1;
-               else
-                       high = middle - 1;
-       }
-       return NULL;
-}
+       if (catalogIdHash == NULL)
+               return NULL;                    /* no objects exist yet */
 
-/*
- * qsort comparator for ExtensionMemberIds
- */
-static int
-ExtensionMemberIdCompare(const void *p1, const void *p2)
-{
-       const ExtensionMemberId *obj1 = (const ExtensionMemberId *) p1;
-       const ExtensionMemberId *obj2 = (const ExtensionMemberId *) p2;
-       int                     cmpval;
-
-       /*
-        * Compare OID first since it's usually unique, whereas there will only be
-        * a few distinct values of tableoid.
-        */
-       cmpval = oidcmp(obj1->catId.oid, obj2->catId.oid);
-       if (cmpval == 0)
-               cmpval = oidcmp(obj1->catId.tableoid, obj2->catId.tableoid);
-       return cmpval;
+       entry = catalogid_lookup(catalogIdHash, catalogId);
+       if (entry == NULL)
+               return NULL;
+       return entry->ext;
 }
 
 
index 3c1cd858a8580d64535eb521322cc42e5eabb74b..6af10a85a2c09c9657e738d3edbd836ba91ea030 100644 (file)
@@ -236,6 +236,7 @@ typedef struct Archive
 
 typedef struct
 {
+       /* Note: this struct must not contain any unused bytes */
        Oid                     tableoid;
        Oid                     oid;
 } CatalogId;
index 52f1a3acb31804907b94b5f674a8464cb3e73ec5..b401b923ac759670360cbb090fb8d417a5dc0a62 100644 (file)
@@ -17918,12 +17918,10 @@ getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
        PQExpBuffer query;
        PGresult   *res;
        int                     ntups,
-                               nextmembers,
                                i;
        int                     i_classid,
                                i_objid,
                                i_refobjid;
-       ExtensionMemberId *extmembers;
        ExtensionInfo *ext;
 
        /* Nothing to do if no extensions */
@@ -17948,12 +17946,7 @@ getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
        i_objid = PQfnumber(res, "objid");
        i_refobjid = PQfnumber(res, "refobjid");
 
-       extmembers = (ExtensionMemberId *) pg_malloc(ntups * sizeof(ExtensionMemberId));
-       nextmembers = 0;
-
        /*
-        * Accumulate data into extmembers[].
-        *
         * Since we ordered the SELECT by referenced ID, we can expect that
         * multiple entries for the same extension will appear together; this
         * saves on searches.
@@ -17980,16 +17973,11 @@ getExtensionMembership(Archive *fout, ExtensionInfo extinfo[],
                        continue;
                }
 
-               extmembers[nextmembers].catId = objId;
-               extmembers[nextmembers].ext = ext;
-               nextmembers++;
+               recordExtensionMembership(objId, ext);
        }
 
        PQclear(res);
 
-       /* Remember the data for use later */
-       setExtensionMembership(extmembers, nextmembers);
-
        destroyPQExpBuffer(query);
 }
 
index 29af845ece6894f9fe677f0f7f50e4646ff8e99f..cc55e598ece089a6e18737ce481ab3de51ad4436 100644 (file)
@@ -647,16 +647,6 @@ typedef struct _SubscriptionInfo
        char       *subpublications;
 } SubscriptionInfo;
 
-/*
- * We build an array of these with an entry for each object that is an
- * extension member according to pg_depend.
- */
-typedef struct _extensionMemberId
-{
-       CatalogId       catId;                  /* tableoid+oid of some member object */
-       ExtensionInfo *ext;                     /* owning extension */
-} ExtensionMemberId;
-
 /*
  *     common utility functions
  */
@@ -682,7 +672,7 @@ extern NamespaceInfo *findNamespaceByOid(Oid oid);
 extern ExtensionInfo *findExtensionByOid(Oid oid);
 extern PublicationInfo *findPublicationByOid(Oid oid);
 
-extern void setExtensionMembership(ExtensionMemberId *extmems, int nextmems);
+extern void recordExtensionMembership(CatalogId catId, ExtensionInfo *ext);
 extern ExtensionInfo *findOwningExtension(CatalogId catalogId);
 
 extern void parseOidArray(const char *str, Oid *array, int arraysize);