/*- * See the file LICENSE for redistribution information. * * Copyright (c) 2001, 2015 Oracle and/or its affiliates. All rights reserved. * * $Id$ */ // NOTE: This example is a simplified version of the RepQuoteExample.java // example that can be found in the db/examples_java/src/db/repquote directory. // // This example is intended only as an aid in learning Replication Manager // concepts. It is not complete in that many features are not exercised // in it, nor are many error conditions properly handled. package db.repquote_gsg; import java.io.FileNotFoundException; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.lang.Thread; import java.lang.InterruptedException; import com.sleepycat.db.Cursor; import com.sleepycat.db.Database; import com.sleepycat.db.DatabaseConfig; import com.sleepycat.db.DatabaseEntry; import com.sleepycat.db.DatabaseException; import com.sleepycat.db.DeadlockException; import com.sleepycat.db.DatabaseType; import com.sleepycat.db.EnvironmentConfig; import com.sleepycat.db.EventHandler; import com.sleepycat.db.LockMode; import com.sleepycat.db.OperationStatus; import com.sleepycat.db.ReplicationHandleDeadException; import com.sleepycat.db.ReplicationHostAddress; import com.sleepycat.db.ReplicationManagerSiteConfig; import com.sleepycat.db.ReplicationManagerAckPolicy; import db.repquote_gsg.RepConfig; public class RepQuoteExampleGSG implements EventHandler { private RepConfig repConfig; private RepQuoteEnvironment dbenv; public static void usage() { System.err.println("usage: " + RepConfig.progname); System.err.println("-h home -l|-L host:port " + "[-r host:port][-p priority]"); System.err.println("\t -h home directory (required)\n" + "\t -l host:port (required unless -L is specified;" + " l stands for local)\n" + "\t -L host:port (optional, L means group creator)\n" + "\t -r host:port (optional; r stands for remote; any " + "number of these\n" + "\t may be specified)\n" + "\t -p priority (optional; defaults to 100)\n"); System.exit(1); } public static void main(String[] argv) throws Exception { RepConfig config = new RepConfig(); boolean isCreator = false; int tmpPort = 0; // Extract the command line parameters. for (int i = 0; i < argv.length; i++) { if (argv[i].compareTo("-h") == 0) { // home is a string arg. i++; config.home = argv[i]; } else if (argv[i].compareTo("-l") == 0 || argv[i].compareTo("-L") == 0) { if (i == argv.length - 1) usage(); if (argv[i].compareTo("-L") == 0) isCreator = true; // "local" should be host:port. i++; String[] words = argv[i].split(":"); if (words.length != 2) { System.err.println( "Invalid host specification host:port needed."); usage(); } try { tmpPort = Integer.parseInt(words[1]); } catch (NumberFormatException nfe) { System.err.println("Invalid host specification, " + "could not parse port number."); usage(); } config.setThisHost(words[0], tmpPort, isCreator); } else if (argv[i].compareTo("-p") == 0) { i++; config.priority = Integer.parseInt(argv[i]); } else if (argv[i].compareTo("-r") == 0) { i++; String[] words = argv[i].split(":"); if (words.length != 2) { System.err.println( "Invalid host specification host:port needed."); usage(); } try { tmpPort = Integer.parseInt(words[1]); } catch (NumberFormatException nfe) { System.err.println("Invalid host specification, " + "could not parse port number."); usage(); } config.addOtherHost(words[0], tmpPort); } else { System.err.println("Unrecognized option: " + argv[i]); usage(); } } // Error check command line. if ((!config.gotListenAddress()) || config.home.length() == 0) usage(); RepQuoteExampleGSG runner = null; try { runner = new RepQuoteExampleGSG(); runner.init(config); runner.doloop(); runner.terminate(); } catch (DatabaseException dbe) { System.err.println("Caught an exception during " + "initialization or processing: " + dbe.toString()); if (runner != null) runner.terminate(); } System.exit(0); } // end main public RepQuoteExampleGSG() throws DatabaseException { repConfig = null; dbenv = null; } public int init(RepConfig config) throws DatabaseException { int ret = 0; repConfig = config; EnvironmentConfig envConfig = new EnvironmentConfig(); envConfig.setErrorStream(System.err); envConfig.setErrorPrefix(RepConfig.progname); envConfig.addReplicationManagerSite(repConfig.getThisHost()); for (ReplicationHostAddress host = repConfig.getFirstOtherHost(); host != null; host = repConfig.getNextOtherHost()){ ReplicationManagerSiteConfig repmgrRemoteSiteConfig = new ReplicationManagerSiteConfig(host.host, host.port); repmgrRemoteSiteConfig.setBootstrapHelper(true); envConfig.addReplicationManagerSite( repmgrRemoteSiteConfig); } envConfig.setReplicationPriority(repConfig.priority); envConfig.setReplicationManagerAckPolicy( ReplicationManagerAckPolicy.ALL); envConfig.setCacheSize(RepConfig.CACHESIZE); envConfig.setTxnNoSync(true); envConfig.setEventHandler(this); envConfig.setAllowCreate(true); envConfig.setRunRecovery(true); envConfig.setThreaded(true); envConfig.setInitializeReplication(true); envConfig.setInitializeLocking(true); envConfig.setInitializeLogging(true); envConfig.setInitializeCache(true); envConfig.setTransactional(true); try { dbenv = new RepQuoteEnvironment(repConfig.getHome(), envConfig); } catch(FileNotFoundException e) { System.err.println("FileNotFound exception: " + e.toString()); System.err.println( "Ensure that the environment directory is pre-created."); ret = 1; } // Start Replication Manager. dbenv.replicationManagerStart(3, repConfig.startPolicy); return ret; } // Provides the main data processing function for our application. // This function provides a command line prompt to which the user // can provide a ticker string and a stock price. Once a value is // entered to the application, the application writes the value to // the database and then displays the entire database. public int doloop() throws DatabaseException { Database db = null; for (;;) { if (db == null) { DatabaseConfig dbconf = new DatabaseConfig(); dbconf.setType(DatabaseType.BTREE); if (dbenv.getIsMaster()) { dbconf.setAllowCreate(true); } dbconf.setTransactional(true); try { db = dbenv.openDatabase (null, RepConfig.progname, null, dbconf); } catch (java.io.FileNotFoundException e) { System.err.println("No stock database available yet."); if (db != null) { db.close(true); db = null; } try { Thread.sleep(RepConfig.SLEEPTIME); } catch (InterruptedException ie) {} continue; } } BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in)); // Listen for input, and add it to the database. System.out.print("QUOTESERVER"); if (!dbenv.getIsMaster()) System.out.print("(read-only)"); System.out.print("> "); System.out.flush(); String nextline = null; try { nextline = stdin.readLine(); } catch (IOException ioe) { System.err.println("Unable to get data from stdin"); break; } String[] words = nextline.split("\\s"); // A blank line causes the DB to be dumped to stdout. if (words.length == 0 || (words.length == 1 && words[0].length() == 0)) { try { printStocks(db); } catch (DeadlockException de) { continue; // Dead replication handles are cased by an election // resulting in a previously committing read becoming // invalid. Close the db handle and reopen. } catch (ReplicationHandleDeadException rhde) { db.close(true); // close no sync. db = null; continue; } catch (DatabaseException e) { System.err.println("Got db exception reading replication" + "DB: " + e.toString()); break; } continue; } if (words.length == 1 && (words[0].compareToIgnoreCase("quit") == 0 || words[0].compareToIgnoreCase("exit") == 0)) { break; } else if (words.length != 2) { System.err.println("Format: TICKER VALUE"); continue; } if (!dbenv.getIsMaster()) { System.err.println("Can't update client."); continue; } DatabaseEntry key = new DatabaseEntry(words[0].getBytes()); DatabaseEntry data = new DatabaseEntry(words[1].getBytes()); db.put(null, key, data); } if (db != null) db.close(true); return 0; } public void terminate() throws DatabaseException { dbenv.close(); } public void handleRepAutoTakeoverFailedEvent() { // Ignored for now. } public void handleRepClientEvent() { dbenv.setIsMaster(false); } public void handleRepConnectBrokenEvent() { // Ignored for now. } public void handleRepConnectEstablishedEvent() { // Ignored for now. } public void handleRepConnectTryFailedEvent() { // Ignored for now. } public void handleRepInitDoneEvent() { // Ignored for now. } public void handleRepInQueueFullEvent() { // Ignored for now. } public void handleRepMasterEvent() { dbenv.setIsMaster(true); } public void handleRepNewMasterEvent(int envId) { // Ignored for now. } public void handleWriteFailedEvent(int errorCode) { System.err.println("Write to stable storage failed!" + "Operating system error code:" + errorCode); System.err.println("Continuing...."); } public void handleRepStartupDoneEvent() { // Ignored for now. } public void handleRepPermFailedEvent() { // Ignored for now. } public void handleRepLocalSiteRemovedEvent() { // Ignored for now. } public void handleRepSiteAddedEvent() { // Ignored for now. } public void handleRepSiteRemovedEvent() { // Ignored for now. } public void handleRepElectedEvent() { // Safely ignored for Replication Manager applications. } public void handleRepElectionFailedEvent() { // Safely ignored for Replication Manager applications that do // not manage their own master selection. } public void handleRepJoinFailureEvent() { // Safely ignored since this application did not turn off AUTOINIT. } public void handleRepMasterFailureEvent() { // Safely ignored for Replication Manager applications that do // not manage their own master selection. } public void handleRepDupmasterEvent() { // Safely ignored for Replication Manager applications that do // not manage their own master selection. } public void handlePanicEvent() { System.err.println("Panic encountered!"); System.err.println("Shutting down."); System.err.println("You should restart, running recovery."); try { terminate(); } catch (DatabaseException dbe) { System.err.println("Caught an exception during " + "termination in handlePanicEvent: " + dbe.toString()); } System.exit(-1); } // Display all the stock quote information in the database. // Return type is void because error conditions are propagated // via exceptions. private void printStocks(Database db) throws DeadlockException, DatabaseException { Cursor dbc = db.openCursor(null, null); System.out.println("\tSymbol\tPrice"); System.out.println("\t======\t====="); DatabaseEntry key = new DatabaseEntry(); DatabaseEntry data = new DatabaseEntry(); OperationStatus ret; for (ret = dbc.getFirst(key, data, LockMode.DEFAULT); ret == OperationStatus.SUCCESS; ret = dbc.getNext(key, data, LockMode.DEFAULT)) { String keystr = new String (key.getData(), key.getOffset(), key.getSize()); String datastr = new String (data.getData(), data.getOffset(), data.getSize()); System.out.println("\t"+keystr+"\t"+datastr); } dbc.close(); } } // end class