diff --git a/hugegraph-server/hugegraph-mysql/src/main/java/org/apache/hugegraph/backend/store/mysql/MysqlStore.java b/hugegraph-server/hugegraph-mysql/src/main/java/org/apache/hugegraph/backend/store/mysql/MysqlStore.java index c5d983feff..ea74c8a99e 100644 --- a/hugegraph-server/hugegraph-mysql/src/main/java/org/apache/hugegraph/backend/store/mysql/MysqlStore.java +++ b/hugegraph-server/hugegraph-mysql/src/main/java/org/apache/hugegraph/backend/store/mysql/MysqlStore.java @@ -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; @@ -54,7 +55,6 @@ public abstract class MysqlStore extends AbstractBackendStore { private final BackendStoreProvider provider; private final Map tables; - private MysqlSessions sessions; public MysqlStore(final BackendStoreProvider provider, @@ -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); } } @@ -345,6 +345,14 @@ protected Collection tables() { return this.tables.values(); } + protected Collection getTruncatedTables() { + // Exclude meta table to preserve system metadata during graph clear + return this.tables.entrySet().stream() + .filter(e -> !(HugeType.META == e.getKey())) + .map(Map.Entry::getValue) + .collect(Collectors.toList()); + } + @Override protected final MysqlTable table(HugeType type) { assert type != null; diff --git a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/UnitTestSuite.java b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/UnitTestSuite.java index 03d3479494..cdcceaedb8 100644 --- a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/UnitTestSuite.java +++ b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/UnitTestSuite.java @@ -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; @@ -130,6 +132,7 @@ /* mysql */ MysqlUtilTest.class, WhereBuilderTest.class, + MysqlTest.class, /* rocksdb */ RocksDBSessionsTest.class, diff --git a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/mysql/BaseMysqlUnitTest.java b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/mysql/BaseMysqlUnitTest.java new file mode 100644 index 0000000000..03d77ae2ec --- /dev/null +++ b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/mysql/BaseMysqlUnitTest.java @@ -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); + } + } + } +} diff --git a/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/mysql/MysqlTest.java b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/mysql/MysqlTest.java new file mode 100644 index 0000000000..84194821ed --- /dev/null +++ b/hugegraph-server/hugegraph-test/src/main/java/org/apache/hugegraph/unit/mysql/MysqlTest.java @@ -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 + 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()); + } + } +}