@@ -60,15 +60,10 @@ typedef struct sequence_magic
60
60
* session. This is needed to hold onto nextval/currval state. (We can't
61
61
* rely on the relcache, since it's only, well, a cache, and may decide to
62
62
* 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.
67
63
*/
68
64
typedef struct SeqTableData
69
65
{
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) */
72
67
Oid filenode ; /* last seen relfilenode of this sequence */
73
68
LocalTransactionId lxid ; /* xact in which we last did a seq op */
74
69
bool last_valid ; /* do we have a valid "last" value? */
@@ -81,7 +76,7 @@ typedef struct SeqTableData
81
76
82
77
typedef SeqTableData * SeqTable ;
83
78
84
- static SeqTable seqtab = NULL ; /* Head of list of SeqTable items */
79
+ static HTAB * seqhashtab = NULL ; /* hash table for SeqTable items */
85
80
86
81
/*
87
82
* last_used_seq is updated by nextval() to point to the last used
@@ -92,6 +87,7 @@ static SeqTableData *last_used_seq = NULL;
92
87
static void fill_seq_with_data (Relation rel , HeapTuple tuple );
93
88
static int64 nextval_internal (Oid relid );
94
89
static Relation open_share_lock (SeqTable seq );
90
+ static void create_seq_hashtable (void );
95
91
static void init_sequence (Oid relid , SeqTable * p_elm , Relation * p_rel );
96
92
static Form_pg_sequence read_seq_tuple (SeqTable elm , Relation rel ,
97
93
Buffer * buf , HeapTuple seqtuple );
@@ -998,6 +994,23 @@ open_share_lock(SeqTable seq)
998
994
return relation_open (seq -> relid , NoLock );
999
995
}
1000
996
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
+
1001
1014
/*
1002
1015
* Given a relation OID, open and lock the sequence. p_elm and p_rel are
1003
1016
* output parameters.
@@ -1007,39 +1020,28 @@ init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel)
1007
1020
{
1008
1021
SeqTable elm ;
1009
1022
Relation seqrel ;
1023
+ bool found ;
1010
1024
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 );
1017
1029
1018
1030
/*
1019
- * Allocate new seqtable entry if we didn't find one .
1031
+ * Initalize the new hash table entry if it did not exist already .
1020
1032
*
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.
1024
1037
*/
1025
- if (elm == NULL )
1038
+ if (! found )
1026
1039
{
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 */
1037
1041
elm -> filenode = InvalidOid ;
1038
1042
elm -> lxid = InvalidLocalTransactionId ;
1039
1043
elm -> last_valid = false;
1040
1044
elm -> last = elm -> cached = elm -> increment = 0 ;
1041
- elm -> next = seqtab ;
1042
- seqtab = elm ;
1043
1045
}
1044
1046
1045
1047
/*
@@ -1609,13 +1611,10 @@ seq_redo(XLogRecPtr lsn, XLogRecord *record)
1609
1611
void
1610
1612
ResetSequenceCaches (void )
1611
1613
{
1612
- SeqTableData * next ;
1613
-
1614
- while (seqtab != NULL )
1614
+ if (seqhashtab )
1615
1615
{
1616
- next = seqtab -> next ;
1617
- free (seqtab );
1618
- seqtab = next ;
1616
+ hash_destroy (seqhashtab );
1617
+ seqhashtab = NULL ;
1619
1618
}
1620
1619
1621
1620
last_used_seq = NULL ;
0 commit comments