# HG changeset patch # User one # Date 1227660074 -32400 # Node ID 795ef563f2a07744bbe01c3a94128aa76c7ba174 # Parent 2724cf17e9f34def518df9dbae05af95fd31bf80 add commnets diff -r 2724cf17e9f3 -r 795ef563f2a0 Todo --- a/Todo Tue Nov 25 18:26:23 2008 +0900 +++ b/Todo Wed Nov 26 09:41:14 2008 +0900 @@ -1,3 +1,9 @@ +Wed Nov 26 08:44:29 JST 2008 + +Todo: +QUITで、まだ、処理があるのにEditorが止まってしまう状況が +あるらしい。 + Tue Nov 25 09:13:42 JST 2008 Todo: @@ -5,6 +11,9 @@ どうも、optimizerのbugっぽいな... いや、違いますね。 getMergeAgainの問題らしいが、直接の原因は良くわからない。 +Done: + なんと、Text.javaのdeleteの条件判断が間違ってました。 + Mon Nov 24 22:51:45 JST 2008 watingCommandInMerge のqueueを一旦0にしてから、manageを diff -r 2724cf17e9f3 -r 795ef563f2a0 rep/ServerMainLoop.java --- a/rep/ServerMainLoop.java Tue Nov 25 18:26:23 2008 +0900 +++ b/rep/ServerMainLoop.java Wed Nov 26 09:41:14 2008 +0900 @@ -21,6 +21,13 @@ import rep.handler.FirstConnector; import rep.handler.REPNode; +/** + * @author kono + * Single Threaded Server Main Loop + * maintain multiple connections + * gui interface is provided. + * Protocols are handled by our manager. + */ public class ServerMainLoop { public static REPLogger logger = REPLogger.singleton(); @@ -35,6 +42,7 @@ protected int parent_port; protected static final int DEFAULT_PORT = 8766; private SessionManagerEvent execAfterConnect = null; + private boolean listLocalEditorOnly = false; public void setReceivePort(int port) { @@ -90,6 +98,12 @@ return false; } + /** + * To avoid dead locks, we write a command one at a time + * during select(). + * @return + * @throws IOException + */ private boolean checkWaitingWrite() throws IOException { PacketSet p = writeQueue.poll(); if (p!=null) { @@ -100,6 +114,10 @@ return false; } + /** + * Debug message + * @param p + */ private void sendLog(PacketSet p) { REPNode to; String s; @@ -120,6 +138,13 @@ // we have to remove session/editor } + /** + * Main Select routing + * check incoming connection request and incoming packet + * A request is handled by a handler object which is attached + * to the SelectionKey. + * @throws IOException + */ private void select() throws IOException { Set> keys = selector.selectedKeys1(); @@ -159,12 +184,17 @@ channel.register(selector, SelectionKey.OP_READ, handler); } + /** + * Notify status change to our GUI + */ protected void updateGUI() { //リストのコピーをGUIに渡す LinkedList sList = new LinkedList(manager.sessionList.values()); LinkedList eList; - if (false) { - // local editor only + if (listLocalEditorOnly ) { + // Do not list an editor or session outside of this session manager to + // avoid confusion. Actually we can joinSession to an editor outside of + // this manager, but is not secure to do this. eList = new LinkedList(); for(REPNode e:manager.editorList.values()) { if (manager.getSMID(e.eid)==manager.smList.sessionManagerID()) { diff -r 2724cf17e9f3 -r 795ef563f2a0 rep/Session.java --- a/rep/Session.java Tue Nov 25 18:26:23 2008 +0900 +++ b/rep/Session.java Wed Nov 26 09:41:14 2008 +0900 @@ -10,13 +10,22 @@ public class Session extends HashMap { /** - * + * Editor Session + * contains interacting editors + * accessed by eid. There is one masterEditor which + * has a file name (is a sessionName). + * + * maintain connection among handlers (Dispatcher, + * Forwarder, Editor). + * first->editor->editor...->last + * first may equal to the last. When a session is + * created, first equals the last. */ private static final long serialVersionUID = 1L; private REPNode masterEditor; private int sessionID; private String sessionName; - // isOnwer means this session has active channels(forwarders). + // isOnwer means this session is owner of an active channels(forwarders). private boolean isOwner = false; private REPNode first; private REPNode last; @@ -35,6 +44,7 @@ master.setSID(sid); put(master.eid,master); if(master.channel!=null) { + // master is a real connected editor first = master; masterEditor.setNext(masterEditor); isOwner = true; @@ -60,7 +70,7 @@ public void addEditor(Editor editor) { // add a not-connected editor in a sassion - // the editor is outside of this manager + // the editor is in the outside of this manager editor.setSID(sessionID); put(editor.eid,editor); } @@ -79,12 +89,19 @@ return sessionName; } - + /* + * Remove and disconnect a forwarder from the session + */ public boolean deleteEditor(REPSocketChannel channel) { + // this is fanatic, one channel may have multiple sessions, but + // a session should have only one channel that is one editor. + // REPNode e = getEditor(channel); + // if (e!=null) { unconnect((Forwarder)e); remove(e); } is Ok. LinkedList toBeRemoved = new LinkedList(); for (REPNode e:values() ) { if (e.getChannel()==channel) { unconnect((Forwarder)e); + // we cannot directly remove this because of the concurrent access toBeRemoved.add(e); } } @@ -99,6 +116,10 @@ return remove(editor)!=null; } + /* + * Clear connection of a forwarder. The rest of the forwarders in this + * session have to be connected properly. + */ private void unconnect(Forwarder e) { boolean hasOwner = false; for(REPNode e1:values()) { @@ -134,6 +155,10 @@ + /** + * Start closing protocol + * not yet implemented. Use quit instead. + */ public void closeSession() { REPNode f = first; if (f!=null) { @@ -150,6 +175,11 @@ } + /** + * @param manager + * + * remove all editors in this session from our manager. + */ public void remove(SessionManager manager) { for(REPNode editor : values()){ if(editor.getChannel() !=null) @@ -159,12 +189,19 @@ } + /** + * @param s + * + * Merge editors from UPDATED session. Only dummy editors + * outside of this manager to be add. + */ public void merge(Session s) { for(REPNode editor : s.values()){ REPNode mine = get(editor.eid); if (mine==null) { put(editor.eid,editor); } else { + // update editor status mine.merge(editor); } } diff -r 2724cf17e9f3 -r 795ef563f2a0 rep/SessionManagerList.java --- a/rep/SessionManagerList.java Tue Nov 25 18:26:23 2008 +0900 +++ b/rep/SessionManagerList.java Wed Nov 26 09:41:14 2008 +0900 @@ -9,7 +9,7 @@ public class SessionManagerList extends LinkedList{ /** - * + * Session Manager List which we have a connection. */ private static final long serialVersionUID = 1L; private int mySMID=0; @@ -36,6 +36,16 @@ return !parent.isForwarder(); } + /** + * Add our slave session manager. Only an empty session manager can + * connect to the other session manager. join_sm() is forwarded to + * the master session manager, and in the master addNewSessionManager() + * is performed. + * + * @param sm + * @param receivedCommand + * @return session manager id (global) + */ public int addNewSessionManager(REPNode sm,REPCommand receivedCommand) { add(sm); int sid = ++smid_root; @@ -53,12 +63,22 @@ return mySMID; } + /** + * An sm_join() is accepted, but we are not the master, forward request + * and register as an waiting sessin manager. + * @param fw + * @param command + */ public void addWaitingSessionManager(REPNode fw, REPCommand command) { // SID assign 待ちのSessionManager Channelを登録する waiting.add(fw); } + /** + * An sm_join_ack() is received. Assign session manager id to the waiter. + * @param sid + */ public void assignSessionManagerIDtoWaitingSM(int sid) { // 待っていたSession Manager ChannelにSession IDを登録し,Session Manager List // に登録する。この次のsm_join_ackでSIDが確定する。 diff -r 2724cf17e9f3 -r 795ef563f2a0 rep/handler/Editor.java --- a/rep/handler/Editor.java Tue Nov 25 18:26:23 2008 +0900 +++ b/rep/handler/Editor.java Wed Nov 26 09:41:14 2008 +0900 @@ -23,7 +23,7 @@ private boolean merging; private REPCommand preMergeCommand; public static boolean noMergeMode=false; - static final boolean doOptimize = false; + static final boolean doOptimize = true; public Editor(SessionManager manager,int editorNo){ // no translator case diff -r 2724cf17e9f3 -r 795ef563f2a0 rep/handler/Translator.java --- a/rep/handler/Translator.java Tue Nov 25 18:26:23 2008 +0900 +++ b/rep/handler/Translator.java Wed Nov 26 09:41:14 2008 +0900 @@ -195,16 +195,16 @@ returnCommand.add(command); } } - int count = 0; - for(REPCommand command: returnCommand) { - switch(command.cmd) { - case REPCMD_INSERT: count++; break; - case REPCMD_DELETE: count--; break; - default: assert false; - } - } - SessionManager.logger.writeLog("MergeAgain ret="+returnCommand.size()+ - " increment="+count); +// int count = 0; +// for(REPCommand command: returnCommand) { +// switch(command.cmd) { +// case REPCMD_INSERT: count++; break; +// case REPCMD_DELETE: count--; break; +// default: assert false; +// } +// } + SessionManager.logger.writeLog("MergeAgain ret="+returnCommand.size()); +// +" increment="+count); mergeAgainList.clear(); optimizedSend(editor, returnCommand); } diff -r 2724cf17e9f3 -r 795ef563f2a0 test/sematest/TestEditor.java --- a/test/sematest/TestEditor.java Tue Nov 25 18:26:23 2008 +0900 +++ b/test/sematest/TestEditor.java Wed Nov 26 09:41:14 2008 +0900 @@ -18,7 +18,7 @@ /** * @author kono - * Basic Temote Editor client implementation + * Basic Remote Editor client implementation * should support multi-session * currently multi-session requires new channel, that is * only one session for this editor. @@ -69,7 +69,6 @@ text = new Text(new String[0]); cmds.add(new REPCommand(REP.SMCMD_JOIN,0,0,0,0,name)); cmds.add(new REPCommand(REP.REPCMD_INSERT_USER,0,0,0,0,"c0")); - cmds.add(new REPCommand(REP.REPCMD_DELETE_USER,0,0,0,0,"c0")); } } @@ -154,6 +153,7 @@ SessionManager.logger.writeLog("Sync Completed."); syncCounter=0; } else { + if (inputLock) return; int i=syncCounter-1; REPCommand del = new REPCommand(REP.REPCMD_DELETE_USER,sid,eid,0,i, text.get(i)); REPCommand ins = new REPCommand(REP.REPCMD_INSERT_USER,sid,eid,0,i, text.get(i)); diff -r 2724cf17e9f3 -r 795ef563f2a0 test/sematest/TestInterManagerSession.java --- a/test/sematest/TestInterManagerSession.java Tue Nov 25 18:26:23 2008 +0900 +++ b/test/sematest/TestInterManagerSession.java Wed Nov 26 09:41:14 2008 +0900 @@ -121,6 +121,7 @@ cmds.add(new REPCommand(REP.SMCMD_PUT,0,0,0,0,"Editor0-file")); cmds.add(new REPCommand(REP.REPCMD_INSERT_USER,0,0,0,0,"m0")); cmds.add(new REPCommand(REP.REPCMD_DELETE_USER,0,0,0,0,"m0")); + cmds.add(new REPCommand(REP.SMCMD_QUIT,0,0,0,0,"")); editorStartCmds = cmds; LinkedListnullcmds = new LinkedList(); editors[0].setCommand(nullcmds);