changeset 47:5b36891db5ca

finished implementing cassandra monotonic tree
author suika6039
date Sat, 29 Jan 2011 03:05:20 +0900
parents a529aad2ac92
children ecba122dd3de
files src/treecms/proto/cassandra/CassBrowser.java src/treecms/proto/cassandra/CassNode.java src/treecms/proto/simple/SimpleDecNodeID.java
diffstat 3 files changed, 382 insertions(+), 89 deletions(-) [+]
line wrap: on
line diff
--- a/src/treecms/proto/cassandra/CassBrowser.java	Sat Jan 22 22:55:19 2011 +0900
+++ b/src/treecms/proto/cassandra/CassBrowser.java	Sat Jan 29 03:05:20 2011 +0900
@@ -1,11 +1,18 @@
 package treecms.proto.cassandra;
 
+import java.nio.CharBuffer;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.StringTokenizer;
+
 import treecms.proto.api.Browser;
 import treecms.proto.api.Node;
 import treecms.proto.api.NodeID;
 
-import org.apache.thrift.TException;
 import org.apache.thrift.transport.TTransport;
 import org.apache.thrift.transport.TFramedTransport;
 import org.apache.thrift.transport.TSocket;
@@ -17,23 +24,26 @@
 import org.apache.cassandra.thrift.ColumnParent;
 import org.apache.cassandra.thrift.ColumnPath;
 import org.apache.cassandra.thrift.ConsistencyLevel;
-import org.apache.cassandra.thrift.InvalidRequestException;
 import org.apache.cassandra.thrift.KeySlice;
 import org.apache.cassandra.thrift.SlicePredicate;
 import org.apache.cassandra.thrift.SliceRange;
-import org.apache.cassandra.thrift.TimedOutException;
-import org.apache.cassandra.thrift.UnavailableException;
 
 public class CassBrowser implements Browser
 {
-	public static void main(String _args[])throws Exception
-	{
-	}
-	
 	private Cassandra.Client m_cassandra;
 	private String m_host,m_port;
 	private String m_keySpace,m_colFamily;
 	
+	private static final String TREEINFO = "TreeInfo";
+	private static final String ROOTNODE = "RootNode";
+	
+	private static final String CLASSNAME = "ClassName";
+	private static final String TITLE = "title";
+	private static final String CHILDREN = "Children";
+	private static final String CHILDREN_DELIM = ",";
+	
+	private static final String ATTR_PREFIX = "_";
+	
 	private CassBrowser(String _host,String _port) throws TTransportException
 	{
 		m_host = _host;
@@ -69,9 +79,270 @@
 		return browser;
 	}
 	
-	public String getColumn(NodeID _id,String _colName)
+	public Node addChild(NodeID _id,Node _child)
+	{
+		LinkedList<Node> tmp = new LinkedList<Node>();
+		tmp.add(_child);
+		addChildren(_id,tmp);
+		return _child;
+	}
+	
+	public void addChildren(NodeID _id,List<Node> _children)
+	{
+		String children = getChildrenRaw(_id);
+		Map<String,Boolean> set = new HashMap<String,Boolean>();
+		StringTokenizer st = new StringTokenizer(children,CHILDREN_DELIM);
+		while(st.hasMoreElements()){
+			set.put(st.nextToken(),Boolean.TRUE);
+		}
+		
+		StringBuffer buf = new StringBuffer();
+		
+		if(!set.isEmpty()){
+			buf.append(CHILDREN_DELIM);
+		}
+		
+		for(int i = 0;i < _children.size() - 1;i ++){
+			String key = _children.get(i).getID().toString();
+			if(set.get(key) != null){
+				return;
+			}
+			
+			buf.append(key).append(CHILDREN_DELIM);
+		}
+		
+		String key = _children.get(_children.size() - 1).getID().toString();
+		if(set.get(key) != null){
+			return;
+		}
+		
+		buf.append(key);
+		
+		setColumn(_id.toString(),CHILDREN,buf.toString(),false);
+	}
+	
+	public void clearChildren(NodeID _id)
+	{
+		setColumn(_id.toString(),CHILDREN,"",false);
+	}
+	
+	public boolean removeChild(NodeID _id,Node _child)
+	{
+		String raw = getChildrenRaw(_id);
+		StringTokenizer token = new StringTokenizer(raw,CHILDREN_DELIM);
+		
+		CharBuffer buf = CharBuffer.allocate(raw.length());
+		
+		boolean changed = false;
+		
+		while(token.hasMoreElements()){
+			String child = token.nextToken();
+			if(child.equals(_child.getID().toString())){
+				changed = true;
+				continue;
+			}
+			
+			buf.append(child);
+			break;
+		}
+		
+		while(token.hasMoreElements()){
+			String child = token.nextToken();
+			if(child.equals(_child.getID().toString())){
+				changed = true;
+				continue;
+			}
+			
+			buf.append(CHILDREN_DELIM+child);
+		}
+		
+		if(changed){
+			setColumn(_id.toString(),CHILDREN,buf.toString(),false);
+		}
+		
+		return changed;
+	}
+	
+	public void replace(NodeID _id,Node _child1,Node _child2)
+	{
+		String children = getChildrenRaw(_id);
+		CharBuffer buf = CharBuffer.allocate(children.length());
+		StringTokenizer tokens = new StringTokenizer(children,CHILDREN_DELIM);
+
+		int flagSuccess = 0;
+		String id1 = _child1.getID().toString();
+		String id2 = _child2.getID().toString();
+		for(String prefix = "";tokens.hasMoreElements();prefix = CHILDREN_DELIM){
+			String token = tokens.nextToken();
+			if(token.equals(id1)){
+				buf.append(prefix+id2);
+				flagSuccess++;
+			}else if(token.equals(id2)){
+				buf.append(prefix+id1);
+				flagSuccess++;
+			}else{
+				buf.append(prefix+token);
+			}
+		}
+		
+		if(flagSuccess == 2){
+			setColumn(_id.toString(),CHILDREN,buf.toString(),false);
+		}
+	}
+	
+	public void down(NodeID _id,Node _child)
 	{
-		return getColumn(_id.toString(),_colName,true);
+		String children = getChildrenRaw(_id);
+		String id = _child.getID().toString();
+		CharBuffer buf = CharBuffer.allocate(children.length());
+		StringTokenizer tokens = new StringTokenizer(children,CHILDREN_DELIM);
+		
+		for(String prefix = "";tokens.hasMoreElements();prefix = CHILDREN_DELIM){
+			String token = tokens.nextToken();
+			if(token.equals(id)){
+				if(tokens.hasMoreElements()){
+					buf.append(prefix+tokens.nextToken());
+					prefix = CHILDREN_DELIM;
+				}
+			}
+			buf.append(prefix+token);
+		}
+		
+		setColumn(_id.toString(),CHILDREN,buf.toString(),false);
+	}
+	
+	public void up(NodeID _id,Node _child)
+	{
+		String children = getChildrenRaw(_id);
+		String id = _child.getID().toString();
+		CharBuffer buf = CharBuffer.allocate(children.length());
+		StringTokenizer tokens = new StringTokenizer(children,CHILDREN_DELIM);
+		
+		String prev = null;
+		String prefix = "";
+		while(tokens.hasMoreElements()){
+			if(prev == null){
+				prev = tokens.nextToken();
+				continue;
+			}
+		
+			String token = tokens.nextToken();
+			if(token.equals(id)){
+				buf.append(prefix+prev);
+				prev = token;
+			}else{
+				buf.append(prefix+prev);
+			}
+		
+			prefix = CHILDREN_DELIM;
+		}
+	}
+	
+	public void setClassName(NodeID _id,String _className)
+	{
+		setColumn(_id.toString(),CLASSNAME,_className,false);
+	}
+	
+	public Node createNode()
+	{
+		return new CassNode(this,new CassDecNodeID(this));
+	}
+	
+	public List<Node> getChildren(NodeID _id)
+	{
+		LinkedList<Node> children = new LinkedList<Node>();
+		
+		String raw = getChildrenRaw(_id);
+		StringTokenizer tokens = new StringTokenizer(raw,CHILDREN_DELIM);
+		
+		while(tokens.hasMoreElements()){
+			String first = tokens.nextToken();
+			StringTokenizer sparator = new StringTokenizer(first,"@");
+			String uuid = sparator.nextToken();
+			long ver = Long.parseLong(sparator.nextToken());
+			NodeID id = new CassDecNodeID(this,uuid,ver);
+			children.add(new CassNode(this,id));
+		}
+		
+		return children;
+	}
+	
+	public CassNode cloneNode(NodeID _id)
+	{
+		NodeID newID = _id.update();
+		
+		
+		return null;
+	}
+	
+	public CassLink createLink(NodeID _id)
+	{
+		return null;
+	}
+	
+	public boolean isChild(NodeID _id,Node _child)
+	{
+		String raw = getChildrenRaw(_id);
+		if(raw.indexOf(_child.getID().toString()) != -1){
+			return true;
+		}
+		return false;
+	}
+	
+	public String getClassName(NodeID _id)
+	{
+		return getColumn(_id.toString(),CLASSNAME,false);
+	}
+	
+	public String getChildrenRaw(NodeID _id)
+	{
+		return getColumn(_id.toString(),CHILDREN,false);
+	}
+	
+	public String getTitle(NodeID _id)
+	{
+		return getColumn(_id.toString(),TITLE,false);
+	}
+	
+	public void setTitle(NodeID _id,String _title)
+	{
+		setColumn(_id.toString(),TITLE,_title,false);
+	}
+	
+	public String getAttribute(NodeID _id,String _attr)
+	{
+		return getColumn(_id.toString(),ATTR_PREFIX+_attr,false);
+	}
+	
+	public void setAttribute(NodeID _id,String _attr,String _value)
+	{
+		setColumn(_id.toString(),ATTR_PREFIX+_attr,_value,false);
+	}
+	
+	public Set<String> getAttributeKeys(NodeID _id)
+	{
+		Set<String> attrs = new HashSet<String>();
+		
+		SliceRange sr = new SliceRange();
+		sr.setStart(new byte[0]);
+		sr.setFinish(new byte[0]);
+		
+		SlicePredicate sp = new SlicePredicate();
+		sp.setSlice_range(sr);
+		
+		try{
+			List<ColumnOrSuperColumn> columns = m_cassandra.get_slice(m_keySpace,_id.toString(),new ColumnParent(m_colFamily),sp,ConsistencyLevel.ONE);
+			for(ColumnOrSuperColumn column : columns){
+				String key = new String(column.column.name);
+				if(key.startsWith(ATTR_PREFIX)){
+					attrs.add(key);
+				}
+			}
+		}catch(Exception _e){
+			_e.printStackTrace();
+		}
+		
+		return attrs;
 	}
 	
 	public NodeID getTipIDFromUUID(String _uuid)
@@ -84,18 +355,12 @@
 		slicePredicate.setSlice_range(sliceRange);
 		
 		try {
-			List<KeySlice> values = m_cassandra.get_range_slice(m_keySpace,new ColumnParent(m_colFamily),slicePredicate,"hogehoge","hogehogea",100,ConsistencyLevel.ONE);
+			List<KeySlice> values = m_cassandra.get_range_slice(m_keySpace,new ColumnParent(m_colFamily),slicePredicate,"","",1,ConsistencyLevel.ONE);
 			String key = values.get(0).getKey();
 			
 			String tip = key.replaceFirst((_uuid+"@").intern(),"");
 			return new CassDecNodeID(this,_uuid,Long.parseLong(tip));
-		}catch(InvalidRequestException _e){
-			_e.printStackTrace();
-		}catch(UnavailableException _e){
-			_e.printStackTrace();
-		}catch(TimedOutException _e){
-			_e.printStackTrace();
-		}catch(TException _e){
+		}catch(Exception _e){
 			_e.printStackTrace();
 		}
 		
@@ -120,6 +385,22 @@
 		return value;
 	}
 	
+	private boolean setColumn(String _row,String _colName,String _value,boolean _retry)
+	{
+		ColumnPath path = new ColumnPath();
+		path.column_family = m_colFamily;
+		path.column = _colName.getBytes();
+	
+		try{
+			m_cassandra.insert(m_keySpace,_row,path,_value.getBytes(),System.currentTimeMillis()/1000,ConsistencyLevel.ONE);
+			return true;
+		}catch(Exception _e){
+			_e.printStackTrace();
+		}
+		
+		return false;
+	}
+	
 	public CassNode createNode(String _id)
 	{
 		return null;
@@ -128,6 +409,8 @@
 	@Override
 	public Node useContents()
 	{
-		return null;
+		String uuid = getColumn(TREEINFO,ROOTNODE,false);
+		NodeID rootID = getTipIDFromUUID(uuid);
+		return new CassNode(this,rootID);
 	}
 }
--- a/src/treecms/proto/cassandra/CassNode.java	Sat Jan 22 22:55:19 2011 +0900
+++ b/src/treecms/proto/cassandra/CassNode.java	Sat Jan 29 03:05:20 2011 +0900
@@ -1,8 +1,11 @@
 package treecms.proto.cassandra;
 
+import java.nio.CharBuffer;
 import java.util.Iterator;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Set;
+import java.util.StringTokenizer;
 
 import treecms.proto.api.Link;
 import treecms.proto.api.Node;
@@ -11,137 +14,145 @@
 public class CassNode implements Node
 {
 	private CassBrowser m_browser;
-	private CassDecNodeID m_id;
+	private NodeID m_id;
 	
-	public CassNode(CassBrowser _browser,CassDecNodeID _id)
+	public CassNode(CassBrowser _browser,NodeID _id)
 	{
 		m_browser = _browser;
 		m_id = _id;
 	}
+	
+	/*
+	 * for implement connection pool
+	 */
+	private CassBrowser getBrowser()
+	{
+		return m_browser;
+	}
 
 	@Override
 	public Node addChild(Node _child)
 	{
-		return null;
-	}
-
-	@Override
-	public void addChildren(List<Node> _child)
-	{
+		return getBrowser().addChild(m_id,_child);
 	}
 
 	@Override
-	public void clearChildren() {
-		// TODO Auto-generated method stub
-		
+	public void addChildren(List<Node> _children)
+	{
+		getBrowser().addChildren(m_id,_children);
+	}
+	
+	@Override
+	public void clearChildren()
+	{
+		getBrowser().clearChildren(m_id);
 	}
 
 	@Override
-	public Node cloneNode() {
-		// TODO Auto-generated method stub
-		return null;
+	public Node cloneNode()
+	{
+		return getBrowser().cloneNode(m_id);
 	}
 
 	@Override
-	public Link createLink() {
-		// TODO Auto-generated method stub
-		return null;
+	public Link createLink()
+	{
+		return getBrowser().createLink(m_id);
 	}
 
 	@Override
-	public Node createNode() {
-		// TODO Auto-generated method stub
-		return null;
+	public Node createNode()
+	{
+		return getBrowser().createNode();
 	}
 
 	@Override
-	public void down(Node child) {
-		// TODO Auto-generated method stub
-		
+	public void down(Node _child)
+	{
+		getBrowser().down(m_id,_child);
 	}
 
 	@Override
-	public String getAttribute(String attr) {
-		// TODO Auto-generated method stub
-		return null;
+	public String getAttribute(String _attr)
+	{
+		return getBrowser().getAttribute(m_id,_attr);
 	}
 
 	@Override
-	public Set<String> getAttributeKeys() {
-		// TODO Auto-generated method stub
-		return null;
+	public Set<String> getAttributeKeys()
+	{
+		return getBrowser().getAttributeKeys(m_id);
 	}
 
 	@Override
-	public List<Node> getChildren() {
-		// TODO Auto-generated method stub
-		return null;
+	public List<Node> getChildren()
+	{
+		return getBrowser().getChildren(m_id);
 	}
 
 	@Override
-	public String getClassName() {
-		// TODO Auto-generated method stub
-		return null;
+	public String getClassName()
+	{
+		return getBrowser().getClassName(m_id);
 	}
 
 	@Override
-	public NodeID getID() {
-		// TODO Auto-generated method stub
-		return null;
+	public NodeID getID()
+	{
+		return m_id;
 	}
 
 	@Override
-	public String getTitle() {
-		// TODO Auto-generated method stub
-		return null;
+	public String getTitle()
+	{
+		return getBrowser().getTitle(m_id);
 	}
 
 	@Override
-	public boolean isChild(Node child) {
-		// TODO Auto-generated method stub
-		return false;
+	public boolean isChild(Node _child)
+	{
+		return getBrowser().isChild(m_id,_child);
 	}
 
 	@Override
-	public Iterator<Node> iterator() {
-		// TODO Auto-generated method stub
-		return null;
+	public Iterator<Node> iterator()
+	{
+		return getChildren().iterator();
 	}
 
 	@Override
-	public boolean removeChild(Node child) {
-		// TODO Auto-generated method stub
-		return false;
+	public boolean removeChild(Node _child)
+	{
+		return getBrowser().removeChild(m_id,_child);
 	}
 
 	@Override
-	public void replace(Node target, Node newChild) {
-		// TODO Auto-generated method stub
-		
+	public void replace(Node _target, Node _newChild)
+	{
+		getBrowser().replace(m_id,_target,_newChild);
 	}
 
 	@Override
-	public void setAttribute(String attr, String value) {
-		// TODO Auto-generated method stub
-		
+	public void setAttribute(String _attr, String _value)
+	{
+		getBrowser().setAttribute(m_id,_attr,_value);
 	}
 
 	@Override
-	public void setClassName(String class1) {
-		// TODO Auto-generated method stub
-		
+	public void setClassName(String _className)
+	{
+		getBrowser().setClassName(m_id,_className);
 	}
 
 	@Override
-	public void setTitle(String title) {
-		// TODO Auto-generated method stub
-		
+	public void setTitle(String _title)
+	{
+		getBrowser().setTitle(m_id,_title);
 	}
 
 	@Override
-	public void up(Node child) {
-		// TODO Auto-generated method stub
-		
+	public void up(Node _child)
+	{
+		getBrowser().up(m_id,_child);
 	}
-
 }
--- a/src/treecms/proto/simple/SimpleDecNodeID.java	Sat Jan 22 22:55:19 2011 +0900
+++ b/src/treecms/proto/simple/SimpleDecNodeID.java	Sat Jan 29 03:05:20 2011 +0900
@@ -18,7 +18,7 @@
 		m_tip = new AtomicLong();
 		m_tip.set(START_VALUE);
 		
-		m_version = m_tip.getAndDecrement();
+		m_version = START_VALUE;
 	}
 	
 	private SimpleDecNodeID(String _uuid,AtomicLong _tip,boolean _doUpdate)
@@ -27,7 +27,7 @@
 		m_tip = _tip;
 		
 		if(_doUpdate){
-			m_version = m_tip.getAndDecrement();
+			m_version = m_tip.decrementAndGet();
 			return;
 		}
 		
@@ -61,7 +61,6 @@
 	@Override
 	public NodeID update()
 	{
-		return new SimpleDecNodeID(m_uuid,m_tip,false);
+		return new SimpleDecNodeID(m_uuid,m_tip,true);
 	}
-
 }