@@ -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) */
7267Oid filenode ;/* last seen relfilenode of this sequence */
7368LocalTransactionId lxid ;/* xact in which we last did a seq op */
7469bool 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 ,
9793Buffer * buf ,HeapTuple seqtuple );
@@ -998,6 +994,23 @@ open_share_lock(SeqTable seq)
998994return 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{
10081021SeqTable elm ;
10091022Relation 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 newseqtable entry ifwe didn't find one .
1031+ *Initalize the newhash table entry ifit 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 */
10371041elm -> filenode = InvalidOid ;
10381042elm -> lxid = InvalidLocalTransactionId ;
10391043elm -> last_valid = false;
10401044elm -> 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
16211620last_used_seq = NULL ;