|
@@ -34,17 +34,21 @@ func (table *Table) InsertRowWithID(pkID uint64, values []types.FieldValue) (uin
|
|
|
if pkID == 0 {
|
|
if pkID == 0 {
|
|
|
pkID = table.AllocPKID()
|
|
pkID = table.AllocPKID()
|
|
|
}
|
|
}
|
|
|
|
|
+ // 游标状态 (预留消费 + 顶起) 统一在 pkMu 内读写, 与 AllocPKID 的
|
|
|
|
|
+ // 取号/预留登记互斥: 并发写者交错时避免游标回退发重号或预留错位。
|
|
|
|
|
+ table.pkMu.Lock()
|
|
|
reserved := table.hasPendingPK && table.pendingPK == pkID
|
|
reserved := table.hasPendingPK && table.pendingPK == pkID
|
|
|
table.hasPendingPK = false
|
|
table.hasPendingPK = false
|
|
|
|
|
+ // 显式指定更大的主键时把游标顶到它之后, 避免后续自增再发一次同样的号
|
|
|
|
|
+ if pkID+1 > table.nextPK {
|
|
|
|
|
+ table.nextPK = pkID + 1
|
|
|
|
|
+ }
|
|
|
|
|
+ table.pkMu.Unlock()
|
|
|
if !reserved {
|
|
if !reserved {
|
|
|
if table.indexMeta.rowStoreHasPK(pkID) {
|
|
if table.indexMeta.rowStoreHasPK(pkID) {
|
|
|
return 0, fmt.Errorf("%w: pkID=%d", ErrDuplicatePK, pkID)
|
|
return 0, fmt.Errorf("%w: pkID=%d", ErrDuplicatePK, pkID)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- // 显式指定更大的主键时把游标顶到它之后, 避免后续自增再发一次同样的号
|
|
|
|
|
- if pkID+1 > table.nextPK {
|
|
|
|
|
- table.nextPK = pkID + 1
|
|
|
|
|
- }
|
|
|
|
|
|
|
|
|
|
rowData, err := table.serializeRow(values, nil)
|
|
rowData, err := table.serializeRow(values, nil)
|
|
|
if err != nil {
|
|
if err != nil {
|
|
@@ -114,7 +118,17 @@ func (table *Table) insertRows(pkIDs []uint64, values [][]types.FieldValue, allR
|
|
|
auto[i] = true
|
|
auto[i] = true
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+ // 预留槽消费与游标顶起都在 pkMu 内, 与 AllocPKID/单行路径互斥
|
|
|
|
|
+ table.pkMu.Lock()
|
|
|
table.hasPendingPK = false // 预留号已被本批整体消费
|
|
table.hasPendingPK = false // 预留号已被本批整体消费
|
|
|
|
|
+ if !allReserved {
|
|
|
|
|
+ for i := 0; i < n; i++ {
|
|
|
|
|
+ if !auto[i] && pkIDs[i]+1 > table.nextPK {
|
|
|
|
|
+ table.nextPK = pkIDs[i] + 1
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ table.pkMu.Unlock()
|
|
|
|
|
|
|
|
// 2) 批内主键查重 (显式 vs 显式, 以及显式撞上自增号段)
|
|
// 2) 批内主键查重 (显式 vs 显式, 以及显式撞上自增号段)
|
|
|
{
|
|
{
|
|
@@ -137,16 +151,7 @@ func (table *Table) insertRows(pkIDs []uint64, values [][]types.FieldValue, allR
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- // 4) 显式大号顶起自增游标 (与单行路径一致; 预留号本就来自游标, 无需)
|
|
|
|
|
- if !allReserved {
|
|
|
|
|
- for i := 0; i < n; i++ {
|
|
|
|
|
- if !auto[i] && pkIDs[i]+1 > table.nextPK {
|
|
|
|
|
- table.nextPK = pkIDs[i] + 1
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 5) 逐行序列化 (动态堆写入在这一步发生)
|
|
|
|
|
|
|
+ // 4) 逐行序列化 (动态堆写入在这一步发生)
|
|
|
rowDatas := make([][]byte, n)
|
|
rowDatas := make([][]byte, n)
|
|
|
for i := 0; i < n; i++ {
|
|
for i := 0; i < n; i++ {
|
|
|
rowData, err := table.serializeRow(values[i], nil)
|
|
rowData, err := table.serializeRow(values[i], nil)
|