From cfd8ef8fce2471016bf846c9158d1fe308599082 Mon Sep 17 00:00:00 2001 From: prachi Date: Wed, 1 Aug 2012 17:23:26 -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 +++++++++++++------ .../cloud/upgrade/dao/Upgrade303to304.java | 8 +++++- setup/db/create-schema.sql | 3 +- setup/db/db/schema-303to304 | 16 +++++++++++ 4 files changed, 44 insertions(+), 11 deletions(-) create mode 100644 setup/db/db/schema-303to304 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/server/src/com/cloud/upgrade/dao/Upgrade303to304.java b/server/src/com/cloud/upgrade/dao/Upgrade303to304.java index 55328e2cc9c..f7fa11b3d2e 100644 --- a/server/src/com/cloud/upgrade/dao/Upgrade303to304.java +++ b/server/src/com/cloud/upgrade/dao/Upgrade303to304.java @@ -23,6 +23,7 @@ import org.apache.log4j.Logger; import com.cloud.utils.crypt.DBEncryptionUtil; import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.script.Script; public class Upgrade303to304 extends Upgrade30xBase implements DbUpgrade { final static Logger s_logger = Logger.getLogger(Upgrade303to304.class); @@ -44,7 +45,12 @@ public class Upgrade303to304 extends Upgrade30xBase implements DbUpgrade { @Override public File[] getPrepareScripts() { - return null; + String script = Script.findScript("", "db/schema-303to304.sql"); + if (script == null) { + throw new CloudRuntimeException("Unable to find db/schema-303to304.sql"); + } + + return new File[] { new File(script) }; } @Override diff --git a/setup/db/create-schema.sql b/setup/db/create-schema.sql index d7cd2d64549..4d4ccbbcd76 100755 --- a/setup/db/create-schema.sql +++ b/setup/db/create-schema.sql @@ -815,7 +815,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-303to304 b/setup/db/db/schema-303to304 new file mode 100644 index 00000000000..b6cbb96d217 --- /dev/null +++ b/setup/db/db/schema-303to304 @@ -0,0 +1,16 @@ +# Copyright 2012 Citrix Systems, Inc. Licensed under the +# Apache License, Version 2.0 (the "License"); you may not use this +# file except in compliance with the License. Citrix Systems, Inc. +# reserves all rights not expressly granted by 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. +# + + +#Schema upgrade from 3.0.3 to 3.0.4; + +ALTER TABLE `cloud`.`host_details` ADD CONSTRAINT UNIQUE KEY (`host_id`, `name`); \ No newline at end of file