apache / apache/hugegraph

[Bug] unique-key index concurrent issue

Open
#2,334 0 comments 2 reactions 0 assignees View on GitHub
bug
Dominant language
Java
Stars
3.2k
Forks
636
Avg merge
3d 11h
Merged PRs (30d)
14

Description

### Bug Type (问题类型)

other exception / error (其他异常报错)

### Before submit

- [X] 我已经确认现有的 [Issues](https://github.com/apache/hugegraph/issues) 与 [FAQ](https://hugegraph.apache.org/docs/guides/faq/) 中没有相同 / 重复问题 (I have confirmed and searched that there are no similar problems in the historical issue and documents)

### Environment (环境信息)

unique key index is not valid when insert two vertex concurrently using mysql as backend store.

### Expected & Actual behavior (期望与实际表现)

![image](https://github.com/apache/incubator-hugegraph/assets/34210641/e54240ec-a5c9-4305-8093-f78305f19de9)

More than one element id can be found with the same index label and the same field value, which is unacceptable for production env. When I read the code, I found the following comment that made in 2019.
```java
Id id = element.id();
// TODO: add lock for updating unique index
if (!removed && this.existUniqueValue(indexLabel, value, id)) {
throw new IllegalArgumentException(String.format(
"Unique constraint %s conflict is found for %s",
indexLabel, element));
}
this.updateIndex(indexLabel, value, element.id(),
expiredTime, removed);
```
and if unique index update process is not lock-protected by now, the schema of mysql unique index table should not reuse the definition of secondary index and maybe change to use FIELD_VALUE and INDEX_LABEL_ID as primary keys. However, this is a break change and will impact lots of current users.
```java
public static class UniqueIndex extends SecondaryIndex {

public static final String TABLE = HugeType.UNIQUE_INDEX.name();

public UniqueIndex(String store) {
// should overwrite the constructor to not use the same keys with SecondaryIndex.
super(store, TABLE, TYPES_MAPPING);
}
}

public static class SecondaryIndex extends Index {

public static final String TABLE = HugeType.SECONDARY_INDEX.name();

public SecondaryIndex(String store) {
this(store, TABLE, TYPES_MAPPING);
}

public SecondaryIndex(String store, String table,
Map typesMapping) {
super(joinTableName(store, table));

this.define = new TableDefine(typesMapping);
this.define.column(HugeKeys.FIELD_VALUES, SMALL_TEXT);
this.define.column(HugeKeys.INDEX_LABEL_ID, DATATYPE_IL);
this.define.column(HugeKeys.ELEMENT_IDS, SMALL_TEXT);
this.define.column(HugeKeys.EXPIRED_TIME, BIGINT);
this.define.keys(HugeKeys.FIELD_VALUES,
HugeKeys.INDEX_LABEL_ID,
HugeKeys.ELEMENT_IDS);
}

@Override
public final String entryId(MysqlBackendEntry entry) {
String fieldValues = entry.column(HugeKeys.FIELD_VALUES);
Integer labelId = entry.column(HugeKeys.INDEX_LABEL_ID);
return SplicingIdGenerator.concat(fieldValues, labelId.toString());
}
}
```
To be honest, it's a little bit frustrating.

### Vertex/Edge example (问题点 / 边数据举例)

_No response_

### Schema [VertexLabel, EdgeLabel, IndexLabel] (元数据结构)

_No response_

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.