From 2fe71ff00cd4787612d1fed93583fc5f12520c44 Mon Sep 17 00:00:00 2001 From: DT Date: Tue, 18 Aug 2026 09:55:27 +0100 Subject: [PATCH 1/7] usage: widen usage_volume unique key to include vm_id createVolumeHelperEvent() writes two usage_volume rows for a single VOLUME.CREATE when the event carries vm_id, both using the same created timestamp. The unique key was left at (volume_id, created) when vm_id was added in 4.22.1, so the second insert always fails with a duplicate key error. Uses the existing idempotent helpers per review guidance on #13399. Refs #13399 --- .../src/main/resources/META-INF/db/schema-42210to42300.sql | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/engine/schema/src/main/resources/META-INF/db/schema-42210to42300.sql b/engine/schema/src/main/resources/META-INF/db/schema-42210to42300.sql index ab5ac7b2b875..a7a7e016b750 100644 --- a/engine/schema/src/main/resources/META-INF/db/schema-42210to42300.sql +++ b/engine/schema/src/main/resources/META-INF/db/schema-42210to42300.sql @@ -646,3 +646,7 @@ CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.backup_schedule', 'isolated', 'TINYI UPDATE `cloud`.`configuration` SET `value`=CONCAT(`value`, ', backupValidationCommandTimeout, backupValidationScreenshotWait, backupValidationBootTimeout') WHERE `name`='user.vm.readonly.details' AND `value` IS NOT NULL; +-- Widen the unique key on cloud_usage.usage_volume to include vm_id, so the two volume +-- usage records introduced in 4.22.1 (cumulative and per-VM) can coexist. See #13399. +CALL `cloud`.`IDEMPOTENT_DROP_UNIQUE_KEY`('cloud_usage.usage_volume', 'id'); +CALL `cloud`.`IDEMPOTENT_ADD_UNIQUE_KEY`('cloud_usage.usage_volume', 'id', '(`volume_id`, `created`, `vm_id`)'); From 1a969211cac53a7342846943ef6994e1792d71c4 Mon Sep 17 00:00:00 2001 From: DT Date: Tue, 18 Aug 2026 10:33:30 +0100 Subject: [PATCH 2/7] usage: add IDEMPOTENT_ADD_UNIQUE_KEY procedure for cloud_usage schema Copy of cloud.IDEMPOTENT_ADD_UNIQUE_KEY with the schema changed, so cloud_usage DDL can go through a cloud_usage procedure like the rest of the usage schema changes. Refs #13399 --- .../usage.idempotent_add_unique_key.sql | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 engine/schema/src/main/resources/META-INF/db/procedures/usage.idempotent_add_unique_key.sql diff --git a/engine/schema/src/main/resources/META-INF/db/procedures/usage.idempotent_add_unique_key.sql b/engine/schema/src/main/resources/META-INF/db/procedures/usage.idempotent_add_unique_key.sql new file mode 100644 index 000000000000..14fc68e109f8 --- /dev/null +++ b/engine/schema/src/main/resources/META-INF/db/procedures/usage.idempotent_add_unique_key.sql @@ -0,0 +1,26 @@ +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. + +-- Idempotent ADD UNIQUE KEY +DROP PROCEDURE IF EXISTS `cloud_usage`.`IDEMPOTENT_ADD_UNIQUE_KEY`; +CREATE PROCEDURE `cloud_usage`.`IDEMPOTENT_ADD_UNIQUE_KEY` ( + IN in_table_name VARCHAR(200) +, IN in_key_name VARCHAR(200) +, IN in_key_definition VARCHAR(1000) +) +BEGIN + DECLARE CONTINUE HANDLER FOR 1061 BEGIN END; SET @ddl = CONCAT('ALTER TABLE ', in_table_name); SET @ddl = CONCAT(@ddl, ' ', 'ADD UNIQUE KEY ', in_key_name); SET @ddl = CONCAT(@ddl, ' ', in_key_definition); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; END; From d1037801b7e8dd075f68e4b0e25f390ddff6dd5e Mon Sep 17 00:00:00 2001 From: DT Date: Tue, 18 Aug 2026 10:35:32 +0100 Subject: [PATCH 3/7] usage: add IDEMPOTENT_DROP_UNIQUE_KEY procedure for cloud_usage schema Copy of cloud.IDEMPOTENT_DROP_UNIQUE_KEY with the schema changed, so cloud_usage DDL can go through a cloud_usage procedure like the rest of the usage schema changes. Refs #13399 --- .../usage.idempotent_drop_unique_key.sql | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 engine/schema/src/main/resources/META-INF/db/procedures/usage.idempotent_drop_unique_key.sql diff --git a/engine/schema/src/main/resources/META-INF/db/procedures/usage.idempotent_drop_unique_key.sql b/engine/schema/src/main/resources/META-INF/db/procedures/usage.idempotent_drop_unique_key.sql new file mode 100644 index 000000000000..9b63a1d83a49 --- /dev/null +++ b/engine/schema/src/main/resources/META-INF/db/procedures/usage.idempotent_drop_unique_key.sql @@ -0,0 +1,26 @@ +-- Licensed to the Apache Software Foundation (ASF) under one +-- or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information +-- regarding copyright ownership. The ASF licenses this file +-- to you under the Apache License, Version 2.0 (the +-- "License"); you may not use this file except in compliance +-- with the License. You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, +-- software distributed under the License is distributed on an +-- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +-- KIND, either express or implied. See the License for the +-- specific language governing permissions and limitations +-- under the License. + +-- in cloud_usage +DROP PROCEDURE IF EXISTS `cloud_usage`.`IDEMPOTENT_DROP_UNIQUE_KEY`; + +CREATE PROCEDURE `cloud_usage`.`IDEMPOTENT_DROP_UNIQUE_KEY` ( + IN in_table_name VARCHAR(200), + IN in_index_name VARCHAR(200) +) +BEGIN + DECLARE CONTINUE HANDLER FOR 1091, 1025 BEGIN END; SET @ddl = CONCAT('ALTER TABLE ', in_table_name, ' DROP KEY ', in_index_name); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; END; From 3a2b69bd0acb20e05a60bdea786d91e712960f5f Mon Sep 17 00:00:00 2001 From: DT Date: Tue, 18 Aug 2026 10:38:00 +0100 Subject: [PATCH 4/7] usage: call the cloud_usage idempotent key procedures Per review on #13399, cloud_usage DDL should use cloud_usage-schema procedures rather than reaching across to the cloud schema. Refs #13399 --- .../src/main/resources/META-INF/db/schema-42210to42300.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/engine/schema/src/main/resources/META-INF/db/schema-42210to42300.sql b/engine/schema/src/main/resources/META-INF/db/schema-42210to42300.sql index a7a7e016b750..7ae6996b4983 100644 --- a/engine/schema/src/main/resources/META-INF/db/schema-42210to42300.sql +++ b/engine/schema/src/main/resources/META-INF/db/schema-42210to42300.sql @@ -648,5 +648,5 @@ UPDATE `cloud`.`configuration` SET `value`=CONCAT(`value`, ', backupValidationCo WHERE `name`='user.vm.readonly.details' AND `value` IS NOT NULL; -- Widen the unique key on cloud_usage.usage_volume to include vm_id, so the two volume -- usage records introduced in 4.22.1 (cumulative and per-VM) can coexist. See #13399. -CALL `cloud`.`IDEMPOTENT_DROP_UNIQUE_KEY`('cloud_usage.usage_volume', 'id'); -CALL `cloud`.`IDEMPOTENT_ADD_UNIQUE_KEY`('cloud_usage.usage_volume', 'id', '(`volume_id`, `created`, `vm_id`)'); +CALL `cloud_usage`.`IDEMPOTENT_DROP_UNIQUE_KEY`('cloud_usage.usage_volume', 'id'); +CALL `cloud_usage`.`IDEMPOTENT_ADD_UNIQUE_KEY`('cloud_usage.usage_volume', 'id', '(`volume_id`, `created`, `vm_id`)'); From 5bfa6922566dc949c960b98e719f6f2b3f5ac430 Mon Sep 17 00:00:00 2001 From: DT Date: Tue, 18 Aug 2026 18:16:53 +0100 Subject: [PATCH 5/7] usage: drop redundant IDEMPOTENT_ADD_UNIQUE_KEY procedure cloud_usage.IDEMPOTENT_ADD_UNIQUE_INDEX is already defined in procedures/cloud.idempotent_add_unique_index.sql (the cloud.* filename notwithstanding) and is loaded on every upgrade by DatabaseUpgradeChecker.executeProcedureScripts(), so a new procedure is unnecessary. Raised by @abh1sar in review. --- .../usage.idempotent_add_unique_key.sql | 26 ------------------- 1 file changed, 26 deletions(-) delete mode 100644 engine/schema/src/main/resources/META-INF/db/procedures/usage.idempotent_add_unique_key.sql diff --git a/engine/schema/src/main/resources/META-INF/db/procedures/usage.idempotent_add_unique_key.sql b/engine/schema/src/main/resources/META-INF/db/procedures/usage.idempotent_add_unique_key.sql deleted file mode 100644 index 14fc68e109f8..000000000000 --- a/engine/schema/src/main/resources/META-INF/db/procedures/usage.idempotent_add_unique_key.sql +++ /dev/null @@ -1,26 +0,0 @@ --- Licensed to the Apache Software Foundation (ASF) under one --- or more contributor license agreements. See the NOTICE file --- distributed with this work for additional information --- regarding copyright ownership. The ASF licenses this file --- to you under the Apache License, Version 2.0 (the --- "License"); you may not use this file except in compliance --- with the License. You may obtain a copy of the License at --- --- http://www.apache.org/licenses/LICENSE-2.0 --- --- Unless required by applicable law or agreed to in writing, --- software distributed under the License is distributed on an --- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY --- KIND, either express or implied. See the License for the --- specific language governing permissions and limitations --- under the License. - --- Idempotent ADD UNIQUE KEY -DROP PROCEDURE IF EXISTS `cloud_usage`.`IDEMPOTENT_ADD_UNIQUE_KEY`; -CREATE PROCEDURE `cloud_usage`.`IDEMPOTENT_ADD_UNIQUE_KEY` ( - IN in_table_name VARCHAR(200) -, IN in_key_name VARCHAR(200) -, IN in_key_definition VARCHAR(1000) -) -BEGIN - DECLARE CONTINUE HANDLER FOR 1061 BEGIN END; SET @ddl = CONCAT('ALTER TABLE ', in_table_name); SET @ddl = CONCAT(@ddl, ' ', 'ADD UNIQUE KEY ', in_key_name); SET @ddl = CONCAT(@ddl, ' ', in_key_definition); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; END; From e5dd47236de7766892d0cbed2508ee6268ed7030 Mon Sep 17 00:00:00 2001 From: DT Date: Tue, 18 Aug 2026 18:17:52 +0100 Subject: [PATCH 6/7] usage: drop redundant IDEMPOTENT_DROP_UNIQUE_KEY procedure cloud_usage.IDEMPOTENT_DROP_INDEX is already defined in procedures/usage.idempotent_drop_index.sql. DROP INDEX ON is equivalent to ALTER TABLE
DROP KEY , so the existing procedure covers this case. Raised by @abh1sar in review. --- .../usage.idempotent_drop_unique_key.sql | 26 ------------------- 1 file changed, 26 deletions(-) delete mode 100644 engine/schema/src/main/resources/META-INF/db/procedures/usage.idempotent_drop_unique_key.sql diff --git a/engine/schema/src/main/resources/META-INF/db/procedures/usage.idempotent_drop_unique_key.sql b/engine/schema/src/main/resources/META-INF/db/procedures/usage.idempotent_drop_unique_key.sql deleted file mode 100644 index 9b63a1d83a49..000000000000 --- a/engine/schema/src/main/resources/META-INF/db/procedures/usage.idempotent_drop_unique_key.sql +++ /dev/null @@ -1,26 +0,0 @@ --- Licensed to the Apache Software Foundation (ASF) under one --- or more contributor license agreements. See the NOTICE file --- distributed with this work for additional information --- regarding copyright ownership. The ASF licenses this file --- to you under the Apache License, Version 2.0 (the --- "License"); you may not use this file except in compliance --- with the License. You may obtain a copy of the License at --- --- http://www.apache.org/licenses/LICENSE-2.0 --- --- Unless required by applicable law or agreed to in writing, --- software distributed under the License is distributed on an --- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY --- KIND, either express or implied. See the License for the --- specific language governing permissions and limitations --- under the License. - --- in cloud_usage -DROP PROCEDURE IF EXISTS `cloud_usage`.`IDEMPOTENT_DROP_UNIQUE_KEY`; - -CREATE PROCEDURE `cloud_usage`.`IDEMPOTENT_DROP_UNIQUE_KEY` ( - IN in_table_name VARCHAR(200), - IN in_index_name VARCHAR(200) -) -BEGIN - DECLARE CONTINUE HANDLER FOR 1091, 1025 BEGIN END; SET @ddl = CONCAT('ALTER TABLE ', in_table_name, ' DROP KEY ', in_index_name); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; END; From 79290bd1ddded183f8abe6d1f5c16519744a7f9e Mon Sep 17 00:00:00 2001 From: DT Date: Tue, 18 Aug 2026 18:23:22 +0100 Subject: [PATCH 7/7] usage: use existing cloud_usage index procedures to widen the key Use the pre-existing cloud_usage procedures instead of the two added in this PR. schema-41600to41610.sql:72 created this same key with IDEMPOTENT_ADD_UNIQUE_INDEX: CALL `cloud_usage`.`IDEMPOTENT_ADD_UNIQUE_INDEX`( 'cloud_usage.usage_volume', 'id', '(volume_id ASC, created ASC)'); so widening it the same way keeps the table's schema history consistent. Note the two procedures take their arguments in opposite orders: IDEMPOTENT_DROP_INDEX is (index_name, table_name), while IDEMPOTENT_ADD_UNIQUE_INDEX is (table_name, index_name, definition). --- .../src/main/resources/META-INF/db/schema-42210to42300.sql | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/engine/schema/src/main/resources/META-INF/db/schema-42210to42300.sql b/engine/schema/src/main/resources/META-INF/db/schema-42210to42300.sql index 7ae6996b4983..417d69a162eb 100644 --- a/engine/schema/src/main/resources/META-INF/db/schema-42210to42300.sql +++ b/engine/schema/src/main/resources/META-INF/db/schema-42210to42300.sql @@ -646,7 +646,8 @@ CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.backup_schedule', 'isolated', 'TINYI UPDATE `cloud`.`configuration` SET `value`=CONCAT(`value`, ', backupValidationCommandTimeout, backupValidationScreenshotWait, backupValidationBootTimeout') WHERE `name`='user.vm.readonly.details' AND `value` IS NOT NULL; + -- Widen the unique key on cloud_usage.usage_volume to include vm_id, so the two volume -- usage records introduced in 4.22.1 (cumulative and per-VM) can coexist. See #13399. -CALL `cloud_usage`.`IDEMPOTENT_DROP_UNIQUE_KEY`('cloud_usage.usage_volume', 'id'); -CALL `cloud_usage`.`IDEMPOTENT_ADD_UNIQUE_KEY`('cloud_usage.usage_volume', 'id', '(`volume_id`, `created`, `vm_id`)'); +CALL `cloud_usage`.`IDEMPOTENT_DROP_INDEX`('id', 'cloud_usage.usage_volume'); +CALL `cloud_usage`.`IDEMPOTENT_ADD_UNIQUE_INDEX`('cloud_usage.usage_volume', 'id', '(volume_id ASC, created ASC, vm_id ASC)');