Java tutorial
// This file is part of MongoMVCC. // // Copyright (c) 2012 Fraunhofer IGD // // MongoMVCC is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // MongoMVCC is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with MongoMVCC. If not, see <http://www.gnu.org/licenses/>. package de.fhg.igd.mongomvcc.impl; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import com.mongodb.CommandResult; import com.mongodb.DB; import com.mongodb.Mongo; import com.mongodb.ServerAddress; import de.fhg.igd.mongomvcc.VBranch; import de.fhg.igd.mongomvcc.VConstants; import de.fhg.igd.mongomvcc.VCounter; import de.fhg.igd.mongomvcc.VDatabase; import de.fhg.igd.mongomvcc.VException; import de.fhg.igd.mongomvcc.VHistory; import de.fhg.igd.mongomvcc.VMaintenance; import de.fhg.igd.mongomvcc.helper.IdMap; import de.fhg.igd.mongomvcc.impl.internal.BuildInfo; import de.fhg.igd.mongomvcc.impl.internal.Commit; import de.fhg.igd.mongomvcc.impl.internal.Tree; /** * MongoDB implementation of a Multiversion Concurrency Control database. * @author Michel Kraemer */ public class MongoDBVDatabase implements VDatabase { /** * The MongoDB database object */ private DB _db; /** * Provides a thread-safe way to generate new unique IDs */ private VCounter _counter; /** * The tree of commits */ private Tree _tree; /** * Build information about the database instance (may be null if the * information is not available) */ private BuildInfo _buildInfo; @Override public void connect(String name) throws VException { Mongo mongo; try { mongo = new Mongo(); } catch (UnknownHostException e) { throw new VException("Unknown host", e); } connectInternal(name, mongo); } @Override public void connect(String name, int port) throws VException { connect(name, ServerAddress.defaultHost(), port); } @Override public void connect(String name, String host, int port) throws VException { Mongo mongo; try { mongo = new Mongo(new ServerAddress(host, port)); } catch (UnknownHostException e) { throw new VException("Unknown host", e); } connectInternal(name, mongo); } @Override public void connectToReplicaSet(String name, Map<String, Integer> hostsWithPort, boolean slaveOk) throws VException { Mongo mongo = null; try { List<ServerAddress> addrs = new ArrayList<ServerAddress>(); for (Map.Entry<String, Integer> e : hostsWithPort.entrySet()) { addrs.add(new ServerAddress(e.getKey(), e.getValue())); } mongo = new Mongo(addrs); if (slaveOk && mongo != null) { mongo.slaveOk(); // mongo.setReadPreference(ReadPreference.SECONDARY); needed with version 2.2 } } catch (UnknownHostException e) { throw new VException("Unknown host", e); } connectInternal(name, mongo); } private void connectInternal(String name, Mongo mongo) { _buildInfo = initBuildInfo(mongo); _db = mongo.getDB(name); _counter = new MongoDBVCounter(_db); _tree = new Tree(_db); //create root commit and master branch if needed if (_tree.isEmpty()) { Commit root = new Commit(_counter.getNextId(), 0, 0, Collections.<String, IdMap>emptyMap()); _tree.addCommit(root); _tree.addBranch(VConstants.MASTER, root.getCID()); } } /** * Obtains build information from the database instance. If any value is * not available, this method will return <code>null</code>. * @param mongo the database * @return the build information or <code>null</code> */ private static BuildInfo initBuildInfo(Mongo mongo) { DB db = mongo.getDB("admin"); if (db == null) { return null; } CommandResult cr = db.command("buildInfo"); String version = (String) cr.get("version"); if (version == null) { return null; } String[] vss = version.split("\\."); if (vss.length <= 2) { return null; } Integer maxBsonObjectSize = (Integer) cr.get("maxBsonObjectSize"); if (maxBsonObjectSize == null) { maxBsonObjectSize = Integer.valueOf(0); } try { return new BuildInfo(Integer.parseInt(vss[0]), Integer.parseInt(vss[1]), Integer.parseInt(vss[2]), maxBsonObjectSize); } catch (NumberFormatException e) { return null; } } /** * @return the underlying MongoDB database */ public DB getDB() { return _db; } /** * @return build information about the database instance (may be null if the * information is not available) */ public BuildInfo getBuildInfo() { return _buildInfo; } @Override public void drop() { _db.dropDatabase(); } @Override public VBranch checkout(String name) { long rootCid = _tree.resolveBranchRootCid(name); return new MongoDBVBranch(name, rootCid, _tree, this); } /** * Determines the root CID for a new branch. Checks if the commit with * the given CID already belongs to a named branch or if it already has * children. If so, the root for the new branch will be the given CID. * Otherwise it is assumed that the commit is the head of an unnamed * branch and so the commit's root ID will be returned. * @param cid the CID of the commit to branch from * @return the root CID for the new branch */ private long determineRootForBranch(long cid) { Commit head = _tree.resolveCommit(cid); long root = head.getRootCID(); if (_tree.existsBranch(root) || _tree.hasChildren(cid)) { //we're trying to create a branch from a commit that belongs //to an existing branch. create a new branch from here on. root = cid; } return root; } @Override public VBranch checkout(long cid) { long root = determineRootForBranch(cid); return new MongoDBVBranch(null, root, _tree, this); } @Override public VBranch createBranch(String name, long headCID) { long root = determineRootForBranch(headCID); _tree.addBranch(name, root); return new MongoDBVBranch(name, root, _tree, this); } @Override public VCounter getCounter() { return _counter; } @Override public VHistory getHistory() { return _tree; } @Override public VMaintenance getMaintenance() { return new MongoDBVMaintenance(this); } }