Skip to content

Commit 8b8bb00

Browse files
sevevmergify[bot]
authored andcommitted
[BugFix] Carry forward untouched indexes into the file-bundling bundle on compaction publish (#76105)
Signed-off-by: sevev <qiangzh95@gmail.com> (cherry picked from commit 35c68c6) # Conflicts: # fe/fe-core/src/main/java/com/starrocks/transaction/PublishVersionDaemon.java
1 parent d575d92 commit 8b8bb00

2 files changed

Lines changed: 256 additions & 0 deletions

File tree

fe/fe-core/src/main/java/com/starrocks/transaction/PublishVersionDaemon.java

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import com.starrocks.catalog.Tablet;
4545
import com.starrocks.common.Config;
4646
import com.starrocks.common.ErrorCode;
47+
import com.starrocks.common.NoAliveBackendException;
4748
import com.starrocks.common.StarRocksException;
4849
import com.starrocks.common.ThreadPoolManager;
4950
import com.starrocks.common.util.FrontendDaemon;
@@ -55,12 +56,19 @@
5556
import com.starrocks.lake.Utils;
5657
import com.starrocks.lake.compaction.Quantiles;
5758
import com.starrocks.metric.MetricRepo;
59+
import com.starrocks.proto.AggregatePublishVersionRequest;
5860
import com.starrocks.proto.DeleteTxnLogRequest;
5961
import com.starrocks.proto.DeleteTxnLogResponse;
6062
import com.starrocks.proto.TabletStatPB;
6163
import com.starrocks.proto.TxnInfoPB;
64+
<<<<<<< HEAD
65+
=======
66+
import com.starrocks.proto.TxnTypePB;
67+
import com.starrocks.proto.VectorIndexBuildInfoPB;
68+
>>>>>>> 35c68c6305 ([BugFix] Carry forward untouched indexes into the file-bundling bundle on compaction publish (#76105))
6269
import com.starrocks.rpc.BrpcProxy;
6370
import com.starrocks.rpc.LakeService;
71+
import com.starrocks.rpc.RpcException;
6472
import com.starrocks.server.GlobalStateMgr;
6573
import com.starrocks.server.RunMode;
6674
import com.starrocks.server.WarehouseManager;
@@ -597,6 +605,7 @@ public boolean publishPartitionBatch(Database db, long tableId, PartitionPublish
597605
// The mapping is shadow index id -> ShadowIndexTxnBatch
598606
Map<Long, ShadowIndexTxnBatch> shadowIndexTxnBatches = null;
599607
Set<Tablet> normalTablets = null;
608+
List<Tablet> carryForwardTablets = null;
600609

601610
Locker locker = new Locker();
602611
locker.lockTablesWithIntensiveDbLock(db.getId(), Lists.newArrayList(tableId), LockType.READ);
@@ -626,6 +635,7 @@ public boolean publishPartitionBatch(Database db, long tableId, PartitionPublish
626635
}
627636

628637
useAggregatePublish = table.isFileBundling();
638+
Set<Long> publishedNormalIndexIds = Sets.newHashSet();
629639
for (int i = 0; i < transactionStates.size(); i++) {
630640
TransactionState txnState = transactionStates.get(i);
631641
computeResource = txnState.getComputeResource();
@@ -650,9 +660,21 @@ public boolean publishPartitionBatch(Database db, long tableId, PartitionPublish
650660
} else {
651661
normalTablets = (normalTablets == null) ? Sets.newHashSet() : normalTablets;
652662
normalTablets.addAll(index.getTablets());
663+
publishedNormalIndexIds.add(index.getId());
653664
}
654665
}
655666
}
667+
// File bundling stores the metadata of ALL tablets of a partition version in a single bundle file.
668+
// The batched transactions' index views are point-in-time (for lake compaction snapshotted at txn
669+
// begin); if a rollup/MV index became visible after they began, none of them touch it, so publishing
670+
// the new version would write a bundle WITHOUT that index's tablets and permanently wedge the
671+
// partition. Carry forward every currently-visible NORMAL index none of these transactions touched
672+
// so the new bundle stays a complete whole-partition snapshot. See collectFileBundlingCarryForwardTablets.
673+
if (useAggregatePublish) {
674+
carryForwardTablets = collectFileBundlingCarryForwardTablets(
675+
partition.getLatestMaterializedIndices(MaterializedIndex.IndexExtState.VISIBLE),
676+
publishedNormalIndexIds);
677+
}
656678
} finally {
657679
locker.unLockTablesWithIntensiveDbLock(db.getId(), Lists.newArrayList(tableId), LockType.READ);
658680
}
@@ -695,7 +717,15 @@ public boolean publishPartitionBatch(Database db, long tableId, PartitionPublish
695717
if (!useAggregatePublish) {
696718
Utils.publishVersionBatch(publishTablets, txnInfos,
697719
startVersion - 1, endVersion, compactionScores, nodeToTablets,
720+
<<<<<<< HEAD
698721
computeResource, tabletStats);
722+
=======
723+
computeResource, tabletStats, vectorIndexBuildInfos);
724+
} else if (CollectionUtils.isNotEmpty(carryForwardTablets)) {
725+
aggregatePublishWithCarryForward(publishTablets, txnInfos, carryForwardTablets,
726+
startVersion - 1, endVersion, nodeToTablets, computeResource, compactionScores,
727+
tabletStats, vectorIndexBuildInfos);
728+
>>>>>>> 35c68c6305 ([BugFix] Carry forward untouched indexes into the file-bundling bundle on compaction publish (#76105))
699729
} else {
700730
Utils.aggregatePublishVersion(publishTablets, txnInfos, startVersion - 1, endVersion,
701731
compactionScores, nodeToTablets, computeResource, tabletStats);
@@ -1038,6 +1068,7 @@ private boolean publishPartition(@NotNull Database db, @NotNull TableCommitInfo
10381068
ComputeResource computeResource = txnState.getComputeResource();
10391069
List<Tablet> normalTablets = null;
10401070
List<Tablet> shadowTablets = null;
1071+
List<Tablet> carryForwardTablets = null;
10411072

10421073
Locker locker = new Locker();
10431074
locker.lockTablesWithIntensiveDbLock(db.getId(), Lists.newArrayList(tableId), LockType.READ);
@@ -1064,6 +1095,7 @@ private boolean publishPartition(@NotNull Database db, @NotNull TableCommitInfo
10641095
}
10651096
baseVersion = partition.getVisibleVersion();
10661097
List<MaterializedIndex> indexes = txnState.getPartitionLoadedIndexes(table.getId(), partition);
1098+
Set<Long> publishedNormalIndexIds = Sets.newHashSet();
10671099
for (MaterializedIndex index : indexes) {
10681100
if (!index.visibleForTransaction(txnId)) {
10691101
LOG.info("Ignored index {} for transaction {}", table.getIndexNameByMetaId(index.getMetaId()), txnId);
@@ -1075,8 +1107,23 @@ private boolean publishPartition(@NotNull Database db, @NotNull TableCommitInfo
10751107
} else {
10761108
normalTablets = (normalTablets == null) ? Lists.newArrayList() : normalTablets;
10771109
normalTablets.addAll(index.getTablets());
1110+
publishedNormalIndexIds.add(index.getId());
10781111
}
10791112
}
1113+
// File bundling stores the metadata of ALL tablets of a partition version in a single bundle
1114+
// file (meta/0_<version>.meta). The index set above comes from the transaction's point-in-time
1115+
// view (for lake compaction it is snapshotted at txn begin). If a materialized-view/rollup
1116+
// index became visible after this transaction began, that stale view omits it, so publishing
1117+
// the new version would write a bundle WITHOUT the rollup index's tablets, dropping them from
1118+
// this version and permanently wedging the partition's publish queue (a later publish reading
1119+
// those tablets at this version gets a 404). Carry forward every currently-visible NORMAL index
1120+
// this transaction did not touch, so the new bundle remains a complete whole-partition snapshot.
1121+
// Only needed for file bundling; without it each tablet keeps its own per-version metadata file.
1122+
if (useAggregatePublish) {
1123+
carryForwardTablets = collectFileBundlingCarryForwardTablets(
1124+
partition.getLatestMaterializedIndices(MaterializedIndex.IndexExtState.VISIBLE),
1125+
publishedNormalIndexIds);
1126+
}
10801127
} finally {
10811128
locker.unLockTablesWithIntensiveDbLock(db.getId(), Lists.newArrayList(tableId), LockType.READ);
10821129
}
@@ -1092,8 +1139,20 @@ private boolean publishPartition(@NotNull Database db, @NotNull TableCommitInfo
10921139
// Per-tablet stats from the publish response: first-load row counts for statistics
10931140
// collection, and range-distribution tablet sizes for real-time reshard triggering.
10941141
Map<Long, TabletStatPB> tabletStats = new HashMap<>();
1142+
<<<<<<< HEAD
10951143
Utils.publishVersion(normalTablets, txnInfo, baseVersion, txnVersion, compactionScores,
10961144
computeResource, tabletStats, useAggregatePublish);
1145+
=======
1146+
List<VectorIndexBuildInfoPB> vectorIndexBuildInfos = new ArrayList<>();
1147+
if (useAggregatePublish && CollectionUtils.isNotEmpty(carryForwardTablets)) {
1148+
aggregatePublishWithCarryForward(normalTablets, Lists.newArrayList(txnInfo), carryForwardTablets,
1149+
baseVersion, txnVersion, null, computeResource, compactionScores, tabletStats,
1150+
vectorIndexBuildInfos);
1151+
} else {
1152+
Utils.publishVersion(normalTablets, txnInfo, baseVersion, txnVersion, compactionScores,
1153+
computeResource, tabletStats, useAggregatePublish, vectorIndexBuildInfos);
1154+
}
1155+
>>>>>>> 35c68c6305 ([BugFix] Carry forward untouched indexes into the file-bundling bundle on compaction publish (#76105))
10971156

10981157
Quantiles quantiles = Quantiles.compute(compactionScores.values());
10991158
partitionCommitInfo.setCompactionScore(quantiles);
@@ -1120,6 +1179,68 @@ private boolean publishPartition(@NotNull Database db, @NotNull TableCommitInfo
11201179
}
11211180
}
11221181

1182+
// For file bundling only: from the partition's currently-visible indexes, return the tablets of every
1183+
// NORMAL index that this transaction did not touch (i.e. whose index id is not in publishedNormalIndexIds).
1184+
// These must be carried forward (empty version bump) into the new version's bundle so it stays a complete
1185+
// whole-partition snapshot; otherwise a transaction with a stale index view (notably lake compaction
1186+
// whose loaded-index set is snapshotted at txn begin, before a rollup/MV index became visible) would
1187+
// publish a bundle missing that index and permanently wedge the partition. Returns null when nothing
1188+
// needs carrying forward (e.g. a normal load already covers every visible index). Caller must hold the
1189+
// table read lock while obtaining visibleIndexes.
1190+
static List<Tablet> collectFileBundlingCarryForwardTablets(List<MaterializedIndex> visibleIndexes,
1191+
Set<Long> publishedNormalIndexIds) {
1192+
List<Tablet> carryForwardTablets = null;
1193+
for (MaterializedIndex index : visibleIndexes) {
1194+
if (index.getState() == MaterializedIndex.IndexState.SHADOW
1195+
|| publishedNormalIndexIds.contains(index.getId())) {
1196+
continue;
1197+
}
1198+
carryForwardTablets = (carryForwardTablets == null) ? Lists.newArrayList() : carryForwardTablets;
1199+
carryForwardTablets.addAll(index.getTablets());
1200+
}
1201+
return carryForwardTablets;
1202+
}
1203+
1204+
// File bundling only. Publish the touched tablets (this publish's real transactions) together with the
1205+
// carry-forward tablets (untouched but currently-visible indexes) in ONE aggregate request, so the whole
1206+
// partition's metadata for the new version lands in a single bundle file (meta/0_<newVersion>.meta). Two
1207+
// separate aggregate publishes would each truncate-write that same bundle and lose one of the two sets.
1208+
//
1209+
// The carry-forward tablets have no txn log for these transactions, so for every real transaction we emit a
1210+
// matching no-op empty transaction (no_op_publish=true): the BE bypasses log loading and advances the tablet
1211+
// version without any data change. The count must match the real transactions because the BE requires
1212+
// new_version == base_version + txns.size() for a multi-transaction batch (a batch of pre-rollup compactions
1213+
// can span several versions).
1214+
static void aggregatePublishWithCarryForward(List<Tablet> touchedTablets, List<TxnInfoPB> txnInfos,
1215+
List<Tablet> carryForwardTablets, long baseVersion,
1216+
long newVersion, Map<ComputeNode, List<Long>> nodeToTablets,
1217+
ComputeResource computeResource,
1218+
Map<Long, Double> compactionScores,
1219+
Map<Long, TabletStatPB> tabletStats,
1220+
List<VectorIndexBuildInfoPB> vectorIndexBuildInfos)
1221+
throws NoAliveBackendException, RpcException {
1222+
AggregatePublishVersionRequest request = new AggregatePublishVersionRequest();
1223+
Utils.createSubRequestForAggregatePublish(touchedTablets, txnInfos, baseVersion, newVersion,
1224+
nodeToTablets, computeResource, request);
1225+
1226+
List<TxnInfoPB> carryForwardTxnInfos = Lists.newArrayListWithCapacity(txnInfos.size());
1227+
for (TxnInfoPB txnInfo : txnInfos) {
1228+
TxnInfoPB emptyTxnInfo = new TxnInfoPB();
1229+
emptyTxnInfo.txnId = -1L;
1230+
emptyTxnInfo.combinedTxnLog = false;
1231+
emptyTxnInfo.commitTime = txnInfo.commitTime;
1232+
emptyTxnInfo.txnType = TxnTypePB.TXN_EMPTY;
1233+
emptyTxnInfo.gtid = txnInfo.gtid;
1234+
emptyTxnInfo.noOpPublish = true;
1235+
carryForwardTxnInfos.add(emptyTxnInfo);
1236+
}
1237+
// The carry-forward tablets have no txn log to delete on success, so do not thread nodeToTablets here.
1238+
Utils.createSubRequestForAggregatePublish(carryForwardTablets, carryForwardTxnInfos, baseVersion, newVersion,
1239+
null, computeResource, request);
1240+
Utils.sendAggregatePublishVersionRequest(request, baseVersion, computeResource, compactionScores, null,
1241+
tabletStats, vectorIndexBuildInfos);
1242+
}
1243+
11231244
// Per-partition publishPartition phase breakdown for slow outliers.
11241245
// total = executor_queue + db_lock_wait + fe_prep + rpc, where:
11251246
// executor_queue = CompletableFuture submit -> lambda entry

0 commit comments

Comments
 (0)