# HG changeset patch # User shoshi # Date 1306164792 -32400 # Node ID 168deb591f2192176e6e97a26919997a57c9ac5c # Parent bb97607607440b3de3f7b6546ac7be9190169d57 commit diff -r bb9760760744 -r 168deb591f21 src/treecms/api/Forest.java --- a/src/treecms/api/Forest.java Sat May 21 04:46:00 2011 +0900 +++ b/src/treecms/api/Forest.java Tue May 24 00:33:12 2011 +0900 @@ -55,4 +55,6 @@ * @return このForestのMainTree、最新版 */ Tree getMainTree(); + + SingleNode create(NodeID _id,NodeData _data); } diff -r bb9760760744 -r 168deb591f21 src/treecms/cassandra/CassandraForest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/treecms/cassandra/CassandraForest.java Tue May 24 00:33:12 2011 +0900 @@ -0,0 +1,95 @@ +package treecms.cassandra; + +import java.util.List; +import java.util.Map; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.cassandra.thrift.Mutation; + +import treecms.api.Forest; +import treecms.api.MonotonicTree; +import treecms.api.NodeID; +import treecms.api.SingleNode; +import treecms.api.Tree; +import treecms.tree.util.NodeData; + + +public class CassandraForest implements Forest +{ + private Map m_nodeTable; + private Map m_tipTable; + + public CassandraForest() + { + m_nodeTable = new ConcurrentHashMap(); + m_tipTable = new ConcurrentHashMap(); + } + + @Override + public SingleNode get(NodeID _id) + { + return m_nodeTable.get(_id); + } + + @Override + public SingleNode getTip(String _uuid) + { + return m_tipTable.get(_uuid); + } + + @Override + public SingleNode create() + { + return null; + } + + @Override + public Tree getTree(SingleNode _root) + { + return null; + } + + @Override + public MonotonicTree getMonotonicTree(Tree _tree) + { + return null; + } + + @Override + public SingleNode create(NodeData _data) + { + return null; + } + + @Override + public Tree getMainTree() + { + return null; + } + + @Override + public SingleNode create(NodeID _id, NodeData _data) + { + return null; + } + + private class CassandraNodeExporter extends TimerTask + { + private List m_updateQueue; + + @Override + public void run() + { + } + } + + private class CassandraNodeImporter extends TimerTask + { + @Override + public void run() + { + } + } +} diff -r bb9760760744 -r 168deb591f21 src/treecms/cassandra/CassandraMonotonicTree.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/treecms/cassandra/CassandraMonotonicTree.java Tue May 24 00:33:12 2011 +0900 @@ -0,0 +1,45 @@ +package treecms.cassandra; + +import treecms.api.MonotonicTree; +import treecms.api.MonotonicTreeNode; +import treecms.api.Tree; + +public class CassandraMonotonicTree implements MonotonicTree +{ + @Override + public boolean commit(boolean _force) { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean pull() { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean check() { + // TODO Auto-generated method stub + return false; + } + + @Override + public void merge() { + // TODO Auto-generated method stub + + } + + @Override + public MonotonicTreeNode getRoot() { + // TODO Auto-generated method stub + return null; + } + + @Override + public Tree getTree() { + // TODO Auto-generated method stub + return null; + } + +} diff -r bb9760760744 -r 168deb591f21 src/treecms/cassandra/CassandraMonotonicTreeNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/treecms/cassandra/CassandraMonotonicTreeNode.java Tue May 24 00:33:12 2011 +0900 @@ -0,0 +1,168 @@ +package treecms.cassandra; + +import java.nio.ByteBuffer; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import treecms.api.Forest; +import treecms.api.MonotonicTreeNode; +import treecms.api.NodeAttributes; +import treecms.api.NodeChildren; +import treecms.api.NodeID; +import treecms.api.SingleNode; + +public class CassandraMonotonicTreeNode implements MonotonicTreeNode +{ + + @Override + public NodeID getID() { + // TODO Auto-generated method stub + return null; + } + + @Override + public Forest getForest() { + // TODO Auto-generated method stub + return null; + } + + @Override + public Map asMap() { + // TODO Auto-generated method stub + return null; + } + + @Override + public Set getKeySet() { + // TODO Auto-generated method stub + return null; + } + + @Override + public void put(ByteBuffer _name, ByteBuffer _value) { + // TODO Auto-generated method stub + + } + + @Override + public void putAll(NodeAttributes _attrs) { + // TODO Auto-generated method stub + + } + + @Override + public ByteBuffer get(ByteBuffer _name) { + // TODO Auto-generated method stub + return null; + } + + @Override + public NodeAttributes getAll() { + // TODO Auto-generated method stub + return null; + } + + @Override + public void remove(ByteBuffer _name) { + // TODO Auto-generated method stub + + } + + @Override + public void removeAll(Set _keySet) { + // TODO Auto-generated method stub + + } + + @Override + public void clearAttributes() { + // TODO Auto-generated method stub + + } + + @Override + public List getList() { + // TODO Auto-generated method stub + return null; + } + + @Override + public Set getUUIDSet() { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean add(MonotonicTreeNode _child) { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean addAll(NodeChildren _children) { + // TODO Auto-generated method stub + return false; + } + + @Override + public MonotonicTreeNode get(String _uuid) { + // TODO Auto-generated method stub + return null; + } + + @Override + public MonotonicTreeNode get(int _index) { + // TODO Auto-generated method stub + return null; + } + + @Override + public MonotonicTreeNode remove(String _uuid) { + // TODO Auto-generated method stub + return null; + } + + @Override + public MonotonicTreeNode remove(int _index) { + // TODO Auto-generated method stub + return null; + } + + @Override + public MonotonicTreeNode replace(MonotonicTreeNode _newChild) { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean contains(String _id) { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean swap(String _uuid1, String _uuid2) { + // TODO Auto-generated method stub + return false; + } + + @Override + public void clearChildren() { + // TODO Auto-generated method stub + + } + + @Override + public MonotonicTreeNode getParent() { + // TODO Auto-generated method stub + return null; + } + + @Override + public SingleNode getNode() { + // TODO Auto-generated method stub + return null; + } + +} diff -r bb9760760744 -r 168deb591f21 src/treecms/cassandra/CassandraSingleNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/treecms/cassandra/CassandraSingleNode.java Tue May 24 00:33:12 2011 +0900 @@ -0,0 +1,154 @@ +package treecms.cassandra; + +import java.nio.ByteBuffer; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import treecms.api.Forest; +import treecms.api.NodeAttributes; +import treecms.api.NodeChildren; +import treecms.api.NodeID; +import treecms.api.SingleNode; + +public class CassandraSingleNode implements SingleNode { + + @Override + public NodeID getID() { + // TODO Auto-generated method stub + return null; + } + + @Override + public Forest getForest() { + // TODO Auto-generated method stub + return null; + } + + @Override + public Map asMap() { + // TODO Auto-generated method stub + return null; + } + + @Override + public Set getKeySet() { + // TODO Auto-generated method stub + return null; + } + + @Override + public void put(ByteBuffer _name, ByteBuffer _value) { + // TODO Auto-generated method stub + + } + + @Override + public void putAll(NodeAttributes _attrs) { + // TODO Auto-generated method stub + + } + + @Override + public ByteBuffer get(ByteBuffer _name) { + // TODO Auto-generated method stub + return null; + } + + @Override + public NodeAttributes getAll() { + // TODO Auto-generated method stub + return null; + } + + @Override + public void remove(ByteBuffer _name) { + // TODO Auto-generated method stub + + } + + @Override + public void removeAll(Set _keySet) { + // TODO Auto-generated method stub + + } + + @Override + public void clearAttributes() { + // TODO Auto-generated method stub + + } + + @Override + public List getList() { + // TODO Auto-generated method stub + return null; + } + + @Override + public Set getUUIDSet() { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean add(SingleNode _child) { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean addAll(NodeChildren _children) { + // TODO Auto-generated method stub + return false; + } + + @Override + public SingleNode get(String _uuid) { + // TODO Auto-generated method stub + return null; + } + + @Override + public SingleNode get(int _index) { + // TODO Auto-generated method stub + return null; + } + + @Override + public SingleNode remove(String _uuid) { + // TODO Auto-generated method stub + return null; + } + + @Override + public SingleNode remove(int _index) { + // TODO Auto-generated method stub + return null; + } + + @Override + public SingleNode replace(SingleNode _newChild) { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean contains(String _id) { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean swap(String _uuid1, String _uuid2) { + // TODO Auto-generated method stub + return false; + } + + @Override + public void clearChildren() { + // TODO Auto-generated method stub + + } + +} diff -r bb9760760744 -r 168deb591f21 src/treecms/cassandra/CassandraTree.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/treecms/cassandra/CassandraTree.java Tue May 24 00:33:12 2011 +0900 @@ -0,0 +1,14 @@ +package treecms.cassandra; + +import treecms.api.Tree; +import treecms.api.TreeNode; + +public class CassandraTree implements Tree { + + @Override + public TreeNode getRoot() { + // TODO Auto-generated method stub + return null; + } + +} diff -r bb9760760744 -r 168deb591f21 src/treecms/cassandra/CassandraTreeNode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/treecms/cassandra/CassandraTreeNode.java Tue May 24 00:33:12 2011 +0900 @@ -0,0 +1,168 @@ +package treecms.cassandra; + +import java.nio.ByteBuffer; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import treecms.api.Forest; +import treecms.api.NodeAttributes; +import treecms.api.NodeChildren; +import treecms.api.NodeID; +import treecms.api.SingleNode; +import treecms.api.TreeNode; + +public class CassandraTreeNode implements TreeNode +{ + + @Override + public NodeID getID() { + // TODO Auto-generated method stub + return null; + } + + @Override + public Forest getForest() { + // TODO Auto-generated method stub + return null; + } + + @Override + public Map asMap() { + // TODO Auto-generated method stub + return null; + } + + @Override + public Set getKeySet() { + // TODO Auto-generated method stub + return null; + } + + @Override + public void put(ByteBuffer _name, ByteBuffer _value) { + // TODO Auto-generated method stub + + } + + @Override + public void putAll(NodeAttributes _attrs) { + // TODO Auto-generated method stub + + } + + @Override + public ByteBuffer get(ByteBuffer _name) { + // TODO Auto-generated method stub + return null; + } + + @Override + public NodeAttributes getAll() { + // TODO Auto-generated method stub + return null; + } + + @Override + public void remove(ByteBuffer _name) { + // TODO Auto-generated method stub + + } + + @Override + public void removeAll(Set _keySet) { + // TODO Auto-generated method stub + + } + + @Override + public void clearAttributes() { + // TODO Auto-generated method stub + + } + + @Override + public List getList() { + // TODO Auto-generated method stub + return null; + } + + @Override + public Set getUUIDSet() { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean add(TreeNode _child) { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean addAll(NodeChildren _children) { + // TODO Auto-generated method stub + return false; + } + + @Override + public TreeNode get(String _uuid) { + // TODO Auto-generated method stub + return null; + } + + @Override + public TreeNode get(int _index) { + // TODO Auto-generated method stub + return null; + } + + @Override + public TreeNode remove(String _uuid) { + // TODO Auto-generated method stub + return null; + } + + @Override + public TreeNode remove(int _index) { + // TODO Auto-generated method stub + return null; + } + + @Override + public TreeNode replace(TreeNode _newChild) { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean contains(String _id) { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean swap(String _uuid1, String _uuid2) { + // TODO Auto-generated method stub + return false; + } + + @Override + public void clearChildren() { + // TODO Auto-generated method stub + + } + + @Override + public TreeNode getParent() { + // TODO Auto-generated method stub + return null; + } + + @Override + public SingleNode getNode() { + // TODO Auto-generated method stub + return null; + } + +} diff -r bb9760760744 -r 168deb591f21 src/treecms/cassandra/util/CassandraClientThread.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/treecms/cassandra/util/CassandraClientThread.java Tue May 24 00:33:12 2011 +0900 @@ -0,0 +1,48 @@ +package treecms.cassandra.util; + +import org.apache.thrift.transport.TTransportException; + +/** + * CassandraのClientを保持したスレッドオブジェクトです。 + * @author shoshi + */ +final class CassandraClientThread extends Thread +{ + private CassandraClientWrapper m_wrapper; + + /** + * コンストラクタです。 + * @param _host Cassandraのホスト名 + * @param _port Cassandraのポート番号 + * @param _runnable このスレッドで動作するRunnable + * @throws TTransportException + */ + private CassandraClientThread(String _host,int _port,Runnable _runnable) throws TTransportException + { + super(_runnable); + m_wrapper = new CassandraClientWrapper(_host,_port,2); + } + + /** + * ファクトリメソッドです。 + * @param _host Cassandraのホスト名 + * @param _port Cassandraのポート番号 + * @param _runnable このスレッドで動作するRunnable + * @return 新しいインスタンス + * @throws TTransportException Cassandraへの接続が失敗したとき + */ + public static CassandraClientThread newInstance(String _host,int _port,Runnable _runnable) throws TTransportException + { + CassandraClientThread thread = new CassandraClientThread(_host,_port,_runnable); + return thread; + } + + /** + * ClientWrapperを取得します + * @return CassandraへのClientWrapper + */ + public CassandraClientWrapper getClientWrapper() + { + return m_wrapper; + } +} diff -r bb9760760744 -r 168deb591f21 src/treecms/cassandra/util/CassandraClientThreadFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/treecms/cassandra/util/CassandraClientThreadFactory.java Tue May 24 00:33:12 2011 +0900 @@ -0,0 +1,42 @@ +package treecms.cassandra.util; + +import java.util.concurrent.ThreadFactory; + +import org.apache.thrift.transport.TTransportException; + +/** + * ローカル変数としてCassandra.Clientを保持するスレッドオブジェクトを生成するスレッドファクトリーです。 + * @author shoshi + */ +final class CassandraClientThreadFactory implements ThreadFactory +{ + private String m_host; + private int m_port; + + /** + * コンストラクタです。 + * @param _host Cassandraのアドレス・ホスト名 + * @param _port Thriftポート番号 + */ + public CassandraClientThreadFactory(String _host,int _port) + { + m_host = _host; + m_port = _port; + } + + /** + * Cassandra.Clientを保持するスレッドオブジェクトを新しく作成します。 + */ + @Override + public Thread newThread(Runnable _runnable) + { + CassandraClientThread client = null; + try{ + client = CassandraClientThread.newInstance(m_host,m_port,_runnable); + }catch(TTransportException _e) { + _e.printStackTrace(); + throw new RuntimeException(_e); + } + return client; + } +} diff -r bb9760760744 -r 168deb591f21 src/treecms/cassandra/util/CassandraClientWrapper.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/treecms/cassandra/util/CassandraClientWrapper.java Tue May 24 00:33:12 2011 +0900 @@ -0,0 +1,200 @@ +package treecms.cassandra.util; + +import java.util.List; +import java.util.Map; +import org.apache.cassandra.thrift.Cassandra; +import org.apache.cassandra.thrift.ColumnOrSuperColumn; +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.KeyRange; +import org.apache.cassandra.thrift.KeySlice; +import org.apache.cassandra.thrift.Mutation; +import org.apache.cassandra.thrift.NotFoundException; +import org.apache.cassandra.thrift.SlicePredicate; +import org.apache.cassandra.thrift.TimedOutException; +import org.apache.cassandra.thrift.UnavailableException; +import org.apache.thrift.TException; +import org.apache.thrift.protocol.TBinaryProtocol; +import org.apache.thrift.transport.TSocket; +import org.apache.thrift.transport.TTransport; +import org.apache.thrift.transport.TTransportException; + +/** + * Cassandra.Clientのラッパークラスです。Cassandra.Clientを使いやすくするための機能を提供します。 + * 接続済みのCassandra.Clientの接続が切断されたときに再接続を行います。このクラスはスレッドセーフでは有りません。 + * + * このラッパークラスはCassandra 0.6.xのAPIをベースに作成します。 + * @author shoshi + */ +final class CassandraClientWrapper +{ + private String m_host; + private int m_port; + private int m_retryCount; + + private TTransport m_tr; + private Cassandra.Client m_client; + + /** + * コンストラクタです。初期化して接続します。 + * @param _host Cassandraのホスト名 + * @param _port Cassandraのポート番号 + * @param _retryCount リクエストが失敗した場合リトライする回数 + * @throws TTransportException + */ + public CassandraClientWrapper(String _host,int _port,int _retryCount) throws TTransportException + { + m_host = _host; + m_port = _port; + m_retryCount = _retryCount; + + connect(); + } + + /** + * Cassandraに接続します。 + * @throws TTransportException + */ + private void connect() throws TTransportException + { + Cassandra.Client client; + TTransport tr = new TSocket(m_host,m_port); + client = new Cassandra.Client(new TBinaryProtocol(tr)); + + m_tr = tr; + m_tr.open(); + + m_client = client; + } + + /** + * ここで共通する例外処理(再接続など)を行う + * @param _e 例外 + */ + private void exceptionHandler(Exception _e) + { + _e.printStackTrace(); + } + + /** + * Cassandra.Client.getのラッパーメソッド + */ + public ColumnOrSuperColumn get(String _ks,String _key,ColumnPath _path,ConsistencyLevel _level) throws InvalidRequestException, NotFoundException, UnavailableException, TimedOutException, TException + { + for(int i = 0;i < m_retryCount;i ++){ + if(m_client == null){ + throw new IllegalStateException("Cassandra.Client is disconnected. "+m_host+":"+m_port); + } + + try { + ColumnOrSuperColumn cors = m_client.get(_ks,_key,_path,_level); + return cors; + }catch(Exception _e){ + exceptionHandler(_e); + } + } + return m_client.get(_ks,_key,_path,_level); + } + + /** + * Cassandra.Client.get_sliceのラッパーメソッド + */ + public List get_slice(String _ks,String _key,ColumnParent _parent,SlicePredicate _predicate,ConsistencyLevel _level) throws InvalidRequestException, UnavailableException, TimedOutException, TException + { + for(int i = 0;i < m_retryCount;i ++){ + if(m_client == null){ + throw new IllegalStateException("Cassandra.Client is disconnected. "+m_host+":"+m_port); + } + + try { + List list = m_client.get_slice(_ks,_key,_parent,_predicate,_level); + return list; + }catch(Exception _e){ + exceptionHandler(_e); + } + } + return m_client.get_slice(_ks,_key,_parent,_predicate,_level); + } + + /** + * Cassandra.Client.get_range_slicesのラッパーメソッド + */ + public List get_range_slices(String _ks,ColumnParent _parent,SlicePredicate _predicate,KeyRange _range,ConsistencyLevel _level) throws InvalidRequestException, UnavailableException, TimedOutException, TException + { + for(int i = 0;i < m_retryCount;i ++){ + if(m_client == null){ + throw new IllegalStateException("Cassandra.Client is disconnected. "+m_host+":"+m_port); + } + + try { + return m_client.get_range_slices(_ks,_parent,_predicate,_range,_level); + }catch(Exception _e){ + exceptionHandler(_e); + } + } + return m_client.get_range_slices(_ks,_parent,_predicate,_range,_level); + } + + /** + * describe_cluster_name の ラッパーメソッド + * @return cluster name + * @throws TException + */ + public String describe_cluster_name() throws TException + { + for(int i = 0;i < m_retryCount;i ++){ + if(m_client == null){ + throw new IllegalStateException("Cassandra.Client is disconnected. "+m_host+":"+m_port); + } + + try { + return m_client.describe_cluster_name(); + }catch(Exception _e){ + exceptionHandler(_e); + } + } + return m_client.describe_cluster_name(); + } + + /** + * Cassandra.Client.insertのラッパーメソッド + */ + public void insert(String _ks,String _key,ColumnPath _path,byte[] _value,long _timestamp,ConsistencyLevel _level) throws InvalidRequestException, UnavailableException, TimedOutException, TException + { + for(int i = 1;i < m_retryCount;i ++){ + if(m_client == null){ + throw new IllegalStateException("Cassandra.Client is disconnected. "+m_host+":"+m_port); + } + + try{ + m_client.insert(_ks,_key,_path,_value,_timestamp,_level); + }catch(Exception _e){ + exceptionHandler(_e); + } + } + m_client.insert(_ks,_key,_path,_value,_timestamp,_level); + return; + } + + /** + * Cassandra.Client.batch_mutateのラッパーメソッド + */ + public void batch_mutate(String _ks,Map>> _mutation_map,ConsistencyLevel _level) throws InvalidRequestException, UnavailableException, TimedOutException, TException + { + for(int i = 1;i < m_retryCount;i ++){ + if(m_client == null){ + throw new IllegalStateException("Cassandra.Client is disconnected. "+m_host+":"+m_port); + } + + try{ + m_client.batch_mutate(_ks,_mutation_map,_level); + }catch(Exception _e){ + exceptionHandler(_e); + } + } + m_client.batch_mutate(_ks,_mutation_map,_level); + return; + } +} diff -r bb9760760744 -r 168deb591f21 src/treecms/cassandra/util/ConcurrentCassandraClient.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/treecms/cassandra/util/ConcurrentCassandraClient.java Tue May 24 00:33:12 2011 +0900 @@ -0,0 +1,124 @@ +package treecms.cassandra.util; + +import java.util.concurrent.Callable; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import org.apache.cassandra.thrift.ColumnOrSuperColumn; +import org.apache.cassandra.thrift.ColumnParent; +import org.apache.cassandra.thrift.ColumnPath; +import org.apache.cassandra.thrift.ConsistencyLevel; +import org.apache.cassandra.thrift.Mutation; +import org.apache.cassandra.thrift.SlicePredicate; + +/** + * + * @author shoshi + */ +public class ConcurrentCassandraClient +{ + private ExecutorService m_service; + + private ConcurrentCassandraClient(String _host,int _port,int _thCount) + { + m_service = Executors.newFixedThreadPool(_thCount,new CassandraClientThreadFactory(_host,_port)); + } + + public static ConcurrentCassandraClient newInstance(String _host,int _port,int _thCount) + { + ConcurrentCassandraClient client = new ConcurrentCassandraClient(_host,_port,_thCount); + return client; + } + + public void disconnect() + { + m_service.shutdown(); + try{ + m_service.awaitTermination(Long.MAX_VALUE,TimeUnit.DAYS); + }catch(InterruptedException _e){ + _e.printStackTrace(); + } + } + + public Future get(final String _ks,final String _key,final ColumnPath _path,final ConsistencyLevel _level) + { + Callable task = new Callable(){ + @Override + public ColumnOrSuperColumn call() throws Exception + { + CassandraClientWrapper client = ((CassandraClientThread)Thread.currentThread()).getClientWrapper(); + ColumnOrSuperColumn cors = client.get(_ks,_key,_path,_level); + return cors; + } + }; + + Future ret = m_service.submit(task); + return ret; + } + + public Future> get_slice(final String _ks,final String _key,final ColumnParent _parent,final SlicePredicate _predicate,final ConsistencyLevel _level) + { + Callable> task = new Callable>(){ + @Override + public List call() throws Exception + { + CassandraClientWrapper client = ((CassandraClientThread)Thread.currentThread()).getClientWrapper(); + List ret = client.get_slice(_ks,_key,_parent,_predicate,_level); + return ret; + } + }; + + Future> ret = m_service.submit(task); + return ret; + } + + public Future batch_mutate(final String _ks,final Map>> _mutation_map,final ConsistencyLevel _level) + { + Callable task = new Callable(){ + @Override + public Boolean call() throws Exception + { + CassandraClientWrapper client = ((CassandraClientThread)Thread.currentThread()).getClientWrapper(); + client.batch_mutate(_ks,_mutation_map,_level); + return true; + } + }; + + Future ret = m_service.submit(task); + return ret; + } + + public Future insert(final String _ks,final String _key,final ColumnPath _path,final byte[] _value,final long _timestamp,final ConsistencyLevel _level) + { + Callable task = new Callable(){ + @Override + public Boolean call() throws Exception + { + CassandraClientWrapper client = ((CassandraClientThread)Thread.currentThread()).getClientWrapper(); + client.insert(_ks,_key,_path,_value,_timestamp,_level); + return true; + } + }; + + Future ret = m_service.submit(task); + return ret; + } + + public Future describe_cluster_name() + { + Callable task = new Callable(){ + @Override + public String call() throws Exception + { + return null; + } + }; + + Future ret = m_service.submit(task); + return ret; + } +} diff -r bb9760760744 -r 168deb591f21 src/treecms/cassandra/util/ConcurrentCassandraClientTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/treecms/cassandra/util/ConcurrentCassandraClientTest.java Tue May 24 00:33:12 2011 +0900 @@ -0,0 +1,64 @@ +package treecms.cassandra.util; + +import java.util.concurrent.ExecutionException; +import org.apache.cassandra.thrift.Cassandra; +import org.apache.cassandra.thrift.ColumnPath; +import org.apache.cassandra.thrift.ConsistencyLevel; +import org.apache.cassandra.thrift.InvalidRequestException; +import org.apache.cassandra.thrift.NotFoundException; +import org.apache.cassandra.thrift.TimedOutException; +import org.apache.cassandra.thrift.UnavailableException; +import org.apache.thrift.TException; +import org.apache.thrift.protocol.TBinaryProtocol; +import org.apache.thrift.transport.TSocket; +import org.apache.thrift.transport.TTransport; + +public class ConcurrentCassandraClientTest +{ + public static void main(String _args[]) throws InterruptedException, ExecutionException, InvalidRequestException, NotFoundException, UnavailableException, TimedOutException, TException + { + String host = "misaka01.cr.ie.u-ryukyu.ac.jp"; + int port = 9160; + int count = 1000; + + System.out.println("Read benchmark."); + ConcurrentCassandraClient conClient = ConcurrentCassandraClient.newInstance(host,port,7); + ColumnPath path = new ColumnPath(); + path.column_family = "Standard1"; + path.column = "fuga".getBytes(); + + long start = System.currentTimeMillis(); + for(int i = 0;i < count;i ++){ + conClient.get("Keyspace1","hoge",path,ConsistencyLevel.ONE); + } + conClient.disconnect(); + System.out.println("concurrent client time = "+(System.currentTimeMillis()-start)); + + TTransport tr = new TSocket(host,port); + Cassandra.Client client = new Cassandra.Client(new TBinaryProtocol(tr)); + tr.open(); + + start = System.currentTimeMillis(); + for(int i = 0;i < count;i ++){ + client.get("Keyspace1","hoge",path,ConsistencyLevel.ONE); + } + System.out.println("normal client time = "+(System.currentTimeMillis()-start)); + + System.out.println("Write benchmark"); + conClient = ConcurrentCassandraClient.newInstance(host,port,30); + + start = System.currentTimeMillis(); + for(int i = 0;i < count;i ++){ + conClient.insert("Keyspace1","hoge",path,"piga".getBytes(),System.currentTimeMillis()/1000,ConsistencyLevel.ONE); + } + conClient.disconnect(); + System.out.println("concurrent client time = "+(System.currentTimeMillis()-start)); + + start = System.currentTimeMillis(); + for(int i = 0;i < count;i ++){ + client.insert("Keyspace1","hoge",path,"piga".getBytes(),System.currentTimeMillis()/1000,ConsistencyLevel.ONE); + } + System.out.println("normal client time = "+(System.currentTimeMillis()-start)); + + } +} diff -r bb9760760744 -r 168deb591f21 src/treecms/gui/AddChildDialog.java --- a/src/treecms/gui/AddChildDialog.java Sat May 21 04:46:00 2011 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -package treecms.gui; - -import java.awt.BorderLayout; -import java.awt.Container; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import java.nio.ByteBuffer; -import java.util.Map; -import javax.swing.JButton; -import javax.swing.JDialog; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JScrollPane; - -class AddChildDialog -{ - private JDialog m_dialog; - private AttributeEditorTable m_table; - private JButton m_submit; - private Map m_data; - private JFrame m_parent; - - public AddChildDialog(JFrame _parent,boolean _modal) - { - m_dialog = new JDialog(_parent,_modal); - m_dialog.setSize(300,200); - m_dialog.setTitle("Add new child"); - m_parent = _parent; - m_table = new AttributeEditorTable(); - m_submit = new JButton("submit"); - m_submit.addActionListener(new ActionListener(){ - @Override - public void actionPerformed(ActionEvent _e) - { - m_data = m_table.getAttributeMap(); - m_dialog.setVisible(false); - } - }); - m_dialog.addWindowListener(new WindowAdapter(){ - @Override - public void windowClosing(WindowEvent _e) - { - m_data = null; - } - }); - - Container cnt = m_dialog.getContentPane(); - cnt.setLayout(new BorderLayout()); - cnt.add(new JLabel("Attributes"),BorderLayout.NORTH); - cnt.add(new JScrollPane(m_table),BorderLayout.CENTER); - cnt.add(m_submit,BorderLayout.SOUTH); - } - - public Map setVisible(boolean _show) - { - m_dialog.setLocationRelativeTo(m_parent); - m_dialog.setVisible(_show); - - return m_data; - } -} diff -r bb9760760744 -r 168deb591f21 src/treecms/gui/AttributeEditorTable.java --- a/src/treecms/gui/AttributeEditorTable.java Sat May 21 04:46:00 2011 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,99 +0,0 @@ -package treecms.gui; - -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.nio.ByteBuffer; -import java.util.HashMap; -import java.util.Map; - -import javax.swing.JTable; -import javax.swing.table.DefaultTableModel; - -class AttributeEditorTable extends JTable -{ - private static final long serialVersionUID = -3520371233895896649L; - private static final String ADD_ROW_STR = "add new attribute..."; - private static final Object ADD_ROW = new Object(){ - @Override - public String toString() - { - return ADD_ROW_STR; - } - }; - - private static final String[] COLUMNS = new String[]{"Key","Value"}; - private static final String[] DEFAULT_VALUES = new String[]{"new key","new value"}; - - public AttributeEditorTable() - { - super(new AETableModel()); - - addMouseListener(new MouseAdapter(){ - @Override - public void mouseClicked(MouseEvent _e) - { - if(_e.getClickCount() == 2){ - int row = getSelectedRow(); - Object val = getValueAt(row,0); - if(val == ADD_ROW){ - DefaultTableModel model = (DefaultTableModel)AttributeEditorTable.this.getModel(); - model.insertRow(row,DEFAULT_VALUES); - } - } - } - }); - } - - public void setAttributeMap(Map _map) - { - AETableModel model = (AETableModel)getModel(); - model.clear(); - for(ByteBuffer _key : _map.keySet()){ - model.insertRow(0,new String[]{new String(_key.array()),new String(_map.get(_key).array())}); - } - } - - public Map getAttributeMap() - { - Map map = new HashMap(); - for(int i = 0;true;i ++){ - Object key = getValueAt(i,0); - Object value = getValueAt(i,1); - - if(key == ADD_ROW){ - break; - } - - ByteBuffer bufKey = ByteBuffer.wrap(key.toString().getBytes()); - ByteBuffer bufValue = ByteBuffer.wrap(value.toString().getBytes()); - map.put(bufKey,bufValue); - } - - return map; - } - - private static class AETableModel extends DefaultTableModel - { - private static final long serialVersionUID = -5641721228388548196L; - - public AETableModel() - { - super(); - setColumnIdentifiers(COLUMNS); - addRow(new Object[]{ADD_ROW,""}); - } - - public void clear() - { - setRowCount(0); - addRow(new Object[]{ADD_ROW,""}); - } - - @Override - public boolean isCellEditable(int _row,int _col) - { - Object val = this.getValueAt(_row,_col); - return (val == ADD_ROW) ? false : true; - } - } -} diff -r bb9760760744 -r 168deb591f21 src/treecms/gui/GUIEditor.java --- a/src/treecms/gui/GUIEditor.java Sat May 21 04:46:00 2011 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,262 +0,0 @@ -package treecms.gui; - -import java.awt.BorderLayout; -import java.awt.Container; -import java.awt.GridLayout; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; -import java.nio.ByteBuffer; -import java.util.Map; -import javax.swing.JButton; -import javax.swing.JFrame; -import javax.swing.JMenuItem; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JPopupMenu; -import javax.swing.JScrollPane; -import javax.swing.JSplitPane; -import javax.swing.JTree; -import javax.swing.SwingUtilities; -import javax.swing.border.TitledBorder; -import javax.swing.event.TreeSelectionEvent; -import javax.swing.event.TreeSelectionListener; -import javax.swing.tree.DefaultMutableTreeNode; -import javax.swing.tree.DefaultTreeModel; - -import treecms.api.Node; -import treecms.api.Tree; -import treecms.api.TreeEditor; -import treecms.memory.OnMemoryForest; -import treecms.tree.util.NodeData; -import treecms.tree.util.PathNotFoundException; - -public class GUIEditor -{ - private static final String TITLE = "GUIEditor"; - - //GUIコンポーネント - private JFrame m_frame; - private NodeViewerTree m_nodeTree; - private AttributeEditorTable m_attrTable; - private JButton m_commit,m_pull,m_check,m_merge; - private JButton m_attrSave,m_attrCancel; - private JPopupMenu m_popup; - private JMenuItem m_addChild,m_removeChild; - - //TreeEditor - private TreeEditor m_editor; - - //イベントハンドラ - private ActionListener m_actionListener; - private MouseListener m_mouseListener; - private TreeSelectionListener m_treeSelectionListener; - - public static void main(String _args[]) - { - OnMemoryForest forest = new OnMemoryForest(); - Tree root = forest.getMainTree(); - TreeEditor editor = forest.getAsTreeEditor(root.getID()); - new GUIEditor(editor); - } - - public GUIEditor(TreeEditor _editor) - { - m_editor = _editor; - m_frame = new JFrame(TITLE+":"+m_editor.toString()); - m_frame.setSize(500,500); - - m_actionListener = new EditorActionListener(); - m_mouseListener = new EditorMouseListener(); - m_treeSelectionListener = new EditorTreeSelectionListener(); - - Container pane = m_frame.getContentPane(); - pane.setLayout(new BorderLayout()); - - JPanel treePanel = initNodeTree(); - JPanel menuPanel = initMenuButtons(); - JPanel attrPanel = initAttributeTable(); - - JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT,treePanel,attrPanel); - - pane.add(menuPanel,BorderLayout.NORTH); - pane.add(splitPane,BorderLayout.CENTER); - m_frame.setVisible(true); - splitPane.setDividerLocation(0.5); - m_frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - } - - private JPanel initMenuButtons() - { - JPanel panel = new JPanel(); - m_commit = new JButton("commit"); - m_pull = new JButton("pull"); - m_check = new JButton("check"); - m_merge = new JButton("merge"); - - panel.setBorder(new TitledBorder("Editor Menu")); - panel.setLayout(new GridLayout(1,4)); - panel.add(m_commit); - panel.add(m_pull); - panel.add(m_check); - panel.add(m_merge); - - return panel; - } - - private JPanel initAttributeTable() - { - JPanel panel = new JPanel(); - m_attrTable = new AttributeEditorTable(); - m_attrSave = new JButton("save"); - m_attrSave.addActionListener(m_actionListener); - m_attrCancel = new JButton("cancel"); - m_attrCancel.addActionListener(m_actionListener); - - JPanel btnPanel = new JPanel(); - btnPanel.setLayout(new GridLayout(1,2)); - btnPanel.add(m_attrSave); - btnPanel.add(m_attrCancel); - - panel.setBorder(new TitledBorder("Attributes")); - panel.setLayout(new BorderLayout()); - panel.add(new JScrollPane(m_attrTable),BorderLayout.CENTER); - panel.add(btnPanel,BorderLayout.SOUTH); - - return panel; - } - - private JPanel initNodeTree() - { - JPanel panel = new JPanel(); - m_nodeTree = new NodeViewerTree(m_editor.getRoot()); - m_nodeTree.addTreeSelectionListener(m_treeSelectionListener); - - m_popup = new JPopupMenu(); - m_addChild = new JMenuItem("Add Child"); - m_removeChild = new JMenuItem("Remove Child"); - m_popup.add(m_addChild); - m_popup.add(m_removeChild); - m_addChild.addActionListener(m_actionListener); - m_removeChild.addActionListener(m_actionListener); - m_nodeTree.addMouseListener(m_mouseListener); - - panel.setBorder(new TitledBorder("Tree Viewer")); - panel.setLayout(new BorderLayout()); - panel.add(new JScrollPane(m_nodeTree),BorderLayout.CENTER); - - return panel; - } - - private class EditorActionListener implements ActionListener - { - @Override - public void actionPerformed(ActionEvent _e) - { - Object source = _e.getSource(); - if(source == m_addChild){ - //新しいノードを追加する - AddChildDialog addDialog = new AddChildDialog(GUIEditor.this.m_frame,true); - Map result = addDialog.setVisible(true); - if(result != null){ - //キャンセルされなかった場合 - NodeData data = new NodeData(); - data.putAll(result); - - //パスの取得 - Object[] treePath = m_nodeTree.getSelectionPath().getPath(); - Node[] nodePath = new Node[treePath.length]; - for(int i = 0;i < treePath.length;i ++){ - System.out.println(treePath[i].getClass().toString()); - DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode)treePath[i]; - nodePath[i] = (Node)treeNode.getUserObject(); - } - - Node target = nodePath[nodePath.length-1]; - Node child = target.getForest().create(data); - NodeData newData = target.getData(); - newData.add(child); - try{ - m_editor.updateTree(target,newData,nodePath); - }catch(PathNotFoundException _err){ - _err.printStackTrace(); - JOptionPane.showMessageDialog(m_frame,"追加に失敗しました:"+_err.getMessage()); - return; - } - - NodeViewerTree.NVTreeModel model = (NodeViewerTree.NVTreeModel)m_nodeTree.getModel(); - model.setTree(m_editor.getRoot(),true); - } - } - - if(source == m_removeChild){ - //ノードを削除する - DefaultMutableTreeNode guiNode = (DefaultMutableTreeNode)m_nodeTree.getLastSelectedPathComponent(); - DefaultMutableTreeNode guiParent = (DefaultMutableTreeNode)guiNode.getParent(); - if(guiParent == null){ - JOptionPane.showMessageDialog(m_frame,"RootNodeは削除できません"); - return; - } - - guiParent.remove(guiNode); - - Node treeNode = (Node)guiNode.getUserObject(); - Node treeParent = (Node)guiNode.getUserObject(); - treeParent.remove(treeNode); - - DefaultTreeModel model = (DefaultTreeModel)m_nodeTree.getModel(); - model.reload(); - } - - if(source == m_attrSave){ - //ノードの変更を保存する - DefaultMutableTreeNode guiNode = (DefaultMutableTreeNode)m_nodeTree.getLastSelectedPathComponent(); - if(guiNode == null){ - //ノードが選択されずに編集された - JOptionPane.showMessageDialog(m_frame,"編集対象のノードが選択されていません。"); - return; - } - - Node treeNode = (Node)guiNode.getUserObject(); - Map attrMap = m_attrTable.getAttributeMap(); - treeNode.putAll(attrMap); - } - - if(source == m_attrCancel){ - //ノードへの編集を捨てる - DefaultMutableTreeNode guiNode = (DefaultMutableTreeNode)m_nodeTree.getLastSelectedPathComponent(); - Node treeNode = (Node)guiNode.getUserObject(); - m_attrTable.setAttributeMap(treeNode.getAll()); - } - } - } - - private class EditorTreeSelectionListener implements TreeSelectionListener - { - @Override - public void valueChanged(TreeSelectionEvent _e) - { - DefaultMutableTreeNode guiNode = (DefaultMutableTreeNode)m_nodeTree.getLastSelectedPathComponent(); - if(guiNode == null){ - return; - } - - Node treeNode = (Node)guiNode.getUserObject(); - m_attrTable.setAttributeMap(treeNode.getAll()); - } - } - - private class EditorMouseListener extends MouseAdapter - { - @Override - public void mouseClicked(MouseEvent _e) - { - if(SwingUtilities.isRightMouseButton(_e) && !m_nodeTree.isSelectionEmpty()){ - //ポップアップメニューを表示する - m_popup.show(m_nodeTree,_e.getX(),_e.getY()); - } - } - } -} diff -r bb9760760744 -r 168deb591f21 src/treecms/gui/NodeViewerTree.java --- a/src/treecms/gui/NodeViewerTree.java Sat May 21 04:46:00 2011 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,65 +0,0 @@ -package treecms.gui; - -import javax.swing.JTree; -import javax.swing.tree.DefaultMutableTreeNode; -import javax.swing.tree.DefaultTreeModel; - -import treecms.api.Node; -import treecms.api.TreeEditor; - -public class NodeViewerTree extends JTree -{ - private static final long serialVersionUID = 8257838201307216301L; - - public NodeViewerTree(Node _node) - { - super(new NVTreeModel(_node)); - } - - public void addChildToSelectedNode(Node _child) - { - DefaultMutableTreeNode node = (DefaultMutableTreeNode)this.getLastSelectedPathComponent(); - if(node == null){ - return; - } - - DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(); - newNode.setUserObject(_child); - node.add(newNode); - } - - static class NVTreeModel extends DefaultTreeModel - { - public NVTreeModel(Node _node) - { - super(new DefaultMutableTreeNode()); - setTree(_node,false); - } - - public void setTree(Node _node,boolean _reload) - { - DefaultMutableTreeNode root = (DefaultMutableTreeNode)getRoot(); - root.removeAllChildren(); - root.setUserObject(_node); - - for(Node child : _node.children()){ - treewalk(child,root); - } - - if(_reload){ - reload(); - } - } - - private void treewalk(Node _node,DefaultMutableTreeNode _treeNode) - { - DefaultMutableTreeNode treeChild = new DefaultMutableTreeNode(); - treeChild.setUserObject(_node); - _treeNode.add(treeChild); - - for(Node child : _node.children()){ - treewalk(child,treeChild); - } - } - } -} diff -r bb9760760744 -r 168deb591f21 src/treecms/memory/OnMemoryForest.java --- a/src/treecms/memory/OnMemoryForest.java Sat May 21 04:46:00 2011 +0900 +++ b/src/treecms/memory/OnMemoryForest.java Tue May 24 00:33:12 2011 +0900 @@ -149,6 +149,12 @@ return new OnMemoryTree(m_tipTable.get(m_mainID)); } + @Override + public SingleNode create(NodeID _id,NodeData _data) + { + return createNode(_id,_data); + } + /** * ランダムにバージョン番号を生成するNodeIDです.ファクトリを内包します. * @author shoshi diff -r bb9760760744 -r 168deb591f21 src/treecms/memory/OnMemoryMonotonicTree.java --- a/src/treecms/memory/OnMemoryMonotonicTree.java Sat May 21 04:46:00 2011 +0900 +++ b/src/treecms/memory/OnMemoryMonotonicTree.java Tue May 24 00:33:12 2011 +0900 @@ -1,7 +1,9 @@ package treecms.memory; import treecms.api.MonotonicTree; + import treecms.api.MonotonicTreeNode; +import treecms.api.SingleNode; import treecms.api.Tree; import treecms.merger.Merger; import treecms.merger.ReplaceMerger; @@ -11,12 +13,13 @@ private volatile OnMemoryTree m_tree; private OnMemoryNode m_old; private OnMemoryMonotonicTreeNode m_root; + private static final Merger m_merger = new ReplaceMerger(); public OnMemoryMonotonicTree(OnMemoryTree _tree) { m_tree = _tree; m_old = (OnMemoryNode)m_tree.getRoot().getNode(); - m_root = new OnMemoryMonotonicTreeNode((OnMemoryNode)m_old,this); + m_root = new OnMemoryMonotonicTreeNode((OnMemoryNode)m_old,null); } @Override @@ -42,6 +45,7 @@ public void merge() { //merge here + m_old = (OnMemoryNode)m_merger.merge(m_tree.getRoot().getNode(),m_root.getNode()); } @Override diff -r bb9760760744 -r 168deb591f21 src/treecms/memory/OnMemoryMonotonicTreeNode.java --- a/src/treecms/memory/OnMemoryMonotonicTreeNode.java Sat May 21 04:46:00 2011 +0900 +++ b/src/treecms/memory/OnMemoryMonotonicTreeNode.java Tue May 24 00:33:12 2011 +0900 @@ -23,7 +23,6 @@ { private OnMemoryNode m_node; private OnMemoryMonotonicTreeNode m_parent; - private OnMemoryMonotonicTree m_tree; /** * コンストラクタです. @@ -37,13 +36,6 @@ m_parent = _parent; } - public OnMemoryMonotonicTreeNode(OnMemoryNode _root,OnMemoryMonotonicTree _tree) - { - m_node = _root; - m_tree = _tree; - m_parent = null; - } - @Override public NodeID getID() { @@ -87,19 +79,28 @@ @Override public void put(ByteBuffer _key, ByteBuffer _value) { - m_node.put(_key,_value); + NodeData d = new NodeData(m_node); + d.put(_key,_value); + + cloneAndTransmit(d); } @Override public void putAll(NodeAttributes _map) { - m_node.putAll(_map); + NodeData d = new NodeData(m_node); + d.putAll(_map); + + cloneAndTransmit(d); } @Override public void remove(ByteBuffer _key) { - m_node.remove(_key); + NodeData d = new NodeData(m_node); + d.remove(_key); + + cloneAndTransmit(d); } @Override @@ -125,6 +126,8 @@ OnMemoryForest f = (OnMemoryForest)m_node.getForest(); OnMemoryNode clone = f.createNode(m_node.getID().update(),_d); transmit(m_node,clone); + + m_node = clone; } /** @@ -168,40 +171,66 @@ @Override public boolean add(MonotonicTreeNode _n) { - return m_node.add(_n.getNode()); + NodeData d = new NodeData(m_node); + boolean ret = d.add(_n.getNode()); + if(ret){ + cloneAndTransmit(d); + } + + return ret; } @Override public boolean addAll(NodeChildren _list) { //MotonicTreeNodeのリストからNodeのリストを作成する. - NodeChildren res = new NodeChildrenImpl(); + NodeChildren c = new NodeChildrenImpl(); for(Iterator it = _list.getList().iterator();it.hasNext();){ MonotonicTreeNode mono = (MonotonicTreeNode)it.next(); - res.add(mono.getNode()); + c.add(mono.getNode()); } - return m_node.addAll(res); + NodeData d = new NodeData(m_node); + boolean ret = d.addAll(c); + if(ret){ + cloneAndTransmit(d); + } + + return ret; } @Override public MonotonicTreeNode remove(String _uuid) { - SingleNode n = m_node.remove(_uuid); - return new OnMemoryMonotonicTreeNode((OnMemoryNode)n,this); + NodeData d = new NodeData(m_node); + SingleNode n = d.remove(_uuid); + if(n != null){ + cloneAndTransmit(d); + return new OnMemoryMonotonicTreeNode((OnMemoryNode)n,null); + } + + return null; } @Override public MonotonicTreeNode remove(int _index) { - SingleNode n = m_node.remove(_index); - return new OnMemoryMonotonicTreeNode((OnMemoryNode)n,(OnMemoryMonotonicTreeNode)null); + NodeData d = new NodeData(m_node); + SingleNode n = d.remove(_index); + if(n != null){ + cloneAndTransmit(d); + return new OnMemoryMonotonicTreeNode((OnMemoryNode)n,null); + } + + return null; } @Override public void clearChildren() { - m_node.clearChildren(); + NodeData d = new NodeData(m_node); + d.clearChildren(); + cloneAndTransmit(d); } @Override @@ -239,8 +268,14 @@ @Override public MonotonicTreeNode replace(MonotonicTreeNode _newChild) { - SingleNode n = m_node.replace(_newChild.getNode()); - return new OnMemoryMonotonicTreeNode((OnMemoryNode)n,(OnMemoryMonotonicTreeNode)null); + NodeData d = new NodeData(m_node); + SingleNode n = d.replace(_newChild.getNode()); + if(n != null){ + cloneAndTransmit(d); + return new OnMemoryMonotonicTreeNode((OnMemoryNode)n,(OnMemoryMonotonicTreeNode)null); + } + + return null; } @Override diff -r bb9760760744 -r 168deb591f21 src/treecms/memory/OnMemoryTree.java --- a/src/treecms/memory/OnMemoryTree.java Sat May 21 04:46:00 2011 +0900 +++ b/src/treecms/memory/OnMemoryTree.java Tue May 24 00:33:12 2011 +0900 @@ -9,7 +9,7 @@ * 木構造のルートとなるNodeをメンバーとして持ち、操作はすべて転送します。 * @author shoshi */ -final class OnMemoryTree implements Tree +public class OnMemoryTree implements Tree { private static final AtomicReferenceFieldUpdater m_refUpdater = AtomicReferenceFieldUpdater.newUpdater(OnMemoryTree.class,OnMemoryNode.class,"m_root"); private volatile OnMemoryNode m_root; diff -r bb9760760744 -r 168deb591f21 src/treecms/memory/test/OnMemoryForestTest.java --- a/src/treecms/memory/test/OnMemoryForestTest.java Sat May 21 04:46:00 2011 +0900 +++ b/src/treecms/memory/test/OnMemoryForestTest.java Tue May 24 00:33:12 2011 +0900 @@ -1,7 +1,6 @@ package treecms.memory.test; import org.junit.runner.JUnitCore; - import treecms.api.Forest; import treecms.memory.OnMemoryForest; import treecms.test.AbstractForestTest; diff -r bb9760760744 -r 168deb591f21 src/treecms/memory/test/OnMemoryMonotonicTreeTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/treecms/memory/test/OnMemoryMonotonicTreeTest.java Tue May 24 00:33:12 2011 +0900 @@ -0,0 +1,22 @@ +package treecms.memory.test; + +import org.junit.runner.JUnitCore; + +import treecms.api.Forest; +import treecms.memory.OnMemoryForest; +import treecms.test.AbstractMonotonicTreeTest; + +public class OnMemoryMonotonicTreeTest extends AbstractMonotonicTreeTest +{ + public static void main(String _args[]) + { + JUnitCore.main(OnMemoryMonotonicTreeTest.class.getName()); + } + @Override + public Forest getForest() + { + OnMemoryForest f = new OnMemoryForest(); + return f; + } + +} diff -r bb9760760744 -r 168deb591f21 src/treecms/merger/Merger.java --- a/src/treecms/merger/Merger.java Sat May 21 04:46:00 2011 +0900 +++ b/src/treecms/merger/Merger.java Tue May 24 00:33:12 2011 +0900 @@ -2,7 +2,7 @@ import treecms.api.Node; -public interface Merger +public interface Merger> { - public Node merge(Node _from,Node _to); + public T merge(T _tree1,T _tree2); } diff -r bb9760760744 -r 168deb591f21 src/treecms/merger/ReplaceMerger.java --- a/src/treecms/merger/ReplaceMerger.java Sat May 21 04:46:00 2011 +0900 +++ b/src/treecms/merger/ReplaceMerger.java Tue May 24 00:33:12 2011 +0900 @@ -2,10 +2,10 @@ import treecms.api.Node; -public class ReplaceMerger implements Merger +public class ReplaceMerger> implements Merger { - public Node merge(Node _from,Node _to) + public T merge(T _tree1,T _tree2) { - return _from; + return _tree1; } } diff -r bb9760760744 -r 168deb591f21 src/treecms/test/AbstractForestTest.java --- a/src/treecms/test/AbstractForestTest.java Sat May 21 04:46:00 2011 +0900 +++ b/src/treecms/test/AbstractForestTest.java Tue May 24 00:33:12 2011 +0900 @@ -1,11 +1,18 @@ package treecms.test; +import java.nio.ByteBuffer; +import java.util.List; +import java.util.Map; import junit.framework.Assert; import org.junit.Test; import treecms.api.Forest; +import treecms.api.MonotonicTree; +import treecms.api.MonotonicTreeNode; import treecms.api.NodeID; import treecms.api.SingleNode; import treecms.api.Tree; +import treecms.api.TreeNode; +import treecms.tree.util.NodeData; /** * Forest実装の基本的なテスト @@ -13,69 +20,125 @@ */ public abstract class AbstractForestTest { - /** - * 基本的なテストを実装するためにはこのメソッドでインスタンスを返す。 - * @return Forest - */ public abstract Forest getInstance(); - /** - * Node作成テスト - * 新しく作成されたNodeがnullでなければOK - */ @Test - public void testCreateNode() + public void testCreate() { Forest forest = getInstance(); - SingleNode newNode = forest.create(); - Assert.assertNotNull(newNode); + + //正常にSingleNodeを作成できることを確認する(引数なし) + SingleNode test1 = forest.create(); + Assert.assertNotNull(test1); + + //正常にSingleNodeを作成できることを確認する(引数あり) + NodeData d = new NodeData(); + d.add(forest.create()); + d.put(ByteBuffer.wrap("name".getBytes()),ByteBuffer.wrap("value".getBytes())); + SingleNode test2 = forest.create(d); + Assert.assertNotNull(test2); + + //指定したNodeDataが正しく継承されているか確認する + List list1 = d.getList(); + List list2 = test2.getList(); + Assert.assertEquals(true,list1.equals(list2)); + + Map map1 = d.asMap(); + Map map2 = test2.asMap(); + Assert.assertEquals(true,map1.equals(map2)); } - /** - * Node取得テスト - * 新しく作成されたNodeからNodeIDを取得し、ForestよりNodeを再取得する - */ @Test - public void testGetNode() + public void testGet() { Forest forest = getInstance(); SingleNode newNode = forest.create(); NodeID newID = newNode.getID(); - SingleNode node = forest.get(newID); + SingleNode test1 = forest.get(newID); + + //同じノードであることを確認する + Assert.assertEquals(newNode,test1); - Assert.assertEquals(newNode,node); + //forest.get(NodeID _id)にnullが渡されたときNullPointerExceptionが発生する + try{ + forest.get(null); + Assert.fail("no NullPointerException occurs when call forest.get(null)"); + }catch(NullPointerException _e){ + } + + //存在しないNodeIDが指定された場合はnullである + NodeID updated = newID.update(); + SingleNode test2 = forest.get(updated); + Assert.assertNull(test2); } - /** - * NodeのTip(最新版)の取得テスト - * 新しく作成されたNodeのUUIDを抜き出し、Forestよりtipを取得する - */ @Test public void testGetTip() { Forest forest = getInstance(); + + //SingleNodeを作成した時点で、最新版と比較し一致することを確認する SingleNode newNode = forest.create(); NodeID newID = newNode.getID(); - SingleNode tip = forest.getTip(newID.getUUID()); Assert.assertEquals(newNode,tip); + + //同じUUIDを持つSingleNodeを登録すると、最新版が更新される + NodeData d = new NodeData(tip,tip); + SingleNode test1 = forest.create(tip.getID().update(),d); + tip = forest.getTip(test1.getID().getUUID()); + + Assert.assertEquals(test1,tip); + + //nullが渡された場合は、NullPointerExceptionが発生する + try{ + forest.getTip(null); + Assert.fail("no NullPointerException occurs when call forest.getTip(null)"); + }catch(NullPointerException _e){ + //OK + } } - /** - * NodeIDを更新したものを作成したとき、きちんと登録されているかテスト - */ @Test - public void updateTest() + public void testGetTree() { + Forest f = getInstance(); + //同一のForestから作成されたSingleNodeから正しくTreeが作成できるか確認する。 + SingleNode n = f.create(); + Tree t = f.getTree(n); + Assert.assertNotNull(t); + + //作成したTreeからTreeNodeのルートが取得できる。 + TreeNode root = t.getRoot(); + Assert.assertNotNull(t.getRoot()); + + //取得したTreeNodeから引数に指定したSingleNodeが取得できるか確認する + Assert.assertEquals(n,root.getNode()); } - /** - * MainTreeが取得できるかテストします。 - * MainTreeとは、コンテンツ全体を含むツリーです - */ + @Test + public void testGetMonotonicTree() + { + Forest f = getInstance(); + SingleNode newNode = f.create(); + + Tree newTree = f.getTree(newNode); + MonotonicTree newMonoTree = f.getMonotonicTree(newTree); + Assert.assertNotNull(newMonoTree); + + MonotonicTreeNode m = newMonoTree.getRoot(); + Assert.assertNotNull(m); + SingleNode n = m.getNode(); + Assert.assertEquals(true,n.equals(newNode)); + + Tree t2 = newMonoTree.getTree(); + Assert.assertNotNull(t2); + Assert.assertEquals(true,t2.equals(t2)); + } + @Test public void testGetMainTree() { diff -r bb9760760744 -r 168deb591f21 src/treecms/test/AbstractMonotonicTreeTest.java --- a/src/treecms/test/AbstractMonotonicTreeTest.java Sat May 21 04:46:00 2011 +0900 +++ b/src/treecms/test/AbstractMonotonicTreeTest.java Tue May 24 00:33:12 2011 +0900 @@ -1,23 +1,35 @@ package treecms.test; import java.nio.ByteBuffer; -import java.util.Arrays; + import junit.framework.Assert; + import org.junit.Test; import treecms.api.Forest; import treecms.api.MonotonicTree; -import treecms.api.Node; -import treecms.api.NodeID; import treecms.api.SingleNode; +import treecms.api.MonotonicTreeNode; import treecms.api.Tree; -import treecms.tree.util.NodeData; +import treecms.tree.util.NodeChildrenImpl; +import treecms.tree.util.NodeFinder; public abstract class AbstractMonotonicTreeTest { public abstract Forest getForest(); @Test - public MonotonicTree testEdit() + public void testInitialize() + { + Forest f = getForest(); + Tree t = f.getMainTree(); + MonotonicTree mt = f.getMonotonicTree(t); + MonotonicTreeNode n = mt.getRoot(); + + Assert.assertEquals(true,t.getRoot().getID().equals(n.getID())); + } + + @Test + public void testEdit() { Forest forest = getForest(); SingleNode root = forest.create(); @@ -25,60 +37,23 @@ SingleNode n1 = forest.create(); SingleNode n11 = forest.create(); SingleNode n12 = forest.create(); - n1.addAll(Arrays.asList(n11,n12)); + n1.addAll(new NodeChildrenImpl(n11,n12)); - Node n2 = forest.create(); - Node n21 = forest.create(); - Node n22 = forest.create(); - n2.addAll(Arrays.asList(n21,n22)); + SingleNode n2 = forest.create(); + SingleNode n21 = forest.create(); + SingleNode n22 = forest.create(); + n2.addAll(new NodeChildrenImpl(n21,n22)); - Node n221 = forest.create(); + SingleNode n221 = forest.create(); n22.add(n221); - root.addAll(Arrays.asList(n1,n2)); - - TreeEditor editor = forest.getTreeEditor(forest.getTree(root)); - - //編集開始 - NodeData data = n221.getData(); - data.put(ByteBuffer.wrap("name".getBytes()),ByteBuffer.wrap("value".getBytes())); - - try{ - Node new221 = editor.updateTree(n221,data); //n221を編集する。パスはroot -> n2 -> n22 -> n221となるはず - NodeID oldID = n221.getID(); - NodeID newID = new221.getID(); - - //編集したノードは同じUUIDを持つはず - Assert.assertTrue(oldID.isFamily(newID)); - - Node newRoot = - NodePathFinder finder = new NodePathFinder() - - }catch(PathNotFoundException _e){ - Assert.fail(_e.getMessage()); - } + root.addAll(new NodeChildrenImpl(n1,n2)); - return editor; - } - - @Test - public void testForceCommit() - { - testEdit(); - } - - @Test - public void testCommitFailsWhenTreeWasUpdated() - { - } - - @Test - public void testCheck() - { - } - - @Test - public void testUpdate() - { + MonotonicTree tree = forest.getMonotonicTree(forest.getTree(root)); + NodeFinder finder = new NodeFinder(tree.getRoot()); + MonotonicTreeNode node = finder.findByNodeID(n221.getID()); + node.put(ByteBuffer.wrap("test".getBytes()),ByteBuffer.wrap("value".getBytes())); + + } } diff -r bb9760760744 -r 168deb591f21 src/treecms/test/AbstractNodeTest.java --- a/src/treecms/test/AbstractNodeTest.java Sat May 21 04:46:00 2011 +0900 +++ b/src/treecms/test/AbstractNodeTest.java Tue May 24 00:33:12 2011 +0900 @@ -61,11 +61,7 @@ SingleNode ch2 = node.getForest().create(); SingleNode ch3 = node.getForest().create(); - NodeChildren list = new NodeChildrenImpl(); - list.add(ch1); - list.add(ch2); - list.add(ch3); - + NodeChildren list = new NodeChildrenImpl(ch1,ch2,ch3); node.addAll(list); List children = node.getList(); diff -r bb9760760744 -r 168deb591f21 src/treecms/test/AbstractTreeTest.java --- a/src/treecms/test/AbstractTreeTest.java Sat May 21 04:46:00 2011 +0900 +++ b/src/treecms/test/AbstractTreeTest.java Tue May 24 00:33:12 2011 +0900 @@ -4,12 +4,13 @@ import junit.framework.Assert; import org.junit.Test; import treecms.api.Tree; +import treecms.api.TreeNode; /** * Tree実装の基本的なテスト * @author shoshi */ -public abstract class AbstractTreeTest extends AbstractNodeTest +public abstract class AbstractTreeTest { /** * インスタンスください @@ -24,60 +25,9 @@ public void testGetRoot() { Tree tree = getInstance(); - Assert.assertNotNull(tree.getRoot()); - } - - /* - @Test - public void testUpdateTree() - { - Node ch1 = m_tree.getForest().create(); - Node ch2 = m_tree.getForest().create(); - - Node ch11 = m_tree.getForest().create(); - Node ch12 = m_tree.getForest().create(); - - LinkedList list = new LinkedList(); - list.add(ch1); - list.add(ch2); - - m_tree.getRoot().getData().add(list); - - LinkedList ch1list = new LinkedList(); - ch1list.add(ch11); - ch1.getData().add(ch1list); - - LinkedList ch2list = new LinkedList(); - ch2list.add(ch12); - ch2.getData().add(ch2list); + TreeNode treeNode = tree.getRoot(); - LinkedList before = findPath(m_tree.getRoot(),ch11); - NodeData newData = ch11.getData().deepCopy(); - m_tree.updateTree(ch11,newData); - LinkedList after = findPath(m_tree.getRoot(),ch11); - - for(int i = 0;i < before.size();i ++){ - boolean result = before.get(i).getID().isFamily(after.get(i).getID()); - Assert.assertEquals(true,result); - } + Assert.assertNotNull(treeNode); + Assert.assertNotNull(treeNode.getNode()); } - - public LinkedList findPath(Node _from,Node _target) - { - if(_from.getID().isFamily(_target.getID())){ - LinkedList path = new LinkedList(); - path.add(_from); - return path; - } - - for(Node child : _from.children()){ - LinkedList path = findPath(child,_target); - if(path != null){ - path.add(_from); - } - } - - return null; - } - */ } diff -r bb9760760744 -r 168deb591f21 src/treecms/test/ByteArrayTest.java --- a/src/treecms/test/ByteArrayTest.java Sat May 21 04:46:00 2011 +0900 +++ b/src/treecms/test/ByteArrayTest.java Tue May 24 00:33:12 2011 +0900 @@ -1,7 +1,5 @@ package treecms.test; -import java.util.*; - public class ByteArrayTest { public static void main(String _args[]) @@ -10,6 +8,5 @@ byte key2[] = new byte[]{12,23,23,43}; System.out.println(key1.equals(key2)); - } } diff -r bb9760760744 -r 168deb591f21 src/treecms/test/GenericsTest.java --- a/src/treecms/test/GenericsTest.java Sat May 21 04:46:00 2011 +0900 +++ b/src/treecms/test/GenericsTest.java Tue May 24 00:33:12 2011 +0900 @@ -1,18 +1,15 @@ package treecms.test; -import java.util.ArrayList; import java.util.List; public class GenericsTest { public static void main(String _args[]) { - GenericsTest h = new GenericsTest(null); } public GenericsTest(E _instance) { - E kasu = (E)_instance.get(); } } diff -r bb9760760744 -r 168deb591f21 src/treecms/tree/cassandra/v1/CassandraForest.java --- a/src/treecms/tree/cassandra/v1/CassandraForest.java Sat May 21 04:46:00 2011 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,186 +0,0 @@ -package treecms.tree.cassandra.v1; - -import java.util.HashMap; - -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Random; -import java.util.StringTokenizer; -import java.util.UUID; -import java.util.concurrent.Callable; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.ThreadFactory; - -import org.apache.cassandra.thrift.Cassandra; -import org.apache.cassandra.thrift.ColumnOrSuperColumn; -import org.apache.cassandra.thrift.ColumnParent; -import org.apache.cassandra.thrift.ColumnPath; -import org.apache.cassandra.thrift.ConsistencyLevel; -import org.apache.cassandra.thrift.Mutation; -import org.apache.cassandra.thrift.NotFoundException; -import org.apache.cassandra.thrift.SlicePredicate; -import org.apache.cassandra.thrift.SliceRange; -import org.apache.thrift.protocol.TBinaryProtocol; -import org.apache.thrift.protocol.TProtocol; -import org.apache.thrift.transport.TSocket; -import org.apache.thrift.transport.TTransport; -import org.apache.thrift.transport.TTransportException; - -import treecms.api.Forest; -import treecms.api.Node; -import treecms.api.NodeID; -import treecms.tree.cassandra.v1.util.CassandraClientThreadFactory; -import treecms.tree.id.AbstractRandomNodeID; -import treecms.tree.util.NodeData; - -/** - * Cassandra上で非破壊的木構造を実現するためのForestの実装です。 - * - * TreeCMSKS.NODETABLE (table of all nodes) - * - * +---------------------------------------------+ - * + Key | Col1 | Col2 | Col3 | ... | - * +---------------------------------------------+ - * + NodeID | Children | _attr1 | _attr2 | ... | - * +---------------------------------------------+ - * - * TreeCMSKS.TIPTABLE (table of tip) - * - * +--------------------+ - * + Key | Col1 | - * +--------------------+ - * + NodeID | version | - * +--------------------+ - * - * @author shoshi - */ - -public class CassandraForest implements Forest -{ - ExecutorService m_service; - - //column families. - static final String NODETABLE = "NODETABLE"; - static final String TIPTABLE = "TIPTABLE"; - - //reserved column. - static final byte[] TIPID = "TIPID".getBytes(); - static final byte[] CHILDREN = "CHILDREN".getBytes(); - static final char PREFIX = '_'; - - //cache - private ConcurrentHashMap m_cache; - private ConcurrentHashMap m_tipCache; - - public CassandraForest(String _host,int _port,String _ks,int _threads) - { - m_service = Executors.newFixedThreadPool(_threads,new CassandraClientThreadFactory(_host,_port)); - - m_cache = new ConcurrentHashMap(); - m_tipCache = new ConcurrentHashMap(); - } - - private void loadContents() - { - } - - @Override - public Node get(NodeID _id) - { - return new CassandraNode(this,_id); - } - - @Override - public Node create() - { - return createNode(null,null); - } - - public NodeData getNodeData(NodeID _id) - { - final NodeID id = _id; - return null; - } - - public NodeID getTipID(String _uuid) - { - final String uuid = _uuid; - return null; - } - - public Node createNode(NodeID _id,NodeData _data) - { - final NodeData data = _data; - final NodeID id = (_id != null) ? _id : createID(null,null); - - Callable task = new Callable(){ - @Override - public Boolean call() throws Exception - { - return true; - } - }; - - m_service.submit(task); - - return new CassandraNode(this,id); - } - - public NodeID createID(String _uuid,String _version) - { - return new RandomNodeID(_uuid,_version); - } - - class RandomNodeID extends AbstractRandomNodeID - { - String m_uuid; - String m_version; - - public RandomNodeID(String _uuid,String _version) - { - m_uuid = (_uuid != null) ? _uuid : UUID.randomUUID().toString(); - m_version = (_version != null) ? _version : Long.toHexString((new Random()).nextLong()); - } - - @Override - public NodeID create() - { - return new RandomNodeID(null,null); - } - - @Override - public NodeID update() - { - return new RandomNodeID(m_uuid,null); - } - - @Override - public String getUUID() - { - return m_uuid; - } - - @Override - public String getVersion() - { - return m_version; - } - } - - @Override - public Node create(NodeData data) - { - return null; - } - - @Override - public Node getTip(String uuid) - { - return null; - } -} diff -r bb9760760744 -r 168deb591f21 src/treecms/tree/cassandra/v1/CassandraNode.java --- a/src/treecms/tree/cassandra/v1/CassandraNode.java Sat May 21 04:46:00 2011 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,39 +0,0 @@ -package treecms.tree.cassandra.v1; - -import treecms.api.Forest; -import treecms.api.Node; -import treecms.api.NodeID; -import treecms.tree.util.NodeData; - -class CassandraNode implements Node -{ - NodeID m_id; - NodeData m_data; - CassandraForest m_forest; - - public CassandraNode(CassandraForest _forest,NodeID _id) - { - m_id = _id; - m_forest = _forest; - m_data = null; - } - - @Override - public NodeID getID() - { - return m_id; - } - - @Override - public NodeData getData() - { - return (m_data != null) ? m_data : (m_data = m_forest.getNodeData(m_id)); - } - - @Override - public Forest getForest() - { - return m_forest; - } - -} diff -r bb9760760744 -r 168deb591f21 src/treecms/tree/cassandra/v1/CassandraTree.java --- a/src/treecms/tree/cassandra/v1/CassandraTree.java Sat May 21 04:46:00 2011 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -package treecms.tree.cassandra.v1; - -import java.util.LinkedList; -import java.util.concurrent.ConcurrentHashMap; -import treecms.api.Forest; -import treecms.api.Node; -import treecms.api.NodeID; -import treecms.api.Tree; -import treecms.tree.util.NodeData; - -class CassandraTree implements Tree -{ - CassandraNode m_root; - CassandraForest m_forest; - ConcurrentHashMap m_table; - - CassandraTree(CassandraNode _node,CassandraForest _forest) - { - m_root = _node; - m_forest = _forest; - m_table = new ConcurrentHashMap(); - } - - @Override - public NodeID getID() - { - return m_root.getID(); - } - - @Override - public NodeData getData() - { - return m_root.getData(); - } - - @Override - public Forest getForest() - { - return m_forest; - } - - @Override - public Node getRoot() - { - return m_root; - } - - @Override - public Node getNodeByUUID(String _uuid) - { - return m_table.get(_uuid); - } - -} diff -r bb9760760744 -r 168deb591f21 src/treecms/tree/cassandra/v1/CassandraTreeEditor.java --- a/src/treecms/tree/cassandra/v1/CassandraTreeEditor.java Sat May 21 04:46:00 2011 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,87 +0,0 @@ -package treecms.tree.cassandra.v1; - -import java.util.LinkedList; - -import treecms.api.Node; -import treecms.api.TreeEditor; -import treecms.merger.Merger; -import treecms.merger.ReplaceMerger; -import treecms.tree.util.NodeData; - -class CassandraTreeEditor extends CassandraTree implements TreeEditor -{ - public CassandraTreeEditor(CassandraTree _tree,CassandraForest _forest) - { - super(_tree.m_root,_forest); - } - - @Override - public boolean commit(boolean _force) - { - return false; - } - - @Override - public boolean pull() - { - return false; - } - - @Override - public boolean check() - { - return false; - } - - @Override - public void merge() - { - Merger merger = new ReplaceMerger(); - } - - @Override - public synchronized Node updateTree(Node _target,NodeData _newData) - { - LinkedList path = findPath(m_root,(CassandraNode)_target,_newData); - - if(path == null) - { - //not found. - return null; - } - - - //clone - - - m_root = path.peekFirst(); - return path.peekLast(); - } - - CassandraNode cloneNode(CassandraNode _target,NodeData _newData) - { - CassandraNode clone = (CassandraNode)m_forest.createNode(_target.getID().update(),_newData); - m_table.put(clone.getID().getUUID(),clone); - return clone; - } - - LinkedList findPath(CassandraNode _parent,CassandraNode _target,NodeData _newData) - { - if(_parent.getID().isFamily(_target.getID())){ - //find. - LinkedList path = new LinkedList(); - path.addFirst(_target); - return path; - } - - for(Node child : _parent.getData().list()){ - LinkedList path = findPath((CassandraNode)child,_target,_newData); - if(path != null){ - path.addFirst(_parent); - return path; - } - } - - return null; //not found. - } -} diff -r bb9760760744 -r 168deb591f21 src/treecms/tree/cassandra/v1/util/CassandraClientThread.java --- a/src/treecms/tree/cassandra/v1/util/CassandraClientThread.java Sat May 21 04:46:00 2011 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,48 +0,0 @@ -package treecms.tree.cassandra.v1.util; - -import org.apache.thrift.transport.TTransportException; - -/** - * CassandraのClientを保持したスレッドオブジェクトです。 - * @author shoshi - */ -final class CassandraClientThread extends Thread -{ - private CassandraClientWrapper m_wrapper; - - /** - * コンストラクタです。 - * @param _host Cassandraのホスト名 - * @param _port Cassandraのポート番号 - * @param _runnable このスレッドで動作するRunnable - * @throws TTransportException - */ - private CassandraClientThread(String _host,int _port,Runnable _runnable) throws TTransportException - { - super(_runnable); - m_wrapper = new CassandraClientWrapper(_host,_port,2); - } - - /** - * ファクトリメソッドです。 - * @param _host Cassandraのホスト名 - * @param _port Cassandraのポート番号 - * @param _runnable このスレッドで動作するRunnable - * @return 新しいインスタンス - * @throws TTransportException Cassandraへの接続が失敗したとき - */ - public static CassandraClientThread newInstance(String _host,int _port,Runnable _runnable) throws TTransportException - { - CassandraClientThread thread = new CassandraClientThread(_host,_port,_runnable); - return thread; - } - - /** - * ClientWrapperを取得します - * @return CassandraへのClientWrapper - */ - public CassandraClientWrapper getClientWrapper() - { - return m_wrapper; - } -} diff -r bb9760760744 -r 168deb591f21 src/treecms/tree/cassandra/v1/util/CassandraClientThreadFactory.java --- a/src/treecms/tree/cassandra/v1/util/CassandraClientThreadFactory.java Sat May 21 04:46:00 2011 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +0,0 @@ -package treecms.tree.cassandra.v1.util; - -import java.util.concurrent.ThreadFactory; - -import org.apache.thrift.transport.TTransportException; - -/** - * ローカル変数としてCassandra.Clientを保持するスレッドオブジェクトを生成するスレッドファクトリーです。 - * @author shoshi - */ -final class CassandraClientThreadFactory implements ThreadFactory -{ - private String m_host; - private int m_port; - - /** - * コンストラクタです。 - * @param _host Cassandraのアドレス・ホスト名 - * @param _port Thriftポート番号 - */ - public CassandraClientThreadFactory(String _host,int _port) - { - m_host = _host; - m_port = _port; - } - - /** - * Cassandra.Clientを保持するスレッドオブジェクトを新しく作成します。 - */ - @Override - public Thread newThread(Runnable _runnable) - { - CassandraClientThread client = null; - try{ - client = CassandraClientThread.newInstance(m_host,m_port,_runnable); - }catch(TTransportException _e) { - _e.printStackTrace(); - throw new RuntimeException(_e); - } - return client; - } -} diff -r bb9760760744 -r 168deb591f21 src/treecms/tree/cassandra/v1/util/CassandraClientWrapper.java --- a/src/treecms/tree/cassandra/v1/util/CassandraClientWrapper.java Sat May 21 04:46:00 2011 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,224 +0,0 @@ -package treecms.tree.cassandra.v1.util; - -import java.util.List; -import java.util.Map; -import org.apache.cassandra.thrift.Cassandra; -import org.apache.cassandra.thrift.ColumnOrSuperColumn; -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.KeyRange; -import org.apache.cassandra.thrift.KeySlice; -import org.apache.cassandra.thrift.Mutation; -import org.apache.cassandra.thrift.NotFoundException; -import org.apache.cassandra.thrift.SlicePredicate; -import org.apache.cassandra.thrift.TimedOutException; -import org.apache.cassandra.thrift.UnavailableException; -import org.apache.thrift.TException; -import org.apache.thrift.protocol.TBinaryProtocol; -import org.apache.thrift.transport.TSocket; -import org.apache.thrift.transport.TTransport; -import org.apache.thrift.transport.TTransportException; - -/** - * Cassandra.Clientのラッパークラスです。Cassandra.Clientを使いやすくするための機能を提供します。 - * 接続済みのCassandra.Clientの接続が切断されたときに再接続を行います。このクラスはスレッドセーフでは有りません。 - * - * このラッパークラスはCassandra 0.6.xのAPIをベースに作成します。 - * @author shoshi - */ -final class CassandraClientWrapper -{ - private String m_host; - private int m_port; - private int m_retryCount; - - private TTransport m_tr; - private Cassandra.Client m_client; - - /** - * コンストラクタです。初期化して接続します。 - * @param _host Cassandraのホスト名 - * @param _port Cassandraのポート番号 - * @param _retryCount リクエストが失敗した場合リトライする回数 - * @throws TTransportException - */ - public CassandraClientWrapper(String _host,int _port,int _retryCount) throws TTransportException - { - m_host = _host; - m_port = _port; - m_retryCount = _retryCount; - - connect(); - } - - /** - * Cassandraに接続します。 - * @throws TTransportException - */ - private void connect() throws TTransportException - { - Cassandra.Client client; - TTransport tr = new TSocket(m_host,m_port); - client = new Cassandra.Client(new TBinaryProtocol(tr)); - - tr.open(); - - m_tr = tr; - m_client = client; - } - - /** - * Cassandraへの接続を切ります。 - */ - private void disconnect() - { - m_tr.close(); - m_client = null; - } - - /** - * Cassandraへ再接続を行います。 - * @return 再接続が成功した場合true - */ - private boolean reconnect() - { - disconnect(); - try { - connect(); - }catch(TTransportException _e){ - _e.printStackTrace(); - } - return true; - } - - /** - * ここで共通する例外処理(再接続など)を行う - * @param _e 例外 - */ - private void exceptionHandler(Exception _e) - { - _e.printStackTrace(); - } - - /** - * Cassandra.Client.getのラッパーメソッド - */ - public ColumnOrSuperColumn get(String _ks,String _key,ColumnPath _path,ConsistencyLevel _level) throws InvalidRequestException, NotFoundException, UnavailableException, TimedOutException, TException - { - for(int i = 0;i < m_retryCount;i ++){ - if(m_client == null){ - throw new IllegalStateException("Cassandra.Client is disconnected. "+m_host+":"+m_port); - } - - try { - ColumnOrSuperColumn cors = m_client.get(_ks,_key,_path,_level); - return cors; - }catch(Exception _e){ - exceptionHandler(_e); - } - } - return m_client.get(_ks,_key,_path,_level); - } - - /** - * Cassandra.Client.get_sliceのラッパーメソッド - */ - public List get_slice(String _ks,String _key,ColumnParent _parent,SlicePredicate _predicate,ConsistencyLevel _level) throws InvalidRequestException, UnavailableException, TimedOutException, TException - { - for(int i = 0;i < m_retryCount;i ++){ - if(m_client == null){ - throw new IllegalStateException("Cassandra.Client is disconnected. "+m_host+":"+m_port); - } - - try { - List list = m_client.get_slice(_ks,_key,_parent,_predicate,_level); - return list; - }catch(Exception _e){ - exceptionHandler(_e); - } - } - return m_client.get_slice(_ks,_key,_parent,_predicate,_level); - } - - /** - * Cassandra.Client.get_range_slicesのラッパーメソッド - */ - public List get_range_slices(String _ks,ColumnParent _parent,SlicePredicate _predicate,KeyRange _range,ConsistencyLevel _level) throws InvalidRequestException, UnavailableException, TimedOutException, TException - { - for(int i = 0;i < m_retryCount;i ++){ - if(m_client == null){ - throw new IllegalStateException("Cassandra.Client is disconnected. "+m_host+":"+m_port); - } - - try { - return m_client.get_range_slices(_ks,_parent,_predicate,_range,_level); - }catch(Exception _e){ - exceptionHandler(_e); - } - } - return m_client.get_range_slices(_ks,_parent,_predicate,_range,_level); - } - - /** - * describe_cluster_name の ラッパーメソッド - * @return cluster name - * @throws TException - */ - public String describe_cluster_name() throws TException - { - for(int i = 0;i < m_retryCount;i ++){ - if(m_client == null){ - throw new IllegalStateException("Cassandra.Client is disconnected. "+m_host+":"+m_port); - } - - try { - return m_client.describe_cluster_name(); - }catch(Exception _e){ - exceptionHandler(_e); - } - } - return m_client.describe_cluster_name(); - } - - /** - * Cassandra.Client.insertのラッパーメソッド - */ - public void insert(String _ks,String _key,ColumnPath _path,byte[] _value,long _timestamp,ConsistencyLevel _level) throws InvalidRequestException, UnavailableException, TimedOutException, TException - { - for(int i = 1;i < m_retryCount;i ++){ - if(m_client == null){ - throw new IllegalStateException("Cassandra.Client is disconnected. "+m_host+":"+m_port); - } - - try{ - m_client.insert(_ks,_key,_path,_value,_timestamp,_level); - }catch(Exception _e){ - exceptionHandler(_e); - } - } - m_client.insert(_ks,_key,_path,_value,_timestamp,_level); - return; - } - - /** - * Cassandra.Client.batch_mutateのラッパーメソッド - */ - public void batch_mutate(String _ks,Map>> _mutation_map,ConsistencyLevel _level) throws InvalidRequestException, UnavailableException, TimedOutException, TException - { - for(int i = 1;i < m_retryCount;i ++){ - if(m_client == null){ - throw new IllegalStateException("Cassandra.Client is disconnected. "+m_host+":"+m_port); - } - - try{ - m_client.batch_mutate(_ks,_mutation_map,_level); - }catch(Exception _e){ - exceptionHandler(_e); - } - } - m_client.batch_mutate(_ks,_mutation_map,_level); - return; - } -} diff -r bb9760760744 -r 168deb591f21 src/treecms/tree/cassandra/v1/util/ConcurrentCassandraClient.java --- a/src/treecms/tree/cassandra/v1/util/ConcurrentCassandraClient.java Sat May 21 04:46:00 2011 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,124 +0,0 @@ -package treecms.tree.cassandra.v1.util; - -import java.util.concurrent.Callable; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; - -import org.apache.cassandra.thrift.ColumnOrSuperColumn; -import org.apache.cassandra.thrift.ColumnParent; -import org.apache.cassandra.thrift.ColumnPath; -import org.apache.cassandra.thrift.ConsistencyLevel; -import org.apache.cassandra.thrift.Mutation; -import org.apache.cassandra.thrift.SlicePredicate; - -/** - * - * @author shoshi - */ -public class ConcurrentCassandraClient -{ - private ExecutorService m_service; - - private ConcurrentCassandraClient(String _host,int _port,int _thCount) - { - m_service = Executors.newFixedThreadPool(_thCount,new CassandraClientThreadFactory(_host,_port)); - } - - public static ConcurrentCassandraClient newInstance(String _host,int _port,int _thCount) - { - ConcurrentCassandraClient client = new ConcurrentCassandraClient(_host,_port,_thCount); - return client; - } - - public void disconnect() - { - m_service.shutdown(); - try{ - m_service.awaitTermination(Long.MAX_VALUE,TimeUnit.DAYS); - }catch(InterruptedException _e){ - _e.printStackTrace(); - } - } - - public Future get(final String _ks,final String _key,final ColumnPath _path,final ConsistencyLevel _level) - { - Callable task = new Callable(){ - @Override - public ColumnOrSuperColumn call() throws Exception - { - CassandraClientWrapper client = ((CassandraClientThread)Thread.currentThread()).getClientWrapper(); - ColumnOrSuperColumn cors = client.get(_ks,_key,_path,_level); - return cors; - } - }; - - Future ret = m_service.submit(task); - return ret; - } - - public Future> get_slice(final String _ks,final String _key,final ColumnParent _parent,final SlicePredicate _predicate,final ConsistencyLevel _level) - { - Callable> task = new Callable>(){ - @Override - public List call() throws Exception - { - CassandraClientWrapper client = ((CassandraClientThread)Thread.currentThread()).getClientWrapper(); - List ret = client.get_slice(_ks,_key,_parent,_predicate,_level); - return ret; - } - }; - - Future> ret = m_service.submit(task); - return ret; - } - - public Future batch_mutate(final String _ks,final Map>> _mutation_map,final ConsistencyLevel _level) - { - Callable task = new Callable(){ - @Override - public Boolean call() throws Exception - { - CassandraClientWrapper client = ((CassandraClientThread)Thread.currentThread()).getClientWrapper(); - client.batch_mutate(_ks,_mutation_map,_level); - return true; - } - }; - - Future ret = m_service.submit(task); - return ret; - } - - public Future insert(final String _ks,final String _key,final ColumnPath _path,final byte[] _value,final long _timestamp,final ConsistencyLevel _level) - { - Callable task = new Callable(){ - @Override - public Boolean call() throws Exception - { - CassandraClientWrapper client = ((CassandraClientThread)Thread.currentThread()).getClientWrapper(); - client.insert(_ks,_key,_path,_value,_timestamp,_level); - return true; - } - }; - - Future ret = m_service.submit(task); - return ret; - } - - public Future describe_cluster_name() - { - Callable task = new Callable(){ - @Override - public String call() throws Exception - { - return null; - } - }; - - Future ret = m_service.submit(task); - return ret; - } -} diff -r bb9760760744 -r 168deb591f21 src/treecms/tree/cassandra/v1/util/ConcurrentCassandraClientTest.java --- a/src/treecms/tree/cassandra/v1/util/ConcurrentCassandraClientTest.java Sat May 21 04:46:00 2011 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -package treecms.tree.cassandra.v1.util; - -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; - -import org.apache.cassandra.thrift.Cassandra; -import org.apache.cassandra.thrift.ColumnOrSuperColumn; -import org.apache.cassandra.thrift.ColumnPath; -import org.apache.cassandra.thrift.ConsistencyLevel; -import org.apache.cassandra.thrift.InvalidRequestException; -import org.apache.cassandra.thrift.NotFoundException; -import org.apache.cassandra.thrift.TimedOutException; -import org.apache.cassandra.thrift.UnavailableException; -import org.apache.thrift.TException; -import org.apache.thrift.protocol.TBinaryProtocol; -import org.apache.thrift.transport.TSocket; -import org.apache.thrift.transport.TTransport; - -public class ConcurrentCassandraClientTest -{ - public static void main(String _args[]) throws InterruptedException, ExecutionException, InvalidRequestException, NotFoundException, UnavailableException, TimedOutException, TException - { - String host = "misaka01.cr.ie.u-ryukyu.ac.jp"; - int port = 9160; - int count = 1000; - - System.out.println("Read benchmark."); - ConcurrentCassandraClient conClient = ConcurrentCassandraClient.newInstance(host,port,7); - ColumnPath path = new ColumnPath(); - path.column_family = "Standard1"; - path.column = "fuga".getBytes(); - - long start = System.currentTimeMillis(); - for(int i = 0;i < count;i ++){ - conClient.get("Keyspace1","hoge",path,ConsistencyLevel.ONE); - } - conClient.disconnect(); - System.out.println("concurrent client time = "+(System.currentTimeMillis()-start)); - - TTransport tr = new TSocket(host,port); - Cassandra.Client client = new Cassandra.Client(new TBinaryProtocol(tr)); - tr.open(); - - start = System.currentTimeMillis(); - for(int i = 0;i < count;i ++){ - client.get("Keyspace1","hoge",path,ConsistencyLevel.ONE); - } - System.out.println("normal client time = "+(System.currentTimeMillis()-start)); - - System.out.println("Write benchmark"); - conClient = ConcurrentCassandraClient.newInstance(host,port,30); - - start = System.currentTimeMillis(); - for(int i = 0;i < count;i ++){ - conClient.insert("Keyspace1","hoge",path,"piga".getBytes(),System.currentTimeMillis()/1000,ConsistencyLevel.ONE); - } - conClient.disconnect(); - System.out.println("concurrent client time = "+(System.currentTimeMillis()-start)); - - start = System.currentTimeMillis(); - for(int i = 0;i < count;i ++){ - client.insert("Keyspace1","hoge",path,"piga".getBytes(),System.currentTimeMillis()/1000,ConsistencyLevel.ONE); - } - System.out.println("normal client time = "+(System.currentTimeMillis()-start)); - - } -} diff -r bb9760760744 -r 168deb591f21 src/treecms/tree/util/NodeAttributesImpl.java --- a/src/treecms/tree/util/NodeAttributesImpl.java Sat May 21 04:46:00 2011 +0900 +++ b/src/treecms/tree/util/NodeAttributesImpl.java Tue May 24 00:33:12 2011 +0900 @@ -17,9 +17,15 @@ m_attrs = new HashMap(); } + public NodeAttributesImpl(Map _map) + { + this(); + m_attrs.putAll(_map); + } + public NodeAttributesImpl(NodeAttributesImpl _attrs) { - super(); + this(); m_attrs.putAll(_attrs.m_attrs); } @@ -78,5 +84,22 @@ { m_attrs.clear(); } - + + @Override + public boolean equals(Object _o) + { + if(_o instanceof NodeAttributes || _o == null){ + return false; + } + + NodeAttributes attr = (NodeAttributes)_o; + Map map = attr.asMap(); + return m_attrs.equals(map); + } + + @Override + public int hashCode() + { + return m_attrs.hashCode(); + } } diff -r bb9760760744 -r 168deb591f21 src/treecms/tree/util/NodeChildrenImpl.java --- a/src/treecms/tree/util/NodeChildrenImpl.java Sat May 21 04:46:00 2011 +0900 +++ b/src/treecms/tree/util/NodeChildrenImpl.java Tue May 24 00:33:12 2011 +0900 @@ -24,6 +24,16 @@ m_set = new HashSet(); } + public NodeChildrenImpl(T... _args) + { + this(); + for(T i : _args){ + if(!add(i)){ + throw new IllegalArgumentException("duplicate Node UUID at "+i.getID().getUUID()); + } + } + } + public NodeChildrenImpl(NodeChildren _list) { this(); @@ -86,6 +96,7 @@ //共通要素がない m_set.addAll(_list.getUUIDSet()); m_list.addAll(_list.getList()); + return true; } return false; } @@ -222,9 +233,4 @@ result = 37*result + m_set.hashCode(); return result; } - - public static NodeChildren> hoge(Node hoge) - { - return null; - } } diff -r bb9760760744 -r 168deb591f21 src/treecms/tree/util/NodeData.java --- a/src/treecms/tree/util/NodeData.java Sat May 21 04:46:00 2011 +0900 +++ b/src/treecms/tree/util/NodeData.java Tue May 24 00:33:12 2011 +0900 @@ -35,8 +35,8 @@ public NodeData(NodeChildren _children,NodeAttributes _attrs) { - m_children = new NodeChildrenImpl(_children); - m_attrs = new NodeAttributesImpl(); + m_children = (_children != null) ? new NodeChildrenImpl(_children) : new NodeChildrenImpl(); + m_attrs = (_attrs != null) ? new NodeAttributesImpl(_attrs.asMap()) : new NodeAttributesImpl(); } @Override diff -r bb9760760744 -r 168deb591f21 src/treecms/tree/util/NodeFinder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/treecms/tree/util/NodeFinder.java Tue May 24 00:33:12 2011 +0900 @@ -0,0 +1,84 @@ +package treecms.tree.util; + +import treecms.api.Node; +import treecms.api.NodeID; + +public class NodeFinder> +{ + private T m_root; + public NodeFinder(T _root) + { + m_root = _root; + } + + public T findByUUID(final String _uuid) + { + Evaluator ev = new Evaluator(){ + private T m_res = null; + @Override + public boolean evaluate(T _target) + { + if(_target.getID().getUUID().equals(_uuid)){ + m_res = _target; + return true; + } + return false; + } + @Override + public T getResult() + { + return m_res; + } + }; + + _recursiveFinder(m_root,ev); + return ev.getResult(); + } + + public T findByNodeID(final NodeID _id) + { + Evaluator ev = new Evaluator(){ + private T m_res = null; + @Override + public boolean evaluate(T _target) + { + if(_target.getID().equals(_id)){ + m_res = _target; + return true; + } + return false; + } + + @Override + public T getResult() + { + return m_res; + } + + }; + + _recursiveFinder(m_root,ev); + return ev.getResult(); + } + + private boolean _recursiveFinder(T _cur,Evaluator _e) + { + if(_e.evaluate(_cur)){ + return true; + } + + for(T child : _cur.getList()){ + if(_recursiveFinder(child,_e)){ + return true; + } + } + + return false; + } + + private static interface Evaluator + { + public boolean evaluate(T _target); + public R getResult(); + } +}