/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. */ package com.liferay.portal.upgrade.v7_0_0; import com.liferay.portal.dao.jdbc.spring.DataSourceFactoryBean; import com.liferay.portal.kernel.log.Log; import com.liferay.portal.kernel.log.LogFactoryUtil; import com.liferay.portal.kernel.upgrade.UpgradeProcess; import com.liferay.portal.kernel.upgrade.util.UpgradeTable; import com.liferay.portal.kernel.upgrade.util.UpgradeTableFactoryUtil; import com.liferay.portal.kernel.util.GetterUtil; import com.liferay.portal.kernel.util.ListUtil; import com.liferay.portal.kernel.util.LoggingTimer; import com.liferay.portal.kernel.util.StringPool; import com.liferay.portal.upgrade.v7_0_0.util.ClassNameTable; import com.liferay.portal.upgrade.v7_0_0.util.ClusterGroupTable; import com.liferay.portal.upgrade.v7_0_0.util.CompanyTable; import com.liferay.portal.upgrade.v7_0_0.util.CounterTable; import com.liferay.portal.upgrade.v7_0_0.util.CountryTable; import com.liferay.portal.upgrade.v7_0_0.util.PortalPreferencesTable; import com.liferay.portal.upgrade.v7_0_0.util.RegionTable; import com.liferay.portal.upgrade.v7_0_0.util.ReleaseTable; import com.liferay.portal.upgrade.v7_0_0.util.ResourceActionTable; import com.liferay.portal.upgrade.v7_0_0.util.ServiceComponentTable; import com.liferay.portal.upgrade.v7_0_0.util.VirtualHostTable; import com.liferay.portal.util.PropsUtil; import java.io.IOException; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import javax.sql.DataSource; /** * @author Manuel de la Peña */ public class UpgradeSharding extends UpgradeProcess { protected void copyCompanyTable( Connection sourceConnection, Connection targetConnection, String shardName) throws Exception { copyControlTable( sourceConnection, targetConnection, CompanyTable.TABLE_NAME, CompanyTable.TABLE_COLUMNS, CompanyTable.TABLE_SQL_CREATE); List<Long> companyIds = getCompanyIds(shardName); String companyIdsString = ListUtil.toString( companyIds, StringPool.NULL, StringPool.COMMA); runSQL( sourceConnection, "delete from Company where companyId in (" + companyIdsString + ")"); runSQL( targetConnection, "delete from Company where companyId not in (" + companyIdsString + ")"); } protected void copyControlTable( Connection sourceConnection, Connection targetConnection, String tableName, Object[][] columns, String createSQL) throws Exception { try { if (hasRows(targetConnection, tableName)) { if (_log.isWarnEnabled()) { _log.warn( "Control table " + tableName + " should not contain " + "data in a nondefault shard"); } } dropTable(targetConnection, tableName); } catch (SQLException sqle) { if (_log.isInfoEnabled()) { _log.info( "Unable to drop control table " + tableName + " because it does not exist in the target shard"); } } UpgradeTable upgradeTable = UpgradeTableFactoryUtil.getUpgradeTable( tableName, columns); upgradeTable.setCreateSQL(createSQL); upgradeTable.copyTable(sourceConnection, targetConnection); } protected void copyControlTables(List<String> shardNames) throws Exception { try (LoggingTimer loggingTimer = new LoggingTimer()) { List<String> uniqueShardNames = ListUtil.unique(shardNames); if (uniqueShardNames.size() == 1) { if (_log.isInfoEnabled()) { _log.info( "Skip copying of control tables because all " + "companies are located in the same shard"); } return; } String defaultShardName = GetterUtil.getString( PropsUtil.get("shard.default.name"), "default"); for (String uniqueShardName : uniqueShardNames) { if (!uniqueShardName.equals(defaultShardName)) { copyControlTables(uniqueShardName); } } } } protected void copyControlTables(String shardName) throws Exception { DataSourceFactoryBean dataSourceFactoryBean = new DataSourceFactoryBean(); dataSourceFactoryBean.setPropertyPrefix("jdbc." + shardName + "."); DataSource dataSource = dataSourceFactoryBean.createInstance(); try (Connection targetConnection = dataSource.getConnection()) { copyCompanyTable(connection, targetConnection, shardName); copyControlTable( connection, targetConnection, ClassNameTable.TABLE_NAME, ClassNameTable.TABLE_COLUMNS, ClassNameTable.TABLE_SQL_CREATE); copyControlTable( connection, targetConnection, ClusterGroupTable.TABLE_NAME, ClusterGroupTable.TABLE_COLUMNS, ClusterGroupTable.TABLE_SQL_CREATE); copyControlTable( connection, targetConnection, CounterTable.TABLE_NAME, CounterTable.TABLE_COLUMNS, CounterTable.TABLE_SQL_CREATE); copyControlTable( connection, targetConnection, CountryTable.TABLE_NAME, CountryTable.TABLE_COLUMNS, CountryTable.TABLE_SQL_CREATE); copyControlTable( connection, targetConnection, PortalPreferencesTable.TABLE_NAME, PortalPreferencesTable.TABLE_COLUMNS, PortalPreferencesTable.TABLE_SQL_CREATE); copyControlTable( connection, targetConnection, RegionTable.TABLE_NAME, RegionTable.TABLE_COLUMNS, RegionTable.TABLE_SQL_CREATE); copyControlTable( connection, targetConnection, ReleaseTable.TABLE_NAME, ReleaseTable.TABLE_COLUMNS, ReleaseTable.TABLE_SQL_CREATE); copyControlTable( connection, targetConnection, ResourceActionTable.TABLE_NAME, ResourceActionTable.TABLE_COLUMNS, ResourceActionTable.TABLE_SQL_CREATE); copyControlTable( connection, targetConnection, ServiceComponentTable.TABLE_NAME, ServiceComponentTable.TABLE_COLUMNS, ServiceComponentTable.TABLE_SQL_CREATE); copyControlTable( connection, targetConnection, VirtualHostTable.TABLE_NAME, VirtualHostTable.TABLE_COLUMNS, VirtualHostTable.TABLE_SQL_CREATE); } catch (Exception e) { _log.error("Unable to copy control tables", e); } } @Override protected void doUpgrade() throws Exception { List<String> shardNames = getShardNames(); if (shardNames.size() <= 1) { return; } copyControlTables(shardNames); } protected void dropTable(Connection connection, String tableName) throws IOException, SQLException { runSQL(connection, "drop table " + tableName); if (_log.isDebugEnabled()) { _log.debug("Deleted table " + tableName); } } protected List<Long> getCompanyIds(String shardName) throws Exception { try (LoggingTimer loggingTimer = new LoggingTimer(); PreparedStatement ps = connection.prepareStatement( "select classPK from Shard where name = ?")) { ps.setString(1, shardName); List<Long> companyIds = new ArrayList<>(); try (ResultSet rs = ps.executeQuery()) { while (rs.next()) { companyIds.add(rs.getLong("classPK")); } } return companyIds; } } protected List<String> getShardNames() throws Exception { try (LoggingTimer loggingTimer = new LoggingTimer(); PreparedStatement ps = connection.prepareStatement( "select name from Shard"); ResultSet rs = ps.executeQuery()) { List<String> shardNames = new ArrayList<>(); while (rs.next()) { shardNames.add(rs.getString("name")); } return shardNames; } } private static final Log _log = LogFactoryUtil.getLog( UpgradeSharding.class); }