@@ -60,15 +60,10 @@ typedef struct sequence_magic
6060 * session. This is needed to hold onto nextval/currval state. (We can't
6161 * rely on the relcache, since it's only, well, a cache, and may decide to
6262 * discard entries.)
63- *
64- * XXX We use linear search to find pre-existing SeqTable entries. This is
65- * good when only a small number of sequences are touched in a session, but
66- * would suck with many different sequences. Perhaps use a hashtable someday.
6763 */
6864typedef struct SeqTableData
6965{
70- struct SeqTableData * next ; /* link to next SeqTable object */
71- Oid relid ; /* pg_class OID of this sequence */
66+ Oid relid ; /* pg_class OID of this sequence (hash key) */
7267 Oid filenode ; /* last seen relfilenode of this sequence */
7368 LocalTransactionId lxid ; /* xact in which we last did a seq op */
7469 bool last_valid ; /* do we have a valid "last" value? */
@@ -81,7 +76,7 @@ typedef struct SeqTableData
8176
8277typedef SeqTableData * SeqTable ;
8378
84- static SeqTable seqtab = NULL ; /* Head of list of SeqTable items */
79+ static HTAB * seqhashtab = NULL ; /* hash table for SeqTable items */
8580
8681/*
8782 * last_used_seq is updated by nextval() to point to the last used
@@ -92,6 +87,7 @@ static SeqTableData *last_used_seq = NULL;
9287static void fill_seq_with_data (Relation rel , HeapTuple tuple );
9388static int64 nextval_internal (Oid relid );
9489static Relation open_share_lock (SeqTable seq );
90+ static void create_seq_hashtable (void );
9591static void init_sequence (Oid relid , SeqTable * p_elm , Relation * p_rel );
9692static Form_pg_sequence read_seq_tuple (SeqTable elm , Relation rel ,
9793 Buffer * buf , HeapTuple seqtuple );
@@ -998,6 +994,23 @@ open_share_lock(SeqTable seq)
998994 return relation_open (seq -> relid , NoLock );
999995}
1000996
997+ /*
998+ * Creates the hash table for storing sequence data
999+ */
1000+ static void
1001+ create_seq_hashtable (void )
1002+ {
1003+ HASHCTL ctl ;
1004+
1005+ memset (& ctl , 0 , sizeof (ctl ));
1006+ ctl .keysize = sizeof (Oid );
1007+ ctl .entrysize = sizeof (SeqTableData );
1008+ ctl .hash = oid_hash ;
1009+
1010+ seqhashtab = hash_create ("Sequence values" , 16 , & ctl ,
1011+ HASH_ELEM | HASH_FUNCTION | HASH_CONTEXT );
1012+ }
1013+
10011014/*
10021015 * Given a relation OID, open and lock the sequence. p_elm and p_rel are
10031016 * output parameters.
@@ -1007,39 +1020,28 @@ init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel)
10071020{
10081021 SeqTable elm ;
10091022 Relation seqrel ;
1023+ bool found ;
10101024
1011- /* Look to see if we already have a seqtable entry for relation */
1012- for (elm = seqtab ; elm != NULL ; elm = elm -> next )
1013- {
1014- if (elm -> relid == relid )
1015- break ;
1016- }
1025+ if (seqhashtab == NULL )
1026+ create_seq_hashtable ();
1027+
1028+ elm = (SeqTable ) hash_search (seqhashtab , & relid , HASH_ENTER , & found );
10171029
10181030 /*
1019- * Allocate new seqtable entry if we didn't find one .
1031+ * Initalize the new hash table entry if it did not exist already .
10201032 *
1021- * NOTE: seqtable entries remain in the list for the life of a backend. If
1022- * the sequence itself is deleted then the entry becomes wasted memory,
1023- * but it's small enough that this should not matter.
1033+ * NOTE: seqtable entries are stored for the life of a backend (unless
1034+ * explictly discarded with DISCARD). If the sequence itself is deleted
1035+ * then the entry becomes wasted memory, but it's small enough that this
1036+ * should not matter.
10241037 */
1025- if (elm == NULL )
1038+ if (! found )
10261039 {
1027- /*
1028- * Time to make a new seqtable entry. These entries live as long as
1029- * the backend does, so we use plain malloc for them.
1030- */
1031- elm = (SeqTable ) malloc (sizeof (SeqTableData ));
1032- if (elm == NULL )
1033- ereport (ERROR ,
1034- (errcode (ERRCODE_OUT_OF_MEMORY ),
1035- errmsg ("out of memory" )));
1036- elm -> relid = relid ;
1040+ /* relid already filled in */
10371041 elm -> filenode = InvalidOid ;
10381042 elm -> lxid = InvalidLocalTransactionId ;
10391043 elm -> last_valid = false;
10401044 elm -> last = elm -> cached = elm -> increment = 0 ;
1041- elm -> next = seqtab ;
1042- seqtab = elm ;
10431045 }
10441046
10451047 /*
@@ -1609,13 +1611,10 @@ seq_redo(XLogRecPtr lsn, XLogRecord *record)
16091611void
16101612ResetSequenceCaches (void )
16111613{
1612- SeqTableData * next ;
1613-
1614- while (seqtab != NULL )
1614+ if (seqhashtab )
16151615 {
1616- next = seqtab -> next ;
1617- free (seqtab );
1618- seqtab = next ;
1616+ hash_destroy (seqhashtab );
1617+ seqhashtab = NULL ;
16191618 }
16201619
16211620 last_used_seq = NULL ;
0 commit comments