/** Opens the database and creates the Map. */ private void open() throws Exception { // use a generic database configuration DatabaseConfig dbConfig = new DatabaseConfig(); dbConfig.setTransactional(true); if (create) { dbConfig.setAllowCreate(true); dbConfig.setType(DatabaseType.BTREE); } // catalog is needed for serial bindings (java serialization) Database catalogDb = env.openDatabase(null, "catalog", null, dbConfig); catalog = new StoredClassCatalog(catalogDb); // use Integer tuple binding for key entries TupleBinding keyBinding = TupleBinding.getPrimitiveBinding(Integer.class); // use String serial binding for data entries SerialBinding dataBinding = new SerialBinding(catalog, String.class); this.db = env.openDatabase(null, "helloworld", null, dbConfig); // create a map view of the database this.map = new StoredSortedMap(db, keyBinding, dataBinding, true); }
public void runTest(DatabaseType type) throws DatabaseException, FileNotFoundException { int i; DatabaseConfig conf = new DatabaseConfig(); conf.setErrorStream(TestUtils.getErrorStream()); conf.setErrorPrefix("HashCompareTest"); conf.setType(type); if (type == DatabaseType.HASH) { conf.setHashComparator(new HashComparator()); } else conf.setBtreeComparator(new BtreeComparator()); conf.setAllowCreate(true); Database db = new Database(HASHCOMPARETEST_DBNAME, null, conf); DatabaseEntry key = new DatabaseEntry(); DatabaseEntry data = new DatabaseEntry("world".getBytes()); for (i = 0; i < 100; i++) { key.setData((new String("key" + i)).getBytes()); db.put(null, key, data); } i = 0; Cursor dbc; dbc = db.openCursor(null, CursorConfig.DEFAULT); while (dbc.getNext(key, data, LockMode.DEFAULT) == OperationStatus.SUCCESS) { ++i; } // System.out.println("retrieved " + i + " entries"); dbc.close(); db.close(); }
public static Database buildsecondary(Database std) { // Parse database loaded try { io.deleteFile("secondarydb"); // SecondaryDatabases started DatabaseConfig dbConfig = new DatabaseConfig(); dbConfig.setType(DatabaseType.HASH); dbConfig.setAllowCreate(true); dbConfig.setUnsortedDuplicates(true); Database secdb = new Database("secondarydb", null, dbConfig); // Cursors started Cursor stdcursor = std.openCursor(null, null); Cursor secdbcursor = secdb.openCursor(null, null); // Key and Data started DatabaseEntry stdkey = new DatabaseEntry(); DatabaseEntry stddata = new DatabaseEntry(); DatabaseEntry seckey = new DatabaseEntry(); DatabaseEntry secdata = new DatabaseEntry(); while (stdcursor.getNext(stdkey, stddata, LockMode.DEFAULT) == OperationStatus.SUCCESS) { // Writing into secondary db String[] key = new String(stdkey.getData()).split(","); String data = new String(stddata.getData()); // DEBUG: // System.out.println("key 0:" + key[0] + " key 1:" + key[1] + " data:" + data); seckey.setData(key[1].getBytes()); OperationStatus operation = secdbcursor.getSearchKey(seckey, secdata, LockMode.DEFAULT); String b = null; while (operation == OperationStatus.SUCCESS) { b = new String(secdata.getData()); secdbcursor.delete(); operation = secdbcursor.getNextDup(seckey, secdata, LockMode.DEFAULT); } if (b == null) { seckey.setData(key[1].getBytes()); secdata.setData(("(" + key[0] + "," + data + ")").getBytes()); secdb.put(null, seckey, secdata); } if (b != null) { secdata.setData(b.concat("(" + key[0] + "," + data + ")").getBytes()); secdb.put(null, seckey, secdata); } seckey.setData(null); secdata.setData(null); stdkey.setData(null); stddata.setData(null); } // io.debugread(secdb); return secdb; } catch (Exception e) { System.out.println("Error creating <user>,<song,rating> secondary table!\n"); System.out.println(e.getMessage()); } return null; // SHOULD NEVER HAPPEN }
public static Database buildtertiary(Database std) { try { // configure new database instance io.deleteFile("tertiarydb"); DatabaseConfig dbConfig = new DatabaseConfig(); dbConfig.setType(DatabaseType.HASH); dbConfig.setAllowCreate(true); dbConfig.setUnsortedDuplicates(true); Database tdb = new Database("tertiarydb", null, dbConfig); // configure cursors and entries Cursor stdCurs = std.openCursor(null, null); Cursor tCurs = tdb.openCursor(null, null); DatabaseEntry stdKey = new DatabaseEntry(); DatabaseEntry stdData = new DatabaseEntry(); DatabaseEntry tKey = new DatabaseEntry(); DatabaseEntry tData = new DatabaseEntry(); // extract from linearly constructed database to populate <song>,<users> table, making // use of songs grouped by id String currUsers = ""; String prevID = "default"; boolean firstIter = true; while (stdCurs.getNext(stdKey, stdData, LockMode.DEFAULT) == OperationStatus.SUCCESS) { // get rating data from current row String[] currIDUser = (new String(stdKey.getData())).split(","); String currID = currIDUser[0].trim(); String currUser = currIDUser[1].trim(); String currRating = (new String(stdData.getData())); stdKey.setData(null); stdData.setData(null); if (currID.equals(prevID) || firstIter) { // concatenate new username with current string currUsers += "(" + currUser + "," + currRating + ")"; } else if (!firstIter) { // insert completed <usernames> into table under key <song id> tKey.setData(prevID.getBytes()); tData.setData(currUsers.substring(0, currUsers.length()).getBytes()); tCurs.put(tKey, tData); tKey.setData(null); tData.setData(null); // DEBUG: // System.out.println(prevID+","+currUsers.substring(0, currUsers.length()-1)); // start the new <usernames> for the next song (in currID) currUsers = "(" + currUser + "," + currRating + ")"; } prevID = currID; firstIter = false; } // repeat iteration for last song tKey.setData(prevID.getBytes()); tData.setData(currUsers.substring(0, currUsers.length()).getBytes()); tCurs.put(tKey, tData); tKey.setData(null); tData.setData(null); // DEBUG: // io.debugread(tdb); tCurs.close(); return tdb; } catch (Exception e) { System.out.println(" error creating <song>,<users> tertiary table\n"); System.out.println(e.getMessage()); } return null; // should never happen }
public static String top3(String line, Database secdb, Database tdb) throws DatabaseException, FileNotFoundException { // configure sqSum db for keeping track of cumulative squaresums io.deleteFile("sqSumdb"); DatabaseConfig dbConfig = new DatabaseConfig(); dbConfig.setType(DatabaseType.HASH); dbConfig.setAllowCreate(true); dbConfig.setUnsortedDuplicates(true); Database sqSumdb = new Database("sqSumdb", null, dbConfig); Cursor sqSumCurs = sqSumdb.openCursor(null, null); DatabaseEntry sqSumKey = new DatabaseEntry(); DatabaseEntry sqSumData = new DatabaseEntry(); Cursor secCurs = secdb.openCursor(null, null); Cursor tCurs = tdb.openCursor(null, null); DatabaseEntry secKey = new DatabaseEntry(); DatabaseEntry secData = new DatabaseEntry(); DatabaseEntry tKey = new DatabaseEntry(); DatabaseEntry tData = new DatabaseEntry(); // get input song users and ratings tKey.setData(line.getBytes()); if (tCurs.getSearchKey(tKey, tData, LockMode.DEFAULT) == OperationStatus.SUCCESS) { // for each user in input song, get songs and ratings HashMap<String, String> iRatings = parseBrace(new String(tData.getData())); for (String user : iRatings.keySet()) { // get current user's rating for input song int inputRating = Integer.parseInt(iRatings.get(user)); // get songs and ratings for user secKey.setData(null); secData.setData(null); secKey.setData(user.getBytes()); if (secCurs.getSearchKey(secKey, secData, null) == OperationStatus.SUCCESS) { // for each song rated by user HashMap<String, String> currSongs = parseBrace(new String(secData.getData())); for (String song : currSongs.keySet()) { // input song should not be compared to itself, otherwise get the users and ratings for // it if (song.equals(line)) continue; // current user's rating for song under inspection int songRating = Integer.parseInt(currSongs.get(song)); sqSumKey.setData(null); sqSumData.setData(null); sqSumKey.setData(song.getBytes()); if (sqSumCurs.getSearchKey(sqSumKey, sqSumData, null) == OperationStatus.SUCCESS) { // if song is already in sqSum,N db, add to it String[] sumN = (new String(sqSumData.getData())).split(","); // add the new square sum to the previous and increment N int sum = Integer.parseInt(sumN[0]); int N = Integer.parseInt(sumN[1]); sum += (inputRating - songRating) * (inputRating - songRating); N += 1; String encoded = Integer.toString(sum) + "," + Integer.toString(N); // remove old entry for current song and replace it with the new one sqSumCurs.delete(); sqSumKey.setData(null); sqSumData.setData(null); sqSumKey.setData(song.getBytes()); sqSumData.setData(encoded.getBytes()); sqSumdb.put(null, sqSumKey, sqSumData); } else { // if song in not already in sqSum,N db, create it int sum = (inputRating - songRating) * (inputRating - songRating); int N = 1; String encoded = Integer.toString(sum) + "," + Integer.toString(N); sqSumKey.setData(null); sqSumData.setData(null); sqSumKey.setData(song.getBytes()); sqSumData.setData(encoded.getBytes()); sqSumdb.put(null, sqSumKey, sqSumData); } } } else { System.out.println("ERROR: user " + user + " not in secondary database."); } } } else { return line + " has not been rated by any user."; } // DEBUG // io.debugread(sqSumdb); // calculate distance for each song in, inserting into the top 3 spots as we iterate through String ranked = rank(sqSumdb); return line + ", " + ranked; }
ObjectStore( String facet, String facetType, boolean createDb, EvictorI evictor, java.util.List<Index> indices, boolean populateEmptyIndices) { _cache = new Cache(this); _facet = facet; _evictor = evictor; _indices = indices; _communicator = evictor.communicator(); _encoding = evictor.encoding(); _keepStats = false; if (facet.equals("")) { _dbName = EvictorI.defaultDb; } else { _dbName = facet; } if (facetType != null) { // // Create a sample servant with this type // Ice.ValueFactory factory = _communicator.getValueFactoryManager().find(facetType); if (factory == null) { throw new DatabaseException( _evictor.errorPrefix() + "No value factory registered for type-id '" + facetType + "'"); } _sampleServant = factory.create(facetType); } Connection connection = Util.createConnection(_communicator, evictor.dbEnv().getEnvName()); try { Catalog catalog = new Catalog(connection, Util.catalogName(), true); CatalogData catalogData = catalog.get(evictor.filename()); if (catalogData != null) { if (catalogData.evictor) { _keepStats = catalogData.value.isEmpty(); } else { DatabaseException ex = new DatabaseException(); ex.message = _evictor.errorPrefix() + evictor.filename() + " is not an evictor database"; throw ex; } } com.sleepycat.db.Environment dbEnv = evictor.dbEnv().getEnv(); // // TODO: FREEZE_DB_MODE // com.sleepycat.db.DatabaseConfig config = new com.sleepycat.db.DatabaseConfig(); config.setType(com.sleepycat.db.DatabaseType.BTREE); config.setAllowCreate(createDb); Ice.Properties properties = _evictor.communicator().getProperties(); String propPrefix = "Freeze.Evictor." + _evictor.filename() + "."; int btreeMinKey = properties.getPropertyAsInt(propPrefix + _dbName + ".BtreeMinKey"); if (btreeMinKey > 2) { if (_evictor.trace() >= 1) { _evictor .communicator() .getLogger() .trace( "Freeze.Evictor", "Setting \"" + _evictor.filename() + "." + _dbName + "\"'s btree minkey to " + btreeMinKey); } config.setBtreeMinKey(btreeMinKey); } boolean checksum = properties.getPropertyAsInt(propPrefix + "Checksum") > 0; if (checksum) { if (_evictor.trace() >= 1) { _evictor .communicator() .getLogger() .trace("Freeze.Evictor", "Turning checksum on for \"" + _evictor.filename() + "\""); } config.setChecksum(true); } int pageSize = properties.getPropertyAsInt(propPrefix + "PageSize"); if (pageSize > 0) { if (_evictor.trace() >= 1) { _evictor .communicator() .getLogger() .trace( "Freeze.Evictor", "Setting \"" + _evictor.filename() + "\"'s pagesize to " + pageSize); } config.setPageSize(pageSize); } try { Transaction tx = connection.beginTransaction(); com.sleepycat.db.Transaction txn = Util.getTxn(tx); _db = dbEnv.openDatabase(txn, evictor.filename(), _dbName, config); for (Index index : _indices) { index.associate(this, txn, createDb, populateEmptyIndices); } if (catalogData == null) { catalogData = new CatalogData(true, "::Ice::Identity", "Object"); catalog.put(evictor.filename(), catalogData); } tx.commit(); } catch (java.io.FileNotFoundException dx) { throw new NotFoundException(_evictor.errorPrefix() + "Db.open: " + dx.getMessage(), dx); } catch (com.sleepycat.db.DatabaseException dx) { throw new DatabaseException(_evictor.errorPrefix() + "Db.open: " + dx.getMessage(), dx); } finally { Transaction tx = connection.currentTransaction(); if (tx != null) { try { tx.rollback(); } catch (DatabaseException de) { } } } } finally { connection.close(); } }
public int doloop() throws DatabaseException { Database db = null; for (; ; ) { if (db == null) { DatabaseConfig dbconf = new DatabaseConfig(); dbconf.setType(DatabaseType.BTREE); if (dbenv.getIsMaster()) { /* * Open database allowing create only if this is a master * database. A client database uses polling to attempt * to open the database without allowing create until * it is successful. * * This polling logic for allowing create can be * simplified under some circumstances. For example, if * the application can be sure a database is already * there, it would never need to open it allowing create. */ 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 { if (dbenv.getInClientSync()) System.err.println("Cannot read data during client initialization - please try again."); else printStocks(db); } catch (DeadlockException de) { continue; } catch (DatabaseException e) { /* * This could be DB_REP_HANDLE_DEAD, which * should close the database and continue. */ System.err.println("Got db exception reading replication" + "DB: " + e); System.err.println( "Expected if it was due to a dead " + "replication handle, otherwise an unexpected error."); db.close(true); /* Close no sync. */ db = null; continue; } continue; } if (words.length == 1 && (words[0].compareToIgnoreCase("quit") == 0 || words[0].compareToIgnoreCase("exit") == 0)) { dbenv.setAppFinished(true); 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; }
/** Open all storage containers, indices, and catalogs. */ public SampleDatabase(String homeDirectory) throws DatabaseException, FileNotFoundException { // Open the Berkeley DB environment in transactional mode. // System.out.println("Opening environment in: " + homeDirectory); EnvironmentConfig envConfig = new EnvironmentConfig(); envConfig.setTransactional(true); envConfig.setAllowCreate(true); envConfig.setInitializeCache(true); envConfig.setInitializeLocking(true); env = new Environment(new File(homeDirectory), envConfig); // Set the Berkeley DB config for opening all stores. // DatabaseConfig dbConfig = new DatabaseConfig(); dbConfig.setTransactional(true); dbConfig.setAllowCreate(true); dbConfig.setType(DatabaseType.BTREE); // Create the Serial class catalog. This holds the serialized class // format for all database records of serial format. // Database catalogDb = env.openDatabase(null, CLASS_CATALOG, null, dbConfig); javaCatalog = new StoredClassCatalog(catalogDb); // Open the Berkeley DB database for the part, supplier and shipment // stores. The stores are opened with no duplicate keys allowed. // partDb = env.openDatabase(null, PART_STORE, null, dbConfig); supplierDb = env.openDatabase(null, SUPPLIER_STORE, null, dbConfig); shipmentDb = env.openDatabase(null, SHIPMENT_STORE, null, dbConfig); // Open the SecondaryDatabase for the city index of the supplier store, // and for the part and supplier indices of the shipment store. // Duplicate keys are allowed since more than one supplier may be in // the same city, and more than one shipment may exist for the same // supplier or part. A foreign key constraint is defined for the // supplier and part indices to ensure that a shipment only refers to // existing part and supplier keys. The CASCADE delete action means // that shipments will be deleted if their associated part or supplier // is deleted. // SecondaryConfig secConfig = new SecondaryConfig(); secConfig.setTransactional(true); secConfig.setAllowCreate(true); secConfig.setType(DatabaseType.BTREE); secConfig.setSortedDuplicates(true); secConfig.setKeyCreator( new SupplierByCityKeyCreator( javaCatalog, SupplierKey.class, SupplierData.class, String.class)); supplierByCityDb = env.openSecondaryDatabase(null, SUPPLIER_CITY_INDEX, null, supplierDb, secConfig); secConfig.setForeignKeyDatabase(partDb); secConfig.setForeignKeyDeleteAction(ForeignKeyDeleteAction.CASCADE); secConfig.setKeyCreator( new ShipmentByPartKeyCreator( javaCatalog, ShipmentKey.class, ShipmentData.class, PartKey.class)); shipmentByPartDb = env.openSecondaryDatabase(null, SHIPMENT_PART_INDEX, null, shipmentDb, secConfig); secConfig.setForeignKeyDatabase(supplierDb); secConfig.setForeignKeyDeleteAction(ForeignKeyDeleteAction.CASCADE); secConfig.setKeyCreator( new ShipmentBySupplierKeyCreator( javaCatalog, ShipmentKey.class, ShipmentData.class, SupplierKey.class)); shipmentBySupplierDb = env.openSecondaryDatabase(null, SHIPMENT_SUPPLIER_INDEX, null, shipmentDb, secConfig); }
// // Initialize the database to the number of accounts, branches, // history records, and tellers given to the constructor. // public void populate() { Database dbp = null; int err; int balance, idnum; int end_anum, end_bnum, end_tnum; int start_anum, start_bnum, start_tnum; int h_nelem; idnum = BEGID; balance = 500000; h_nelem = accounts; try { DatabaseConfig config = new DatabaseConfig(); config.setType(DatabaseType.HASH); config.setHashNumElements(h_nelem); config.setAllowCreate(true); dbp = dbenv.openDatabase(null, "account", null, config); } catch (Exception e1) { // can be DatabaseException or FileNotFoundException errExit(e1, "Open of account file failed"); } start_anum = idnum; populateTable(dbp, idnum, balance, h_nelem, "account"); idnum += h_nelem; end_anum = idnum - 1; try { dbp.close(); } catch (DatabaseException e2) { errExit(e2, "Account file close failed"); } if (verbose) System.out.println( "Populated accounts: " + String.valueOf(start_anum) + " - " + String.valueOf(end_anum)); // // Since the number of branches is very small, we want to use very // small pages and only 1 key per page. This is the poor-man's way // of getting key locking instead of page locking. // h_nelem = (int) branches; try { DatabaseConfig config = new DatabaseConfig(); config.setType(DatabaseType.HASH); config.setHashNumElements(h_nelem); config.setHashFillFactor(1); config.setPageSize(512); config.setAllowCreate(true); dbp = dbenv.openDatabase(null, "branch", null, config); } catch (Exception e3) { // can be DatabaseException or FileNotFoundException errExit(e3, "Branch file create failed"); } start_bnum = idnum; populateTable(dbp, idnum, balance, h_nelem, "branch"); idnum += h_nelem; end_bnum = idnum - 1; try { dbp.close(); } catch (DatabaseException dbe4) { errExit(dbe4, "Close of branch file failed"); } if (verbose) System.out.println( "Populated branches: " + String.valueOf(start_bnum) + " - " + String.valueOf(end_bnum)); // // In the case of tellers, we also want small pages, but we'll let // the fill factor dynamically adjust itself. // h_nelem = (int) tellers; try { DatabaseConfig config = new DatabaseConfig(); config.setType(DatabaseType.HASH); config.setHashNumElements(h_nelem); config.setHashFillFactor(0); config.setPageSize(512); config.setAllowCreate(true); dbp = dbenv.openDatabase(null, "teller", null, config); } catch (Exception e5) { // can be DatabaseException or FileNotFoundException errExit(e5, "Teller file create failed"); } start_tnum = idnum; populateTable(dbp, idnum, balance, h_nelem, "teller"); idnum += h_nelem; end_tnum = idnum - 1; try { dbp.close(); } catch (DatabaseException e6) { errExit(e6, "Close of teller file failed"); } if (verbose) System.out.println( "Populated tellers: " + String.valueOf(start_tnum) + " - " + String.valueOf(end_tnum)); try { DatabaseConfig config = new DatabaseConfig(); config.setType(DatabaseType.RECNO); config.setRecordLength(HISTORY_LEN); config.setAllowCreate(true); dbp = dbenv.openDatabase(null, "history", null, config); } catch (Exception e7) { // can be DatabaseException or FileNotFoundException errExit(e7, "Create of history file failed"); } populateHistory(dbp); try { dbp.close(); } catch (DatabaseException e8) { errExit(e8, "Close of history file failed"); } }
@Test public void testDraining() throws Exception { EnvironmentConfig masterConfig = makeBasicConfig(); masterConfig.setReplicationLimit(100000000); ReplicationManagerSiteConfig site = new ReplicationManagerSiteConfig("localhost", masterPort); site.setLocalSite(true); site.setLegacy(true); masterConfig.addReplicationManagerSite(site); site = new ReplicationManagerSiteConfig("localhost", clientPort); site.setLegacy(true); masterConfig.addReplicationManagerSite(site); site = new ReplicationManagerSiteConfig("localhost", client2Port); site.setLegacy(true); masterConfig.addReplicationManagerSite(site); site = new ReplicationManagerSiteConfig("localhost", client3Port); site.setLegacy(true); masterConfig.addReplicationManagerSite(site); Environment master = new Environment(mkdir("master"), masterConfig); setTimeouts(master); // Prevent connection retries, so that all connections // originate from clients master.setReplicationTimeout(ReplicationTimeoutType.CONNECTION_RETRY, Integer.MAX_VALUE); master.replicationManagerStart(2, ReplicationManagerStartPolicy.REP_MASTER); DatabaseConfig dc = new DatabaseConfig(); dc.setTransactional(true); dc.setAllowCreate(true); dc.setType(DatabaseType.BTREE); dc.setPageSize(4096); Database db = master.openDatabase(null, "test.db", null, dc); DatabaseEntry key = new DatabaseEntry(); DatabaseEntry value = new DatabaseEntry(); value.setData(data); for (int i = 0; ((BtreeStats) db.getStats(null, null)).getPageCount() < 500; i++) { String k = "The record number is: " + i; key.setData(k.getBytes()); db.put(null, key, value); } // tell fiddler to stop reading once it sees a PAGE message Socket s = new Socket("localhost", mgrPort); OutputStreamWriter w = new OutputStreamWriter(s.getOutputStream()); String path1 = "{" + masterPort + "," + clientPort + "}"; // looks like {6000,6001} w.write("{init," + path1 + ",page_clog}\r\n"); w.flush(); BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream())); br.readLine(); assertEquals("ok", br.readLine()); // create client // EnvironmentConfig ec = makeBasicConfig(); site = new ReplicationManagerSiteConfig("localhost", clientPort); site.setLocalSite(true); site.setLegacy(true); ec.addReplicationManagerSite(site); site = new ReplicationManagerSiteConfig("localhost", masterPort); site.setLegacy(true); ec.addReplicationManagerSite(site); site = new ReplicationManagerSiteConfig("localhost", client2Port); site.setLegacy(true); ec.addReplicationManagerSite(site); site = new ReplicationManagerSiteConfig("localhost", client3Port); site.setLegacy(true); ec.addReplicationManagerSite(site); Environment client = new Environment(mkdir("client"), ec); setTimeouts(client); client.replicationManagerStart(1, ReplicationManagerStartPolicy.REP_CLIENT); // wait til it gets stuck Thread.sleep(5000); // FIXME // Do the same for another client, because the master has 2 // msg processing threads. (It's no longer possible to // configure just 1.) String path2 = "{" + masterPort + "," + client2Port + "}"; w.write("{init," + path2 + ",page_clog}\r\n"); w.flush(); br = new BufferedReader(new InputStreamReader(s.getInputStream())); br.readLine(); assertEquals("ok", br.readLine()); ec = makeBasicConfig(); site = new ReplicationManagerSiteConfig("localhost", client2Port); site.setLocalSite(true); site.setLegacy(true); ec.addReplicationManagerSite(site); site = new ReplicationManagerSiteConfig("localhost", masterPort); site.setLegacy(true); ec.addReplicationManagerSite(site); site = new ReplicationManagerSiteConfig("localhost", clientPort); site.setLegacy(true); ec.addReplicationManagerSite(site); site = new ReplicationManagerSiteConfig("localhost", client3Port); site.setLegacy(true); ec.addReplicationManagerSite(site); Environment client2 = new Environment(mkdir("client2"), ec); setTimeouts(client2); client2.replicationManagerStart(1, ReplicationManagerStartPolicy.REP_CLIENT); // wait til it gets stuck Thread.sleep(5000); // With the connection stuck, the master cannot write out log // records for new "live" transactions. Knowing we didn't // write the record, we should not bother waiting for an ack // that cannot possibly arrive; so we should simply return // quickly. The duration should be very quick, but anything // less than the ack timeout indicates correct behavior (in // case this test runs on a slow, overloaded system). // long startTime = System.currentTimeMillis(); key.setData("one extra record".getBytes()); db.put(null, key, value); long duration = System.currentTimeMillis() - startTime; assertTrue("txn duration: " + duration, duration < 29000); System.out.println("txn duration: " + duration); db.close(); // Tell fiddler to close the connections. That should trigger // us to abandon the timeout. Then create another client and // see that it can complete its internal init quickly. Since // we have limited threads at the master, this demonstrates // that they were abandoned. // path1 = "{" + clientPort + "," + masterPort + "}"; // looks like {6001,6000} w.write("{" + path1 + ",shutdown}\r\n"); w.flush(); assertEquals("ok", br.readLine()); path2 = "{" + client2Port + "," + masterPort + "}"; // looks like {6001,6000} w.write("{" + path2 + ",shutdown}\r\n"); w.flush(); assertEquals("ok", br.readLine()); ec = makeBasicConfig(); site = new ReplicationManagerSiteConfig("localhost", client3Port); site.setLocalSite(true); site.setLegacy(true); ec.addReplicationManagerSite(site); site = new ReplicationManagerSiteConfig("localhost", masterPort); site.setLegacy(true); ec.addReplicationManagerSite(site); site = new ReplicationManagerSiteConfig("localhost", clientPort); site.setLegacy(true); ec.addReplicationManagerSite(site); site = new ReplicationManagerSiteConfig("localhost", client2Port); site.setLegacy(true); ec.addReplicationManagerSite(site); EventHandler clientMonitor = new EventHandler(); ec.setEventHandler(clientMonitor); Environment client3 = new Environment(mkdir("client3"), ec); setTimeouts(client3); startTime = System.currentTimeMillis(); client3.replicationManagerStart(2, ReplicationManagerStartPolicy.REP_CLIENT); clientMonitor.await(); duration = System.currentTimeMillis() - startTime; assertTrue("sync duration: " + duration, duration < 20000); // 20 seconds should be plenty client3.close(); master.close(); w.write("shutdown\r\n"); w.flush(); assertEquals("ok", br.readLine()); s.close(); }