b04decf8b5
Add the following information: 1. how many rows were migrated 2. how much time it took 3. what was migration speed (rows per/sec) So that it is more consistent with Reindex operation output. Change-Id: If49da15ed9806f2b0dd2e63911445a55785a5cfb
162 lines
5.9 KiB
Java
162 lines
5.9 KiB
Java
// Copyright (C) 2017 The Android Open Source Project
|
|
//
|
|
// Licensed 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.
|
|
|
|
package com.google.gerrit.pgm;
|
|
|
|
import com.google.auto.value.AutoValue;
|
|
import com.google.common.base.Stopwatch;
|
|
import com.google.common.base.Strings;
|
|
import com.google.gerrit.pgm.util.SiteProgram;
|
|
import com.google.gerrit.server.config.GerritServerConfig;
|
|
import com.google.gerrit.server.config.SitePaths;
|
|
import com.google.gerrit.server.config.ThreadSettingsConfig;
|
|
import com.google.gerrit.server.schema.DataSourceProvider;
|
|
import com.google.gerrit.server.schema.JdbcAccountPatchReviewStore;
|
|
import com.google.inject.Injector;
|
|
import com.google.inject.Key;
|
|
import java.sql.Connection;
|
|
import java.sql.PreparedStatement;
|
|
import java.sql.ResultSet;
|
|
import java.sql.SQLException;
|
|
import java.sql.Statement;
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
import java.util.concurrent.TimeUnit;
|
|
import org.eclipse.jgit.lib.Config;
|
|
import org.kohsuke.args4j.Option;
|
|
|
|
/** Migrates AccountPatchReviewDb from one to another */
|
|
public class MigrateAccountPatchReviewDb extends SiteProgram {
|
|
|
|
@Option(name = "--sourceUrl", usage = "Url of source database")
|
|
private String sourceUrl;
|
|
|
|
@Option(
|
|
name = "--chunkSize",
|
|
usage = "chunk size of fetching from source and push to target on each time"
|
|
)
|
|
private static long chunkSize = 100000;
|
|
|
|
@Override
|
|
public int run() throws Exception {
|
|
Injector dbInjector = createDbInjector(DataSourceProvider.Context.SINGLE_USER);
|
|
SitePaths sitePaths = new SitePaths(getSitePath());
|
|
ThreadSettingsConfig threadSettingsConfig = dbInjector.getInstance(ThreadSettingsConfig.class);
|
|
Config fakeCfg = new Config();
|
|
if (!Strings.isNullOrEmpty(sourceUrl)) {
|
|
fakeCfg.setString("accountPatchReviewDb", null, "url", sourceUrl);
|
|
}
|
|
JdbcAccountPatchReviewStore sourceJdbcAccountPatchReviewStore =
|
|
JdbcAccountPatchReviewStore.createAccountPatchReviewStore(
|
|
fakeCfg, sitePaths, threadSettingsConfig);
|
|
|
|
Config cfg = dbInjector.getInstance(Key.get(Config.class, GerritServerConfig.class));
|
|
String targetUrl = cfg.getString("accountPatchReviewDb", null, "url");
|
|
if (targetUrl == null) {
|
|
System.err.println("accountPatchReviewDb.url is null in gerrit.config");
|
|
return 1;
|
|
}
|
|
System.out.println("target Url: " + targetUrl);
|
|
JdbcAccountPatchReviewStore targetJdbcAccountPatchReviewStore =
|
|
JdbcAccountPatchReviewStore.createAccountPatchReviewStore(
|
|
cfg, sitePaths, threadSettingsConfig);
|
|
targetJdbcAccountPatchReviewStore.createTableIfNotExists();
|
|
|
|
if (!isTargetTableEmpty(targetJdbcAccountPatchReviewStore)) {
|
|
System.err.println("target table is not empty, cannot proceed");
|
|
return 1;
|
|
}
|
|
|
|
try (Connection sourceCon = sourceJdbcAccountPatchReviewStore.getConnection();
|
|
Connection targetCon = targetJdbcAccountPatchReviewStore.getConnection();
|
|
PreparedStatement sourceStmt =
|
|
sourceCon.prepareStatement(
|
|
"SELECT account_id, change_id, patch_set_id, file_name "
|
|
+ "FROM account_patch_reviews "
|
|
+ "LIMIT ? "
|
|
+ "OFFSET ?");
|
|
PreparedStatement targetStmt =
|
|
targetCon.prepareStatement(
|
|
"INSERT INTO account_patch_reviews "
|
|
+ "(account_id, change_id, patch_set_id, file_name) VALUES "
|
|
+ "(?, ?, ?, ?)")) {
|
|
targetCon.setAutoCommit(false);
|
|
long offset = 0;
|
|
Stopwatch sw = Stopwatch.createStarted();
|
|
List<Row> rows = selectRows(sourceStmt, offset);
|
|
while (!rows.isEmpty()) {
|
|
insertRows(targetCon, targetStmt, rows);
|
|
offset += rows.size();
|
|
System.out.printf("%8d rows migrated\n", offset);
|
|
rows = selectRows(sourceStmt, offset);
|
|
}
|
|
double t = sw.elapsed(TimeUnit.MILLISECONDS) / 1000d;
|
|
System.out.printf("Migrated %d rows in %.01fs (%.01f/s)\n", offset, t, offset / t);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
@AutoValue
|
|
abstract static class Row {
|
|
abstract int accountId();
|
|
|
|
abstract int changeId();
|
|
|
|
abstract int patchSetId();
|
|
|
|
abstract String fileName();
|
|
}
|
|
|
|
private static boolean isTargetTableEmpty(JdbcAccountPatchReviewStore store) throws SQLException {
|
|
try (Connection con = store.getConnection();
|
|
Statement s = con.createStatement();
|
|
ResultSet r = s.executeQuery("SELECT COUNT(1) FROM account_patch_reviews")) {
|
|
if (r.next()) {
|
|
return r.getInt(1) == 0;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
private static List<Row> selectRows(PreparedStatement stmt, long offset) throws SQLException {
|
|
List<Row> results = new ArrayList<>();
|
|
stmt.setLong(1, chunkSize);
|
|
stmt.setLong(2, offset);
|
|
try (ResultSet rs = stmt.executeQuery()) {
|
|
while (rs.next()) {
|
|
results.add(
|
|
new AutoValue_MigrateAccountPatchReviewDb_Row(
|
|
rs.getInt("account_id"),
|
|
rs.getInt("change_id"),
|
|
rs.getInt("patch_set_id"),
|
|
rs.getString("file_name")));
|
|
}
|
|
}
|
|
return results;
|
|
}
|
|
|
|
private static void insertRows(Connection con, PreparedStatement stmt, List<Row> rows)
|
|
throws SQLException {
|
|
for (Row r : rows) {
|
|
stmt.setLong(1, r.accountId());
|
|
stmt.setLong(2, r.changeId());
|
|
stmt.setLong(3, r.patchSetId());
|
|
stmt.setString(4, r.fileName());
|
|
stmt.addBatch();
|
|
}
|
|
stmt.executeBatch();
|
|
con.commit();
|
|
}
|
|
}
|