Mercurial > hg > RemoteEditor > REPSessionManager
annotate rep/handler/Editor.java @ 488:c49a86a7ab8f
termination of new merge command...
author | one |
---|---|
date | Thu, 21 Oct 2010 23:03:22 +0900 |
parents | 455df381449a |
children | 4aba8ae3125b |
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; |
468 | 4 import java.util.Comparator; |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
5 import java.util.LinkedList; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
6 import java.util.List; |
468 | 7 import java.util.TreeSet; |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
8 |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
9 import rep.REP; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
10 import rep.REPCommand; |
384 | 11 import rep.ServerMainLoop; |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
12 import rep.SessionManager; |
468 | 13 import rep.channel.REPLogger; |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
14 import rep.channel.REPSelectionKey; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
15 import rep.channel.REPSocketChannel; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
16 import rep.optimizers.*; |
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 public class Editor extends Forwarder { |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
19 |
387 | 20 // REPCommands we are going to send to the next editor |
439 | 21 private LinkedList<REPCommand> sentList = new LinkedList<REPCommand>(); |
464 | 22 // Expected acknowledge list |
23 private LinkedList<REPCommand> ackList = new LinkedList<REPCommand>(); | |
460 | 24 public LinkedList<REPCommand> waitingCommandInMerge= new LinkedList<REPCommand>(); |
462 | 25 private REPCommand quit_2=null; |
442 | 26 private REPCommand preMergeCommand; |
468 | 27 |
28 public REPCommandOptimizer optimizer; | |
29 private LinkedList<REPCommand> unMergedCmds; | |
30 private LinkedList<REPCommand> sentMergedList; | |
31 private TreeSet<REPCommand> sortedEditCmds; | |
32 boolean mergeAgain; | |
33 public REPLogger logger = SessionManager.logger; | |
487 | 34 private boolean blocking = false; |
35 private boolean merging = false; | |
486 | 36 private LinkedList<REPCommand> writeQueue = new LinkedList<REPCommand>(); |
37 private REPCommand mergeMark =new REPCommand(REP.REPCMD_MERGE_MARK,0,0, REP.MERGE_EID.id, 0, ""); | |
468 | 38 |
482 | 39 public enum MergeMode { |
40 NoMerge, // no merge | |
41 Slow, // merge at Ack | |
42 Early, // merge at returned command and Ack | |
43 Direct // merge at incoming command | |
44 } | |
486 | 45 public static MergeMode mergeMode = MergeMode.Direct; |
445 | 46 static final boolean doOptimize = false; |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
47 |
385 | 48 public Editor(SessionManager manager,int editorNo){ |
387 | 49 // no translator case |
50 super(manager, null); | |
51 } | |
52 | |
468 | 53 public Editor(int eid, REPCommandOptimizer optimizer) { |
54 super(null, null); | |
55 this.optimizer = optimizer; | |
56 } | |
57 | |
387 | 58 public Editor(int editorNo, SessionManager manager,REPSocketChannel<REPCommand> channel){ |
59 super(editorNo,manager,channel); | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
60 eid = editorNo; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
61 if (doOptimize) optimizer = new DeleteInsertOptimizer(); //タカノがつくったおぷてぃまいざ |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
62 else optimizer = new NullOptimizer(); //なにもしないけどOptimizer. |
468 | 63 |
64 unMergedCmds = new LinkedList<REPCommand>(); | |
65 mergeAgain = false; | |
66 sentMergedList = new LinkedList<REPCommand>(); | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
67 } |
387 | 68 |
427 | 69 /* |
70 * Merge Protocol | |
445 | 71 (0) Editor へのコマンドは、ack 以外は直接 Editor へ送られてしまう。(next.send(cmd)) |
72 Editor から返ってくるコマンドをtranslatorが処理する。 | |
427 | 73 (1) Editor CommandをSession Ring 上に流し、それが戻って来るまでに、他のEditorから |
74 受け取った Editor Command をキューに入れておく。 | |
482 | 75 sentList 外に送り出したEditor Command |
76 unMergedList 接続されたEditorのundo list (reverse order) | |
77 MergingSentList Mergeするlist 。Mergeのやり直し用。 | |
78 Slow/Early | |
427 | 79 (2) 戻って来たタイミングで、キュー上のEditor Commandを、eid とCommandの |
482 | 80 順序を基にソートする。(self merge (Early)) |
427 | 81 (3) 他のEditorにソートのタイミングを与えるために、Editor Command の |
82 ack を、もう一周させる。 | |
83 (4) 他のEditorのCommandを受け取ってから、ack が来るまでのCommandをキューに | |
482 | 84 入れておき、ack が来たら、eid とCommandの順序を基にソートする。(other merge (Slow)) |
85 Direct | |
86 (5) 他のEditor Command が来た時点で、すぐにmergeする | |
87 (6) 自分のEditor Command が来て、 | |
88 未確定の他のEditor Command があれば、それを確定(sentList/unMergedListから削除) | |
89 自分のEditor Command はsentListに追加 (unMergedListには既に入っている) | |
90 (7) Ackが来たら、そのEditor Command まで確定 | |
427 | 91 |
92 Editor には、ソートした編集結果になるように、それまで行なった編集をUndo | |
93 して、ソートした編集結果を適用する。Undo が無駄な動作をしないように最適化する。 | |
482 | 94 */ |
95 | |
96 /* | |
427 | 97 handle() |
98 セッションの処理 | |
99 manage() | |
100 編集コマンドは translate() へ | |
101 一周して来た編集コマンドのACKは廃棄 (merge queue から削除) | |
102 一周して来た自分のコマンドならself merge | |
103 他のエディタの編集コマンドのACK->other merge | |
104 それ以外は、そのまま実行、merge queue へ格納 | |
105 merge は checkReturnedCommand() から | |
106 startMerge() へ | |
107 まず、接続されている Editor に START_MERGE を送る | |
108 邪魔されないように、他のcommand は block する | |
109 manager() | |
110 START_MERGE_ACK が来たら、translator.mergeAck() で教えて、 | |
111 merge()-> | |
112 translator.checkOwnCommand() へ | |
113 ここで、sort されて、Merge Command をEditorへ送信 | |
114 checkEndMerge()から | |
115 endMerge() が呼ばれる。 | |
116 自分のエディタにEND_MERGE で Merge終了を通知 | |
117 自分のコマンドは、ACKに変えて送信 (3) | |
118 それ以外は、そのまま送信 (一周させる) | |
119 | |
120 */ | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
121 |
468 | 122 |
397 | 123 public void translate(REPCommand command){ |
124 switch(command.cmd) { | |
125 case REPCMD_INSERT_ACK: | |
126 case REPCMD_DELETE_ACK: | |
127 if (command.eid==eid) { | |
482 | 128 if (mergeMode==MergeMode.Slow) { |
462 | 129 checkReturnedCommand(command); |
130 checkQuit(); | |
131 return; | |
484 | 132 } |
397 | 133 // Second Phase が終わって同期が終了。 |
442 | 134 // SessionManager.logger.writeLog("Complete "+command); |
452 | 135 checkAck(command); |
410 | 136 checkQuit(); |
397 | 137 return; |
138 } | |
485 | 139 if (mergeMode==MergeMode.Direct) { |
140 checkAck(command); | |
141 truncateUnMergedCmds(command); | |
486 | 142 ServerMainLoop.logger.writeLog("Editor"+eid+": send ackCommand "+command+report()); |
485 | 143 next.send(command); |
144 checkQuit(); | |
145 } else | |
146 checkReturnedCommand(command); | |
397 | 147 return; |
400 | 148 case REPCMD_INSERT_USER: |
149 command.cmd = REP.REPCMD_INSERT; | |
150 userEditorCommand(command); | |
151 return; | |
152 case REPCMD_DELETE_USER: | |
406 | 153 command.cmd = REP.REPCMD_DELETE; |
400 | 154 userEditorCommand(command); |
155 return; | |
401 | 156 case REPCMD_INSERT: |
157 case REPCMD_DELETE: | |
465 | 158 case REPCMD_MERGE_MARK: |
401 | 159 if (command.eid == REP.MERGE_EID.id){ |
160 //マージコマンドが返ってきた | |
468 | 161 if(checkMergeConflict(command)){ |
401 | 162 //マージ中にエディタからの割り込みがあった場合 |
483 | 163 getMergeAgain(); |
401 | 164 } |
165 checkEndMerge(); | |
166 return; | |
457 | 167 } |
168 if (command.eid == eid){ | |
401 | 169 // 編集コマンドが一周して来た |
482 | 170 if (mergeMode==MergeMode.Slow) { |
462 | 171 checkAck(command); |
172 sendAck(command); | |
485 | 173 } else if (mergeMode==MergeMode.Direct) { |
174 truncateUnMergedCmds(command); | |
175 checkAck(command); | |
176 sendAck(command); | |
462 | 177 } else { |
178 checkReturnedCommand(command); | |
179 } | |
400 | 180 return; |
181 } | |
401 | 182 |
183 //他のエディタからの編集コマンド | |
468 | 184 transReceiveCmd(next,command); |
486 | 185 if (mergeMode==MergeMode.Direct) { |
186 sendEditorCommand(command); | |
187 sentList.addLast(mergeMark ); | |
483 | 188 startMerge(command); |
486 | 189 } else |
483 | 190 sendEditorCommand(command); |
400 | 191 return; |
401 | 192 default: |
193 assert(false); | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
194 } |
400 | 195 } |
196 | |
197 private void userEditorCommand(REPCommand command) { | |
198 //エディタからの新たな編集コマンド | |
486 | 199 if (mergeMode==MergeMode.Direct) { |
483 | 200 truncateSentList(command); |
486 | 201 ServerMainLoop.logger.writeLog("Editor"+eid+": User Command "+command+report()); |
202 } | |
400 | 203 if (next==this) return; // singleton case |
468 | 204 transSendCmd(command); |
400 | 205 sendEditorCommand(command); |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
206 return; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
207 } |
398 | 208 |
404 | 209 // private void checkDouble(List<REPCommand> sentList) { |
210 // if (sentList.size()==0) return; | |
211 // int count = 0; | |
212 // REPCommand f = sentList.get(0); | |
213 // for(REPCommand c:sentList) { | |
214 // if (c.eid==f.eid&&c.seq==f.seq) { | |
215 // count++; | |
216 // } | |
217 // } | |
218 // assert(count==1); | |
219 // if (true) return; | |
220 // count = 0; | |
221 // for(PacketSet c:waitingCommandInMerge) { | |
222 // for(REPCommand g:sentList) { | |
223 // if (c.command.eid==g.eid&&c.command.seq==g.seq) { | |
224 // count++; | |
225 // } | |
226 // } | |
227 // } | |
228 // assert(count==0); | |
229 // } | |
399 | 230 |
483 | 231 |
232 /** | |
460 | 233 * Sending to Editor and waiting Queue |
234 * +--------+ | |
235 * send() --> write() -> | Editor | -> handle() -> manager() | |
236 * +--------+ | |
237 * waitingQueue | |
238 * writeQueue | |
239 * | |
240 * send() は、他のEditor Node から呼ばれる | |
241 * write() は、内部で優先的に送信するのに用いる | |
242 * writeQueue は、waitingQueue よりも常に先に実行される必要がある | |
243 | |
244 * Manageの送信キューはここでは使わない | |
245 * send() manage | |
246 */ | |
247 @Override | |
248 public void send(REPCommand command) { | |
487 | 249 if (blocking || isMerging() || waitingCommandInMerge.size()>0) { |
460 | 250 waitingCommandInMerge.addLast(command); |
251 ServerMainLoop.logger.writeLog("Editor eid:"+eid+" waitingCommandInMerge = "+waitingCommandInMerge); | |
252 return; | |
253 } | |
254 if (isMergeCommand(command)) { | |
487 | 255 blocking = true; |
460 | 256 ServerMainLoop.logger.writeLog("Editor"+eid+": merging=true (send)"+command); |
257 } | |
258 writeQueue.add(command); | |
398 | 259 } |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
260 |
460 | 261 /** |
262 * Check waiting command in merge | |
263 * periodically called from manager | |
264 */ | |
265 public void checkWaitingCommandInMerge() { | |
266 if (writeQueue.size()>0) { | |
267 REPCommand command =writeQueue.pollFirst(); | |
268 ServerMainLoop.logger.writeLog("Editor"+eid+": write comand="+command); | |
269 super.write(command); | |
270 return; | |
271 } | |
487 | 272 if (blocking || isMerging()) return; |
460 | 273 if (waitingCommandInMerge.size()>0) { |
274 REPCommand command = waitingCommandInMerge.pollFirst(); | |
275 ServerMainLoop.logger.writeLog("Editor"+eid+": send waiting comand="+command); | |
276 super.write(command); | |
277 if (isMergeCommand(command)) { | |
487 | 278 blocking = true; |
460 | 279 } |
280 } | |
399 | 281 } |
431 | 282 /** |
283 * 他のエディタへのコマンドの送信 | |
284 * @param command | |
285 * | |
286 * sendList にキープする必要がある。 | |
287 */ | |
397 | 288 private void sendEditorCommand(REPCommand command) { |
289 REPCommand keep = new REPCommand(command); | |
290 sentList.add(keep); | |
464 | 291 ackList.add(keep); |
407 | 292 //ServerMainLoop.logger.writeLog("Editor eid:"+eid+" sentList = "+sentList); |
464 | 293 assert(ackList.size()<limit); |
431 | 294 if (command.cmd==REP.REPCMD_DELETE) { |
295 // delete のundo用の文字列は、外に出す意味はない | |
296 command.string=null; | |
297 } | |
397 | 298 next.send(command); |
299 } | |
300 | |
391 | 301 /** |
302 * 一周して来たcommandの処理。 | |
404 | 303 * |
304 * INSERT/DELETEを受け取った時に、sentListに登録 | |
305 * INSERT_ACK/DELETE_ACKが来たら一周。そこで、Mergeする。 | |
306 * | |
307 * 自分が出したINSERT/DELETEが戻って来たら、ACKに変更して、Merge。 | |
308 * | |
309 * 途中から参加した場合、自分が受けとってないcommandのACKが先に来ることが | |
310 * ある。それは、無視して良い。 | |
391 | 311 * @param command |
312 */ | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
313 void checkReturnedCommand(REPCommand command) { |
483 | 314 startMerge(command); |
315 } | |
316 | |
317 void startMerge(REPCommand command) { | |
451 | 318 ServerMainLoop.logger.writeLog("Editor"+eid+": startMerge "+command); |
397 | 319 preMergeCommand = new REPCommand(command); |
391 | 320 // merge は必須だが、EditorのCommand実装をテストするには邪魔なので、off に出来るようにする。 |
482 | 321 if (mergeMode==MergeMode.NoMerge) { |
410 | 322 checkQuit(); |
396 | 323 endMerge(); |
391 | 324 return; |
325 } | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
326 // START_MERGE を送る |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
327 // 送らないで良い場合もある? |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
328 REPCommand cmd = new REPCommand(REP.SMCMD_START_MERGE,command.sid,REP.SM_EID.id,seq(),0,""); |
450 | 329 sendToEditor(cmd); |
387 | 330 merging = true; |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
331 // Session Manager 側で、このeditorへの他のeditorからの |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
332 // 入力を止めて、merge にそなえる。merge は、eidtor 側から |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
333 // ACKが来てから始まる。 |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
334 } |
483 | 335 |
463 | 336 /** |
337 * sentList と ack を見比べて、正しい順序で来たかどうかを調べる。途中参加したEditorの場合は、Ackは | |
338 * 無視して良い。 | |
339 * @param command | |
340 * @return | |
341 */ | |
457 | 342 private boolean checkAck(REPCommand command) { |
466 | 343 REPCommand prev = null; |
344 try { | |
487 | 345 if(mergeMode!=MergeMode.Direct && isMerging()) throw new Exception(); |
346 if(ackList.size()==0) throw new Exception(); | |
466 | 347 prev=ackList.remove(0); |
348 if (prev==null || prev.seq != command.seq || prev.eid!=command.eid) throw new Exception(); | |
349 } catch (Exception n) { | |
457 | 350 // should be more robust to allow communication failure |
351 String err = "Editor eid="+eid+" checkReturnedCommand() : command = " + command + " prev="+ | |
466 | 352 (prev==null?"null":prev)+" ackList="; |
464 | 353 err += ackList; |
487 | 354 err += "merging="+isMerging(); |
457 | 355 ServerMainLoop.logger.writeLog(err); |
356 assert(false); | |
357 } | |
358 return true; | |
359 } | |
360 | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
361 |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
362 @Override |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
363 public void setQuit2(REPCommand cmd) { |
462 | 364 quit_2 = cmd; |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
365 checkQuit(); |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
366 // 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
|
367 // command |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
368 } |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
369 |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
370 @Override |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
371 public void setEID(int eid) { |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
372 this.eid = eid; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
373 } |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
374 |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
375 public String toString(){ |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
376 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
|
377 } |
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 void checkEndMerge() { |
488 | 380 if (blocking) { |
468 | 381 if (isMerging()) return; |
396 | 382 endMerge(); |
487 | 383 blocking = false; |
387 | 384 } |
462 | 385 if (quit_2!=null) checkQuit(); |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
386 } |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
387 |
442 | 388 |
396 | 389 private void endMerge() { |
390 REPCommand mergeEnd = new REPCommand(REP.SMCMD_END_MERGE,sid,eid,seq(),0,""); | |
450 | 391 sendToEditor(mergeEnd); |
483 | 392 if (mergeMode==MergeMode.Direct) { |
486 | 393 REPCommand last = sentList.getLast(); |
394 if (last!=null && last.eid==eid && last.sid==sid) | |
395 truncateSentList(last); | |
483 | 396 preMergeCommand = null; |
397 return ; | |
398 } | |
399 sortedEditCmds = null; | |
452 | 400 checkAck(preMergeCommand); |
397 | 401 if (preMergeCommand.eid==eid) { |
482 | 402 if (mergeMode==MergeMode.Early) { |
462 | 403 sendAck(preMergeCommand); |
463 | 404 } |
397 | 405 } else { |
468 | 406 ServerMainLoop.logger.writeLog("Editor"+eid+": send preMergeCommand "+preMergeCommand); |
397 | 407 next.send(preMergeCommand); |
408 } | |
465 | 409 // sentList.clear(); |
397 | 410 preMergeCommand = null; |
396 | 411 } |
412 | |
484 | 413 /** |
414 * User Editor Command Fix the command order of | |
415 * other editor commands except own command | |
416 * truncate sentList and unMergedCmds. | |
417 */ | |
418 private void truncateSentList(REPCommand commit) { | |
487 | 419 if (merging) return; |
483 | 420 LinkedList<REPCommand>u = new LinkedList<REPCommand>(); |
421 for(REPCommand command:unMergedCmds) { | |
486 | 422 if (command.cmd==REP.REPCMD_MERGE_MARK) continue; |
484 | 423 if (command.eid!=eid) break; |
424 u.addLast(command); | |
425 } | |
426 unMergedCmds = u; | |
427 LinkedList<REPCommand>s = new LinkedList<REPCommand>(); | |
428 for(REPCommand command:sentList) { | |
429 if (command.eid!=eid) { | |
430 s.clear(); | |
431 continue; | |
483 | 432 } |
484 | 433 s.addLast(command); |
483 | 434 } |
484 | 435 sentList = s; |
436 } | |
437 | |
438 /** | |
439 * Returned command fixed command order. Remove from | |
440 * sentList and unMergedCmds | |
441 * @param commit | |
442 */ | |
443 public void truncateUnMergedCmds(REPCommand commit) { | |
487 | 444 assert(!merging); |
484 | 445 LinkedList<REPCommand>u = new LinkedList<REPCommand>(); |
446 for(REPCommand command:unMergedCmds) { | |
486 | 447 if (command.cmd==REP.REPCMD_MERGE_MARK) continue; |
484 | 448 if (command.isSameSeq(commit)) break; |
449 u.addLast(command); | |
450 } | |
483 | 451 unMergedCmds = u; |
484 | 452 boolean flag = false; |
453 LinkedList<REPCommand>s = new LinkedList<REPCommand>(); | |
454 for(REPCommand command:sentList) { | |
487 | 455 if (command.isSameSeq(commit)) { |
456 flag = true; continue; | |
457 } | |
484 | 458 if (flag) s.addLast(command); |
459 } | |
460 if (flag) sentList = s; | |
483 | 461 } |
462 | |
462 | 463 private void sendAck(REPCommand command) { |
464 REPCommand keep = new REPCommand(command); | |
465 // First Phase End, send ACK | |
466 switch(keep.cmd) { | |
467 case REPCMD_INSERT: keep.cmd = REP.REPCMD_INSERT_ACK;break; | |
468 case REPCMD_DELETE: keep.cmd = REP.REPCMD_DELETE_ACK;break; | |
469 default: assert(false); | |
470 } | |
464 | 471 ackList.addLast(keep); |
463 | 472 ServerMainLoop.logger.writeLog("Editor"+eid+": sendAck sentList = "+sentList); |
464 | 473 assert(ackList.size()<limit); |
463 | 474 keep.string = ""; |
462 | 475 next.send(keep); |
476 } | |
477 | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
478 private boolean checkQuit() { |
488 | 479 if (quit_2!=null && ackList.size()==0 &&!isMerging() && waitingCommandInMerge.size()==0) { |
480 if (emptySentList() ){ | |
462 | 481 sendToEditor(quit_2); |
482 quit_2 = null; | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
483 return true; |
488 | 484 } |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
485 } |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
486 return false; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
487 } |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
488 |
488 | 489 private boolean emptySentList() { |
490 return sentList.size()==0||(sentList.size()==1 && sentList.getFirst().cmd==REP.REPCMD_MERGE_MARK); | |
491 } | |
492 | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
493 @Override |
387 | 494 public boolean manage(REPCommand command) { |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
495 |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
496 |
387 | 497 switch(command.cmd){ |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
498 // Editor Command |
396 | 499 |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
500 case REPCMD_DELETE: |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
501 case REPCMD_INSERT: |
400 | 502 case REPCMD_DELETE_USER: |
503 case REPCMD_INSERT_USER: | |
396 | 504 case REPCMD_DELETE_ACK: |
505 case REPCMD_INSERT_ACK: | |
465 | 506 case REPCMD_MERGE_MARK: |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
507 { |
387 | 508 translate(command); |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
509 break; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
510 } |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
511 |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
512 case SMCMD_START_MERGE_ACK: |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
513 { |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
514 // マージの処理と次のエディタへコマンドを送信する処理 |
468 | 515 mergeAck(); |
483 | 516 if (!merge(preMergeCommand)) { |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
517 // nothing to do, send END_MERGE |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
518 checkEndMerge(); |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
519 } |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
520 break; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
521 } |
386 | 522 |
523 case SMCMD_SYNC: | |
524 if (isMaster()) | |
450 | 525 sendToEditor(command); |
386 | 526 else |
387 | 527 next.send(command); |
386 | 528 |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
529 case SMCMD_QUIT: |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
530 { |
387 | 531 next.send(command); |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
532 break; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
533 } |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
534 case SMCMD_QUIT_2: |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
535 { |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
536 // QUIT_2 is returned. |
387 | 537 if (command.eid!=eid) { |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
538 // 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
|
539 // by QUIT_2_ACK |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
540 manager.remove(this); |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
541 } |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
542 // 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
|
543 // merge is processed. |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
544 // this does not work in distributed case. |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
545 if (next.isDirect()) |
387 | 546 next.setQuit2(command); |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
547 else |
387 | 548 next.send(command); |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
549 break; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
550 } |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
551 case SMCMD_QUIT_2_ACK: |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
552 { |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
553 manager.remove(this); |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
554 break; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
555 } |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
556 default: |
396 | 557 assert false; |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
558 return false; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
559 } |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
560 return true; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
561 } |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
562 |
442 | 563 |
450 | 564 private boolean isMergeCommand(REPCommand command) { |
485 | 565 if (mergeMode==MergeMode.Direct) |
566 return (command.eid!=eid&&command.cmd==REP.REPCMD_INSERT || command.cmd==REP.REPCMD_DELETE); | |
450 | 567 switch(command.cmd) { |
568 case REPCMD_INSERT: case REPCMD_DELETE: | |
482 | 569 return mergeMode==MergeMode.Slow?false:command.eid==eid; |
450 | 570 case REPCMD_INSERT_ACK: case REPCMD_DELETE_ACK: |
482 | 571 return mergeMode==MergeMode.Slow?true:command.eid!=eid; |
450 | 572 } |
573 return false; | |
574 } | |
575 | |
576 public void sendToEditor(REPCommand command) { | |
460 | 577 writeQueue.add(command); |
450 | 578 } |
579 | |
442 | 580 @Override |
387 | 581 public void handle(REPCommand command, REPSelectionKey<REPCommand> key) throws IOException { |
582 if (command.cmd==REP.SMCMD_JOIN||command.cmd==REP.SMCMD_PUT) { | |
404 | 583 // assert false; |
427 | 584 // 一つのエディタ上に複数のセッションが作られた場合。 |
387 | 585 // 若干問題があるらしい |
586 next = new Forwarder(manager,next.channel); | |
587 REPNode first = new FirstConnector(manager,channel); | |
588 first.handle(command, key); | |
589 key.attach(new Dispatcher(manager,channel)); | |
590 return; | |
591 } | |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
592 if (manager.sessionManage(this, command)) return; |
471 | 593 // ServerMainLoop.logger.writeLog("Editor"+eid+": handle command="+command); |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
594 manage(command); |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
595 } |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
596 |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
597 @Override |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
598 public void cancel(REPSocketChannel<REPCommand> socketChannel) { |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
599 manager.remove(socketChannel); |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
600 } |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
601 |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
602 public boolean isMaster() { |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
603 return mode==REP.SMCMD_PUT; |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
604 } |
386 | 605 |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
606 |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
607 /* Handle special case first, usually these cases |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
608 * 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
|
609 * it is forwarded here. |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
610 */ |
385 | 611 public void forwardedCommandManage(REPCommand command) { |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
612 if (command.cmd==REP.SMCMD_QUIT_2) { |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
613 // 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
|
614 // 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
|
615 // state. Only this session manager knows it. |
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
616 setQuit2(command); |
401 | 617 return; |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
618 } |
385 | 619 send(command); |
620 } | |
621 | |
468 | 622 /** |
623 * New command from an editor | |
624 * The command is sent to the next editor | |
625 * @param cmd | |
626 * @return translated command. | |
627 */ | |
628 public REPCommand transSendCmd(REPCommand cmd){ | |
629 assert(cmd.eid==eid); | |
630 unMergedCmds.addLast(cmd); | |
631 | |
632 //マージ中にユーザから割り込みがあった場合 | |
633 if(isMerging()){ | |
634 mergeAgain = true; | |
635 } | |
636 | |
637 return cmd; | |
638 } | |
639 | |
640 /** | |
641 * My command is returned from the session ring, and START_MERGE_ACK | |
642 * is returned. At this | |
643 * stage my writeQueue is empty, our editor is waiting for me. | |
644 * Start merge process. | |
645 * @param cmd | |
646 */ | |
483 | 647 public boolean merge(REPCommand prev){ |
468 | 648 logger.writeLog("beforeMerge"+eid+":"+unMergedCmds); |
649 LinkedList<REPCommand> output = new LinkedList<REPCommand>(); | |
650 LinkedList<REPCommand> newSentList = new LinkedList<REPCommand>(); | |
651 // merge queue上にあるコマンドを全部undoコマンドするのと同時に | |
652 // sort したコマンド列を生成する | |
653 for( REPCommand cmd0 : unMergedCmds) { | |
654 output.addLast( createUndo(cmd0) ); | |
655 } | |
656 | |
657 sortedEditCmds = new TreeSet<REPCommand>(new REPCommandComparator(1)); | |
483 | 658 logger.writeLog("sentList"+eid+":"+sentList); |
486 | 659 boolean flag = true; |
483 | 660 for( REPCommand cmd0 : sentList ) { |
487 | 661 if (cmd0.cmd==REP.REPCMD_MERGE_MARK) { |
662 flag = false; | |
663 } | |
664 if (cmd0.cmd==REP.REPCMD_INSERT || cmd0.cmd==REP.REPCMD_DELETE) { | |
665 if (flag) sortedEditCmds.add(cmd0); | |
666 else newSentList.add(cmd0); | |
486 | 667 } |
487 | 668 } |
669 output.addLast(mergeMark); | |
670 output.addAll(sortedEditCmds); | |
671 output.addAll(newSentList); | |
672 logger.writeLog("sortedMerge"+eid+":"+sentList); | |
673 // unMerged command のdeleteのundo string は、この時点で使えない。 | |
674 // Editor 側から送り返して来たものを使う必要がある。 | |
675 unMergedCmds.clear(); | |
676 logger.writeLog("outputMerge"+eid+":"+output); | |
677 return optimizedSend(this,output); | |
678 } | |
679 | |
680 public boolean mergeEarly(REPCommand prev){ | |
681 logger.writeLog("beforeMerge"+eid+":"+unMergedCmds); | |
682 LinkedList<REPCommand> output = new LinkedList<REPCommand>(); | |
683 LinkedList<REPCommand> newSentList = new LinkedList<REPCommand>(); | |
684 // merge queue上にあるコマンドを全部undoコマンドするのと同時に | |
685 // sort したコマンド列を生成する | |
686 for( REPCommand cmd0 : unMergedCmds) { | |
687 output.addLast( createUndo(cmd0) ); | |
688 } | |
689 | |
690 sortedEditCmds = new TreeSet<REPCommand>(new REPCommandComparator(1)); | |
691 logger.writeLog("sentList"+eid+":"+sentList); | |
692 boolean flag = true; | |
693 for( REPCommand cmd0 : sentList ) { | |
468 | 694 if (cmd0.cmd==REP.REPCMD_INSERT || cmd0.cmd==REP.REPCMD_DELETE) { |
486 | 695 if (flag) sortedEditCmds.add(cmd0); |
696 else newSentList.add(cmd0); | |
468 | 697 } |
698 } | |
469 | 699 output.addAll(sortedEditCmds); |
487 | 700 output.addLast(mergeMark); |
468 | 701 logger.writeLog("sortedMerge"+eid+":"+sortedEditCmds); |
702 // unMerged command のdeleteのundo string は、この時点で使えない。 | |
703 // Editor 側から送り返して来たものを使う必要がある。 | |
704 unMergedCmds.clear(); | |
487 | 705 sentList = newSentList; |
468 | 706 logger.writeLog("outputMerge"+eid+":"+output); |
483 | 707 return optimizedSend(this,output); |
468 | 708 } |
709 | |
710 /** | |
711 * Sent optimized merged command list | |
712 * @param editor | |
713 * @param output | |
714 * @return if any sent commands output | |
715 */ | |
716 public boolean optimizedSend(REPNode editor, LinkedList<REPCommand> output) { | |
717 /* | |
718 * Optimized send の場合は、unMergedCommand のつじつまを合わせる必要がある。 | |
719 */ | |
720 sentMergedList.clear(); | |
721 List<REPCommand> output1 = optimizer.optimize(output); | |
722 if (output1.size()==0) { | |
486 | 723 merging = false; |
468 | 724 return false; |
725 } | |
726 for(REPCommand c:output1) { | |
727 REPCommand m = new REPCommand(c); | |
728 m.setEID(REP.MERGE_EID.id); | |
729 m.setSEQID(editor.seq()); | |
730 sentMergedList.addLast(m); | |
731 editor.sendToEditor(m); | |
732 } | |
733 logger.writeLog("OptimizedOutputMerge"+eid+":"+sentMergedList); | |
486 | 734 merging = true; |
468 | 735 return true; |
736 } | |
737 | |
738 private REPCommand createUndo(REPCommand cmd){ | |
739 REPCommand retCmd = new REPCommand(cmd); | |
740 if (cmd.cmd==REP.REPCMD_INSERT) { | |
741 retCmd.cmd=REP.REPCMD_DELETE; | |
742 retCmd.string=""; | |
743 } | |
744 else if (cmd.cmd==REP.REPCMD_DELETE) retCmd.cmd=REP.REPCMD_INSERT; | |
745 return retCmd; | |
746 } | |
747 | |
748 class REPCommandComparator implements Comparator<REPCommand>{ | |
749 int base; | |
750 REPCommandComparator(int base) { | |
751 this.base = base; | |
752 } | |
753 public int compare(REPCommand o1, REPCommand o2) { | |
754 int eid1 = o1.eid-base; if (eid1<0) eid1 += Integer.MAX_VALUE; | |
755 int eid2 = o2.eid-base; if (eid2<0) eid2 += Integer.MAX_VALUE; | |
756 if ( eid1<eid2 ) return -1; | |
757 if ( eid1>eid2 ) return 1; | |
758 if ( o1.seq<o2.seq ) return -1; | |
759 if ( o1.seq>o2.seq ) return 1; | |
760 // assert(false); // this can happen in MergedAgain case | |
761 return 0; | |
762 } | |
763 } | |
764 | |
765 /** | |
766 * Translate Command that was received from SeMa. | |
767 * @param cmd the command to be translated. | |
768 * @return translated command. | |
769 */ | |
770 public void transReceiveCmd(REPNode nextEditor,REPCommand cmd){ | |
771 assert (cmd.eid != eid); | |
471 | 772 unMergedCmds.addFirst(new REPCommand(cmd)); |
468 | 773 } |
774 | |
775 public void setEid(int _eid){ | |
776 eid = _eid; | |
777 } | |
778 | |
779 public boolean checkMergeConflict(REPCommand command) { | |
471 | 780 unMergedCmds.addFirst(new REPCommand(command)); |
468 | 781 |
782 REPCommand prev = sentMergedList.getFirst(); | |
783 if (prev.seq==command.seq) { | |
784 // logger.writeLog("Input eid="+eid+"SentMergedList = "+sentMergedList); | |
785 sentMergedList.removeFirst(); | |
786 } | |
787 // previous merge command may be returned | |
788 | |
789 if(sentMergedList.size()==0 && !mergeAgain) { | |
486 | 790 merging=false; |
468 | 791 } |
792 return mergeAgain; | |
793 } | |
794 | |
483 | 795 public void getMergeAgain() { |
468 | 796 if (sentMergedList.size()>0) return; // wait for previous merge completion |
487 | 797 if (mergeMode==MergeMode.Direct) { |
798 logger.writeLog("MergeAgain "+eid); | |
488 | 799 mergeAgain = false; |
487 | 800 merge(preMergeCommand); |
801 return; | |
802 } | |
468 | 803 |
804 LinkedList<REPCommand> returnCommand = new LinkedList<REPCommand>(); | |
805 for(REPCommand command : unMergedCmds) { | |
806 if (command.cmd==REP.REPCMD_INSERT||command.cmd==REP.REPCMD_DELETE) | |
807 returnCommand.add(createUndo(command)); | |
808 } | |
809 returnCommand.addAll(sortedEditCmds); | |
483 | 810 returnCommand.addLast(new REPCommand(REP.REPCMD_MERGE_MARK,0, sid, REP.MERGE_EID.id, seq(), "")); |
811 returnCommand.addAll(sentList); | |
468 | 812 unMergedCmds.clear(); |
813 logger.writeLog("MergeAgain "+eid+" ret="+returnCommand.size()); | |
814 mergeAgain = false; | |
483 | 815 optimizedSend(this, returnCommand); |
468 | 816 } |
817 // | |
818 // public boolean isFinished() { | |
819 // if(unMergedCmds.size() > 0) return false; | |
820 // if(sentMergedList.size() > 0) return false; | |
821 // return true; | |
822 // } | |
823 | |
824 public boolean isMerging() { | |
486 | 825 return merging; |
468 | 826 } |
827 | |
828 /** | |
829 * receive SMCMD_START_MERGE_ACK | |
830 */ | |
831 public void mergeAck() { | |
832 logger.writeLog("Editor"+eid+": START MERGE "+ | |
833 ((unMergedCmds.size()>0)?" and top of unMergedCmds = "+ unMergedCmds.getLast():"")); | |
486 | 834 merging = true; |
468 | 835 } |
836 | |
485 | 837 /** |
838 * Dead lock reporter | |
839 */ | |
840 public String report() { | |
841 String s = ""; | |
486 | 842 s += "\n sentList:"+sentList; |
485 | 843 s += "\n ackList:"+ackList; |
844 s += "\n unMergedList:"+unMergedCmds; | |
486 | 845 s += "\n mergeMode=:"+merging; |
485 | 846 return s; |
847 } | |
399 | 848 |
382
4b87f89b3afd
REP Session Manager (Java version)
one@firefly.cr.ie.u-ryukyu.ac.jp
parents:
diff
changeset
|
849 } |