Mercurial > hg > RemoteEditor > REPSessionManager
annotate rep/handler/Editor.java @ 451:fa7d9ec2008e
too much blocking
author | one |
---|---|
date | Thu, 23 Sep 2010 19:51:19 +0900 |
parents | 21cb16b7f3df |
children | d0d2449000f5 |
rev | line source |
---|---|
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
1 package rep.handler; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
2 |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
3 import java.io.IOException; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
4 import java.util.LinkedList; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
5 import java.util.List; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
6 |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
7 import rep.PacketSet; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
8 import rep.REP; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
9 import rep.REPCommand; |
384 | 10 import rep.ServerMainLoop; |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
11 import rep.SessionManager; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
12 import rep.channel.REPSelectionKey; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
13 import rep.channel.REPSocketChannel; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
14 import rep.optimizers.*; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
15 |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
16 public class Editor extends Forwarder { |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
17 |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
18 private Translator translator; |
387 | 19 // REPCommands we are going to send to the next editor |
439 | 20 private LinkedList<REPCommand> sentList = new LinkedList<REPCommand>(); |
406 | 21 protected LinkedList<PacketSet> waitingCommandInMerge= new LinkedList<PacketSet>(); |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
22 private REPCommand quit2=null; |
442 | 23 private REPCommand preMergeCommand; |
387 | 24 private boolean merging; |
449 | 25 private REPCommand mergeMark = new REPCommand(REP.SMCMD_START_MERGE, 0,0, 0, 0, ""); |
391 | 26 public static boolean noMergeMode=false; |
445 | 27 static final boolean doOptimize = false; |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
28 |
385 | 29 public Editor(SessionManager manager,int editorNo){ |
387 | 30 // no translator case |
31 super(manager, null); | |
32 } | |
33 | |
34 public Editor(int editorNo, SessionManager manager,REPSocketChannel<REPCommand> channel){ | |
35 super(editorNo,manager,channel); | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
36 eid = editorNo; |
449 | 37 sentList.add(mergeMark); // merge mark |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
38 REPCommandOptimizer optimizer; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
39 if (doOptimize) optimizer = new DeleteInsertOptimizer(); //タカノがつくったおぷてぃまいざ |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
40 else optimizer = new NullOptimizer(); //なにもしないけどOptimizer. |
383 | 41 translator = new Translator(eid,optimizer); |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
42 } |
387 | 43 |
427 | 44 /* |
45 * Merge Protocol | |
445 | 46 (0) Editor へのコマンドは、ack 以外は直接 Editor へ送られてしまう。(next.send(cmd)) |
47 Editor から返ってくるコマンドをtranslatorが処理する。 | |
427 | 48 (1) Editor CommandをSession Ring 上に流し、それが戻って来るまでに、他のEditorから |
49 受け取った Editor Command をキューに入れておく。 | |
50 (2) 戻って来たタイミングで、キュー上のEditor Commandを、eid とCommandの | |
51 順序を基にソートする。(self merge) | |
52 (3) 他のEditorにソートのタイミングを与えるために、Editor Command の | |
53 ack を、もう一周させる。 | |
54 (4) 他のEditorのCommandを受け取ってから、ack が来るまでのCommandをキューに | |
55 入れておき、ack が来たら、eid とCommandの順序を基にソートする。(other merge) | |
56 | |
57 Editor には、ソートした編集結果になるように、それまで行なった編集をUndo | |
58 して、ソートした編集結果を適用する。Undo が無駄な動作をしないように最適化する。 | |
59 | |
60 handle() | |
61 セッションの処理 | |
62 manage() | |
63 編集コマンドは translate() へ | |
64 一周して来た編集コマンドのACKは廃棄 (merge queue から削除) | |
65 一周して来た自分のコマンドならself merge | |
66 他のエディタの編集コマンドのACK->other merge | |
67 それ以外は、そのまま実行、merge queue へ格納 | |
68 merge は checkReturnedCommand() から | |
69 startMerge() へ | |
70 まず、接続されている Editor に START_MERGE を送る | |
71 邪魔されないように、他のcommand は block する | |
72 manager() | |
73 START_MERGE_ACK が来たら、translator.mergeAck() で教えて、 | |
74 merge()-> | |
75 translator.checkOwnCommand() へ | |
76 ここで、sort されて、Merge Command をEditorへ送信 | |
77 checkEndMerge()から | |
78 endMerge() が呼ばれる。 | |
79 自分のエディタにEND_MERGE で Merge終了を通知 | |
80 自分のコマンドは、ACKに変えて送信 (3) | |
81 それ以外は、そのまま送信 (一周させる) | |
82 | |
83 */ | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
84 |
397 | 85 public void translate(REPCommand command){ |
86 switch(command.cmd) { | |
87 case REPCMD_INSERT_ACK: | |
88 case REPCMD_DELETE_ACK: | |
444 | 89 if (waitingRequired(command,null)) return; |
449 | 90 checkAck(command); |
397 | 91 if (command.eid==eid) { |
92 // Second Phase が終わって同期が終了。 | |
442 | 93 // SessionManager.logger.writeLog("Complete "+command); |
410 | 94 checkQuit(); |
397 | 95 return; |
96 } | |
97 checkReturnedCommand(command); | |
98 return; | |
400 | 99 case REPCMD_INSERT_USER: |
100 command.cmd = REP.REPCMD_INSERT; | |
101 userEditorCommand(command); | |
102 return; | |
103 case REPCMD_DELETE_USER: | |
406 | 104 command.cmd = REP.REPCMD_DELETE; |
400 | 105 userEditorCommand(command); |
106 return; | |
401 | 107 case REPCMD_INSERT: |
108 case REPCMD_DELETE: | |
109 if (command.eid == REP.MERGE_EID.id){ | |
110 //マージコマンドが返ってきた | |
111 if(translator.checkMergeConflict(command)){ | |
112 //マージ中にエディタからの割り込みがあった場合 | |
113 translator.getMergeAgain(this); | |
114 } | |
115 checkEndMerge(); | |
116 return; | |
117 } else if (command.eid == eid){ | |
118 // 編集コマンドが一周して来た | |
444 | 119 if (waitingRequired(command,null)) return; |
401 | 120 checkReturnedCommand(command); |
400 | 121 return; |
122 } | |
401 | 123 |
124 //他のエディタからの編集コマンド | |
444 | 125 if (waitingRequired(command,null)) return; |
401 | 126 translator.transReceiveCmd(next,command); |
431 | 127 |
401 | 128 sendEditorCommand(command); |
400 | 129 return; |
401 | 130 default: |
131 assert(false); | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
132 } |
400 | 133 } |
134 | |
135 private void userEditorCommand(REPCommand command) { | |
136 //エディタからの新たな編集コマンド | |
137 if (next==this) return; // singleton case | |
138 translator.transSendCmd(command); | |
139 sendEditorCommand(command); | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
140 return; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
141 } |
398 | 142 |
404 | 143 // private void checkDouble(List<REPCommand> sentList) { |
144 // if (sentList.size()==0) return; | |
145 // int count = 0; | |
146 // REPCommand f = sentList.get(0); | |
147 // for(REPCommand c:sentList) { | |
148 // if (c.eid==f.eid&&c.seq==f.seq) { | |
149 // count++; | |
150 // } | |
151 // } | |
152 // assert(count==1); | |
153 // if (true) return; | |
154 // count = 0; | |
155 // for(PacketSet c:waitingCommandInMerge) { | |
156 // for(REPCommand g:sentList) { | |
157 // if (c.command.eid==g.eid&&c.command.seq==g.seq) { | |
158 // count++; | |
159 // } | |
160 // } | |
161 // } | |
162 // assert(count==0); | |
163 // } | |
399 | 164 |
444 | 165 private boolean waitingRequired(REPCommand command, REPSocketChannel<REPCommand> channel) { |
399 | 166 if (hasWaitingCommand()) { |
398 | 167 // We cannot do this operation before watingCommandQueue. |
450 | 168 addWaitingCommand(new PacketSet(this, new REPCommand(command))); |
398 | 169 return true; |
170 } else if (isMerging()) { | |
450 | 171 addWaitingCommand(new PacketSet(this, new REPCommand(command))); |
398 | 172 return true; |
173 } | |
407 | 174 //ServerMainLoop.logger.writeLog("Editor eid:"+eid+" no waiting"); |
398 | 175 return false; |
176 } | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
177 |
442 | 178 public void addWaitingCommand(PacketSet set) { |
179 // if (preMergeCommand!=null) { | |
180 // if (preMergeCommand.eid==set.command.eid | |
181 // && preMergeCommand.seq==set.command.seq) { | |
182 // assert(false); | |
183 // } | |
184 // } | |
399 | 185 waitingCommandInMerge.add(set); |
186 } | |
431 | 187 |
188 /** | |
189 * 他のエディタへのコマンドの送信 | |
190 * @param command | |
191 * | |
192 * sendList にキープする必要がある。 | |
193 */ | |
397 | 194 private void sendEditorCommand(REPCommand command) { |
195 REPCommand keep = new REPCommand(command); | |
196 sentList.add(keep); | |
407 | 197 //ServerMainLoop.logger.writeLog("Editor eid:"+eid+" sentList = "+sentList); |
397 | 198 assert(sentList.size()<limit); |
431 | 199 if (command.cmd==REP.REPCMD_DELETE) { |
200 // delete のundo用の文字列は、外に出す意味はない | |
201 command.string=null; | |
202 } | |
397 | 203 next.send(command); |
204 } | |
205 | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
206 boolean merge(REPCommand command) { |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
207 //マージして送信 |
435 | 208 return translator.catchOwnCommand(this, command); |
431 | 209 } |
210 | |
211 @Override | |
212 public List<REPCommand> getSentList() { | |
213 return sentList; | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
214 } |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
215 |
391 | 216 /** |
217 * 一周して来たcommandの処理。 | |
404 | 218 * |
219 * INSERT/DELETEを受け取った時に、sentListに登録 | |
220 * INSERT_ACK/DELETE_ACKが来たら一周。そこで、Mergeする。 | |
221 * | |
222 * 自分が出したINSERT/DELETEが戻って来たら、ACKに変更して、Merge。 | |
223 * | |
224 * 途中から参加した場合、自分が受けとってないcommandのACKが先に来ることが | |
225 * ある。それは、無視して良い。 | |
391 | 226 * @param command |
227 */ | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
228 void checkReturnedCommand(REPCommand command) { |
439 | 229 startMerge(command); |
406 | 230 return; |
231 } | |
232 | |
434 | 233 private boolean checkAck(REPCommand command) { |
450 | 234 assert(!isMerging()); |
449 | 235 REPCommand prev; |
236 if (sentList.getFirst()==mergeMark) prev=sentList.remove(1); else prev=sentList.remove(0); | |
439 | 237 if (prev==null || prev.seq != command.seq || prev.eid!=command.eid) { |
449 | 238 // should be more robust to allow communication failure |
439 | 239 String err = "Editor eid="+eid+" checkReturnedCommand() : command = " + command + " prev="+ |
240 (prev==null?"null":prev)+" sentList="; | |
241 err += sentList; | |
242 ServerMainLoop.logger.writeLog(err); | |
243 assert(false); | |
244 } | |
406 | 245 return true; |
395 | 246 } |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
247 |
395 | 248 private void startMerge(REPCommand command) { |
451 | 249 ServerMainLoop.logger.writeLog("Editor"+eid+": startMerge "+command); |
397 | 250 preMergeCommand = new REPCommand(command); |
391 | 251 // merge は必須だが、EditorのCommand実装をテストするには邪魔なので、off に出来るようにする。 |
252 if (noMergeMode) { | |
410 | 253 checkQuit(); |
396 | 254 endMerge(); |
391 | 255 return; |
256 } | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
257 // START_MERGE を送る |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
258 // 送らないで良い場合もある? |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
259 REPCommand cmd = new REPCommand(REP.SMCMD_START_MERGE,command.sid,REP.SM_EID.id,seq(),0,""); |
450 | 260 sendToEditor(cmd); |
387 | 261 merging = true; |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
262 // Session Manager 側で、このeditorへの他のeditorからの |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
263 // 入力を止めて、merge にそなえる。merge は、eidtor 側から |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
264 // ACKが来てから始まる。 |
427 | 265 translator.startMerge(command); |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
266 } |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
267 |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
268 @Override |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
269 public void setQuit2(REPCommand cmd) { |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
270 quit2 = cmd; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
271 checkQuit(); |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
272 // do not send quit2 until we received all pending |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
273 // command |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
274 } |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
275 |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
276 @Override |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
277 public void setEID(int eid) { |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
278 this.eid = eid; |
387 | 279 if (translator!=null) |
280 translator.setEid(eid); | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
281 } |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
282 |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
283 public String toString(){ |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
284 return ("Editor eid="+eid+" sid="+sid+" " + host + ":" + file); |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
285 } |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
286 |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
287 public boolean isMerging() { |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
288 return translator.isMerging(); |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
289 } |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
290 |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
291 |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
292 void checkEndMerge() { |
387 | 293 if (merging) { |
434 | 294 if (translator.isMerging()) return; |
396 | 295 endMerge(); |
387 | 296 merging = false; |
297 } | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
298 if (quit2!=null) checkQuit(); |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
299 } |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
300 |
442 | 301 |
396 | 302 private void endMerge() { |
445 | 303 translator.endMerge(); |
396 | 304 REPCommand mergeEnd = new REPCommand(REP.SMCMD_END_MERGE,sid,eid,seq(),0,""); |
450 | 305 sendToEditor(mergeEnd); |
397 | 306 if (preMergeCommand.eid==eid) { |
449 | 307 // Ackの場合はcheckAck() で既にremoveされている |
308 if (sentList.getFirst()==mergeMark) sentList.remove(1); else sentList.remove(0); | |
397 | 309 // First Phase End, send ACK |
310 REPCommand keep = new REPCommand(preMergeCommand); | |
311 switch(keep.cmd) { | |
398 | 312 case REPCMD_INSERT: keep.cmd = REP.REPCMD_INSERT_ACK;break; |
313 case REPCMD_DELETE: keep.cmd = REP.REPCMD_DELETE_ACK;break; | |
406 | 314 default: assert(false); |
397 | 315 } |
449 | 316 sentList.addLast(preMergeCommand); |
407 | 317 //ServerMainLoop.logger.writeLog("Editor eid:"+eid+" sentList = "+sentList); |
397 | 318 assert(sentList.size()<limit); |
319 next.send(keep); | |
320 } else { | |
321 next.send(preMergeCommand); | |
322 } | |
449 | 323 sentList.remove(mergeMark); |
324 sentList.addLast(mergeMark); | |
397 | 325 preMergeCommand = null; |
396 | 326 } |
327 | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
328 private boolean checkQuit() { |
449 | 329 if (quit2!=null && sentList.size()==1&&!isMerging()) { |
450 | 330 sendToEditor(quit2); |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
331 quit2 = null; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
332 return true; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
333 } |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
334 return false; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
335 } |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
336 |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
337 @Override |
387 | 338 public boolean manage(REPCommand command) { |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
339 |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
340 |
387 | 341 switch(command.cmd){ |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
342 // Editor Command |
396 | 343 |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
344 case REPCMD_DELETE: |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
345 case REPCMD_INSERT: |
400 | 346 case REPCMD_DELETE_USER: |
347 case REPCMD_INSERT_USER: | |
396 | 348 case REPCMD_DELETE_ACK: |
349 case REPCMD_INSERT_ACK: | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
350 { |
387 | 351 translate(command); |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
352 break; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
353 } |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
354 |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
355 case SMCMD_START_MERGE_ACK: |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
356 { |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
357 // マージの処理と次のエディタへコマンドを送信する処理 |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
358 translator.mergeAck(); |
434 | 359 if (!merge(preMergeCommand)) { |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
360 // nothing to do, send END_MERGE |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
361 checkEndMerge(); |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
362 } |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
363 break; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
364 } |
386 | 365 |
366 case SMCMD_SYNC: | |
367 if (isMaster()) | |
450 | 368 sendToEditor(command); |
386 | 369 else |
387 | 370 next.send(command); |
386 | 371 |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
372 case SMCMD_QUIT: |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
373 { |
387 | 374 next.send(command); |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
375 break; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
376 } |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
377 case SMCMD_QUIT_2: |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
378 { |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
379 // QUIT_2 is returned. |
387 | 380 if (command.eid!=eid) { |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
381 // stop this editor unless this is the start, starter will stopped |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
382 // by QUIT_2_ACK |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
383 manager.remove(this); |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
384 } |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
385 // don't send quit_2 directly to the editor until all pending |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
386 // merge is processed. |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
387 // this does not work in distributed case. |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
388 if (next.isDirect()) |
387 | 389 next.setQuit2(command); |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
390 else |
387 | 391 next.send(command); |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
392 break; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
393 } |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
394 case SMCMD_QUIT_2_ACK: |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
395 { |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
396 manager.remove(this); |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
397 break; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
398 } |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
399 default: |
396 | 400 assert false; |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
401 return false; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
402 } |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
403 return true; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
404 } |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
405 |
443 | 406 /** |
450 | 407 * write command to the editor |
443 | 408 * called from another Editor instance such as next.send(command) |
409 */ | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
410 @Override |
450 | 411 public void write(REPCommand command) { |
451 | 412 if (merging) { |
413 addWaitingCommand(new PacketSet(this, new REPCommand(command))); | |
414 return; | |
415 } | |
416 if (!waitingRequired(command,channel)) { | |
450 | 417 if (isMergeCommand(command)) { |
418 merging = true; | |
419 } | |
420 super.write(command); | |
442 | 421 } |
422 } | |
423 | |
450 | 424 private boolean isMergeCommand(REPCommand command) { |
425 switch(command.cmd) { | |
426 case REPCMD_INSERT: case REPCMD_DELETE: | |
427 return command.eid==eid; | |
428 case REPCMD_INSERT_ACK: case REPCMD_DELETE_ACK: | |
429 return command.eid!=eid; | |
430 } | |
431 return false; | |
432 } | |
433 | |
434 public void sendToEditor(REPCommand command) { | |
435 super.write(command); | |
436 } | |
437 | |
442 | 438 @Override |
387 | 439 public void handle(REPCommand command, REPSelectionKey<REPCommand> key) throws IOException { |
442 | 440 //ServerMainLoop.logger.writeLog("Manager "+manager.getId()+" read : command = " + command |
441 // +" from "+manager.editorList.editorByChannel(channel)); | |
387 | 442 if (command.cmd==REP.SMCMD_JOIN||command.cmd==REP.SMCMD_PUT) { |
404 | 443 // assert false; |
427 | 444 // 一つのエディタ上に複数のセッションが作られた場合。 |
387 | 445 // 若干問題があるらしい |
446 next = new Forwarder(manager,next.channel); | |
447 REPNode first = new FirstConnector(manager,channel); | |
448 first.handle(command, key); | |
449 key.attach(new Dispatcher(manager,channel)); | |
450 return; | |
451 } | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
452 if (manager.sessionManage(this, command)) return; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
453 manage(command); |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
454 } |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
455 |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
456 @Override |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
457 public void cancel(REPSocketChannel<REPCommand> socketChannel) { |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
458 manager.remove(socketChannel); |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
459 } |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
460 |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
461 public boolean isMaster() { |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
462 return mode==REP.SMCMD_PUT; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
463 } |
386 | 464 |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
465 |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
466 /* Handle special case first, usually these cases |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
467 * are handled in the next Editor in a session manager, but |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
468 * it is forwarded here. |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
469 */ |
385 | 470 public void forwardedCommandManage(REPCommand command) { |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
471 if (command.cmd==REP.SMCMD_QUIT_2) { |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
472 // we have to wait next editor's finishing before sending this. |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
473 // this is odd, but the editor itself does not know it's merging |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
474 // state. Only this session manager knows it. |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
475 setQuit2(command); |
401 | 476 return; |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
477 } |
385 | 478 send(command); |
479 } | |
480 | |
399 | 481 /** |
482 * Check waiting command in merge | |
483 * @return true if there is a processed waiting command | |
484 * @throws IOException | |
485 */ | |
486 public void checkWaitingCommandInMerge() { | |
406 | 487 if (translator==null||isMerging()) return; |
488 LinkedList<PacketSet> w = waitingCommandInMerge; | |
489 waitingCommandInMerge = new LinkedList<PacketSet>(); | |
490 while(w.size()>0) { | |
491 if (isMerging()) { | |
492 w.addAll(waitingCommandInMerge); | |
493 waitingCommandInMerge = w; | |
494 return; | |
495 } | |
496 PacketSet p = w.remove(0); | |
399 | 497 try { |
444 | 498 if (p.channel!=null) |
450 | 499 write(p.command); |
444 | 500 else |
501 manage(p.command); | |
399 | 502 } catch (Exception e1) { |
406 | 503 assert false; |
450 | 504 manager.close(p.channel.channel); |
406 | 505 return; |
399 | 506 } |
507 } | |
508 } | |
509 | |
510 | |
511 public boolean hasWaitingCommand() { | |
512 return waitingCommandInMerge.size()>0; | |
513 } | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
514 } |