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