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,7 @@
/* mysql */
MysqlUtilTest.class,
WhereBuilderTest.class,
MysqlTest.class,

/* rocksdb */
RocksDBSessionsTest.class,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* 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;
import org.junit.Assume;

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();
String backend = conf.getString("backend", "memory");
// Only run mysql related tests when backend is mysql
Assume.assumeTrue("Skip MySQL tests when backend is not mysql",
"mysql".equalsIgnoreCase(backend));
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