1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 2001-2009 Oracle. All rights reserved. 5 * 6 * $Id$ 7 */ 8 9// NOTE: This example is a simplified version of the RepQuoteExample.java 10// example that can be found in the db/examples_java/src/db/repquote directory. 11// 12// This example is intended only as an aid in learning Replication Manager 13// concepts. It is not complete in that many features are not exercised 14// in it, nor are many error conditions properly handled. 15 16package db.repquote_gsg; 17 18import java.io.FileNotFoundException; 19import java.io.BufferedReader; 20import java.io.InputStreamReader; 21import java.io.IOException; 22import java.io.UnsupportedEncodingException; 23import java.lang.Thread; 24import java.lang.InterruptedException; 25 26import com.sleepycat.db.Cursor; 27import com.sleepycat.db.Database; 28import com.sleepycat.db.DatabaseConfig; 29import com.sleepycat.db.DatabaseEntry; 30import com.sleepycat.db.DatabaseException; 31import com.sleepycat.db.DeadlockException; 32import com.sleepycat.db.DatabaseType; 33import com.sleepycat.db.EnvironmentConfig; 34import com.sleepycat.db.EventHandler; 35import com.sleepycat.db.LockMode; 36import com.sleepycat.db.OperationStatus; 37import com.sleepycat.db.ReplicationHandleDeadException; 38import com.sleepycat.db.ReplicationHostAddress; 39import com.sleepycat.db.ReplicationManagerStartPolicy; 40import com.sleepycat.db.ReplicationManagerAckPolicy; 41import db.repquote_gsg.RepConfig; 42 43public class RepQuoteExampleGSG implements EventHandler 44{ 45 private RepConfig repConfig; 46 private RepQuoteEnvironment dbenv; 47 48 public static void usage() 49 { 50 System.err.println("usage: " + RepConfig.progname); 51 System.err.println("-h home -l host:port [-r host:port]" + 52 "[-n nsites][-p priority]"); 53 54 System.err.println("\t -h home directory (required)\n" + 55 "\t -l host:port (required; l stands for local)\n" + 56 "\t -r host:port (optional; r stands for remote; any " + 57 "number of these\n" + 58 "\t may be specified)\n" + 59 "\t -n nsites (optional; number of sites in replication " + 60 "group; defaults\n" + 61 "\t to 0 to try to dynamically compute nsites)\n" + 62 "\t -p priority (optional; defaults to 100)\n"); 63 64 System.exit(1); 65 } 66 67 public static void main(String[] argv) 68 throws Exception 69 { 70 RepConfig config = new RepConfig(); 71 String tmpHost; 72 int tmpPort = 0; 73 // Extract the command line parameters. 74 for (int i = 0; i < argv.length; i++) 75 { 76 if (argv[i].compareTo("-h") == 0) { 77 // home is a string arg. 78 i++; 79 config.home = argv[i]; 80 } else if (argv[i].compareTo("-l") == 0) { 81 // "local" should be host:port. 82 i++; 83 String[] words = argv[i].split(":"); 84 if (words.length != 2) { 85 System.err.println( 86 "Invalid host specification host:port needed."); 87 usage(); 88 } 89 try { 90 tmpPort = Integer.parseInt(words[1]); 91 } catch (NumberFormatException nfe) { 92 System.err.println("Invalid host specification, " + 93 "could not parse port number."); 94 usage(); 95 } 96 config.setThisHost(words[0], tmpPort); 97 } else if (argv[i].compareTo("-n") == 0) { 98 i++; 99 config.totalSites = Integer.parseInt(argv[i]); 100 } else if (argv[i].compareTo("-p") == 0) { 101 i++; 102 config.priority = Integer.parseInt(argv[i]); 103 } else if (argv[i].compareTo("-r") == 0) { 104 i++; 105 String[] words = argv[i].split(":"); 106 if (words.length != 2) { 107 System.err.println( 108 "Invalid host specification host:port needed."); 109 usage(); 110 } 111 try { 112 tmpPort = Integer.parseInt(words[1]); 113 } catch (NumberFormatException nfe) { 114 System.err.println("Invalid host specification, " + 115 "could not parse port number."); 116 usage(); 117 } 118 config.addOtherHost(words[0], tmpPort); 119 } else { 120 System.err.println("Unrecognized option: " + argv[i]); 121 usage(); 122 } 123 124 } 125 126 // Error check command line. 127 if ((!config.gotListenAddress()) || config.home.length() == 0) 128 usage(); 129 130 RepQuoteExampleGSG runner = null; 131 try { 132 runner = new RepQuoteExampleGSG(); 133 runner.init(config); 134 135 runner.doloop(); 136 runner.terminate(); 137 } catch (DatabaseException dbe) { 138 System.err.println("Caught an exception during " + 139 "initialization or processing: " + dbe.toString()); 140 if (runner != null) 141 runner.terminate(); 142 } 143 System.exit(0); 144 } // end main 145 146 public RepQuoteExampleGSG() 147 throws DatabaseException 148 { 149 repConfig = null; 150 dbenv = null; 151 } 152 153 public int init(RepConfig config) 154 throws DatabaseException 155 { 156 int ret = 0; 157 repConfig = config; 158 EnvironmentConfig envConfig = new EnvironmentConfig(); 159 envConfig.setErrorStream(System.err); 160 envConfig.setErrorPrefix(RepConfig.progname); 161 162 envConfig.setReplicationManagerLocalSite(repConfig.getThisHost()); 163 for (ReplicationHostAddress host = repConfig.getFirstOtherHost(); 164 host != null; host = repConfig.getNextOtherHost()) 165 envConfig.replicationManagerAddRemoteSite(host, false); 166 167 if (repConfig.totalSites > 0) 168 envConfig.setReplicationNumSites(repConfig.totalSites); 169 envConfig.setReplicationPriority(repConfig.priority); 170 171 envConfig.setReplicationManagerAckPolicy( 172 ReplicationManagerAckPolicy.ALL); 173 envConfig.setCacheSize(RepConfig.CACHESIZE); 174 envConfig.setTxnNoSync(true); 175 176 envConfig.setEventHandler(this); 177 178 envConfig.setAllowCreate(true); 179 envConfig.setRunRecovery(true); 180 envConfig.setThreaded(true); 181 envConfig.setInitializeReplication(true); 182 envConfig.setInitializeLocking(true); 183 envConfig.setInitializeLogging(true); 184 envConfig.setInitializeCache(true); 185 envConfig.setTransactional(true); 186 try { 187 dbenv = new RepQuoteEnvironment(repConfig.getHome(), envConfig); 188 } catch(FileNotFoundException e) { 189 System.err.println("FileNotFound exception: " + e.toString()); 190 System.err.println( 191 "Ensure that the environment directory is pre-created."); 192 ret = 1; 193 } 194 195 // Start Replication Manager. 196 dbenv.replicationManagerStart(3, repConfig.startPolicy); 197 return ret; 198 } 199 200 // Provides the main data processing function for our application. 201 // This function provides a command line prompt to which the user 202 // can provide a ticker string and a stock price. Once a value is 203 // entered to the application, the application writes the value to 204 // the database and then displays the entire database. 205 public int doloop() 206 throws DatabaseException 207 { 208 Database db = null; 209 210 for (;;) 211 { 212 if (db == null) { 213 DatabaseConfig dbconf = new DatabaseConfig(); 214 dbconf.setType(DatabaseType.BTREE); 215 if (dbenv.getIsMaster()) { 216 dbconf.setAllowCreate(true); 217 } 218 dbconf.setTransactional(true); 219 220 try { 221 db = dbenv.openDatabase 222 (null, RepConfig.progname, null, dbconf); 223 } catch (java.io.FileNotFoundException e) { 224 System.err.println("No stock database available yet."); 225 if (db != null) { 226 db.close(true); 227 db = null; 228 } 229 try { 230 Thread.sleep(RepConfig.SLEEPTIME); 231 } catch (InterruptedException ie) {} 232 continue; 233 } 234 } 235 236 BufferedReader stdin = 237 new BufferedReader(new InputStreamReader(System.in)); 238 239 // Listen for input, and add it to the database. 240 System.out.print("QUOTESERVER"); 241 if (!dbenv.getIsMaster()) 242 System.out.print("(read-only)"); 243 System.out.print("> "); 244 System.out.flush(); 245 String nextline = null; 246 try { 247 nextline = stdin.readLine(); 248 } catch (IOException ioe) { 249 System.err.println("Unable to get data from stdin"); 250 break; 251 } 252 String[] words = nextline.split("\\s"); 253 254 // A blank line causes the DB to be dumped to stdout. 255 if (words.length == 0 || 256 (words.length == 1 && words[0].length() == 0)) { 257 try { 258 printStocks(db); 259 } catch (DeadlockException de) { 260 continue; 261 // Dead replication handles are cased by an election 262 // resulting in a previously committing read becoming 263 // invalid. Close the db handle and reopen. 264 } catch (ReplicationHandleDeadException rhde) { 265 db.close(true); // close no sync. 266 db = null; 267 continue; 268 } catch (DatabaseException e) { 269 System.err.println("Got db exception reading replication" + 270 "DB: " + e.toString()); 271 break; 272 } 273 continue; 274 } 275 276 if (words.length == 1 && 277 (words[0].compareToIgnoreCase("quit") == 0 || 278 words[0].compareToIgnoreCase("exit") == 0)) { 279 break; 280 } else if (words.length != 2) { 281 System.err.println("Format: TICKER VALUE"); 282 continue; 283 } 284 285 if (!dbenv.getIsMaster()) { 286 System.err.println("Can't update client."); 287 continue; 288 } 289 290 DatabaseEntry key = new DatabaseEntry(words[0].getBytes()); 291 DatabaseEntry data = new DatabaseEntry(words[1].getBytes()); 292 293 db.put(null, key, data); 294 } 295 if (db != null) 296 db.close(true); 297 return 0; 298 } 299 300 public void terminate() 301 throws DatabaseException 302 { 303 dbenv.close(); 304 } 305 306 public void handleRepClientEvent() 307 { 308 dbenv.setIsMaster(false); 309 } 310 311 public void handleRepMasterEvent() 312 { 313 dbenv.setIsMaster(true); 314 } 315 316 public void handleRepNewMasterEvent(int envId) 317 { 318 // Ignored for now. 319 } 320 321 public void handleWriteFailedEvent(int errorCode) 322 { 323 System.err.println("Write to stable storage failed!" + 324 "Operating system error code:" + errorCode); 325 System.err.println("Continuing...."); 326 } 327 328 public void handleRepStartupDoneEvent() 329 { 330 // Ignored for now. 331 } 332 333 public void handleRepPermFailedEvent() 334 { 335 // Ignored for now. 336 } 337 338 public void handleRepElectedEvent() 339 { 340 // Safely ignored for Replication Manager applications. 341 } 342 343 public void handlePanicEvent() 344 { 345 System.err.println("Panic encountered!"); 346 System.err.println("Shutting down."); 347 System.err.println("You should restart, running recovery."); 348 try { 349 terminate(); 350 } catch (DatabaseException dbe) { 351 System.err.println("Caught an exception during " + 352 "termination in handlePanicEvent: " + dbe.toString()); 353 } 354 System.exit(-1); 355 } 356 357 // Display all the stock quote information in the database. 358 // Return type is void because error conditions are propagated 359 // via exceptions. 360 private void printStocks(Database db) 361 throws DeadlockException, DatabaseException 362 { 363 Cursor dbc = db.openCursor(null, null); 364 365 System.out.println("\tSymbol\tPrice"); 366 System.out.println("\t======\t====="); 367 368 DatabaseEntry key = new DatabaseEntry(); 369 DatabaseEntry data = new DatabaseEntry(); 370 OperationStatus ret; 371 for (ret = dbc.getFirst(key, data, LockMode.DEFAULT); 372 ret == OperationStatus.SUCCESS; 373 ret = dbc.getNext(key, data, LockMode.DEFAULT)) { 374 String keystr = new String 375 (key.getData(), key.getOffset(), key.getSize()); 376 String datastr = new String 377 (data.getData(), data.getOffset(), data.getSize()); 378 System.out.println("\t"+keystr+"\t"+datastr); 379 } 380 dbc.close(); 381 } 382} // end class 383 384