Java tutorial
/** * Copyright (C) 2015 Greg Brandt (brandt.greg@gmail.com) * * 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.github.brandtg.switchboard; import com.google.code.or.common.util.CodecUtils; import com.google.code.or.common.util.MySQLConstants; import junit.framework.Assert; import org.apache.commons.dbcp2.ConnectionFactory; import org.apache.commons.dbcp2.DriverManagerConnectionFactory; import org.apache.commons.dbcp2.PoolableConnection; import org.apache.commons.dbcp2.PoolableConnectionFactory; import org.apache.commons.dbcp2.PoolingDataSource; import org.apache.commons.io.FileUtils; import org.apache.commons.pool2.ObjectPool; import org.apache.commons.pool2.impl.GenericObjectPool; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import javax.management.ObjectName; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.net.URLEncoder; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.Statement; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; public class TestMysqlReplicationApplier { private String jdbc; @BeforeClass public void beforeClass() throws Exception { jdbc = "jdbc:mysql://localhost:3306/test"; resetMysql(); } @Test public void testRestoreFromBinlog() throws Exception { MysqlReplicationApplier applier = null; try (Connection conn = DriverManager.getConnection(jdbc, "root", "")) { // Write some rows, so we have binlog entries PreparedStatement pstmt = conn.prepareStatement("INSERT INTO simple VALUES(?, ?)"); for (int i = 0; i < 10; i++) { pstmt.setInt(1, i); pstmt.setInt(2, i); pstmt.execute(); } // Copy the binlog somewhere Statement stmt = conn.createStatement(); ResultSet rset = stmt.executeQuery("SHOW BINARY LOGS"); rset.next(); String binlogName = rset.getString("Log_name"); rset = stmt.executeQuery("SELECT @@datadir"); rset.next(); String dataDir = rset.getString("@@datadir"); File copyFile = new File(System.getProperty("java.io.tmpdir"), TestMysqlReplicationApplier.class.getName()); FileUtils.copyFile(new File(dataDir + binlogName), copyFile); // Clear everything in MySQL resetMysql(); // Get input stream, skipping and checking binlog magic number InputStream inputStream = new FileInputStream(copyFile); byte[] magic = new byte[MySQLConstants.BINLOG_MAGIC.length]; int bytesRead = inputStream.read(magic); Assert.assertEquals(bytesRead, MySQLConstants.BINLOG_MAGIC.length); Assert.assertTrue(CodecUtils.equals(magic, MySQLConstants.BINLOG_MAGIC)); // Restore from binlog PoolingDataSource<PoolableConnection> dataSource = getDataSource(); applier = new MysqlReplicationApplier(inputStream, dataSource); ExecutorService executorService = Executors.newSingleThreadExecutor(new ThreadFactory() { @Override public Thread newThread(Runnable r) { Thread t = new Thread(r); t.setDaemon(true); return t; } }); executorService.submit(applier); // Poll until we have restored long startTime = System.currentTimeMillis(); long currentTime = startTime; do { stmt = conn.createStatement(); rset = stmt.executeQuery("SELECT COUNT(*) FROM test.simple"); rset.next(); long count = rset.getLong(1); if (count == 10) { return; } Thread.sleep(1000); currentTime = System.currentTimeMillis(); } while (currentTime - startTime < 10000); } finally { if (applier != null) { applier.shutdown(); } } Assert.fail("Timed out when polling"); } private void resetMysql() throws Exception { // Reset and setup local MySQL try (Connection conn = DriverManager.getConnection(jdbc, "root", "")) { Statement stmt = conn.createStatement(); stmt.execute("RESET MASTER"); stmt.execute("GRANT ALL ON *.* TO 'switchboard'@'localhost' IDENTIFIED BY 'switchboard'"); stmt.execute("DROP TABLE IF EXISTS simple"); stmt.execute("CREATE TABLE simple (k INT, v INT)"); } } private PoolingDataSource<PoolableConnection> getDataSource() throws Exception { // DBCP2 pool ConnectionFactory connectionFactory = new DriverManagerConnectionFactory(jdbc, "root", ""); ObjectName poolName = new ObjectName(JdbcBasedLogIndex.class.getCanonicalName(), URLEncoder.encode(jdbc, "UTF-8"), "replicatorConnectionPool"); PoolableConnectionFactory poolableConnectionFactory = new PoolableConnectionFactory(connectionFactory, poolName); ObjectPool<PoolableConnection> connectionPool = new GenericObjectPool<PoolableConnection>( poolableConnectionFactory); poolableConnectionFactory.setPool(connectionPool); return new PoolingDataSource<PoolableConnection>(connectionPool); } }