All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sleepycat.je.rep.utilint.DbSync Maven / Gradle / Ivy

The newest version!
/*-
 * Copyright (C) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
 *
 * This file was distributed by Oracle as part of a version of Oracle Berkeley
 * DB Java Edition made available at:
 *
 * http://www.oracle.com/technetwork/database/database-technologies/berkeleydb/downloads/index.html
 *
 * Please see the LICENSE file included in the top-level directory of the
 * appropriate version of Oracle Berkeley DB Java Edition for a copy of the
 * license and additional information.
 */

package com.sleepycat.je.rep.utilint;

import static com.sleepycat.je.rep.impl.RepParams.NODE_HOST_PORT;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import com.sleepycat.je.Durability;
import com.sleepycat.je.EnvironmentConfig;
import com.sleepycat.je.Transaction;
import com.sleepycat.je.rep.GroupShutdownException;
import com.sleepycat.je.rep.QuorumPolicy;
import com.sleepycat.je.rep.ReplicatedEnvironment;
import com.sleepycat.je.rep.ReplicationNetworkConfig;
import com.sleepycat.je.rep.ReplicationConfig;
import com.sleepycat.je.rep.StateChangeEvent;
import com.sleepycat.je.rep.StateChangeListener;
import com.sleepycat.je.utilint.CmdUtil;

/**
 * DbSync is a utility for ensuring that a group of replication nodes have
 * fully caught up on the replication stream. The target use case is
 * testing. If a replication group has crashed abruptly, nodes may have closed
 * without finishing the full replay of the replication stream and the
 * environments might not have the same contents. This makes it impossible to
 * compare the contents of the environments for correctness.
 * 

* DbSync assumes that all nodes are down. The utility is invoked for each node * in the group. The node will come up and rejoin the group, causing the whole * group to reach the same point in the replication stream. If the node becomes * the master, it will issue a shutdown request. Otherwise, a node is a * replica, and will wait for the shutdown message to come, and will then * close. */ public class DbSync { public static final String DBSYNC_ENV = "-env"; public static final String DBSYNC_GROUP_NAME = "-groupName"; public static final String DBSYNC_NODE_NAME = "-nodeName"; public static final String DBSYNC_NODE_HOST = "-nodeHost"; public static final String DBSYNC_HELPER_HOST = "-helperHost"; public static final String DBSYNC_TIMEOUT = "-timeout"; public static final String DBSYNC_NET_PROPS = "-netProps"; private static final String FORMAT = "%1$-15s"; private String envHome; private ReplicationConfig repConfig; private EnvironmentConfig envConfig; private String helperHost; /* The group shutdown timeout value, in milliseconds. */ private long timeout; private static final String usageString = "usage: " + CmdUtil.getJavaCommand(DbSync.class) + "\n" + String.format(FORMAT, DBSYNC_ENV) + "# environment home directory for the node\n" + String.format(FORMAT, DBSYNC_GROUP_NAME) + "# name of the replication group\n" + String.format(FORMAT, DBSYNC_NODE_NAME) + "# name of the node in the group\n" + String.format(FORMAT, DBSYNC_NODE_HOST) + "# host name or IP address and port number for the node\n" + String.format(FORMAT, DBSYNC_HELPER_HOST) + "# helperHost for the node\n" + String.format(FORMAT, DBSYNC_TIMEOUT) + "# time for the node to catch up with master, in milliseconds\n"; public static void main(String[] args) throws Exception { DbSync syncup = new DbSync(); syncup.parseArgs(args); syncup.sync(); } private void printUsage(String msg) { System.err.println(msg); System.err.println(usageString); System.exit(-1); } private void parseArgs(String[] args) throws Exception { int argc = 0; int nArgs = args.length; String nodeName = null; String nodeHost = null; String groupName = null; String netPropsName = null; while (argc < nArgs) { String thisArg = args[argc++].trim(); if (thisArg.equals(DBSYNC_ENV)) { if (argc < nArgs) { envHome = args[argc++]; } else { printUsage(DBSYNC_ENV + " requires an argument"); } } else if (thisArg.equals(DBSYNC_GROUP_NAME)) { if (argc < nArgs) { groupName = args[argc++]; } else { printUsage(DBSYNC_GROUP_NAME + " requires an argument"); } } else if (thisArg.equals(DBSYNC_NODE_NAME)) { if (argc < nArgs) { nodeName = args[argc++]; } else { printUsage(DBSYNC_NODE_NAME + " requires an argument"); } } else if (thisArg.equals(DBSYNC_NODE_HOST)) { if (argc < nArgs) { nodeHost = args[argc++]; } else { printUsage(DBSYNC_NODE_HOST + " requires an argument"); } } else if (thisArg.equals(DBSYNC_HELPER_HOST)) { if (argc < nArgs) { helperHost = args[argc++]; } else { printUsage(DBSYNC_HELPER_HOST + " requires an argument"); } } else if (thisArg.equals(DBSYNC_TIMEOUT)) { if (argc < nArgs) { timeout = Long.parseLong(args[argc++]); } else { printUsage(DBSYNC_TIMEOUT + " requires an argument"); } } else if (thisArg.equals(DBSYNC_NET_PROPS)) { if (argc < nArgs) { netPropsName = args[argc++]; } else { printUsage(DBSYNC_NET_PROPS + " requires an argument"); } } } if (envHome == null) { printUsage(DBSYNC_ENV + " is a required argument."); } if (groupName == null) { printUsage(DBSYNC_GROUP_NAME + " is a required argument."); } if (nodeName == null) { printUsage(DBSYNC_NODE_NAME + " is a required argument."); } if (nodeHost == null) { printUsage(DBSYNC_NODE_HOST + " is a required argument."); } if (helperHost == null) { printUsage(DBSYNC_HELPER_HOST + " is a required argument."); } if (timeout <= 0) { printUsage(DBSYNC_TIMEOUT + " should be a positive long number."); } try { NODE_HOST_PORT.validateValue(nodeHost); } catch (IllegalArgumentException e) { e.printStackTrace(); printUsage("Host and Port pair for this node is illegal."); } ReplicationNetworkConfig repNetConfig = ReplicationNetworkConfig.createDefault(); if (netPropsName != null) { try { repNetConfig = ReplicationNetworkConfig.create(new File(netPropsName)); } catch (FileNotFoundException fnfe) { printUsage("The netProps file " + netPropsName + " does not exist."); } catch (IllegalArgumentException iae) { printUsage("The net properties file " + netPropsName + " is not valid: " + iae.getMessage()); } } envConfig = new EnvironmentConfig(); envConfig.setAllowCreate(true); envConfig.setTransactional(true); repConfig = new ReplicationConfig(); repConfig.setNodeName(nodeName); repConfig.setGroupName(groupName); repConfig.setNodeHostPort(nodeHost); repConfig.setHelperHosts(helperHost); repConfig.setRepNetConfig(repNetConfig); } private DbSync() { } /** * Create a DbSync object for the purposed of syncing up a specific * replication group. * * @param envHome The Environment home directories of this replica. * @param helperHost The helper host for this replica. * @param timeout The permitted time period, in milliseconds, for the * replica to catch up with master. */ public DbSync(String envHome, EnvironmentConfig envConfig, ReplicationConfig repConfig, String helperHost, long timeout) { this.envHome = envHome; this.envConfig = envConfig; this.repConfig = repConfig; this.helperHost = helperHost; this.timeout = timeout; } /** * Open this replication node. Block until the node has opened, synced up, * and closed. */ public void sync() throws Exception { /* * Set the ReplicaAckPolicy to ALL, so that all the replicas can get * into a same sync point. */ Durability durability = new Durability(Durability.SyncPolicy.WRITE_NO_SYNC, Durability.SyncPolicy.WRITE_NO_SYNC, Durability.ReplicaAckPolicy.ALL); envConfig.setDurability(durability); repConfig.setHelperHosts(helperHost); /* Exit if can't create a replicated Environment successfully. */ StatusListener listener = new StatusListener(); ReplicatedEnvironment repEnv = null; try { repEnv = new ReplicatedEnvironment(new File(envHome), repConfig, envConfig, null, QuorumPolicy.ALL); repEnv.setStateChangeListener(listener); } catch (Exception e) { System.err.println("Can't successfully initialize " + repConfig.getNodeName() + " because of " + e); System.exit(-1); } /* Wait until the node becomes active. */ listener.awaitActiveState(); if (repEnv.getState().isMaster()) { /* * If master, start a transaction as a way of ascertaining whether * all nodes are up. Since the ReplicaAckPolicy is ALL, the * transaction will only begin when all the nodes are available. */ Transaction txn = repEnv.beginTransaction(null, null); txn.abort(); /* Invoke the group shutdown API. */ repEnv.shutdownGroup(timeout, TimeUnit.SECONDS); } else if (repEnv.getState().isReplica()) { for (long i = 0; i < timeout; i++) { try { /* * The replica will throw a GroupShutdownException if it * has received and processed the group close command from * the master. */ repEnv.getState(); Thread.sleep(1000); } catch (GroupShutdownException e) { break; } } } /* Shutdown the rep node. */ repEnv.close(); } /** * Wait for this node to become either a master or a replica. */ private class StatusListener implements StateChangeListener { CountDownLatch activeLatch = new CountDownLatch(1); @Override public void stateChange(StateChangeEvent stateChangeEvent) throws RuntimeException { switch (stateChangeEvent.getState()) { case MASTER: case REPLICA: activeLatch.countDown(); break; default: System.err.println (repConfig.getNodeName() + " is disconnected from group."); break; } } public void awaitActiveState() throws InterruptedException { activeLatch.await(); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy