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