From c55489224b930eabc7caa499b7d74c46df500d9e Mon Sep 17 00:00:00 2001 From: prachi Date: Wed, 1 Aug 2012 14:29:38 -0700 Subject: [PATCH] CS-12510: Deleting the host_details and inserting them back causes deadlocks. Reviewed-By: Alex Changes: - Deleting and inserting the host_details in one transaction leads to this MySQL deadlock issue sometimes - This fix is to use the ON DUPLICATE KEY UPDATE MySQL query that will insert the deatils if they are new or update the ones that are existing. - This needs a UNIQUE constraint on host_details. --- .../cloud/host/dao/HostDetailsDaoImpl.java | 28 +++++++++++++------ setup/db/create-schema.sql | 3 +- setup/db/db/schema-304to305.sql | 1 + 3 files changed, 22 insertions(+), 10 deletions(-) diff --git a/server/src/com/cloud/host/dao/HostDetailsDaoImpl.java b/server/src/com/cloud/host/dao/HostDetailsDaoImpl.java index d0fa8d813b7..096586080ed 100644 --- a/server/src/com/cloud/host/dao/HostDetailsDaoImpl.java +++ b/server/src/com/cloud/host/dao/HostDetailsDaoImpl.java @@ -12,6 +12,8 @@ // Automatically generated by addcopyright.py at 04/03/2012 package com.cloud.host.dao; +import java.sql.PreparedStatement; +import java.sql.SQLException; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -24,6 +26,7 @@ import com.cloud.utils.db.GenericDaoBase; import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.Transaction; +import com.cloud.utils.exception.CloudRuntimeException; @Local(value=HostDetailsDao.class) public class HostDetailsDaoImpl extends GenericDaoBase implements HostDetailsDao { @@ -84,19 +87,26 @@ public class HostDetailsDaoImpl extends GenericDaoBase implement @Override public void persist(long hostId, Map details) { + final String InsertOrUpdateSql = "INSERT INTO `cloud`.`host_details` (host_id, name, value) VALUES (?,?,?) ON DUPLICATE KEY UPDATE value=?"; + Transaction txn = Transaction.currentTxn(); txn.start(); - SearchCriteria sc = HostSearch.create(); - sc.setParameters("hostId", hostId); - expunge(sc); for (Map.Entry detail : details.entrySet()) { - String value = detail.getValue(); - if("password".equals(detail.getKey())){ - value = DBEncryptionUtil.encrypt(value); - } - DetailVO vo = new DetailVO(hostId, detail.getKey(), value); - persist(vo); + String value = detail.getValue(); + if("password".equals(detail.getKey())){ + value = DBEncryptionUtil.encrypt(value); + } + try { + PreparedStatement pstmt = txn.prepareAutoCloseStatement(InsertOrUpdateSql); + pstmt.setLong(1, hostId); + pstmt.setString(2, detail.getKey()); + pstmt.setString(3, value); + pstmt.setString(4, value); + pstmt.executeUpdate(); + } catch (SQLException e) { + throw new CloudRuntimeException("Unable to persist the host_details key: "+ detail.getKey() +" for host id: "+hostId, e); + } } txn.commit(); } diff --git a/setup/db/create-schema.sql b/setup/db/create-schema.sql index 8a8e7bd90f9..f76d2837641 100755 --- a/setup/db/create-schema.sql +++ b/setup/db/create-schema.sql @@ -832,7 +832,8 @@ CREATE TABLE `cloud`.`host_details` ( `name` varchar(255) NOT NULL, `value` varchar(255) NOT NULL, PRIMARY KEY (`id`), - CONSTRAINT `fk_host_details__host_id` FOREIGN KEY (`host_id`) REFERENCES `host`(`id`) ON DELETE CASCADE + CONSTRAINT `fk_host_details__host_id` FOREIGN KEY (`host_id`) REFERENCES `host`(`id`) ON DELETE CASCADE, + CONSTRAINT UNIQUE KEY (`host_id`, `name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `cloud`.`mshost` ( diff --git a/setup/db/db/schema-304to305.sql b/setup/db/db/schema-304to305.sql index 8c9e78f5ac4..7108e7c2652 100755 --- a/setup/db/db/schema-304to305.sql +++ b/setup/db/db/schema-304to305.sql @@ -350,3 +350,4 @@ UPDATE `cloud`.`hypervisor_capabilities` SET `max_data_volumes_limit`=13 WHERE ` SET SQL_SAFE_UPDATES=1; UPDATE `cloud`.`configuration` SET description='In second, timeout for creating volume from snapshot' WHERE name='create.volume.from.snapshot.wait'; +ALTER TABLE `cloud`.`host_details` ADD CONSTRAINT UNIQUE KEY (`host_id`, `name`);