From b0f21c92c67e3e6737cab2194a5f5b2dd28292a9 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Mon, 2 Dec 2024 15:22:34 +0800 Subject: [PATCH] [BugFix] Fix the issue where FE restart fails when creating a table containing too many tablets (backport #53062) (#53354) Signed-off-by: gengjun-git Co-authored-by: gengjun-git --- .../java/com/starrocks/catalog/Database.java | 9 +++++ .../starrocks/journal/SerializeException.java | 21 ++++++++++ .../java/com/starrocks/persist/EditLog.java | 7 +++- .../com/starrocks/server/LocalMetastore.java | 5 +++ .../starrocks/server/LocalMetaStoreTest.java | 16 +++++++- .../server/SerializeFailedTable.java | 39 +++++++++++++++++++ 6 files changed, 94 insertions(+), 3 deletions(-) create mode 100644 fe/fe-core/src/main/java/com/starrocks/journal/SerializeException.java create mode 100644 fe/fe-core/src/test/java/com/starrocks/server/SerializeFailedTable.java diff --git a/fe/fe-core/src/main/java/com/starrocks/catalog/Database.java b/fe/fe-core/src/main/java/com/starrocks/catalog/Database.java index d2e5fce30ac5d..bace81d5566e5 100644 --- a/fe/fe-core/src/main/java/com/starrocks/catalog/Database.java +++ b/fe/fe-core/src/main/java/com/starrocks/catalog/Database.java @@ -482,6 +482,15 @@ public boolean registerTableUnlocked(Table table) { } } + public void unRegisterTableUnlocked(Table table) { + if (table == null) { + return; + } + + idToTable.remove(table.getId()); + nameToTable.remove(table.getName()); + } + public void dropTable(String tableName, boolean isSetIfExists, boolean isForce) throws DdlException { Table table; writeLock(); diff --git a/fe/fe-core/src/main/java/com/starrocks/journal/SerializeException.java b/fe/fe-core/src/main/java/com/starrocks/journal/SerializeException.java new file mode 100644 index 0000000000000..06389c0c552a3 --- /dev/null +++ b/fe/fe-core/src/main/java/com/starrocks/journal/SerializeException.java @@ -0,0 +1,21 @@ +// Copyright 2021-present StarRocks, Inc. All rights reserved. +// +// Licensed 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 +// +// https://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 com.starrocks.journal; + +public class SerializeException extends RuntimeException { + public SerializeException(String message) { + super(message); + } +} diff --git a/fe/fe-core/src/main/java/com/starrocks/persist/EditLog.java b/fe/fe-core/src/main/java/com/starrocks/persist/EditLog.java index 836ecada1c9f4..d0c523197b3c0 100644 --- a/fe/fe-core/src/main/java/com/starrocks/persist/EditLog.java +++ b/fe/fe-core/src/main/java/com/starrocks/persist/EditLog.java @@ -36,6 +36,7 @@ import com.google.common.base.Preconditions; import com.google.common.collect.Lists; +import com.google.gson.JsonParseException; import com.starrocks.alter.AlterJobV2; import com.starrocks.alter.BatchAlterJobPersistInfo; import com.starrocks.authentication.UserAuthenticationInfo; @@ -64,6 +65,7 @@ import com.starrocks.journal.JournalEntity; import com.starrocks.journal.JournalInconsistentException; import com.starrocks.journal.JournalTask; +import com.starrocks.journal.SerializeException; import com.starrocks.journal.bdbje.Timestamp; import com.starrocks.load.DeleteInfo; import com.starrocks.load.DeleteMgr; @@ -1169,9 +1171,10 @@ private JournalTask submitLog(short op, Writable writable, long maxWaitIntervalM entity.setOpCode(op); entity.setData(writable); entity.write(buffer); - } catch (IOException e) { + } catch (IOException | JsonParseException e) { // The old implementation swallow exception like this - LOG.info("failed to serialize, ", e); + LOG.info("failed to serialize journal data", e); + throw new SerializeException("failed to serialize journal data"); } JournalTask task = new JournalTask(startTimeNano, buffer, maxWaitIntervalMs); diff --git a/fe/fe-core/src/main/java/com/starrocks/server/LocalMetastore.java b/fe/fe-core/src/main/java/com/starrocks/server/LocalMetastore.java index b578a68671ddd..ff85534b03878 100644 --- a/fe/fe-core/src/main/java/com/starrocks/server/LocalMetastore.java +++ b/fe/fe-core/src/main/java/com/starrocks/server/LocalMetastore.java @@ -123,6 +123,7 @@ import com.starrocks.common.util.concurrent.CountingLatch; import com.starrocks.connector.ConnectorMetadata; import com.starrocks.connector.exception.StarRocksConnectorException; +import com.starrocks.journal.SerializeException; import com.starrocks.lake.DataCacheInfo; import com.starrocks.lake.LakeMaterializedView; import com.starrocks.lake.LakeTablet; @@ -2123,6 +2124,10 @@ void onCreate(Database db, Table table, String storageVolumeId, boolean isSetIfN CreateTableInfo createTableInfo = new CreateTableInfo(db.getFullName(), table, storageVolumeId); GlobalStateMgr.getCurrentState().getEditLog().logCreateTable(createTableInfo); table.onCreate(db); + } catch (SerializeException e) { + db.unRegisterTableUnlocked(table); + LOG.warn("create table failed", e); + ErrorReport.reportDdlException(ErrorCode.ERR_CANT_CREATE_TABLE, table.getName(), e.getMessage()); } finally { db.writeUnlock(); } diff --git a/fe/fe-core/src/test/java/com/starrocks/server/LocalMetaStoreTest.java b/fe/fe-core/src/test/java/com/starrocks/server/LocalMetaStoreTest.java index 0fcce55ee2c02..a3dbca912dff5 100644 --- a/fe/fe-core/src/test/java/com/starrocks/server/LocalMetaStoreTest.java +++ b/fe/fe-core/src/test/java/com/starrocks/server/LocalMetaStoreTest.java @@ -60,7 +60,7 @@ public static void beforeClass() throws Exception { Config.alter_scheduler_interval_millisecond = 1000; FeConstants.runningUnitTest = true; - UtFrameUtils.createMinStarRocksCluster(); + UtFrameUtils.createMinStarRocksCluster(true, RunMode.SHARED_NOTHING); // create connect context connectContext = UtFrameUtils.createDefaultCtx(); @@ -204,4 +204,18 @@ public void testAlterTableProperties() throws Exception { Assert.assertEquals("Cannot parse text to Duration", e.getMessage()); } } + + @Test + public void testCreateTableSerializeException() { + final long tableId = 1000010L; + final String tableName = "test"; + Database db = connectContext.getGlobalStateMgr().getLocalMetastore().getDb("test"); + LocalMetastore localMetastore = connectContext.getGlobalStateMgr().getLocalMetastore(); + SerializeFailedTable table = new SerializeFailedTable(1000010L, "serialize_test"); + + Assert.assertThrows(DdlException.class, () -> localMetastore.onCreate(db, table, "", true)); + + Assert.assertNull(db.getTable(tableId)); + Assert.assertNull(db.getTable(tableName)); + } } diff --git a/fe/fe-core/src/test/java/com/starrocks/server/SerializeFailedTable.java b/fe/fe-core/src/test/java/com/starrocks/server/SerializeFailedTable.java new file mode 100644 index 0000000000000..c0091cc44fdf5 --- /dev/null +++ b/fe/fe-core/src/test/java/com/starrocks/server/SerializeFailedTable.java @@ -0,0 +1,39 @@ +// Copyright 2021-present StarRocks, Inc. All rights reserved. +// +// Licensed 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 +// +// https://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 com.starrocks.server; + +import com.starrocks.catalog.Table; +import com.starrocks.persist.gson.GsonPreProcessable; + +import java.io.DataOutput; +import java.io.IOException; +import java.util.ArrayList; + +public class SerializeFailedTable extends Table implements GsonPreProcessable { + + public SerializeFailedTable(long id, String name) { + super(id, name, TableType.OLAP, new ArrayList<>()); + } + + @Override + public void write(DataOutput out) throws IOException { + throw new IOException("failed"); + } + + @Override + public void gsonPreProcess() throws IOException { + throw new IOException("failed"); + } +}