Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

import org.apache.hugegraph.backend.BackendException;
import org.apache.hugegraph.backend.id.Id;
Expand Down Expand Up @@ -54,7 +55,6 @@ public abstract class MysqlStore extends AbstractBackendStore<Session> {
private final BackendStoreProvider provider;

private final Map<HugeType, MysqlTable> tables;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Minor: Unnecessary whitespace change

This blank line removal is an unrelated formatting change. Please keep formatting changes separate from functional fixes to make code reviews easier.


private MysqlSessions sessions;

public MysqlStore(final BackendStoreProvider provider,
Expand Down Expand Up @@ -336,7 +336,7 @@ protected void clearTables() {

protected void truncateTables() {
Session session = this.sessions.session();
for (MysqlTable table : this.tables()) {
for (MysqlTable table : this.getTruncatedTables()) {
table.truncate(session);
}
}
Expand All @@ -345,6 +345,14 @@ protected Collection<MysqlTable> tables() {
return this.tables.values();
}

protected Collection<MysqlTable> getTruncatedTables() {
// Exclude meta table to preserve system metadata during graph clear
return this.tables.entrySet().stream()
.filter(e -> !(HugeType.META == e.getKey()))
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The comparison !(HugeType.META == e.getKey()) is unconventional. Consider using the more natural form: e.getKey() != HugeType.META

Suggested change
.filter(e -> !(HugeType.META == e.getKey()))
.filter(e -> e.getKey() != HugeType.META)

Copilot uses AI. Check for mistakes.
.map(Map.Entry::getValue)
.collect(Collectors.toList());
}

@Override
protected final MysqlTable table(HugeType type) {
assert type != null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@
import org.apache.hugegraph.unit.id.IdTest;
import org.apache.hugegraph.unit.id.IdUtilTest;
import org.apache.hugegraph.unit.id.SplicingIdGeneratorTest;
import org.apache.hugegraph.unit.mysql.BaseMysqlUnitTest;
import org.apache.hugegraph.unit.mysql.MysqlTest;
import org.apache.hugegraph.unit.mysql.MysqlUtilTest;
import org.apache.hugegraph.unit.mysql.WhereBuilderTest;
import org.apache.hugegraph.unit.rocksdb.RocksDBCountersTest;
Expand Down Expand Up @@ -130,6 +132,8 @@
/* mysql */
MysqlUtilTest.class,
WhereBuilderTest.class,
BaseMysqlUnitTest.class,
Copy link

Copilot AI Dec 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BaseMysqlUnitTest doesn't contain any test methods (no @Test annotations), so it shouldn't be included in the test suite. Only concrete test classes like MysqlTest should be registered here. Consider removing this line.

Copilot uses AI. Check for mistakes.
MysqlTest.class,

/* rocksdb */
RocksDBSessionsTest.class,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.hugegraph.unit.mysql;

import org.apache.commons.configuration2.Configuration;
import org.apache.hugegraph.backend.store.mysql.MysqlSessions;
import org.apache.hugegraph.backend.store.mysql.MysqlStoreProvider;
import org.apache.hugegraph.config.HugeConfig;
import org.apache.hugegraph.testutil.Utils;
import org.apache.hugegraph.unit.BaseUnitTest;
import org.junit.After;

public class BaseMysqlUnitTest extends BaseUnitTest {

private static final String GRAPH_NAME = "test_graph";

protected HugeConfig config;
protected MysqlStoreProvider provider;
protected MysqlSessions sessions;

public void setup() throws Exception {
Configuration conf = Utils.getConf();
this.config = new HugeConfig(conf);
this.provider = new MysqlStoreProvider();
this.provider.open(GRAPH_NAME);
this.provider.loadSystemStore(config).open(config);
this.provider.loadGraphStore(config).open(config);
this.provider.loadSchemaStore(config).open(config);
this.provider.init();
this.sessions = new MysqlSessions(config, GRAPH_NAME, this.provider.loadGraphStore(config).store());
this.sessions.open();
}

@After
public void down() {
if (this.provider != null) {
try {
this.provider.close();
} catch (Exception e) {
LOG.warn("Mysql provider close failed ", e);
}
}
if (this.sessions != null) {
try {
this.sessions.close();
} catch (Exception e) {
LOG.warn("Mysql sessions close failed ", e);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.hugegraph.unit.mysql;

import org.apache.hugegraph.backend.store.BackendStore;
import org.apache.hugegraph.backend.store.mysql.MysqlSessions;
import org.apache.hugegraph.backend.store.mysql.ResultSetWrapper;
import org.apache.hugegraph.testutil.Assert;
import org.junit.Before;
import org.junit.Test;

import java.sql.SQLException;

public class MysqlTest extends BaseMysqlUnitTest {

@Before
public void setUp() throws Exception {
super.setup();
}

@Test
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Important: Incomplete test coverage

The test only verifies that the version is preserved, but doesn't verify:

  1. That data in non-meta tables IS actually cleared - The bug could still exist if truncate silently fails
  2. That the Counters table content is preserved (if that's intentional)
  3. That schema data is cleared - The fix might have side effects on other stores

Suggested additions:

@Test
public void testMysqlTruncateClearsDataButPreservesMeta() {
    // 1. Insert some test data into graph store
    // 2. Record meta version before truncate
    // 3. Call truncate
    // 4. Verify meta version unchanged
    // 5. Verify test data was actually cleared
    // 6. Verify Counters table state (if needed)
}

public void testMysqlMetaVersion() throws SQLException {
BackendStore systemStore = this.provider.loadSystemStore(config);

// Record system version before truncation
String beforeVersion = systemStore.storedVersion();

// Get sessions for direct table operations
MysqlSessions.Session session = this.sessions.session();
session.open();

// Get the actual table names from the store
String vertexTable = "g_v";
String edgeOutTable = "g_oe";
String edgeInTable = "g_ie";

// Insert test vertex data directly using simple SQL
String insertVertex = String.format(
"INSERT INTO %s (ID, LABEL, PROPERTIES, EXPIRED_TIME) VALUES ('test_vertex', 1, " +
"'{\"name\":\"test_vertex\"}', 0)",
vertexTable
);
session.execute(insertVertex);

// Insert test edge data directly using simple SQL
String insertEdgeOut = String.format(
"INSERT INTO %s (OWNER_VERTEX, DIRECTION, LABEL, SUB_LABEL, SORT_VALUES, " +
"OTHER_VERTEX, PROPERTIES, EXPIRED_TIME) VALUES ('test_vertex', 0, 1, 0, '', " +
"'target_vertex', '{\"weight\":1.0}', 0)",
edgeOutTable
);
session.execute(insertEdgeOut);

String insertEdgeIn = String.format(
"INSERT INTO %s (OWNER_VERTEX, DIRECTION, LABEL, SUB_LABEL, SORT_VALUES, " +
"OTHER_VERTEX, PROPERTIES, EXPIRED_TIME) VALUES ('target_vertex', 1, 1, 0, '', " +
"'test_vertex', '{\"weight\":1.0}', 0)",
edgeInTable
);
session.execute(insertEdgeIn);

// Verify data exists by querying
String selectVertex = String.format("SELECT * FROM %s WHERE ID = 'test_vertex'", vertexTable);
String selectEdgeOut = String.format(
"SELECT * FROM %s WHERE OWNER_VERTEX = 'test_vertex' AND DIRECTION = 0",
edgeOutTable);
String selectEdgeIn = String.format(
"SELECT * FROM %s WHERE OWNER_VERTEX = 'target_vertex' AND DIRECTION = 1",
edgeInTable);
try (
ResultSetWrapper vResult = session.select(selectVertex);
ResultSetWrapper oeResult = session.select(selectEdgeOut);
ResultSetWrapper ieResult = session.select(selectEdgeIn);
) {
Assert.assertTrue("vertex data should exist", vResult.next());
Assert.assertTrue("out edge data should exist", oeResult.next());
Assert.assertTrue("in edge data should exist", ieResult.next());
}

// Execute truncate operation, clears all graph data but preserves system tables
this.provider.truncate();

// Verify system version remains unchanged after truncation
String afterVersion = systemStore.storedVersion();
Assert.assertNotNull("System metadata version should exist", afterVersion);
Assert.assertEquals("System metadata version should remain unchanged after truncation",
beforeVersion, afterVersion);

// Verify data has been cleared
try (
ResultSetWrapper vResult = session.select(selectVertex);
ResultSetWrapper oeResult = session.select(selectEdgeOut);
ResultSetWrapper ieResult = session.select(selectEdgeIn);
) {
Assert.assertFalse("vertex data should not exist", vResult.next());
Assert.assertFalse("out edge data should not exist", oeResult.next());
Assert.assertFalse("in edge data should not exist", ieResult.next());
}
}
}
Loading