feat: complete IM P0 and P1 reliability work

This commit is contained in:
richjohnrambo
2026-08-17 13:43:27 +08:00
parent ddf0f7a55e
commit f2c229135b
43 changed files with 4512 additions and 1181 deletions
+81 -81
View File
@@ -68,75 +68,75 @@ DROP PROCEDURE assert_default_tenant;
-- 2. Add nullable tenant_id columns first.
-- ---------------------------------------------------------------------------
ALTER TABLE users
ALTER TABLE im_users
ADD COLUMN tenant_id BIGINT NULL AFTER id;
ALTER TABLE usertags
ALTER TABLE im_usertags
ADD COLUMN tenant_id BIGINT NULL AFTER id;
ALTER TABLE devices
ALTER TABLE im_devices
ADD COLUMN tenant_id BIGINT NULL AFTER id;
ALTER TABLE auth
ALTER TABLE im_auth
ADD COLUMN tenant_id BIGINT NULL AFTER id;
ALTER TABLE topics
ALTER TABLE im_topics
ADD COLUMN tenant_id BIGINT NULL AFTER id;
ALTER TABLE topictags
ALTER TABLE im_topictags
ADD COLUMN tenant_id BIGINT NULL AFTER id;
ALTER TABLE subscriptions
ALTER TABLE im_subscriptions
ADD COLUMN tenant_id BIGINT NULL AFTER id;
ALTER TABLE messages
ALTER TABLE im_messages
ADD COLUMN tenant_id BIGINT NULL AFTER id;
ALTER TABLE dellog
ALTER TABLE im_dellog
ADD COLUMN tenant_id BIGINT NULL AFTER id;
ALTER TABLE credentials
ALTER TABLE im_credentials
ADD COLUMN tenant_id BIGINT NULL AFTER id;
ALTER TABLE fileuploads
ALTER TABLE im_fileuploads
ADD COLUMN tenant_id BIGINT NULL AFTER id;
ALTER TABLE filemsglinks
ALTER TABLE im_filemsglinks
ADD COLUMN tenant_id BIGINT NULL AFTER id;
-- ---------------------------------------------------------------------------
-- 3. Backfill all existing rows into the default tenant.
-- ---------------------------------------------------------------------------
UPDATE users SET tenant_id = @default_tenant_id WHERE tenant_id IS NULL;
UPDATE usertags SET tenant_id = @default_tenant_id WHERE tenant_id IS NULL;
UPDATE devices SET tenant_id = @default_tenant_id WHERE tenant_id IS NULL;
UPDATE auth SET tenant_id = @default_tenant_id WHERE tenant_id IS NULL;
UPDATE topics SET tenant_id = @default_tenant_id WHERE tenant_id IS NULL;
UPDATE topictags SET tenant_id = @default_tenant_id WHERE tenant_id IS NULL;
UPDATE subscriptions SET tenant_id = @default_tenant_id WHERE tenant_id IS NULL;
UPDATE messages SET tenant_id = @default_tenant_id WHERE tenant_id IS NULL;
UPDATE dellog SET tenant_id = @default_tenant_id WHERE tenant_id IS NULL;
UPDATE credentials SET tenant_id = @default_tenant_id WHERE tenant_id IS NULL;
UPDATE fileuploads SET tenant_id = @default_tenant_id WHERE tenant_id IS NULL;
UPDATE filemsglinks SET tenant_id = @default_tenant_id WHERE tenant_id IS NULL;
UPDATE im_users SET tenant_id = @default_tenant_id WHERE tenant_id IS NULL;
UPDATE im_usertags SET tenant_id = @default_tenant_id WHERE tenant_id IS NULL;
UPDATE im_devices SET tenant_id = @default_tenant_id WHERE tenant_id IS NULL;
UPDATE im_auth SET tenant_id = @default_tenant_id WHERE tenant_id IS NULL;
UPDATE im_topics SET tenant_id = @default_tenant_id WHERE tenant_id IS NULL;
UPDATE im_topictags SET tenant_id = @default_tenant_id WHERE tenant_id IS NULL;
UPDATE im_subscriptions SET tenant_id = @default_tenant_id WHERE tenant_id IS NULL;
UPDATE im_messages SET tenant_id = @default_tenant_id WHERE tenant_id IS NULL;
UPDATE im_dellog SET tenant_id = @default_tenant_id WHERE tenant_id IS NULL;
UPDATE im_credentials SET tenant_id = @default_tenant_id WHERE tenant_id IS NULL;
UPDATE im_fileuploads SET tenant_id = @default_tenant_id WHERE tenant_id IS NULL;
UPDATE im_filemsglinks SET tenant_id = @default_tenant_id WHERE tenant_id IS NULL;
-- Validate the backfill before adding NOT NULL constraints.
DELIMITER $$
CREATE PROCEDURE assert_no_null_tenant_id()
BEGIN
IF EXISTS (SELECT 1 FROM users WHERE tenant_id IS NULL LIMIT 1)
OR EXISTS (SELECT 1 FROM usertags WHERE tenant_id IS NULL LIMIT 1)
OR EXISTS (SELECT 1 FROM devices WHERE tenant_id IS NULL LIMIT 1)
OR EXISTS (SELECT 1 FROM auth WHERE tenant_id IS NULL LIMIT 1)
OR EXISTS (SELECT 1 FROM topics WHERE tenant_id IS NULL LIMIT 1)
OR EXISTS (SELECT 1 FROM topictags WHERE tenant_id IS NULL LIMIT 1)
OR EXISTS (SELECT 1 FROM subscriptions WHERE tenant_id IS NULL LIMIT 1)
OR EXISTS (SELECT 1 FROM messages WHERE tenant_id IS NULL LIMIT 1)
OR EXISTS (SELECT 1 FROM dellog WHERE tenant_id IS NULL LIMIT 1)
OR EXISTS (SELECT 1 FROM credentials WHERE tenant_id IS NULL LIMIT 1)
OR EXISTS (SELECT 1 FROM fileuploads WHERE tenant_id IS NULL LIMIT 1)
OR EXISTS (SELECT 1 FROM filemsglinks WHERE tenant_id IS NULL LIMIT 1)
IF EXISTS (SELECT 1 FROM im_users WHERE tenant_id IS NULL LIMIT 1)
OR EXISTS (SELECT 1 FROM im_usertags WHERE tenant_id IS NULL LIMIT 1)
OR EXISTS (SELECT 1 FROM im_devices WHERE tenant_id IS NULL LIMIT 1)
OR EXISTS (SELECT 1 FROM im_auth WHERE tenant_id IS NULL LIMIT 1)
OR EXISTS (SELECT 1 FROM im_topics WHERE tenant_id IS NULL LIMIT 1)
OR EXISTS (SELECT 1 FROM im_topictags WHERE tenant_id IS NULL LIMIT 1)
OR EXISTS (SELECT 1 FROM im_subscriptions WHERE tenant_id IS NULL LIMIT 1)
OR EXISTS (SELECT 1 FROM im_messages WHERE tenant_id IS NULL LIMIT 1)
OR EXISTS (SELECT 1 FROM im_dellog WHERE tenant_id IS NULL LIMIT 1)
OR EXISTS (SELECT 1 FROM im_credentials WHERE tenant_id IS NULL LIMIT 1)
OR EXISTS (SELECT 1 FROM im_fileuploads WHERE tenant_id IS NULL LIMIT 1)
OR EXISTS (SELECT 1 FROM im_filemsglinks WHERE tenant_id IS NULL LIMIT 1)
THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'tenant_id backfill is incomplete';
@@ -152,18 +152,18 @@ DROP PROCEDURE assert_no_null_tenant_id;
-- No DEFAULT is retained: new code must always provide a tenant explicitly.
-- ---------------------------------------------------------------------------
ALTER TABLE users MODIFY COLUMN tenant_id BIGINT NOT NULL;
ALTER TABLE usertags MODIFY COLUMN tenant_id BIGINT NOT NULL;
ALTER TABLE devices MODIFY COLUMN tenant_id BIGINT NOT NULL;
ALTER TABLE auth MODIFY COLUMN tenant_id BIGINT NOT NULL;
ALTER TABLE topics MODIFY COLUMN tenant_id BIGINT NOT NULL;
ALTER TABLE topictags MODIFY COLUMN tenant_id BIGINT NOT NULL;
ALTER TABLE subscriptions MODIFY COLUMN tenant_id BIGINT NOT NULL;
ALTER TABLE messages MODIFY COLUMN tenant_id BIGINT NOT NULL;
ALTER TABLE dellog MODIFY COLUMN tenant_id BIGINT NOT NULL;
ALTER TABLE credentials MODIFY COLUMN tenant_id BIGINT NOT NULL;
ALTER TABLE fileuploads MODIFY COLUMN tenant_id BIGINT NOT NULL;
ALTER TABLE filemsglinks MODIFY COLUMN tenant_id BIGINT NOT NULL;
ALTER TABLE im_users MODIFY COLUMN tenant_id BIGINT NOT NULL;
ALTER TABLE im_usertags MODIFY COLUMN tenant_id BIGINT NOT NULL;
ALTER TABLE im_devices MODIFY COLUMN tenant_id BIGINT NOT NULL;
ALTER TABLE im_auth MODIFY COLUMN tenant_id BIGINT NOT NULL;
ALTER TABLE im_topics MODIFY COLUMN tenant_id BIGINT NOT NULL;
ALTER TABLE im_topictags MODIFY COLUMN tenant_id BIGINT NOT NULL;
ALTER TABLE im_subscriptions MODIFY COLUMN tenant_id BIGINT NOT NULL;
ALTER TABLE im_messages MODIFY COLUMN tenant_id BIGINT NOT NULL;
ALTER TABLE im_dellog MODIFY COLUMN tenant_id BIGINT NOT NULL;
ALTER TABLE im_credentials MODIFY COLUMN tenant_id BIGINT NOT NULL;
ALTER TABLE im_fileuploads MODIFY COLUMN tenant_id BIGINT NOT NULL;
ALTER TABLE im_filemsglinks MODIFY COLUMN tenant_id BIGINT NOT NULL;
-- ---------------------------------------------------------------------------
-- 5. Drop existing single-column foreign keys.
@@ -197,15 +197,15 @@ BEGIN
END$$
DELIMITER ;
CALL drop_table_foreign_keys('usertags');
CALL drop_table_foreign_keys('devices');
CALL drop_table_foreign_keys('auth');
CALL drop_table_foreign_keys('topictags');
CALL drop_table_foreign_keys('subscriptions');
CALL drop_table_foreign_keys('messages');
CALL drop_table_foreign_keys('dellog');
CALL drop_table_foreign_keys('credentials');
CALL drop_table_foreign_keys('filemsglinks');
CALL drop_table_foreign_keys('im_usertags');
CALL drop_table_foreign_keys('im_devices');
CALL drop_table_foreign_keys('im_auth');
CALL drop_table_foreign_keys('im_topictags');
CALL drop_table_foreign_keys('im_subscriptions');
CALL drop_table_foreign_keys('im_messages');
CALL drop_table_foreign_keys('im_dellog');
CALL drop_table_foreign_keys('im_credentials');
CALL drop_table_foreign_keys('im_filemsglinks');
DROP PROCEDURE drop_table_foreign_keys;
@@ -214,40 +214,40 @@ DROP PROCEDURE drop_table_foreign_keys;
-- Parent identity indexes are also added for composite foreign keys.
-- ---------------------------------------------------------------------------
ALTER TABLE users
ALTER TABLE im_users
ADD UNIQUE KEY uk_users_tenant_id_id (tenant_id, id),
ADD KEY idx_users_tenant_state_stateat (tenant_id, state, stateat),
ADD KEY idx_users_tenant_lastseen_updatedat (tenant_id, lastseen, updatedat);
ALTER TABLE usertags
ALTER TABLE im_usertags
ADD UNIQUE KEY uk_usertags_tenant_user_tag (tenant_id, userid, tag),
ADD KEY idx_usertags_tenant_tag (tenant_id, tag),
DROP INDEX usertags_userid_tag;
ALTER TABLE devices
ALTER TABLE im_devices
ADD UNIQUE KEY uk_devices_tenant_hash (tenant_id, hash),
ADD KEY idx_devices_tenant_user (tenant_id, userid),
DROP INDEX devices_hash;
ALTER TABLE auth
ALTER TABLE im_auth
ADD UNIQUE KEY uk_auth_tenant_user_scheme (tenant_id, userid, scheme),
ADD UNIQUE KEY uk_auth_tenant_uname (tenant_id, uname),
DROP INDEX auth_userid_scheme,
DROP INDEX auth_uname;
ALTER TABLE topics
ALTER TABLE im_topics
ADD UNIQUE KEY uk_topics_tenant_name (tenant_id, name),
ADD KEY idx_topics_tenant_owner (tenant_id, owner),
ADD KEY idx_topics_tenant_state_stateat (tenant_id, state, stateat),
ADD KEY idx_topics_tenant_name_state_seqid (tenant_id, name, state, seqid),
DROP INDEX topics_name;
ALTER TABLE topictags
ALTER TABLE im_topictags
ADD UNIQUE KEY uk_topictags_tenant_topic_tag (tenant_id, topic, tag),
ADD KEY idx_topictags_tenant_tag (tenant_id, tag),
DROP INDEX topictags_topic_tag;
ALTER TABLE subscriptions
ALTER TABLE im_subscriptions
ADD UNIQUE KEY uk_subscriptions_tenant_topic_user (tenant_id, topic, userid),
ADD KEY idx_subscriptions_tenant_user_topic_deleted
(tenant_id, userid, topic, deletedat),
@@ -255,30 +255,30 @@ ALTER TABLE subscriptions
(tenant_id, topic, deletedat),
DROP INDEX subscriptions_topic_userid;
ALTER TABLE messages
ALTER TABLE im_messages
ADD UNIQUE KEY uk_messages_tenant_id (tenant_id, id),
ADD UNIQUE KEY uk_messages_tenant_topic_seqid (tenant_id, topic, seqid),
DROP INDEX messages_topic_seqid;
ALTER TABLE dellog
ALTER TABLE im_dellog
ADD KEY idx_dellog_tenant_topic_delid_user
(tenant_id, topic, delid, deletedfor),
ADD KEY idx_dellog_tenant_topic_user_low_hi
(tenant_id, topic, deletedfor, low, hi),
ADD KEY idx_dellog_tenant_deletedfor (tenant_id, deletedfor);
ALTER TABLE credentials
ALTER TABLE im_credentials
ADD UNIQUE KEY uk_credentials_tenant_synthetic (tenant_id, synthetic),
ADD KEY idx_credentials_tenant_user_method
(tenant_id, userid, method, deletedat),
DROP INDEX credentials_uniqueness;
ALTER TABLE fileuploads
ALTER TABLE im_fileuploads
ADD UNIQUE KEY uk_fileuploads_tenant_id (tenant_id, id),
ADD KEY idx_fileuploads_tenant_status_updated
(tenant_id, status, updatedat);
ALTER TABLE filemsglinks
ALTER TABLE im_filemsglinks
ADD KEY idx_filemsglinks_tenant_file (tenant_id, fileid),
ADD KEY idx_filemsglinks_tenant_message (tenant_id, msgid),
ADD KEY idx_filemsglinks_tenant_topic (tenant_id, topic),
@@ -295,32 +295,32 @@ ALTER TABLE filemsglinks
-- ---------------------------------------------------------------------------
SELECT 'user_tags_without_same_tenant_user' AS check_name, COUNT(*) AS invalid_count
FROM usertags child
LEFT JOIN users parent
FROM im_usertags child
LEFT JOIN im_users parent
ON parent.tenant_id = child.tenant_id AND parent.id = child.userid
WHERE parent.id IS NULL
UNION ALL
SELECT 'subscriptions_without_same_tenant_user', COUNT(*)
FROM subscriptions child
LEFT JOIN users parent
FROM im_subscriptions child
LEFT JOIN im_users parent
ON parent.tenant_id = child.tenant_id AND parent.id = child.userid
WHERE parent.id IS NULL
UNION ALL
SELECT 'subscriptions_without_same_tenant_topic', COUNT(*)
FROM subscriptions child
LEFT JOIN topics parent
FROM im_subscriptions child
LEFT JOIN im_topics parent
ON parent.tenant_id = child.tenant_id AND parent.name = child.topic
WHERE parent.name IS NULL
UNION ALL
SELECT 'messages_without_same_tenant_topic', COUNT(*)
FROM messages child
LEFT JOIN topics parent
FROM im_messages child
LEFT JOIN im_topics parent
ON parent.tenant_id = child.tenant_id AND parent.name = child.topic
WHERE parent.name IS NULL
UNION ALL
SELECT 'file_links_without_same_tenant_file', COUNT(*)
FROM filemsglinks child
LEFT JOIN fileuploads parent
FROM im_filemsglinks child
LEFT JOIN im_fileuploads parent
ON parent.tenant_id = child.tenant_id AND parent.id = child.fileid
WHERE parent.id IS NULL;
@@ -328,11 +328,11 @@ WHERE parent.id IS NULL;
-- 9. Update the schema version only after all validation succeeds.
-- ---------------------------------------------------------------------------
UPDATE kvmeta
UPDATE im_kvmeta
SET `value` = '119'
WHERE `key` = 'version';
-- Intentionally unchanged:
-- * im_tenant: it is the tenant registry itself.
-- * kvmeta: it stores platform-level schema metadata. Tenant-scoped cache
-- * im_kvmeta: it stores platform-level schema metadata. Tenant-scoped cache
-- data must use a separate table or a mandatory tenant key namespace.