/* * Implementation of 2Phase Commit first make request to all other replicas. * If "ACCEPT" is received from all the replicas then proceed to second phase, which is to commit changes. * Used by the PUT and DELETE methods as they are the only ones that make write operations. */ public boolean TwoPCommit(String command, String key, String value) { int accept = 0; String result = ""; String host = ""; int portNumber = 0; // ASK proxies at other servers in cluster for (int a = 0; a < numReplicas; a++) { result = ""; try { host = InetAddress.getByName(hostPorts[a][0]).getHostAddress(); portNumber = Integer.parseInt(hostPorts[a][1]); RMIServerInterface remoteImpl = (RMIServerInterface) Naming.lookup("rmi://" + host.trim() + ":" + portNumber + "/Calls"); long startTime = System.currentTimeMillis(); // Timeout after 10s while (result.isEmpty()) { if ((System.currentTimeMillis() - startTime) > 10000) { log.error("Unable to ASK " + host + ":" + portNumber + "Timed-out!"); break; } result = remoteImpl.ASK(command, key, value); } } catch (Exception e) { // TODO Auto-generated catch block log.error("Connection to " + host + ":" + portNumber + " met error with " + e.getMessage()); } log.info(result + " for " + host + ":" + portNumber); if (result.trim().toUpperCase().equals(ACCEPT)) ++accept; } /* * If all the replicas have accepted the requested command via the ASK method, then make commit. */ if (accept == numReplicas) { for (int a = 0; a < numReplicas; a++) { result = ""; try { host = InetAddress.getByName(hostPorts[a][0]).getHostAddress(); portNumber = Integer.parseInt(hostPorts[a][1]); RMIServerInterface remoteImpl = (RMIServerInterface) Naming.lookup("rmi://" + host.trim() + ":" + portNumber + "/Calls"); long startTime = System.currentTimeMillis(); // Timeout after 10s while (!result.equals(ACK)) { if ((System.currentTimeMillis() - startTime) > 10000) { log.error("Unable to commit update to " + host + ":" + portNumber + "Timed-out!"); break; } if (command.toUpperCase().equals("PUT")) result = (remoteImpl.PUT(true, host + ":" + port, key, value)); else if (command.toUpperCase().equals("DELETE")) result = (remoteImpl.DELETE(true, host + ":" + port, key)); } } catch (Exception e) { log.error( "Connection to " + host + ":" + portNumber + " met error with " + e.getMessage()); } } return true; } return false; }
public static void main(String[] args) throws IOException { /** max number of elements to import */ final long max = (int) 1e6; /** Open database in temporary directory */ File dbFile = File.createTempFile("mapdb", "temp"); DB db = DBMaker.newFileDB(dbFile) /** disabling Write Ahead Log makes import much faster */ .transactionDisable() .make(); long time = System.currentTimeMillis(); /** * Source of data which randomly generates strings. In real world this would return data from * file. */ Iterator<String> source = new Iterator<String>() { long counter = 0; @Override public boolean hasNext() { return counter < max; } @Override public String next() { counter++; return randomString(10); } @Override public void remove() {} }; /** * BTreeMap Data Pump requires data source to be presorted in reverse order (highest to lowest). * There is method in Data Pump we can use to sort data. It uses temporarly files and can handle * fairly large data sets. */ source = Pump.sort( source, true, 100000, Collections.reverseOrder(BTreeMap.COMPARABLE_COMPARATOR), // reverse order comparator db.getDefaultSerializer()); /** * Disk space used by serialized keys should be minimised. Keys are sorted, so only difference * between consequential keys is stored. This method is called delta-packing and typically saves * 60% of disk space. */ BTreeKeySerializer<String> keySerializer = BTreeKeySerializer.STRING; /** Translates Map Key into Map Value. */ Fun.Function1<Integer, String> valueExtractor = new Fun.Function1<Integer, String>() { @Override public Integer run(String s) { return s.hashCode(); } }; /** Create BTreeMap and fill it with data */ Map<String, Integer> map = db.createTreeMap("map") .pumpSource(source, valueExtractor) // .pumpPresort(100000) // for presorting data we could also use this method .keySerializer(keySerializer) .make(); System.out.println( "Finished; total time: " + (System.currentTimeMillis() - time) / 1000 + "s; there are " + map.size() + " items in map"); db.close(); }