Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BugFix] Fix several problem for logical view restore #52291

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
import com.starrocks.catalog.OlapTable;
import com.starrocks.catalog.Partition;
import com.starrocks.catalog.Table;
import com.starrocks.catalog.View;
import com.starrocks.common.Config;
import com.starrocks.common.DdlException;
import com.starrocks.common.ErrorCode;
Expand Down Expand Up @@ -98,6 +99,7 @@
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;

import static com.starrocks.scheduler.MVActiveChecker.MV_BACKUP_INACTIVE_REASON;

Expand Down Expand Up @@ -437,14 +439,21 @@ private void restore(Repository repository, Database db, RestoreStmt stmt) throw
// Also remove all unrelated objs
Preconditions.checkState(infos.size() == 1);
BackupJobInfo jobInfo = infos.get(0);

BackupMeta backupMeta = downloadAndDeserializeMetaInfo(jobInfo, repository, stmt);

// If TableRefs is empty, it means that we do not specify any table in Restore stmt.
// So, we should restore all table in current database.
if (stmt.getTableRefs().size() != 0) {
checkAndFilterRestoreObjsExistInSnapshot(jobInfo, stmt.getTableRefs());
List<View> restoredViews = Lists.newArrayList();
if (backupMeta != null) {
if (stmt.getTableRefs().size() != 0) {
checkAndFilterRestoreObjsExistInSnapshot(jobInfo, stmt.getTableRefs(), backupMeta, restoredViews);
} else {
restoredViews = backupMeta.getTables().values().stream().filter(Table::isOlapView)
.map(x -> (View) x).collect(Collectors.toList());
}
}

BackupMeta backupMeta = downloadAndDeserializeMetaInfo(jobInfo, repository, stmt);

// Create a restore job
RestoreJob restoreJob = null;
if (backupMeta != null) {
Expand All @@ -461,6 +470,7 @@ private void restore(Repository repository, Database db, RestoreStmt stmt) throw
restoreJob = new RestoreJob(stmt.getLabel(), stmt.getBackupTimestamp(),
db.getId(), db.getOriginName(), jobInfo, stmt.allowLoad(), stmt.getReplicationNum(),
stmt.getTimeoutMs(), globalStateMgr, repository.getId(), backupMeta, mvRestoreContext);
restoreJob.setRestoredViews(restoredViews);
globalStateMgr.getEditLog().logRestoreJob(restoreJob);

// must put to dbIdToBackupOrRestoreJob after edit log, otherwise the state of job may be changed.
Expand Down Expand Up @@ -488,11 +498,22 @@ private BackupMeta downloadAndDeserializeMetaInfo(BackupJobInfo jobInfo, Reposit
return backupMetas.get(0);
}

private void checkAndFilterRestoreObjsExistInSnapshot(BackupJobInfo jobInfo, List<TableRef> tblRefs)
private void checkAndFilterRestoreObjsExistInSnapshot(BackupJobInfo jobInfo, List<TableRef> tblRefs, BackupMeta backupMeta,
List<View> restoredViews)
throws DdlException {
Set<String> allTbls = Sets.newHashSet();
for (TableRef tblRef : tblRefs) {
String tblName = tblRef.getName().getTbl();
Table tbl = backupMeta.getTable(tblName);
if (tbl != null && tbl.isOlapView()) {
if (tblRef.hasExplicitAlias()) {
// simple reset alias for view in backupMeta to be restored.
tbl.setName(tblRef.getExplicitAlias());
}
restoredViews.add((View) tbl);
continue;
}

if (!jobInfo.containsTbl(tblName)) {
ErrorReport.reportDdlException(ErrorCode.ERR_COMMON_ERROR,
"Table " + tblName + " does not exist in snapshot " + jobInfo.name);
Copy link

Choose a reason for hiding this comment

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

The most risky bug in this code is:
downloadAndDeserializeMetaInfo is called twice unnecessarily, which may lead to performance issues or unexpected behavior if the method has side effects.

You can modify the code like this:

// Move this line above the if condition
BackupMeta backupMeta = downloadAndDeserializeMetaInfo(jobInfo, repository, stmt);

// If TableRefs is empty, it means that we do not specify any table in Restore stmt.
// So, we should restore all table in current database.
if (stmt.getTableRefs().size() != 0) {
    checkAndFilterRestoreObjsExistInSnapshot(jobInfo, stmt.getTableRefs(), backupMeta);
}

// Removed redundant call to downloadAndDeserializeMetaInfo
// Create a restore job
RestoreJob restoreJob = null;
if (backupMeta != null) {

This change ensures that downloadAndDeserializeMetaInfo is called only once before its result is used in different logic branches.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,16 @@ private static void genFromJson(String json, BackupJobInfo jobInfo) {

JSONObject backupObjs = root.getJSONObject("backup_objects");
String[] tblNames = JSONObject.getNames(backupObjs);
if (tblNames == null) {
// it is possible for snapshot without any OlapTable or MV
String result = root.getString("backup_result");
if (result.equals("succeed")) {
jobInfo.success = true;
} else {
jobInfo.success = false;
}
return;
}
for (String tblName : tblNames) {
BackupTableInfo tblInfo = new BackupTableInfo();
tblInfo.name = tblName;
Expand Down
23 changes: 16 additions & 7 deletions fe/fe-core/src/main/java/com/starrocks/backup/RestoreJob.java
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,9 @@ public enum RestoreJobState {
private AgentBatchTask batchTask;

boolean enableColocateRestore = Config.enable_colocate_restore;

@SerializedName(value = "restoredViews")
private List<View> restoredViews = Lists.newArrayList();

public RestoreJob() {
super(JobType.RESTORE);
Expand Down Expand Up @@ -789,9 +792,7 @@ private void checkAndPrepareMeta() {
}

// add all restored olap view into globalStateMgr
List<View> restoredOlapViews = backupMeta.getTables().values().stream().filter(Table::isOlapView)
.map(x -> (View) x).collect(Collectors.toList());
addRestoreOlapView(restoredOlapViews);
addRestoreOlapView(restoredViews);
if (!status.ok()) {
return;
}
Expand Down Expand Up @@ -1170,14 +1171,13 @@ private void replayCheckAndPrepareMeta() {
modifyInvertedIndex((OlapTable) restoreTbl, restorePart);
}
}

// restored view need not to be added again here, because
// another edit log created by createView will done.
} finally {
locker.unLockDatabase(db.getId(), LockType.WRITE);
}

List<View> restoredOlapViews = backupMeta.getTables().values().stream().filter(Table::isOlapView)
.map(x -> (View) x).collect(Collectors.toList());
addRestoreOlapView(restoredOlapViews);

LOG.info("replay check and prepare meta. {}", this);
}

Expand Down Expand Up @@ -1622,6 +1622,10 @@ private void replayWaitingAllTabletsCommitted() {
allTabletCommitted(true /* is replay */);
}

public void setRestoredViews(List<View> restoredViews) {
this.restoredViews = restoredViews;
}

public List<String> getInfo() {
List<String> info = Lists.newArrayList();
info.add(String.valueOf(jobId));
Expand Down Expand Up @@ -1740,6 +1744,11 @@ public void cancelInternal(boolean isReplay) {

restoreTbl.dropPartition(dbId, entry.second.getName(), true /* is restore */);
}

// remove restored View
for (View restoredView : restoredViews) {
db.dropTable(restoredView.getName());
}
} finally {
locker.unLockDatabase(db.getId(), LockType.WRITE);
}
Expand Down
Loading