This is an automated email from the ASF dual-hosted git repository.
mtaha pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/age.git
The following commit(s) were added to refs/heads/master by this push:
new 571c1982 Fix issue 2245 - Creating more than 41 vlabels causes crash
in drop_graph (#2248)
571c1982 is described below
commit 571c1982437fc3a9a0bebca293418c22ba64e270
Author: John Gemignani <[email protected]>
AuthorDate: Wed Nov 19 13:45:44 2025 -0800
Fix issue 2245 - Creating more than 41 vlabels causes crash in drop_graph
(#2248)
Fixed issue 2245 - Creating more than 41 vlabels causes drop_grapth to fail
with "label (relation) cache corrupted" and crashing out on the following
command.
This was due to corruption of the label_relation_cache during the
HASH_DELETE
process.
As the issue was with a cache flush routine, it was necessary to fix them
all. Here is the list of the flush functions that were fixed -
static void flush_graph_name_cache(void)
static void flush_graph_namespace_cache(void)
static void flush_label_name_graph_cache(void)
static void flush_label_graph_oid_cache(void)
static void flush_label_relation_cache(void)
static void flush_label_seq_name_graph_cache(void)
Added regression tests.
modified: regress/expected/catalog.out
modified: regress/sql/catalog.sql
modified: src/backend/utils/cache/ag_cache.c
---
regress/expected/catalog.out | 141 +++++++++++++++++++++++++++++-
regress/sql/catalog.sql | 42 ++++++++-
src/backend/utils/cache/ag_cache.c | 174 +++++++++++++------------------------
3 files changed, 241 insertions(+), 116 deletions(-)
diff --git a/regress/expected/catalog.out b/regress/expected/catalog.out
index d06a0ce6..a15fa469 100644
--- a/regress/expected/catalog.out
+++ b/regress/expected/catalog.out
@@ -457,7 +457,146 @@ NOTICE: graph does not exist
(1 row)
DROP FUNCTION raise_notice(TEXT);
--- dropping the graph
+--
+-- Fix issue 2245 - Creating more than 41 vlabels causes drop_graph to fail
with
+-- label (relation) cache corrupted
+--
+-- this result will change if another graph was created prior to this point.
+SELECT count(*) FROM ag_label;
+ count
+-------
+ 2
+(1 row)
+
+SELECT * FROM create_graph('issue_2245');
+NOTICE: graph "issue_2245" has been created
+ create_graph
+--------------
+
+(1 row)
+
+SELECT * FROM cypher('issue_2245', $$
+ CREATE (a1:Part1 {part_num: '123'}), (a2:Part2 {part_num: '345'}), (a3:Part3
{part_num: '456'}),
+ (a4:Part4 {part_num: '789'}), (a5:Part5 {part_num: '123'}), (a6:Part6
{part_num: '345'}),
+ (a7:Part7 {part_num: '456'}), (a8:Part8 {part_num: '789'}), (a9:Part9
{part_num: '123'}),
+ (a10:Part10 {part_num: '345'}), (a11:Part11 {part_num: '456'}),
(a12:Part12 {part_num: '789'}),
+ (a13:Part13 {part_num: '123'}), (a14:Part14 {part_num: '345'}),
(a15:Part15 {part_num: '456'}),
+ (a16:Part16 {part_num: '789'}), (a17:Part17 {part_num: '123'}),
(a18:Part18 {part_num: '345'}),
+ (a19:Part19 {part_num: '456'}), (a20:Part20 {part_num: '789'}),
(a21:Part21 {part_num: '123'}),
+ (a22:Part22 {part_num: '345'}), (a23:Part23 {part_num: '456'}),
(a24:Part24 {part_num: '789'}),
+ (a25:Part25 {part_num: '123'}), (a26:Part26 {part_num: '345'}),
(a27:Part27 {part_num: '456'}),
+ (a28:Part28 {part_num: '789'}), (a29:Part29 {part_num: '789'}),
(a30:Part30 {part_num: '123'}),
+ (a31:Part31 {part_num: '345'}), (a32:Part32 {part_num: '456'}),
(a33:Part33 {part_num: '789'}),
+ (a34:Part34 {part_num: '123'}), (a35:Part35 {part_num: '345'}),
(a36:Part36 {part_num: '456'}),
+ (a37:Part37 {part_num: '789'}), (a38:Part38 {part_num: '123'}),
(a39:Part39 {part_num: '345'}),
+ (a40:Part40 {part_num: '456'}), (a41:Part41 {part_num: '789'}),
(a42:Part42 {part_num: '345'}),
+ (a43:Part43 {part_num: '456'}), (a44:Part44 {part_num: '789'}),
(a45:Part45 {part_num: '456'}),
+ (a46:Part46 {part_num: '789'}), (a47:Part47 {part_num: '456'}),
(a48:Part48 {part_num: '789'}),
+ (a49:Part49 {part_num: '789'}), (a50:Part50 {part_num: '456'}),
(a51:Part51 {part_num: '789'})
+ $$) AS (result agtype);
+ result
+--------
+(0 rows)
+
+SELECT count(*) FROM ag_label;
+ count
+-------
+ 55
+(1 row)
+
+SELECT drop_graph('issue_2245', true);
+NOTICE: drop cascades to 53 other objects
+DETAIL: drop cascades to table issue_2245._ag_label_vertex
+drop cascades to table issue_2245._ag_label_edge
+drop cascades to table issue_2245."Part1"
+drop cascades to table issue_2245."Part2"
+drop cascades to table issue_2245."Part3"
+drop cascades to table issue_2245."Part4"
+drop cascades to table issue_2245."Part5"
+drop cascades to table issue_2245."Part6"
+drop cascades to table issue_2245."Part7"
+drop cascades to table issue_2245."Part8"
+drop cascades to table issue_2245."Part9"
+drop cascades to table issue_2245."Part10"
+drop cascades to table issue_2245."Part11"
+drop cascades to table issue_2245."Part12"
+drop cascades to table issue_2245."Part13"
+drop cascades to table issue_2245."Part14"
+drop cascades to table issue_2245."Part15"
+drop cascades to table issue_2245."Part16"
+drop cascades to table issue_2245."Part17"
+drop cascades to table issue_2245."Part18"
+drop cascades to table issue_2245."Part19"
+drop cascades to table issue_2245."Part20"
+drop cascades to table issue_2245."Part21"
+drop cascades to table issue_2245."Part22"
+drop cascades to table issue_2245."Part23"
+drop cascades to table issue_2245."Part24"
+drop cascades to table issue_2245."Part25"
+drop cascades to table issue_2245."Part26"
+drop cascades to table issue_2245."Part27"
+drop cascades to table issue_2245."Part28"
+drop cascades to table issue_2245."Part29"
+drop cascades to table issue_2245."Part30"
+drop cascades to table issue_2245."Part31"
+drop cascades to table issue_2245."Part32"
+drop cascades to table issue_2245."Part33"
+drop cascades to table issue_2245."Part34"
+drop cascades to table issue_2245."Part35"
+drop cascades to table issue_2245."Part36"
+drop cascades to table issue_2245."Part37"
+drop cascades to table issue_2245."Part38"
+drop cascades to table issue_2245."Part39"
+drop cascades to table issue_2245."Part40"
+drop cascades to table issue_2245."Part41"
+drop cascades to table issue_2245."Part42"
+drop cascades to table issue_2245."Part43"
+drop cascades to table issue_2245."Part44"
+drop cascades to table issue_2245."Part45"
+drop cascades to table issue_2245."Part46"
+drop cascades to table issue_2245."Part47"
+drop cascades to table issue_2245."Part48"
+drop cascades to table issue_2245."Part49"
+drop cascades to table issue_2245."Part50"
+drop cascades to table issue_2245."Part51"
+NOTICE: graph "issue_2245" has been dropped
+ drop_graph
+------------
+
+(1 row)
+
+-- this result should be the same as the one before the create_graph
+SELECT count(*) FROM ag_label;
+ count
+-------
+ 2
+(1 row)
+
+-- create the graph again
+SELECT * FROM create_graph('issue_2245');
+NOTICE: graph "issue_2245" has been created
+ create_graph
+--------------
+
+(1 row)
+
+SELECT count(*) FROM ag_label;
+ count
+-------
+ 4
+(1 row)
+
+-- dropping the graphs
+SELECT drop_graph('issue_2245', true);
+NOTICE: drop cascades to 2 other objects
+DETAIL: drop cascades to table issue_2245._ag_label_vertex
+drop cascades to table issue_2245._ag_label_edge
+NOTICE: graph "issue_2245" has been dropped
+ drop_graph
+------------
+
+(1 row)
+
SELECT drop_graph('graph', true);
NOTICE: drop cascades to 2 other objects
DETAIL: drop cascades to table graph._ag_label_vertex
diff --git a/regress/sql/catalog.sql b/regress/sql/catalog.sql
index 85fc4e8a..bb72c349 100644
--- a/regress/sql/catalog.sql
+++ b/regress/sql/catalog.sql
@@ -193,5 +193,45 @@ SELECT raise_notice('graph1');
DROP FUNCTION raise_notice(TEXT);
--- dropping the graph
+--
+-- Fix issue 2245 - Creating more than 41 vlabels causes drop_graph to fail
with
+-- label (relation) cache corrupted
+--
+
+-- this result will change if another graph was created prior to this point.
+SELECT count(*) FROM ag_label;
+
+SELECT * FROM create_graph('issue_2245');
+SELECT * FROM cypher('issue_2245', $$
+ CREATE (a1:Part1 {part_num: '123'}), (a2:Part2 {part_num: '345'}), (a3:Part3
{part_num: '456'}),
+ (a4:Part4 {part_num: '789'}), (a5:Part5 {part_num: '123'}), (a6:Part6
{part_num: '345'}),
+ (a7:Part7 {part_num: '456'}), (a8:Part8 {part_num: '789'}), (a9:Part9
{part_num: '123'}),
+ (a10:Part10 {part_num: '345'}), (a11:Part11 {part_num: '456'}),
(a12:Part12 {part_num: '789'}),
+ (a13:Part13 {part_num: '123'}), (a14:Part14 {part_num: '345'}),
(a15:Part15 {part_num: '456'}),
+ (a16:Part16 {part_num: '789'}), (a17:Part17 {part_num: '123'}),
(a18:Part18 {part_num: '345'}),
+ (a19:Part19 {part_num: '456'}), (a20:Part20 {part_num: '789'}),
(a21:Part21 {part_num: '123'}),
+ (a22:Part22 {part_num: '345'}), (a23:Part23 {part_num: '456'}),
(a24:Part24 {part_num: '789'}),
+ (a25:Part25 {part_num: '123'}), (a26:Part26 {part_num: '345'}),
(a27:Part27 {part_num: '456'}),
+ (a28:Part28 {part_num: '789'}), (a29:Part29 {part_num: '789'}),
(a30:Part30 {part_num: '123'}),
+ (a31:Part31 {part_num: '345'}), (a32:Part32 {part_num: '456'}),
(a33:Part33 {part_num: '789'}),
+ (a34:Part34 {part_num: '123'}), (a35:Part35 {part_num: '345'}),
(a36:Part36 {part_num: '456'}),
+ (a37:Part37 {part_num: '789'}), (a38:Part38 {part_num: '123'}),
(a39:Part39 {part_num: '345'}),
+ (a40:Part40 {part_num: '456'}), (a41:Part41 {part_num: '789'}),
(a42:Part42 {part_num: '345'}),
+ (a43:Part43 {part_num: '456'}), (a44:Part44 {part_num: '789'}),
(a45:Part45 {part_num: '456'}),
+ (a46:Part46 {part_num: '789'}), (a47:Part47 {part_num: '456'}),
(a48:Part48 {part_num: '789'}),
+ (a49:Part49 {part_num: '789'}), (a50:Part50 {part_num: '456'}),
(a51:Part51 {part_num: '789'})
+ $$) AS (result agtype);
+
+SELECT count(*) FROM ag_label;
+SELECT drop_graph('issue_2245', true);
+
+-- this result should be the same as the one before the create_graph
+SELECT count(*) FROM ag_label;
+
+-- create the graph again
+SELECT * FROM create_graph('issue_2245');
+SELECT count(*) FROM ag_label;
+
+-- dropping the graphs
+SELECT drop_graph('issue_2245', true);
SELECT drop_graph('graph', true);
diff --git a/src/backend/utils/cache/ag_cache.c
b/src/backend/utils/cache/ag_cache.c
index e3c4d079..493ffcfa 100644
--- a/src/backend/utils/cache/ag_cache.c
+++ b/src/backend/utils/cache/ag_cache.c
@@ -286,52 +286,34 @@ static void invalidate_graph_caches(Datum arg, int
cache_id, uint32 hash_value)
static void flush_graph_name_cache(void)
{
- HASH_SEQ_STATUS hash_seq;
-
- hash_seq_init(&hash_seq, graph_name_cache_hash);
- for (;;)
+ /*
+ * If the graph_name_cache exists, destroy it. This will avoid any
+ * potential corruption issues.
+ */
+ if (graph_name_cache_hash)
{
- graph_name_cache_entry *entry;
- void *removed;
-
- entry = hash_seq_search(&hash_seq);
- if (!entry)
- {
- break;
- }
- removed = hash_search(graph_name_cache_hash, &entry->name, HASH_REMOVE,
- NULL);
- if (!removed)
- {
- ereport(ERROR, (errmsg_internal("graph (name) cache corrupted")));
- }
+ hash_destroy(graph_name_cache_hash);
+ graph_name_cache_hash = NULL;
}
+
+ /* recreate the graph_name_cache */
+ create_graph_name_cache();
}
static void flush_graph_namespace_cache(void)
{
- HASH_SEQ_STATUS hash_seq;
-
- hash_seq_init(&hash_seq, graph_namespace_cache_hash);
- for (;;)
+ /*
+ * If the graph_namespace_cache exists, destroy it. This will avoid any
+ * potential corruption issues.
+ */
+ if (graph_namespace_cache_hash)
{
- graph_namespace_cache_entry *entry;
- void *removed;
-
- entry = hash_seq_search(&hash_seq);
- if (!entry)
- {
- break;
- }
-
- removed = hash_search(graph_namespace_cache_hash, &entry->namespace,
- HASH_REMOVE, NULL);
- if (!removed)
- {
- ereport(ERROR,
- (errmsg_internal("graph (namespace) cache corrupted")));
- }
+ hash_destroy(graph_namespace_cache_hash);
+ graph_namespace_cache_hash = NULL;
}
+
+ /* recreate the graph_namespace_cache */
+ create_graph_namespace_cache();
}
graph_cache_data *search_graph_name_cache(const char *name)
@@ -664,27 +646,18 @@ static void invalidate_label_name_graph_cache(Oid relid)
static void flush_label_name_graph_cache(void)
{
- HASH_SEQ_STATUS hash_seq;
-
- hash_seq_init(&hash_seq, label_name_graph_cache_hash);
- for (;;)
+ /*
+ * If the label_name_graph_cache exists, destroy it. This will avoid any
+ * potential corruption issues.
+ */
+ if (label_name_graph_cache_hash)
{
- label_name_graph_cache_entry *entry;
- void *removed;
-
- entry = hash_seq_search(&hash_seq);
- if (!entry)
- {
- break;
- }
- removed = hash_search(label_name_graph_cache_hash, &entry->key,
- HASH_REMOVE, NULL);
- if (!removed)
- {
- ereport(ERROR,
- (errmsg_internal("label (name, graph) cache corrupted")));
- }
+ hash_destroy(label_name_graph_cache_hash);
+ label_name_graph_cache_hash = NULL;
}
+
+ /* recreate the label_name_graph_cache */
+ create_label_name_graph_cache();
}
static void invalidate_label_graph_oid_cache(Oid relid)
@@ -722,27 +695,18 @@ static void invalidate_label_graph_oid_cache(Oid relid)
static void flush_label_graph_oid_cache(void)
{
- HASH_SEQ_STATUS hash_seq;
-
- hash_seq_init(&hash_seq, label_graph_oid_cache_hash);
- for (;;)
+ /*
+ * If the label_graph_oid_cache exists, destroy it. This will avoid any
+ * potential corruption issues.
+ */
+ if (label_graph_oid_cache_hash)
{
- label_graph_oid_cache_entry *entry;
- void *removed;
-
- entry = hash_seq_search(&hash_seq);
- if (!entry)
- {
- break;
- }
- removed = hash_search(label_graph_oid_cache_hash, &entry->key,
- HASH_REMOVE, NULL);
- if (!removed)
- {
- ereport(ERROR,
- (errmsg_internal("label (graph, id) cache corrupted")));
- }
+ hash_destroy(label_graph_oid_cache_hash);
+ label_graph_oid_cache_hash = NULL;
}
+
+ /* recreate the label_graph_oid_cache */
+ create_label_graph_oid_cache();
}
static void invalidate_label_relation_cache(Oid relid)
@@ -765,27 +729,18 @@ static void invalidate_label_relation_cache(Oid relid)
static void flush_label_relation_cache(void)
{
- HASH_SEQ_STATUS hash_seq;
-
- hash_seq_init(&hash_seq, label_relation_cache_hash);
- for (;;)
+ /*
+ * If the label_relation_cache exists, destroy it. This will avoid any
+ * potential corruption issues.
+ */
+ if (label_relation_cache_hash)
{
- label_relation_cache_entry *entry;
- void *removed;
-
- entry = hash_seq_search(&hash_seq);
- if (!entry)
- {
- break;
- }
- removed = hash_search(label_relation_cache_hash, &entry->relation,
- HASH_REMOVE, NULL);
- if (!removed)
- {
- ereport(ERROR,
- (errmsg_internal("label (relation) cache corrupted")));
- }
+ hash_destroy(label_relation_cache_hash);
+ label_relation_cache_hash = NULL;
}
+
+ /* recreate the label_relation_cache */
+ create_label_relation_cache();
}
static void invalidate_label_seq_name_graph_cache(Oid relid)
@@ -823,27 +778,18 @@ static void invalidate_label_seq_name_graph_cache(Oid
relid)
static void flush_label_seq_name_graph_cache(void)
{
- HASH_SEQ_STATUS hash_seq;
-
- hash_seq_init(&hash_seq, label_seq_name_graph_cache_hash);
- for (;;)
+ /*
+ * If the label_seq_name_graph_cache exists, destroy it. This will
+ * avoid any potential corruption issues by deleting entries.
+ */
+ if (label_seq_name_graph_cache_hash)
{
- label_seq_name_graph_cache_entry *entry;
- void *removed;
-
- entry = hash_seq_search(&hash_seq);
- if (!entry)
- {
- break;
- }
- removed = hash_search(label_seq_name_graph_cache_hash, &entry->key,
- HASH_REMOVE, NULL);
- if (!removed)
- {
- ereport(ERROR,
- (errmsg_internal("label (seq_name, graph) cache
corrupted")));
- }
+ hash_destroy(label_seq_name_graph_cache_hash);
+ label_seq_name_graph_cache_hash = NULL;
}
+
+ /* recreate the label_seq_name_graph_cache */
+ create_label_seq_name_graph_cache();
}
label_cache_data *search_label_name_graph_cache(const char *name, Oid graph)