refactor(server): support update TTL in labels & enhance configs (#2938)

This commit is contained in:
imbajin 2026-01-22 16:38:44 +08:00 committed by GitHub
parent 37be6cdde3
commit e0f572b54c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 291 additions and 49 deletions

View File

@ -18,9 +18,8 @@
github:
features:
issues: true
# Enable wiki for documentation
wiki: true
# Enable projects for project management boards
# Enable projects for project (task)management boards
projects: true
discussions: true
description: A graph database that supports more than 100+ billion data, high performance and scalability (Include OLTP Engine & REST-API & Backends)
@ -46,11 +45,12 @@ github:
required_pull_request_reviews:
dismiss_stale_reviews: true
require_code_owner_reviews: false
required_approving_review_count: 2
required_approving_review_count: 1
# (for non-committer): assign/edit/close issues & PR, without write access to the code
collaborators:
- Pengzna
- haohao0103
- kenssa4eedfd
- Tsukilc
# refer https://cwiki.apache.org/confluence/display/INFRA/Git+-+.asf.yaml+features#Git.asf.yamlfeatures-Notificationsettingsforrepositories
notifications:

View File

@ -389,7 +389,7 @@ public class ServerOptions extends OptionHolder {
"batch.max_vertices_per_batch",
"The maximum number of vertices submitted per batch.",
positiveInt(),
500
2500
);
public static final ConfigOption<Integer> MAX_EDGES_PER_BATCH =
@ -397,7 +397,7 @@ public class ServerOptions extends OptionHolder {
"batch.max_edges_per_batch",
"The maximum number of edges submitted per batch.",
positiveInt(),
500
2500
);
public static final ConfigOption<Integer> MAX_WRITE_RATIO =
@ -406,7 +406,7 @@ public class ServerOptions extends OptionHolder {
"The maximum thread ratio for batch writing, " +
"only take effect if the batch.max_write_threads is 0.",
rangeInt(0, 100),
50
70
);
public static final ConfigOption<Integer> MAX_WRITE_THREADS =

View File

@ -61,7 +61,7 @@ public class EdgeLabelBuilder extends AbstractBuilder
private Set<String> properties;
private List<String> sortKeys;
private Set<String> nullableKeys;
private long ttl;
private Long ttl;
private String ttlStartTime;
private Boolean enableLabelIndex;
private Userdata userdata;
@ -80,7 +80,7 @@ public class EdgeLabelBuilder extends AbstractBuilder
this.properties = new HashSet<>();
this.sortKeys = new ArrayList<>();
this.nullableKeys = new HashSet<>();
this.ttl = 0L;
this.ttl = null;
this.ttlStartTime = null;
this.enableLabelIndex = null;
this.userdata = new Userdata();
@ -122,11 +122,7 @@ public class EdgeLabelBuilder extends AbstractBuilder
}
edgeLabel.frequency(this.frequency == Frequency.DEFAULT ?
Frequency.SINGLE : this.frequency);
edgeLabel.ttl(this.ttl);
if (this.ttlStartTime != null) {
edgeLabel.ttlStartTime(this.graph().propertyKey(
this.ttlStartTime).id());
}
this.updateTTL(edgeLabel);
edgeLabel.enableLabelIndex(this.enableLabelIndex == null ||
this.enableLabelIndex);
for (String key : this.properties) {
@ -209,7 +205,7 @@ public class EdgeLabelBuilder extends AbstractBuilder
this.checkSortKeys();
this.checkNullableKeys(Action.INSERT);
Userdata.check(this.userdata, Action.INSERT);
this.checkTtl();
this.checkTTL();
this.checkUserdata(Action.INSERT);
edgeLabel = this.build();
@ -312,6 +308,7 @@ public class EdgeLabelBuilder extends AbstractBuilder
PropertyKey propertyKey = this.graph().propertyKey(key);
edgeLabel.nullableKey(propertyKey.id());
}
this.updateTTL(edgeLabel);
edgeLabel.userdata(this.userdata);
this.graph().updateEdgeLabel(edgeLabel);
return edgeLabel;
@ -670,7 +667,35 @@ public class EdgeLabelBuilder extends AbstractBuilder
}
}
private void checkTtl() {
/**
* Update TTL in two cases:
* 1) ttl > 0L: set or change a positive TTL
* 2) ttl == 0L and existing ttl > 0L: explicitly clear an existing TTL
* This allows removing TTL from a label that previously had TTL configured.
* Note: ttl == null means not set, so we skip the update.
*/
private void updateTTL(EdgeLabel edgeLabel) {
if (this.ttl == null) {
return;
}
if (this.ttl > 0L) {
edgeLabel.ttl(this.ttl);
if (this.ttlStartTime != null) {
edgeLabel.ttlStartTime(this.graph().propertyKey(this.ttlStartTime).id());
}
} else if (this.ttl == 0L && edgeLabel.ttl() > 0L) {
// Clear TTL and ttlStartTime
edgeLabel.ttl(0L);
edgeLabel.ttlStartTime(IdGenerator.ZERO);
}
}
private void checkTTL() {
if (this.ttl == null) {
E.checkArgument(this.ttlStartTime == null,
"Can't set ttl start time if ttl is not set");
return;
}
E.checkArgument(this.ttl >= 0,
"The ttl must be >= 0, but got: %s", this.ttl);
if (this.ttl == 0L) {

View File

@ -52,7 +52,7 @@ public class VertexLabelBuilder extends AbstractBuilder implements VertexLabel.B
private final Set<String> properties;
private final List<String> primaryKeys;
private final Set<String> nullableKeys;
private long ttl;
private Long ttl;
private String ttlStartTime;
private Boolean enableLabelIndex;
private final Userdata userdata;
@ -68,7 +68,7 @@ public class VertexLabelBuilder extends AbstractBuilder implements VertexLabel.B
this.properties = new HashSet<>();
this.primaryKeys = new ArrayList<>();
this.nullableKeys = new HashSet<>();
this.ttl = 0L;
this.ttl = null;
this.ttlStartTime = null;
this.enableLabelIndex = null;
this.userdata = new Userdata();
@ -99,13 +99,8 @@ public class VertexLabelBuilder extends AbstractBuilder implements VertexLabel.B
this.id, this.name);
VertexLabel vertexLabel = new VertexLabel(this.graph(), id, this.name);
vertexLabel.idStrategy(this.idStrategy);
vertexLabel.enableLabelIndex(this.enableLabelIndex == null ||
this.enableLabelIndex);
vertexLabel.ttl(this.ttl);
if (this.ttlStartTime != null) {
vertexLabel.ttlStartTime(this.graph().propertyKey(
this.ttlStartTime).id());
}
vertexLabel.enableLabelIndex(this.enableLabelIndex == null || this.enableLabelIndex);
this.updateTTL(vertexLabel);
// Assign properties
for (String key : this.properties) {
PropertyKey propertyKey = this.graph().propertyKey(key);
@ -142,7 +137,7 @@ public class VertexLabelBuilder extends AbstractBuilder implements VertexLabel.B
this.checkIdStrategy();
this.checkNullableKeys(Action.INSERT);
Userdata.check(this.userdata, Action.INSERT);
this.checkTtl();
this.checkTTL();
this.checkUserdata(Action.INSERT);
vertexLabel = this.build();
@ -225,6 +220,7 @@ public class VertexLabelBuilder extends AbstractBuilder implements VertexLabel.B
PropertyKey propertyKey = this.graph().propertyKey(key);
vertexLabel.nullableKey(propertyKey.id());
}
this.updateTTL(vertexLabel);
vertexLabel.userdata(this.userdata);
this.graph().updateVertexLabel(vertexLabel);
return vertexLabel;
@ -276,8 +272,7 @@ public class VertexLabelBuilder extends AbstractBuilder implements VertexLabel.B
@Override
public VertexLabelBuilder idStrategy(IdStrategy idStrategy) {
E.checkArgument(this.idStrategy == IdStrategy.DEFAULT ||
this.idStrategy == idStrategy,
E.checkArgument(this.idStrategy == IdStrategy.DEFAULT || this.idStrategy == idStrategy,
"Not allowed to change id strategy for " +
"vertex label '%s'", this.name);
this.idStrategy = idStrategy;
@ -434,18 +429,15 @@ public class VertexLabelBuilder extends AbstractBuilder implements VertexLabel.B
if (action == Action.ELIMINATE) {
if (!this.nullableKeys.isEmpty()) {
throw new NotAllowException(
"Not support to eliminate nullableKeys " +
"for vertex label currently");
"Not support to eliminate nullableKeys for vertex label currently");
}
return;
}
VertexLabel vertexLabel = this.vertexLabelOrNull(this.name);
// The originProps is empty when firstly create vertex label
List<String> originProps = vertexLabel == null ?
ImmutableList.of() :
this.graph()
.mapPkId2Name(vertexLabel.properties());
List<String> originProps = vertexLabel == null ? ImmutableList.of() :
this.graph().mapPkId2Name(vertexLabel.properties());
Set<String> appendProps = this.properties;
E.checkArgument(CollectionUtil.union(originProps, appendProps)
@ -454,10 +446,8 @@ public class VertexLabelBuilder extends AbstractBuilder implements VertexLabel.B
"must belong to the origin/new properties: %s/%s",
this.nullableKeys, originProps, appendProps);
List<String> primaryKeys = vertexLabel == null ?
this.primaryKeys :
this.graph()
.mapPkId2Name(vertexLabel.primaryKeys());
List<String> primaryKeys = vertexLabel == null ? this.primaryKeys :
this.graph().mapPkId2Name(vertexLabel.primaryKeys());
E.checkArgument(!CollectionUtil.hasIntersection(primaryKeys,
this.nullableKeys),
"The nullableKeys: %s are not allowed to " +
@ -465,11 +455,9 @@ public class VertexLabelBuilder extends AbstractBuilder implements VertexLabel.B
this.nullableKeys, primaryKeys, this.name);
if (action == Action.APPEND) {
Collection<String> newAddedProps = CollectionUtils.subtract(
appendProps, originProps);
Collection<String> newAddedProps = CollectionUtils.subtract(appendProps, originProps);
E.checkArgument(this.nullableKeys.containsAll(newAddedProps),
"The new added properties: %s must be nullable",
newAddedProps);
"The new added properties: %s must be nullable", newAddedProps);
}
}
@ -498,8 +486,7 @@ public class VertexLabelBuilder extends AbstractBuilder implements VertexLabel.B
"when using '%s' id strategy", strategy);
break;
default:
throw new AssertionError(String.format(
"Unknown id strategy '%s'", strategy));
throw new AssertionError(String.format("Unknown id strategy '%s'", strategy));
}
if (this.idStrategy == IdStrategy.PRIMARY_KEY) {
this.checkPrimaryKeys();
@ -546,7 +533,35 @@ public class VertexLabelBuilder extends AbstractBuilder implements VertexLabel.B
}
}
private void checkTtl() {
/**
* Update TTL in two cases:
* 1) ttl > 0L: set or change a positive TTL
* 2) ttl == 0L and existing ttl > 0L: explicitly clear an existing TTL
* This allows removing TTL from a label that previously had TTL configured.
* Note: ttl == null means not set, so we skip the update.
*/
private void updateTTL(VertexLabel vertexLabel) {
if (this.ttl == null) {
return;
}
if (this.ttl > 0L) {
vertexLabel.ttl(this.ttl);
if (this.ttlStartTime != null) {
vertexLabel.ttlStartTime(this.graph().propertyKey(this.ttlStartTime).id());
}
} else if (this.ttl == 0L && vertexLabel.ttl() > 0L) {
// Clear TTL and ttlStartTime
vertexLabel.ttl(0L);
vertexLabel.ttlStartTime(IdGenerator.ZERO);
}
}
private void checkTTL() {
if (this.ttl == null) {
E.checkArgument(this.ttlStartTime == null,
"Can't set ttl start time if ttl is not set");
return;
}
E.checkArgument(this.ttl >= 0,
"The ttl must be >= 0, but got: %s", this.ttl);
if (this.ttl == 0L) {
@ -588,8 +603,7 @@ public class VertexLabelBuilder extends AbstractBuilder implements VertexLabel.B
// pass
break;
default:
throw new AssertionError(String.format(
"Unknown schema action '%s'", action));
throw new AssertionError(String.format("Unknown schema action '%s'", action));
}
}

View File

@ -480,7 +480,7 @@ public class EdgeLabelCoreTest extends SchemaCoreTest {
}
@Test
public void testAddEdgeLabelWithTtl() {
public void testAddEdgeLabelWithTTL() {
super.initPropertyKeys();
SchemaManager schema = graph().schema();
@ -561,6 +561,124 @@ public class EdgeLabelCoreTest extends SchemaCoreTest {
assertContainsPk(ImmutableSet.of(write.ttlStartTime()), "date");
}
@Test
public void testAppendEdgeLabelWithTTL() {
super.initPropertyKeys();
SchemaManager schema = graph().schema();
schema.propertyKey("date").asDate().ifNotExist().create();
schema.vertexLabel("person")
.properties("name", "age", "city")
.primaryKeys("name")
.nullableKeys("city")
.create();
schema.vertexLabel("book")
.properties("name")
.primaryKeys("name")
.create();
// Create an edge label without TTL
EdgeLabel read = schema.edgeLabel("read").link("person", "book")
.properties("date", "weight")
.create();
Assert.assertNotNull(read);
Assert.assertEquals("read", read.name());
Assert.assertEquals(0L, read.ttl());
// Update the edge label with TTL via append
read = schema.edgeLabel("read")
.ttl(86400L)
.append();
Assert.assertNotNull(read);
Assert.assertEquals("read", read.name());
Assert.assertEquals(86400L, read.ttl());
}
@Test
public void testAppendEdgeLabelResetTTL() {
super.initPropertyKeys();
SchemaManager schema = graph().schema();
schema.vertexLabel("person")
.properties("name", "age", "city")
.primaryKeys("name")
.nullableKeys("city")
.create();
schema.vertexLabel("book")
.properties("name")
.primaryKeys("name")
.create();
// Create an edge label with TTL
EdgeLabel read = schema.edgeLabel("read").link("person", "book")
.properties("time", "weight")
.ttl(86400L)
.create();
Assert.assertNotNull(read);
Assert.assertEquals("read", read.name());
Assert.assertEquals(86400L, read.ttl());
// Reset TTL to 0 via append
read = schema.edgeLabel("read")
.ttl(0L)
.append();
Assert.assertNotNull(read);
Assert.assertEquals("read", read.name());
Assert.assertEquals(0L, read.ttl());
}
@Test
public void testAppendEdgeLabelWithoutTTLShouldNotClearExistingTTL() {
super.initPropertyKeys();
SchemaManager schema = graph().schema();
schema.propertyKey("date").asDate().ifNotExist().create();
schema.vertexLabel("person")
.properties("name", "age", "city")
.primaryKeys("name")
.nullableKeys("city")
.create();
schema.vertexLabel("book")
.properties("name")
.primaryKeys("name")
.create();
// Create edge label with TTL and ttlStartTime
EdgeLabel read = schema.edgeLabel("read").link("person", "book")
.properties("date", "weight")
.ttl(86400L)
.ttlStartTime("date")
.create();
Assert.assertNotNull(read);
Assert.assertEquals(86400L, read.ttl());
Assert.assertNotNull(read.ttlStartTime());
assertContainsPk(ImmutableSet.of(read.ttlStartTime()), "date");
// Append property WITHOUT specifying ttl
read = schema.edgeLabel("read")
.nullableKeys("weight")
.append();
// Both TTL and ttlStartTime should remain unchanged
Assert.assertNotNull(read);
Assert.assertEquals(86400L, read.ttl());
Assert.assertNotNull(read.ttlStartTime());
assertContainsPk(ImmutableSet.of(read.ttlStartTime()), "date");
}
@Test
public void testAppendEdgeLabelWithUndefinedNullableKeys() {
super.initPropertyKeys();

View File

@ -566,7 +566,7 @@ public class VertexLabelCoreTest extends SchemaCoreTest {
}
@Test
public void testAddVertexLabelWithTtl() {
public void testAddVertexLabelWithTTL() {
super.initPropertyKeys();
SchemaManager schema = graph().schema();
@ -633,6 +633,91 @@ public class VertexLabelCoreTest extends SchemaCoreTest {
assertContainsPk(ImmutableSet.of(student.ttlStartTime()), "born");
}
@Test
public void testAppendVertexLabelWithTTL() {
super.initPropertyKeys();
SchemaManager schema = graph().schema();
schema.propertyKey("born").asDate().ifNotExist().create();
// Create a vertex label without TTL
VertexLabel person = schema.vertexLabel("person")
.properties("name", "age", "city", "born")
.create();
Assert.assertNotNull(person);
Assert.assertEquals("person", person.name());
Assert.assertEquals(0L, person.ttl());
// Update the vertex label with TTL via append
person = schema.vertexLabel("person")
.ttl(86400L)
.append();
Assert.assertNotNull(person);
Assert.assertEquals("person", person.name());
Assert.assertEquals(86400L, person.ttl());
}
@Test
public void testAppendVertexLabelResetTTL() {
super.initPropertyKeys();
SchemaManager schema = graph().schema();
// Create a vertex label with TTL
VertexLabel person = schema.vertexLabel("person")
.properties("name", "age", "city")
.ttl(86400L)
.create();
Assert.assertNotNull(person);
Assert.assertEquals("person", person.name());
Assert.assertEquals(86400L, person.ttl());
// Reset TTL to 0 via append
person = schema.vertexLabel("person")
.ttl(0L)
.append();
Assert.assertNotNull(person);
Assert.assertEquals("person", person.name());
Assert.assertEquals(0L, person.ttl());
}
@Test
public void testAppendVertexLabelWithoutTTLShouldNotClearExistingTTL() {
super.initPropertyKeys();
SchemaManager schema = graph().schema();
schema.propertyKey("born").asDate().ifNotExist().create();
// Create label with TTL and ttlStartTime
VertexLabel person = schema.vertexLabel("person")
.properties("name", "age", "city", "born")
.ttl(86400L)
.ttlStartTime("born")
.create();
Assert.assertNotNull(person);
Assert.assertEquals(86400L, person.ttl());
Assert.assertNotNull(person.ttlStartTime());
assertContainsPk(ImmutableSet.of(person.ttlStartTime()), "born");
// Append property WITHOUT specifying ttl
person = schema.vertexLabel("person")
.nullableKeys("city")
.append();
// Both TTL and ttlStartTime should remain unchanged
Assert.assertNotNull(person);
Assert.assertEquals(86400L, person.ttl());
Assert.assertNotNull(person.ttlStartTime());
assertContainsPk(ImmutableSet.of(person.ttlStartTime()), "born");
}
@Test
public void testAppendVertexLabelWithUndefinedNullableKeys() {
super.initPropertyKeys();