001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.upgrade.v7_0_0;
016    
017    import com.liferay.portal.dao.jdbc.spring.DataSourceFactoryBean;
018    import com.liferay.portal.kernel.log.Log;
019    import com.liferay.portal.kernel.log.LogFactoryUtil;
020    import com.liferay.portal.kernel.upgrade.UpgradeProcess;
021    import com.liferay.portal.kernel.upgrade.util.UpgradeTable;
022    import com.liferay.portal.kernel.upgrade.util.UpgradeTableFactoryUtil;
023    import com.liferay.portal.kernel.util.GetterUtil;
024    import com.liferay.portal.kernel.util.ListUtil;
025    import com.liferay.portal.kernel.util.LoggingTimer;
026    import com.liferay.portal.kernel.util.StringPool;
027    import com.liferay.portal.upgrade.v7_0_0.util.ClassNameTable;
028    import com.liferay.portal.upgrade.v7_0_0.util.ClusterGroupTable;
029    import com.liferay.portal.upgrade.v7_0_0.util.CompanyTable;
030    import com.liferay.portal.upgrade.v7_0_0.util.CounterTable;
031    import com.liferay.portal.upgrade.v7_0_0.util.CountryTable;
032    import com.liferay.portal.upgrade.v7_0_0.util.PortalPreferencesTable;
033    import com.liferay.portal.upgrade.v7_0_0.util.RegionTable;
034    import com.liferay.portal.upgrade.v7_0_0.util.ReleaseTable;
035    import com.liferay.portal.upgrade.v7_0_0.util.ResourceActionTable;
036    import com.liferay.portal.upgrade.v7_0_0.util.ServiceComponentTable;
037    import com.liferay.portal.upgrade.v7_0_0.util.VirtualHostTable;
038    import com.liferay.portal.util.PropsUtil;
039    
040    import java.io.IOException;
041    
042    import java.sql.Connection;
043    import java.sql.PreparedStatement;
044    import java.sql.ResultSet;
045    import java.sql.SQLException;
046    
047    import java.util.ArrayList;
048    import java.util.List;
049    
050    import javax.sql.DataSource;
051    
052    /**
053     * @author Manuel de la Pe??a
054     */
055    public class UpgradeSharding extends UpgradeProcess {
056    
057            protected void copyCompanyTable(
058                            Connection sourceConnection, Connection targetConnection,
059                            String shardName)
060                    throws Exception {
061    
062                    copyControlTable(
063                            sourceConnection, targetConnection, CompanyTable.TABLE_NAME,
064                            CompanyTable.TABLE_COLUMNS, CompanyTable.TABLE_SQL_CREATE);
065    
066                    List<Long> companyIds = getCompanyIds(shardName);
067    
068                    String companyIdsString = ListUtil.toString(
069                            companyIds, StringPool.NULL, StringPool.COMMA);
070    
071                    runSQL(
072                            sourceConnection,
073                            "delete from Company where companyId in (" + companyIdsString +
074                                    ")");
075    
076                    runSQL(
077                            targetConnection,
078                            "delete from Company where companyId not in (" + companyIdsString +
079                                    ")");
080            }
081    
082            protected void copyControlTable(
083                            Connection sourceConnection, Connection targetConnection,
084                            String tableName, Object[][] columns, String createSQL)
085                    throws Exception {
086    
087                    try {
088                            if (hasRows(targetConnection, tableName)) {
089                                    if (_log.isWarnEnabled()) {
090                                            _log.warn(
091                                                    "Control table " + tableName + " should not contain " +
092                                                            "data in a nondefault shard");
093                                    }
094                            }
095    
096                            dropTable(targetConnection, tableName);
097                    }
098                    catch (SQLException sqle) {
099                            if (_log.isInfoEnabled()) {
100                                    _log.info(
101                                            "Unable to drop control table " + tableName +
102                                                    " because it  does not exist in the target shard");
103                            }
104                    }
105    
106                    UpgradeTable upgradeTable = UpgradeTableFactoryUtil.getUpgradeTable(
107                            tableName, columns);
108    
109                    upgradeTable.setCreateSQL(createSQL);
110    
111                    upgradeTable.copyTable(sourceConnection, targetConnection);
112            }
113    
114            protected void copyControlTables(List<String> shardNames) throws Exception {
115                    try (LoggingTimer loggingTimer = new LoggingTimer()) {
116                            List<String> uniqueShardNames = ListUtil.unique(shardNames);
117    
118                            if (uniqueShardNames.size() == 1) {
119                                    if (_log.isInfoEnabled()) {
120                                            _log.info(
121                                                    "Skip copying of control tables because all " +
122                                                            "companies are located in the same shard");
123                                    }
124    
125                                    return;
126                            }
127    
128                            String defaultShardName = GetterUtil.getString(
129                                    PropsUtil.get("shard.default.name"), "default");
130    
131                            for (String uniqueShardName : uniqueShardNames) {
132                                    if (!uniqueShardName.equals(defaultShardName)) {
133                                            copyControlTables(uniqueShardName);
134                                    }
135                            }
136                    }
137            }
138    
139            protected void copyControlTables(String shardName) throws Exception {
140                    DataSourceFactoryBean dataSourceFactoryBean =
141                            new DataSourceFactoryBean();
142    
143                    dataSourceFactoryBean.setPropertyPrefix("jdbc." + shardName + ".");
144    
145                    DataSource dataSource = dataSourceFactoryBean.createInstance();
146    
147                    try (Connection targetConnection = dataSource.getConnection()) {
148                            copyCompanyTable(connection, targetConnection, shardName);
149                            copyControlTable(
150                                    connection, targetConnection, ClassNameTable.TABLE_NAME,
151                                    ClassNameTable.TABLE_COLUMNS, ClassNameTable.TABLE_SQL_CREATE);
152                            copyControlTable(
153                                    connection, targetConnection, ClusterGroupTable.TABLE_NAME,
154                                    ClusterGroupTable.TABLE_COLUMNS,
155                                    ClusterGroupTable.TABLE_SQL_CREATE);
156                            copyControlTable(
157                                    connection, targetConnection, CounterTable.TABLE_NAME,
158                                    CounterTable.TABLE_COLUMNS, CounterTable.TABLE_SQL_CREATE);
159                            copyControlTable(
160                                    connection, targetConnection, CountryTable.TABLE_NAME,
161                                    CountryTable.TABLE_COLUMNS, CountryTable.TABLE_SQL_CREATE);
162                            copyControlTable(
163                                    connection, targetConnection, PortalPreferencesTable.TABLE_NAME,
164                                    PortalPreferencesTable.TABLE_COLUMNS,
165                                    PortalPreferencesTable.TABLE_SQL_CREATE);
166                            copyControlTable(
167                                    connection, targetConnection, RegionTable.TABLE_NAME,
168                                    RegionTable.TABLE_COLUMNS, RegionTable.TABLE_SQL_CREATE);
169                            copyControlTable(
170                                    connection, targetConnection, ReleaseTable.TABLE_NAME,
171                                    ReleaseTable.TABLE_COLUMNS, ReleaseTable.TABLE_SQL_CREATE);
172                            copyControlTable(
173                                    connection, targetConnection, ResourceActionTable.TABLE_NAME,
174                                    ResourceActionTable.TABLE_COLUMNS,
175                                    ResourceActionTable.TABLE_SQL_CREATE);
176                            copyControlTable(
177                                    connection, targetConnection, ServiceComponentTable.TABLE_NAME,
178                                    ServiceComponentTable.TABLE_COLUMNS,
179                                    ServiceComponentTable.TABLE_SQL_CREATE);
180                            copyControlTable(
181                                    connection, targetConnection, VirtualHostTable.TABLE_NAME,
182                                    VirtualHostTable.TABLE_COLUMNS,
183                                    VirtualHostTable.TABLE_SQL_CREATE);
184                    }
185                    catch (Exception e) {
186                            _log.error("Unable to copy control tables", e);
187                    }
188            }
189    
190            @Override
191            protected void doUpgrade() throws Exception {
192                    List<String> shardNames = getShardNames();
193    
194                    if (shardNames.size() <= 1) {
195                            return;
196                    }
197    
198                    copyControlTables(shardNames);
199            }
200    
201            protected void dropTable(Connection connection, String tableName)
202                    throws IOException, SQLException {
203    
204                    runSQL(connection, "drop table " + tableName);
205    
206                    if (_log.isDebugEnabled()) {
207                            _log.debug("Deleted table " + tableName);
208                    }
209            }
210    
211            protected List<Long> getCompanyIds(String shardName) throws Exception {
212                    try (LoggingTimer loggingTimer = new LoggingTimer();
213                            PreparedStatement ps = connection.prepareStatement(
214                                    "select classPK from Shard where name = ?")) {
215    
216                            ps.setString(1, shardName);
217    
218                            List<Long> companyIds = new ArrayList<>();
219    
220                            try (ResultSet rs = ps.executeQuery()) {
221                                    while (rs.next()) {
222                                            companyIds.add(rs.getLong("classPK"));
223                                    }
224                            }
225    
226                            return companyIds;
227                    }
228            }
229    
230            protected List<String> getShardNames() throws Exception {
231                    try (LoggingTimer loggingTimer = new LoggingTimer();
232                            PreparedStatement ps = connection.prepareStatement(
233                                    "select name from Shard");
234                            ResultSet rs = ps.executeQuery()) {
235    
236                            List<String> shardNames = new ArrayList<>();
237    
238                            while (rs.next()) {
239                                    shardNames.add(rs.getString("name"));
240                            }
241    
242                            return shardNames;
243                    }
244            }
245    
246            private static final Log _log = LogFactoryUtil.getLog(
247                    UpgradeSharding.class);
248    
249    }