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