com.github.brandtg.switchboard.TestMysqlReplicationApplier.java Source code

Java tutorial

Introduction

Here is the source code for com.github.brandtg.switchboard.TestMysqlReplicationApplier.java

Source

/**
 * 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);
    }
}