|
42 | 42 | #include "catalog/ag_graph.h" |
43 | 43 | #include "catalog/ag_label.h" |
44 | 44 | #include "commands/label_commands.h" |
| 45 | +#include "common/hashfn.h" |
45 | 46 | #include "parser/cypher_analyze.h" |
46 | 47 | #include "parser/cypher_clause.h" |
47 | 48 | #include "parser/cypher_expr.h" |
48 | 49 | #include "parser/cypher_item.h" |
49 | 50 | #include "parser/cypher_parse_agg.h" |
50 | 51 | #include "parser/cypher_transform_entity.h" |
| 52 | +#include "storage/lock.h" |
51 | 53 | #include "utils/ag_cache.h" |
52 | 54 | #include "utils/ag_func.h" |
53 | 55 | #include "utils/ag_guc.h" |
@@ -5872,15 +5874,23 @@ transform_create_cypher_edge(cypher_parsestate *cpstate, List **target_list, |
5872 | 5874 | /* create the label entry if it does not exist */ |
5873 | 5875 | if (!label_exists(edge->label, cpstate->graph_oid)) |
5874 | 5876 | { |
| 5877 | + LOCKTAG tag; |
| 5878 | + uint32 key; |
5875 | 5879 | List *parent; |
5876 | 5880 |
|
5877 | | - rv = get_label_range_var(cpstate->graph_name, cpstate->graph_oid, |
5878 | | - AG_DEFAULT_LABEL_EDGE); |
| 5881 | + key = hash_bytes((const unsigned char *)edge->label, strlen(edge->label)); |
| 5882 | + SET_LOCKTAG_ADVISORY(tag, MyDatabaseId, key, cpstate->graph_oid, 3); |
| 5883 | + (void) LockAcquire(&tag, ExclusiveLock, false, false); |
| 5884 | + if (!label_exists(edge->label, cpstate->graph_oid)) |
| 5885 | + { |
| 5886 | + rv = get_label_range_var(cpstate->graph_name, cpstate->graph_oid, |
| 5887 | + AG_DEFAULT_LABEL_EDGE); |
5879 | 5888 |
|
5880 | | - parent = list_make1(rv); |
| 5889 | + parent = list_make1(rv); |
5881 | 5890 |
|
5882 | | - create_label(cpstate->graph_name, edge->label, LABEL_TYPE_EDGE, |
5883 | | - parent); |
| 5891 | + create_label(cpstate->graph_name, edge->label, LABEL_TYPE_EDGE, |
| 5892 | + parent); |
| 5893 | + } |
5884 | 5894 | } |
5885 | 5895 |
|
5886 | 5896 | /* lock the relation of the label */ |
@@ -6149,15 +6159,23 @@ transform_create_cypher_new_node(cypher_parsestate *cpstate, |
6149 | 6159 | /* create the label entry if it does not exist */ |
6150 | 6160 | if (!label_exists(node->label, cpstate->graph_oid)) |
6151 | 6161 | { |
| 6162 | + LOCKTAG tag; |
| 6163 | + uint32 key; |
6152 | 6164 | List *parent; |
6153 | 6165 |
|
6154 | | - rv = get_label_range_var(cpstate->graph_name, cpstate->graph_oid, |
6155 | | - AG_DEFAULT_LABEL_VERTEX); |
| 6166 | + key = hash_bytes((const unsigned char *)node->label, strlen(node->label)); |
| 6167 | + SET_LOCKTAG_ADVISORY(tag, MyDatabaseId, key, cpstate->graph_oid, 3); |
| 6168 | + (void) LockAcquire(&tag, ExclusiveLock, false, false); |
| 6169 | + if (!label_exists(node->label, cpstate->graph_oid)) |
| 6170 | + { |
| 6171 | + rv = get_label_range_var(cpstate->graph_name, cpstate->graph_oid, |
| 6172 | + AG_DEFAULT_LABEL_VERTEX); |
6156 | 6173 |
|
6157 | | - parent = list_make1(rv); |
| 6174 | + parent = list_make1(rv); |
6158 | 6175 |
|
6159 | | - create_label(cpstate->graph_name, node->label, LABEL_TYPE_VERTEX, |
6160 | | - parent); |
| 6176 | + create_label(cpstate->graph_name, node->label, LABEL_TYPE_VERTEX, |
| 6177 | + parent); |
| 6178 | + } |
6161 | 6179 | } |
6162 | 6180 |
|
6163 | 6181 | rel->flags = CYPHER_TARGET_NODE_FLAG_INSERT; |
@@ -7222,19 +7240,36 @@ transform_merge_cypher_edge(cypher_parsestate *cpstate, List **target_list, |
7222 | 7240 | /* check to see if the label exists, create the label entry if it does not. */ |
7223 | 7241 | if (edge->label && !label_exists(edge->label, cpstate->graph_oid)) |
7224 | 7242 | { |
| 7243 | + LOCKTAG tag; |
| 7244 | + uint32 key; |
7225 | 7245 | List *parent; |
| 7246 | + |
7226 | 7247 | /* |
7227 | | - * setup the default edge table as the parent table, that we |
7228 | | - * will inherit from. |
| 7248 | + * When merging nodes or edges concurrently, there is label with the same |
| 7249 | + * name created by different transactions. Advisory lock is acquired before |
| 7250 | + * creating label, and then check if label already exists. Note, the lock is |
| 7251 | + * not released until current transaction is over. This can ensure that the |
| 7252 | + * new tuple inserted in ag_label catalog table will be sent out, so other |
| 7253 | + * transactions can receive it when checking label exists after acquiring lock. |
7229 | 7254 | */ |
7230 | | - rv = get_label_range_var(cpstate->graph_name, cpstate->graph_oid, |
7231 | | - AG_DEFAULT_LABEL_EDGE); |
| 7255 | + key = hash_bytes((const unsigned char *)edge->label, strlen(edge->label)); |
| 7256 | + SET_LOCKTAG_ADVISORY(tag, MyDatabaseId, key, cpstate->graph_oid, 3); |
| 7257 | + (void) LockAcquire(&tag, ExclusiveLock, false, false); |
| 7258 | + if (!label_exists(edge->label, cpstate->graph_oid)) |
| 7259 | + { |
| 7260 | + /* |
| 7261 | + * setup the default edge table as the parent table, that we |
| 7262 | + * will inherit from. |
| 7263 | + */ |
| 7264 | + rv = get_label_range_var(cpstate->graph_name, cpstate->graph_oid, |
| 7265 | + AG_DEFAULT_LABEL_EDGE); |
7232 | 7266 |
|
7233 | | - parent = list_make1(rv); |
| 7267 | + parent = list_make1(rv); |
7234 | 7268 |
|
7235 | | - /* create the label */ |
7236 | | - create_label(cpstate->graph_name, edge->label, LABEL_TYPE_EDGE, |
7237 | | - parent); |
| 7269 | + /* create the label */ |
| 7270 | + create_label(cpstate->graph_name, edge->label, LABEL_TYPE_EDGE, |
| 7271 | + parent); |
| 7272 | + } |
7238 | 7273 | } |
7239 | 7274 |
|
7240 | 7275 | /* lock the relation of the label */ |
@@ -7357,20 +7392,28 @@ transform_merge_cypher_node(cypher_parsestate *cpstate, List **target_list, |
7357 | 7392 | /* check to see if the label exists, create the label entry if it does not. */ |
7358 | 7393 | if (node->label && !label_exists(node->label, cpstate->graph_oid)) |
7359 | 7394 | { |
| 7395 | + LOCKTAG tag; |
| 7396 | + uint32 key; |
7360 | 7397 | List *parent; |
7361 | 7398 |
|
7362 | | - /* |
7363 | | - * setup the default vertex table as the parent table, that we |
7364 | | - * will inherit from. |
7365 | | - */ |
7366 | | - rv = get_label_range_var(cpstate->graph_name, cpstate->graph_oid, |
7367 | | - AG_DEFAULT_LABEL_VERTEX); |
| 7399 | + key = hash_bytes((const unsigned char *)node->label, strlen(node->label)); |
| 7400 | + SET_LOCKTAG_ADVISORY(tag, MyDatabaseId, key, cpstate->graph_oid, 3); |
| 7401 | + (void) LockAcquire(&tag, ExclusiveLock, false, false); |
| 7402 | + if (!label_exists(node->label, cpstate->graph_oid)) |
| 7403 | + { |
| 7404 | + /* |
| 7405 | + * setup the default vertex table as the parent table, that we |
| 7406 | + * will inherit from. |
| 7407 | + */ |
| 7408 | + rv = get_label_range_var(cpstate->graph_name, cpstate->graph_oid, |
| 7409 | + AG_DEFAULT_LABEL_VERTEX); |
7368 | 7410 |
|
7369 | | - parent = list_make1(rv); |
| 7411 | + parent = list_make1(rv); |
7370 | 7412 |
|
7371 | | - /* create the label */ |
7372 | | - create_label(cpstate->graph_name, node->label, LABEL_TYPE_VERTEX, |
7373 | | - parent); |
| 7413 | + /* create the label */ |
| 7414 | + create_label(cpstate->graph_name, node->label, LABEL_TYPE_VERTEX, |
| 7415 | + parent); |
| 7416 | + } |
7374 | 7417 | } |
7375 | 7418 |
|
7376 | 7419 | rel->flags |= CYPHER_TARGET_NODE_FLAG_INSERT; |
|
0 commit comments