@@ -204,10 +204,10 @@ add_deactivated_query(uint64 queryid)
204204/*
205205 * Update AQO statistics.
206206 *
207- * Add a record (and replace old, if all stat slots is full) to stat slot for
208- * a query class.
207+ * Add a record (or update an existed) to stat storage for the query class.
209208 * Returns a copy of stat entry, allocated in current memory context. Caller is
210209 * in charge to free this struct after usage.
210+ * If stat hash table is full, return NULL and log this fact.
211211 */
212212StatEntry *
213213aqo_stat_store (uint64 queryid ,bool use_aqo ,
@@ -216,16 +216,36 @@ aqo_stat_store(uint64 queryid, bool use_aqo,
216216StatEntry * entry ;
217217bool found ;
218218int pos ;
219+ bool tblOverflow ;
220+ HASHACTION action ;
219221
220222Assert (stat_htab );
221223
222224LWLockAcquire (& aqo_state -> stat_lock ,LW_EXCLUSIVE );
223- entry = (StatEntry * )hash_search (stat_htab ,& queryid ,HASH_ENTER ,& found );
225+ tblOverflow = hash_get_num_entries (stat_htab )< fs_max_items ? false : true;
226+ action = tblOverflow ?HASH_FIND :HASH_ENTER ;
227+ entry = (StatEntry * )hash_search (stat_htab ,& queryid ,action ,& found );
224228
225229/* Initialize entry on first usage */
226230if (!found )
227231{
228- uint64 qid = entry -> queryid ;
232+ uint64 qid ;
233+
234+ if (action == HASH_FIND )
235+ {
236+ /*
237+ * Hash table is full. To avoid possible problems - don't try to add
238+ * more, just exit
239+ */
240+ LWLockRelease (& aqo_state -> stat_lock );
241+ ereport (LOG ,
242+ (errcode (ERRCODE_OUT_OF_MEMORY ),
243+ errmsg ("[AQO] Stat storage is full. No more feature spaces can be added." ),
244+ errhint ("Increase value of aqo.fs_max_items on restart of the instance" )));
245+ return NULL ;
246+ }
247+
248+ qid = entry -> queryid ;
229249memset (entry ,0 ,sizeof (StatEntry ));
230250entry -> queryid = qid ;
231251}
@@ -907,6 +927,8 @@ aqo_qtext_store(uint64 queryid, const char *query_string)
907927{
908928QueryTextEntry * entry ;
909929bool found ;
930+ bool tblOverflow ;
931+ HASHACTION action ;
910932
911933Assert (!LWLockHeldByMe (& aqo_state -> qtexts_lock ));
912934
@@ -916,7 +938,12 @@ aqo_qtext_store(uint64 queryid, const char *query_string)
916938dsa_init ();
917939
918940LWLockAcquire (& aqo_state -> qtexts_lock ,LW_EXCLUSIVE );
919- entry = (QueryTextEntry * )hash_search (qtexts_htab ,& queryid ,HASH_ENTER ,
941+
942+ /* Check hash table overflow */
943+ tblOverflow = hash_get_num_entries (qtexts_htab )< fs_max_items ? false : true;
944+ action = tblOverflow ?HASH_FIND :HASH_ENTER ;
945+
946+ entry = (QueryTextEntry * )hash_search (qtexts_htab ,& queryid ,action ,
920947& found );
921948
922949/* Initialize entry on first usage */
@@ -925,6 +952,20 @@ aqo_qtext_store(uint64 queryid, const char *query_string)
925952size_t size = strlen (query_string )+ 1 ;
926953char * strptr ;
927954
955+ if (action == HASH_FIND )
956+ {
957+ /*
958+ * Hash table is full. To avoid possible problems - don't try to add
959+ * more, just exit
960+ */
961+ LWLockRelease (& aqo_state -> qtexts_lock );
962+ ereport (LOG ,
963+ (errcode (ERRCODE_OUT_OF_MEMORY ),
964+ errmsg ("[AQO] Query texts storage is full. No more feature spaces can be added." ),
965+ errhint ("Increase value of aqo.fs_max_items on restart of the instance" )));
966+ return false;
967+ }
968+
928969entry -> queryid = queryid ;
929970entry -> qtext_dp = dsa_allocate (qtext_dsa ,size );
930971Assert (DsaPointerIsValid (entry -> qtext_dp ));
@@ -933,7 +974,7 @@ aqo_qtext_store(uint64 queryid, const char *query_string)
933974aqo_state -> qtexts_changed = true;
934975}
935976LWLockRelease (& aqo_state -> qtexts_lock );
936- return ! found ;
977+ return true ;
937978}
938979
939980Datum
@@ -1089,17 +1130,38 @@ aqo_data_store(uint64 fs, int fss, OkNNrdata *data, List *reloids)
10891130char * ptr ;
10901131ListCell * lc ;
10911132size_t size ;
1133+ bool tblOverflow ;
1134+ HASHACTION action ;
10921135
10931136Assert (!LWLockHeldByMe (& aqo_state -> data_lock ));
10941137
10951138dsa_init ();
10961139
10971140LWLockAcquire (& aqo_state -> data_lock ,LW_EXCLUSIVE );
1098- entry = (DataEntry * )hash_search (data_htab ,& key ,HASH_ENTER ,& found );
1141+
1142+ /* Check hash table overflow */
1143+ tblOverflow = hash_get_num_entries (data_htab )< fss_max_items ? false : true;
1144+ action = tblOverflow ?HASH_FIND :HASH_ENTER ;
1145+
1146+ entry = (DataEntry * )hash_search (data_htab ,& key ,action ,& found );
10991147
11001148/* Initialize entry on first usage */
11011149if (!found )
11021150{
1151+ if (action == HASH_FIND )
1152+ {
1153+ /*
1154+ * Hash table is full. To avoid possible problems - don't try to add
1155+ * more, just exit
1156+ */
1157+ LWLockRelease (& aqo_state -> data_lock );
1158+ ereport (LOG ,
1159+ (errcode (ERRCODE_OUT_OF_MEMORY ),
1160+ errmsg ("[AQO] Data storage is full. No more data can be added." ),
1161+ errhint ("Increase value of aqo.fss_max_items on restart of the instance" )));
1162+ return false;
1163+ }
1164+
11031165entry -> cols = data -> cols ;
11041166entry -> rows = data -> rows ;
11051167entry -> nrels = list_length (reloids );
@@ -1603,11 +1665,13 @@ aqo_queries_remove(PG_FUNCTION_ARGS)
16031665}
16041666
16051667bool
1606- aqo_queries_store (uint64 queryid ,uint64 fs , bool learn_aqo ,
1607- bool use_aqo ,bool auto_tuning )
1668+ aqo_queries_store (uint64 queryid ,
1669+ uint64 fs , bool learn_aqo , bool use_aqo ,bool auto_tuning )
16081670{
16091671QueriesEntry * entry ;
16101672bool found ;
1673+ bool tblOverflow ;
1674+ HASHACTION action ;
16111675
16121676Assert (queries_htab );
16131677
@@ -1616,8 +1680,29 @@ aqo_queries_store(uint64 queryid, uint64 fs, bool learn_aqo,
16161680use_aqo == false&& auto_tuning == false));
16171681
16181682LWLockAcquire (& aqo_state -> queries_lock ,LW_EXCLUSIVE );
1619- entry = (QueriesEntry * )hash_search (queries_htab ,& queryid ,HASH_ENTER ,
1683+
1684+ /* Check hash table overflow */
1685+ tblOverflow = hash_get_num_entries (queries_htab )< fs_max_items ? false : true;
1686+ action = tblOverflow ?HASH_FIND :HASH_ENTER ;
1687+
1688+ entry = (QueriesEntry * )hash_search (queries_htab ,& queryid ,action ,
16201689& found );
1690+
1691+ /* Initialize entry on first usage */
1692+ if (!found && action == HASH_FIND )
1693+ {
1694+ /*
1695+ * Hash table is full. To avoid possible problems - don't try to add
1696+ * more, just exit
1697+ */
1698+ LWLockRelease (& aqo_state -> queries_lock );
1699+ ereport (LOG ,
1700+ (errcode (ERRCODE_OUT_OF_MEMORY ),
1701+ errmsg ("[AQO] Queries storage is full. No more feature spaces can be added." ),
1702+ errhint ("Increase value of aqo.fs_max_items on restart of the instance" )));
1703+ return false;
1704+ }
1705+
16211706entry -> fs = fs ;
16221707entry -> learn_aqo = learn_aqo ;
16231708entry -> use_aqo = use_aqo ;