Skip to content

Commit 48b6964

Browse files
VioletQwQ-0ULookupmergify[bot]
authored
feat(auto-increment): add transactional epoch fence (#26027)
## What type of PR is this? - [x] API-change - [ ] BUG - [x] Improvement - [ ] Documentation - [ ] Feature - [x] Test and CI - [ ] Code Refactoring ## Which issue(s) this PR fixes: issue #23143 ## What this PR does / why we need it: This is the first AUTO_INCREMENT-specific prerequisite split from the closed #25883. It does not expose `ALTER TABLE ... AUTO_INCREMENT=N` yet. The invariant introduced here is: a CN write carries the AUTO_INCREMENT epoch observed when its values were allocated, and TN accepts the write only when that epoch matches the table epoch. Once a table enters a fenced epoch, legacy writers that cannot provide an epoch fail closed. | Correctness requirement | Change in this PR | | --- | --- | | Preserve the allocator generation across the write path | Persist the epoch in `SchemaExtra` / `plan.TableDef`, propagate it through disttae workspace, row and object writes, flush/compaction, RPC, and TN relations | | Prevent stale cached values from committing after a reset | Validate the known epoch at TN prepare/commit and require every epoch transition to be exactly `current + 1` | | Keep the fence effective after restart | Rebuild committed DML watermarks during replay and keep prepared replay transactions fenced until commit or rollback | | Remain compatible before the feature is enabled | Treat an unknown legacy epoch as zero only while the table epoch is zero; after the first reset, unknown writers are rejected | Additional guards reject epoch exhaustion before mutation and keep ordinary schema ALTER operations from advancing the AUTO_INCREMENT epoch. ### Explicit non-goals - no allocator offset/cache reset API; - no COPY/CLONE allocator reconciliation; - no user-facing `ALTER TABLE ... AUTO_INCREMENT=N` planner or compile entry point; - no generic prepared/committing 2PC recovery redesign. The independent TN route/cancellation prerequisite was merged in #25956. ### Diff size - handwritten code and tests: 23 files, `+1283/-131`; - generated protobuf code: 2 files, `+1565/-1079`; - total: 25 files. Proto sources and generated files are committed together. ### Validation - `go test ./pkg/vm/engine/disttae ./pkg/vm/engine/tae/catalog ./pkg/vm/engine/tae/rpc ./pkg/vm/engine/tae/txn/txnimpl ./pkg/vm/engine/tae/db/test` - focused `-race` coverage for epoch transitions and replay commit/rollback lifecycle - protobuf regeneration stability check - `git diff --check` - `mo-pr-preflight-review`: PASS at exact head `4122a7add078c79757121a4add2d8771113c7980` - `mo-self-review`: no open blocker The PR is intentionally Draft while its full CI runs and while this prerequisite is reviewed independently. --------- Co-authored-by: ULookup <CHBulookup@outlook.com> Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
1 parent f6070a0 commit 48b6964

25 files changed

Lines changed: 2848 additions & 1210 deletions

File tree

pkg/pb/api/api.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,19 @@ func CloneExtra(info *SchemaExtra) *SchemaExtra {
7676
FeatureFlag: info.FeatureFlag,
7777
IndexTables: append([]uint64{}, info.IndexTables...),
7878
ParentTableID: info.ParentTableID,
79+
AutoIncrOffset: info.AutoIncrOffset,
80+
AutoIncrEpoch: info.AutoIncrEpoch,
81+
}
82+
}
83+
84+
func NewUpdateAutoIncrementReq(did, tid, offset uint64, epoch uint32) *AlterTableReq {
85+
return &AlterTableReq{
86+
DbId: did,
87+
TableId: tid,
88+
Kind: AlterKind_UpdateAutoIncrement,
89+
Operation: &AlterTableReq_UpdateAutoIncrement{
90+
UpdateAutoIncrement: &AlterTableAutoIncrement{Offset: offset, Epoch: epoch},
91+
},
7992
}
8093
}
8194

pkg/pb/api/api.pb.go

Lines changed: 679 additions & 233 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/pb/plan/plan.pb.go

Lines changed: 886 additions & 846 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/sql/plan/deepcopy.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,7 @@ func DeepCopyTableDef(table *plan.TableDef, withCols bool) *plan.TableDef {
507507
TableLockType: table.TableLockType,
508508
IsTemporary: table.IsTemporary,
509509
AutoIncrOffset: table.AutoIncrOffset,
510+
AutoIncrEpoch: table.AutoIncrEpoch,
510511
DbName: table.DbName,
511512
DbId: table.DbId,
512513
FeatureFlag: table.FeatureFlag,

pkg/vm/engine/cmd_util/operations.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,13 @@ type WriteReq struct {
162162
TableID uint64
163163
DatabaseName string
164164
TableName string
165-
Schema *catalog2.Schema
166-
Batch *batch.Batch
165+
// AutoIncrEpoch is the allocator epoch used by CN to plan the write.
166+
// AutoIncrEpochKnown distinguishes a valid initial zero epoch from an
167+
// old CN that did not send the dependency.
168+
AutoIncrEpoch uint32
169+
AutoIncrEpochKnown bool
170+
Schema *catalog2.Schema
171+
Batch *batch.Batch
167172
//[IncrementalDedup|FullSkipWorkspaceDedup|FullDedup], default is IncrementalDedup.
168173
//If incremental-dedup in dn.toml is false, IncrementalDedup will be treated as FullSkipWorkspaceDedup.
169174
//IncrementalDedup do not check uniqueness of PK before txn's snapshot TS.

pkg/vm/engine/disttae/cache/catalog.go

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -853,24 +853,26 @@ func getTableDef(tblItem *TableItem, coldefs []engine.TableDef) (*plan.TableDef,
853853
}
854854

855855
return &plan.TableDef{
856-
TblId: tblItem.Id,
857-
Name: tblItem.Name,
858-
DbName: tblItem.DatabaseName,
859-
Cols: cols,
860-
Name2ColIndex: name2index,
861-
Defs: defs,
862-
TableType: TableType,
863-
Createsql: Createsql,
864-
Pkey: primarykey,
865-
ViewSql: viewSql,
866-
Fkeys: foreignKeys,
867-
RefChildTbls: refChildTbls,
868-
ClusterBy: clusterByDef,
869-
Indexes: indexes,
870-
Version: tblItem.Version,
871-
DbId: tblItem.DatabaseId,
872-
Partition: partition,
873-
FeatureFlag: tblItem.ExtraInfo.GetFeatureFlag(),
874-
LogicalId: tblItem.LogicalId,
856+
TblId: tblItem.Id,
857+
Name: tblItem.Name,
858+
DbName: tblItem.DatabaseName,
859+
Cols: cols,
860+
Name2ColIndex: name2index,
861+
Defs: defs,
862+
TableType: TableType,
863+
Createsql: Createsql,
864+
Pkey: primarykey,
865+
ViewSql: viewSql,
866+
Fkeys: foreignKeys,
867+
RefChildTbls: refChildTbls,
868+
ClusterBy: clusterByDef,
869+
Indexes: indexes,
870+
Version: tblItem.Version,
871+
DbId: tblItem.DatabaseId,
872+
Partition: partition,
873+
FeatureFlag: tblItem.ExtraInfo.GetFeatureFlag(),
874+
AutoIncrOffset: tblItem.ExtraInfo.GetAutoIncrOffset(),
875+
AutoIncrEpoch: tblItem.ExtraInfo.GetAutoIncrEpoch(),
876+
LogicalId: tblItem.LogicalId,
875877
}, tableDef
876878
}

pkg/vm/engine/disttae/tools.go

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -173,14 +173,16 @@ func toPBEntry(e Entry) (*api.Entry, error) {
173173
return nil, err
174174
}
175175
return &api.Entry{
176-
Bat: bat,
177-
EntryType: typ,
178-
TableId: e.tableId,
179-
DatabaseId: e.databaseId,
180-
TableName: e.tableName,
181-
DatabaseName: e.databaseName,
182-
FileName: e.fileName,
183-
PkCheckByTn: int32(e.pkChkByTN),
176+
Bat: bat,
177+
EntryType: typ,
178+
TableId: e.tableId,
179+
DatabaseId: e.databaseId,
180+
TableName: e.tableName,
181+
DatabaseName: e.databaseName,
182+
FileName: e.fileName,
183+
PkCheckByTn: int32(e.pkChkByTN),
184+
AutoIncrEpoch: e.autoIncrEpoch,
185+
AutoIncrEpochKnown: e.autoIncrEpochKnown,
184186
}, nil
185187
}
186188

pkg/vm/engine/disttae/transfer.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,11 +148,12 @@ func transferTombstoneObjects(
148148

149149
if bat.RowCount() > 0 {
150150
fileName := slist[0].ObjectName().String()
151-
if err = txn.WriteFileLocked(
151+
if err = txn.writeFileLockedWithAutoIncrEpoch(
152152
DELETE,
153153
tbl.accountId, tbl.db.databaseId, tbl.tableId,
154154
tbl.db.databaseName, tbl.tableName, fileName,
155155
bat, txn.tnStores[0],
156+
tbl.extraInfo.AutoIncrEpoch,
156157
); err != nil {
157158
return err
158159
}

0 commit comments

Comments
 (0)