view rep/Editor.java @ 313:0585fd2410b8 single-insert-command

Single Insert Command worked.
author kono
date Sun, 05 Oct 2008 22:36:24 +0900
parents c5be84d53c7f
children 20fb70068089
line wrap: on
line source

package rep;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import rep.channel.REPLogger;
import rep.channel.REPSocketChannel;
import rep.optimizers.*;
import rep.translater.TranslaterImp1;

public class Editor {
	private int eid;            // unique id in a session
	private int sid = -1 ;      // globally unique session id
	private int seq = 0;
	private REPSocketChannel<REPCommand> myChannel;
	private String host;
	private String file;
	private TranslaterImp1 translater;
	private List<REPCommand> sentList;
	private List<REPCommand> sentMergedList;
	private REPCommandOptimizer optimizer;
	private List<REPCommand> writeQueue;
	private REPCommand quit2 = null;
	private REPLogger ns = REPLogger.singleton();
	private final int limit=100;
	
	public Editor(){
		this(true);
	}
	public Editor(boolean doOptimize){
		setHostAndPort(myChannel);
		translater = new TranslaterImp1(eid);
		sentList = new LinkedList<REPCommand>();
		sentMergedList = new LinkedList<REPCommand>();
		writeQueue = new LinkedList<REPCommand>();

		if (doOptimize) optimizer = new DeleteInsertOptimizer(); //タカノがつくったおぷてぃまいざ
		else            optimizer = new NullOptimizer();         //なにもしないけどOptimizer.
		
	}

	public Editor(int editorNo, REPSocketChannel<REPCommand> channel){
		this.eid = editorNo;
		this.myChannel = channel;
		translater = new TranslaterImp1(eid);
		sentList = new LinkedList<REPCommand>();
		sentMergedList = new LinkedList<REPCommand>();
		writeQueue = new LinkedList<REPCommand>();
		setHostAndPort(myChannel);
	}
	
	public Editor(REPSocketChannel<REPCommand> channel) {
		this.myChannel = channel;
		setHostAndPort(myChannel);
		translater = new TranslaterImp1(eid);
		sentList = new LinkedList<REPCommand>();
		writeQueue = new LinkedList<REPCommand>();
	}
	
	public List<REPCommand> translate(REPCommand command){
		List<REPCommand> list = new LinkedList<REPCommand>();
		if(command.eid == eid){
			if(checkReturnedCommand(command)){
				//エディタからのコマンドが元のエディタに戻ってきた
				// START_MERGE を送る
				REPCommand cmd = new REPCommand(REP.SMCMD_START_MERGE,command.sid,REP.SM_EID.id,seq(),0,"");
				list.add(cmd);
				return list;
			}else{
				//エディタからの新たな編集コマンド
				sentList.add(command);
				assert(sentList.size()<limit);
				translater.transSendCmd(command);
				list.add(command);
			}
		}else if(eid == REP.MERGE_EID.id){
			//マージコマンドが返ってきた
			if(translater.checkMergeConflict(command)){
				//マージ中にエディタからの割り込みがあった場合
				List<REPCommand> mergeAgainList = translater.getMergeAgain();

				mergeAgainList = optimizer.optimize(mergeAgainList);
				writeQueue.addAll(mergeAgainList);
				assert(writeQueue.size()<limit);
			}
		}else{
			//他のエディタからの編集コマンド
			REPCommand[] cmds = translater.transReceiveCmd(command);
			for(REPCommand cmd : cmds){
				list.add(cmd);
			}
		}
		return list;
	}
	
	boolean merge(REPCommand command) {
		REPCommand prev = translater.prev();
		if(prev==null) return false;
		assert(prev.eid==command.eid);
		//マージして送信
		ArrayList<REPCommand> cmds = translater.catchOwnCommand();
		//optimizer
		if (cmds.size()==0) 
			return false; // no merge phase is necessary
		//マージ中のエディタからの割り込み検知に使う
		sentMergedList.addAll(cmds);
		sendMergedCommand(cmds);
		return true;
	}
	
	private void sendMergedCommand(ArrayList<REPCommand> cmds) {
		for(REPCommand mergeCommand : cmds){
			mergeCommand.setEID(REP.MERGE_EID.id);
			mergeCommand.setSEQID(seq());
			writeQueue.add(mergeCommand);
			assert(writeQueue.size()<limit);
		}
	}

	boolean checkReturnedCommand(REPCommand command) {
		if(sentList.size() > 0){
			if(sentList.get(0).seq == command.seq){
				sentList.remove(0);
				return true;
			}else{
				System.err.println("Editor.checkReturnedCommand() : command = " + command);
				//assert(false);
			}
		}
		return false;
	}

	
	public boolean doWaitingWrite() {
		//  一気に送ると、向こう側(Editor)で、dead lock する可能性がある。
		//  select loop の中で一つ一つ送るしかない。Editor側から割り込まれる可能性も
		//  ある。その時に複数のコマンドを送っていると、どこに割り込まれたかを判断する
		// ことが出来ない。そこで、一つ一つReturnを確認する必要がある。つまり、
		// select loop で送るしかない。
		REPCommand cmd;
		if (writeQueue.size()>0) {
			cmd = new REPCommand(writeQueue.remove(0));
			ns.writeLog("SessionManager write to "+myChannel+" cmd="+cmd);
			myChannel.write(cmd);
			return true;
		} else if (quit2!=null && sentList.size()==0) {
			//myChannel.write(quit2);
			quit2 = null;
			return true;
		}
		return false;
	}
	
	public void setQuit2(REPCommand cmd) {
		quit2 = cmd;
	}
	
	private void setHostAndPort(REPSocketChannel<REPCommand> myChannel2) {
		//host = myChannel2.socket().getRemoteSocketAddress().toString();
		
	}

	public REPSocketChannel<REPCommand> getChannel() {
		return myChannel;
	}
	
	public void setHost(String host){
		this.host = host;
	}

	
	public String getHost(){
		return host;
	}


	public int getEID() {
		return eid;
	}

	public void setEID(int eid) {
		this.eid = eid;
		translater.setEid(eid);
	}
	public String toString(){
		return ("Editor eid="+eid+" sid="+sid+" " + host  + ":" + file);
	}

	public String getName() {
		return file;
	}

	public void setName(String string) {
		file = string;
	}

	public void send(REPCommand command) {
		writeQueue.add(command);
		assert(writeQueue.size()<limit);
	}

	public void setChannel(REPSocketChannel<REPCommand> channel) {
		myChannel = channel;
	}

	public boolean isMerging() {
		return translater.isMerging();
	}
	public boolean hasSession() {
		return sid != -1;
	}
	public void setSID(int sessionID) {
		sid   = sessionID;
	}
	public int seq() {
		return seq++;
	}

}