fix shared-db tenant runtime gaps

This commit is contained in:
richjohnrambo
2026-09-22 19:28:33 +08:00
parent 49e43aa3cf
commit 9ddf6ec5ee
12 changed files with 346 additions and 58 deletions
+78 -6
View File
@@ -897,6 +897,78 @@ func tenantTopicCreate(tx *sqlx.Tx, topic *t.Topic) error {
return addTenantTags(tx, topic.TenantID, "im_topictags", "topic", topic.Id, topic.Tags, false)
}
// createTenantSubscription mirrors createSubscription but keeps the subscription
// bound to the logical tenant in shared-database deployments.
func createTenantSubscription(tx *sqlx.Tx, tenantID t.TenantID, sub *t.Subscription, undelete bool) error {
if sub == nil || tenantID.IsZero() || sub.TenantID != tenantID {
return t.ErrMalformed
}
isOwner := (sub.ModeGiven & sub.ModeWant).IsOwner()
jpriv := common.ToJSON(sub.Private)
decodedUID := decodeUID(t.ParseUid(sub.User))
existing := struct {
ID int64 `db:"id"`
DeletedAt sql.NullTime `db:"deletedat"`
}{}
err := tx.Get(&existing,
"SELECT id,deletedat FROM im_subscriptions WHERE tenant_id=? AND topic=? AND userid=? ORDER BY deletedat IS NULL DESC,id ASC LIMIT 1",
tenantID, sub.Topic, decodedUID)
if err != nil && err != sql.ErrNoRows {
return err
}
if err == nil {
if existing.DeletedAt.Valid {
_, err = tx.Exec("UPDATE im_subscriptions SET createdat=?,updatedat=?,deletedat=NULL,modeWant=?,modeGiven=?,"+
"delid=0,recvseqid=0,readseqid=0,private=? WHERE tenant_id=? AND id=?",
sub.CreatedAt, sub.UpdatedAt, sub.ModeWant.String(), sub.ModeGiven.String(), jpriv, tenantID, existing.ID)
} else {
_, err = tx.Exec("UPDATE im_subscriptions SET updatedat=?,modeWant=?,modeGiven=?,private=? WHERE tenant_id=? AND id=?",
sub.UpdatedAt, sub.ModeWant.String(), sub.ModeGiven.String(), jpriv, tenantID, existing.ID)
}
if err != nil {
return err
}
if isOwner {
_, err = tx.Exec("UPDATE im_topics SET owner=? WHERE tenant_id=? AND name=?", decodedUID, tenantID, sub.Topic)
}
return err
}
subID, err := nextSnowflakeID()
if err != nil {
return err
}
_, err = tx.Exec(
"INSERT INTO im_subscriptions(id,tenant_id,createdat,updatedat,deletedat,userid,topic,modeWant,modeGiven,private) "+
"VALUES(?,?,?,?,NULL,?,?,?,?,?)",
subID, tenantID, sub.CreatedAt, sub.UpdatedAt, decodedUID, sub.Topic, sub.ModeWant.String(), sub.ModeGiven.String(), jpriv)
if isIDOutOfRange(err) {
_, err = tx.Exec(
"INSERT INTO im_subscriptions(tenant_id,createdat,updatedat,deletedat,userid,topic,modeWant,modeGiven,private) "+
"VALUES(?,?,?,NULL,?,?,?,?,?)",
tenantID, sub.CreatedAt, sub.UpdatedAt, decodedUID, sub.Topic, sub.ModeWant.String(), sub.ModeGiven.String(), jpriv)
}
if err != nil && isDupe(err) {
if undelete {
_, err = tx.Exec("UPDATE im_subscriptions SET createdat=?,updatedat=?,deletedat=NULL,modeWant=?,modeGiven=?,"+
"delid=0,recvseqid=0,readseqid=0 WHERE tenant_id=? AND topic=? AND userid=?",
sub.CreatedAt, sub.UpdatedAt, sub.ModeWant.String(), sub.ModeGiven.String(), tenantID, sub.Topic, decodedUID)
} else {
_, err = tx.Exec("UPDATE im_subscriptions SET createdat=?,updatedat=?,deletedat=NULL,modeWant=?,modeGiven=?,"+
"delid=0,recvseqid=0,readseqid=0,private=? WHERE tenant_id=? AND topic=? AND userid=?",
sub.CreatedAt, sub.UpdatedAt, sub.ModeWant.String(), sub.ModeGiven.String(), jpriv, tenantID, sub.Topic, decodedUID)
}
}
if err == nil && isOwner {
_, err = tx.Exec("UPDATE im_topics SET owner=? WHERE tenant_id=? AND name=?", decodedUID, tenantID, sub.Topic)
}
return err
}
func (a *adapter) TenantTopicCreate(id t.TenantID, topic *t.Topic) error {
tenantAdp, err := a.routedTenantAdapter(id)
if err != nil || topic == nil || topic.TenantID != id {
@@ -951,17 +1023,17 @@ func (a *adapter) TenantTopicCreateP2P(id t.TenantID, one, two *t.Subscription)
tx.Rollback()
}
}()
if err = createSubscription(tx, one, false); err != nil {
if err = createTenantSubscription(tx, id, one, false); err != nil {
return err
}
if err = createSubscription(tx, two, true); err != nil {
if err = createTenantSubscription(tx, id, two, true); err != nil {
return err
}
topic := &t.Topic{TenantID: id, ObjHeader: t.ObjHeader{Id: one.Topic}}
topic.ObjHeader.MergeTimes(&one.ObjHeader)
topic.TouchedAt = one.GetTouchedAt()
var existingTopicID int64
err = tx.Get(&existingTopicID, "SELECT id FROM im_topics WHERE name=? ORDER BY id ASC LIMIT 1", topic.Id)
err = tx.Get(&existingTopicID, "SELECT id FROM im_topics WHERE tenant_id=? AND name=? ORDER BY id ASC LIMIT 1", id, topic.Id)
if err != nil && err != sql.ErrNoRows {
return err
}
@@ -969,8 +1041,8 @@ func (a *adapter) TenantTopicCreateP2P(id t.TenantID, one, two *t.Subscription)
if err = tenantTopicCreate(tx, topic); err != nil {
return err
}
} else if _, err = tx.ExecContext(ctx, "UPDATE im_topics SET updatedat=?,touchedat=?,state=? WHERE id=?",
topic.UpdatedAt, topic.TouchedAt, t.StateOK, existingTopicID); err != nil {
} else if _, err = tx.ExecContext(ctx, "UPDATE im_topics SET updatedat=?,touchedat=?,state=? WHERE tenant_id=? AND id=?",
topic.UpdatedAt, topic.TouchedAt, t.StateOK, id, existingTopicID); err != nil {
return err
}
return tx.Commit()
@@ -1403,7 +1475,7 @@ func (a *adapter) TenantTopicShare(id t.TenantID, topic string, subs []*t.Subscr
}
}()
for _, sub := range subs {
if err = createSubscription(tx, sub, true); err != nil {
if err = createTenantSubscription(tx, id, sub, true); err != nil {
return err
}
}