390
|
1 package rep.handler;
|
|
2
|
|
3 import java.util.Comparator;
|
|
4 import java.util.LinkedList;
|
|
5 import java.util.List;
|
|
6 import java.util.TreeSet;
|
|
7
|
|
8 import rep.REP;
|
|
9 import rep.REPCommand;
|
407
|
10 import rep.SessionManager;
|
421
|
11 import rep.channel.REPLogger;
|
390
|
12 import rep.optimizers.REPCommandOptimizer;
|
|
13
|
|
14 public class Translator {
|
|
15 public int eid;
|
|
16
|
|
17 public REPCommandOptimizer optimizer;
|
|
18 private LinkedList<REPCommand> unMergedCmds;
|
438
|
19 private LinkedList<REPCommand> sentMergedList;
|
431
|
20 boolean mergeAgain;
|
421
|
21 public REPLogger logger = SessionManager.logger;
|
390
|
22 boolean merge_mode = false;
|
|
23
|
|
24 public Translator(int _eid,REPCommandOptimizer opt){
|
|
25 eid = _eid;
|
|
26 optimizer = opt;
|
|
27 unMergedCmds = new LinkedList<REPCommand>();
|
431
|
28 mergeAgain = false;
|
390
|
29 sentMergedList = new LinkedList<REPCommand>();
|
|
30 }
|
|
31
|
|
32 /**
|
|
33 * New command from an editor
|
|
34 * The command is sent to the next editor
|
|
35 * @param cmd
|
|
36 * @return translated command.
|
|
37 */
|
|
38 public REPCommand transSendCmd(REPCommand cmd){
|
|
39 assert(cmd.eid==eid);
|
431
|
40 unMergedCmds.addLast(cmd);
|
390
|
41
|
|
42 //マージ中にユーザから割り込みがあった場合
|
|
43 if(isMerging()){
|
431
|
44 mergeAgain = true;
|
390
|
45 }
|
|
46
|
|
47 return cmd;
|
|
48 }
|
431
|
49
|
390
|
50 /**
|
|
51 * My command is returned from the session ring, and START_MERGE_ACK
|
|
52 * is returned. At this
|
|
53 * stage my writeQueue is empty, our editor is waiting for me.
|
|
54 * Start merge process.
|
|
55 * @param cmd
|
|
56 */
|
435
|
57 public boolean catchOwnCommand(REPNode editor, REPCommand prev){
|
427
|
58 logger.writeLog("beforeMerge:"+unMergedCmds);
|
390
|
59 LinkedList<REPCommand> output = new LinkedList<REPCommand>();
|
427
|
60 // merge queue上にあるコマンドを全部undoコマンドするのと同時に
|
|
61 // sort したコマンド列を生成する
|
|
62 for( REPCommand cmd0 : unMergedCmds) {
|
390
|
63 output.add( createUndo(cmd0) );
|
431
|
64 }
|
434
|
65
|
435
|
66 TreeSet<REPCommand> cmds = new TreeSet<REPCommand>(new REPCommandComparator(1));
|
431
|
67 for( REPCommand cmd0 : editor.getSentList()) {
|
433
|
68 if (cmd0.cmd==REP.REPCMD_INSERT || cmd0.cmd==REP.REPCMD_DELETE)
|
|
69 cmds.add(cmd0);
|
390
|
70 }
|
435
|
71 logger.writeLog("Ediotr"+eid+" Merge:: sorted sent list => Eid="+eid+cmds+" ack="+prev);
|
390
|
72 output.addAll(cmds);
|
427
|
73 // ACKが来たものは必ず先頭
|
431
|
74
|
|
75 // unMerged command のdeleteのundo string は、この時点で使えない。
|
|
76 // Editor 側から送り返して来たものを使う必要がある。
|
|
77 unMergedCmds.clear();
|
426
|
78 logger.writeLog("outputMerge:"+output);
|
390
|
79 return optimizedSend(editor,output);
|
|
80 }
|
|
81
|
|
82 /**
|
|
83 * Sent optimized merged command list
|
|
84 * @param editor
|
|
85 * @param output
|
|
86 * @return if any sent commands output
|
|
87 */
|
|
88 public boolean optimizedSend(REPNode editor, LinkedList<REPCommand> output) {
|
439
|
89 sentMergedList.clear();
|
390
|
90 List<REPCommand> output1 = optimizer.optimize(output);
|
|
91 if (output1.size()==0) {
|
|
92 merge_mode = false;
|
|
93 return false;
|
|
94 }
|
|
95 for(REPCommand c:output1) {
|
|
96 REPCommand m = new REPCommand(c);
|
|
97 m.setEID(REP.MERGE_EID.id);
|
|
98 m.setSEQID(editor.seq());
|
|
99 sentMergedList.add(m);
|
|
100 editor.send(m);
|
|
101 }
|
|
102 merge_mode = true;
|
|
103 return true;
|
|
104 }
|
|
105
|
|
106 private REPCommand createUndo(REPCommand cmd){
|
|
107 REPCommand retCmd = new REPCommand(cmd);
|
|
108 if (cmd.cmd==REP.REPCMD_INSERT) retCmd.cmd=REP.REPCMD_DELETE;
|
|
109 else if (cmd.cmd==REP.REPCMD_DELETE) retCmd.cmd=REP.REPCMD_INSERT;
|
|
110 return retCmd;
|
|
111 }
|
|
112
|
|
113 class REPCommandComparator implements Comparator<REPCommand>{
|
431
|
114 int base;
|
|
115 REPCommandComparator(int base) {
|
|
116 this.base = base;
|
|
117 }
|
390
|
118 public int compare(REPCommand o1, REPCommand o2) {
|
431
|
119 int eid1 = o1.eid-base; if (eid1<0) eid1 += Integer.MAX_VALUE;
|
|
120 int eid2 = o2.eid-base; if (eid2<0) eid2 += Integer.MAX_VALUE;
|
|
121 if ( eid1<eid2 ) return -1;
|
|
122 if ( eid1>eid2 ) return 1;
|
427
|
123 if ( o1.seq<o2.seq ) return -1;
|
|
124 if ( o1.seq>o2.seq ) return 1;
|
|
125 assert(false);
|
|
126 return 0;
|
390
|
127 }
|
|
128 }
|
|
129
|
|
130 /**
|
439
|
131 * Translate Command that was received from SeMa.
|
390
|
132 * @param cmd the command to be translated.
|
439
|
133 * @return translated command.
|
390
|
134 */
|
|
135 public void transReceiveCmd(REPNode nextEditor,REPCommand cmd){
|
|
136 assert (cmd.eid != eid);
|
433
|
137 unMergedCmds.addFirst(cmd);
|
390
|
138 }
|
|
139
|
|
140 public void setEid(int _eid){
|
|
141 eid = _eid;
|
|
142 }
|
|
143
|
|
144 public boolean checkMergeConflict(REPCommand command) {
|
433
|
145 unMergedCmds.addFirst(command);
|
390
|
146
|
431
|
147 if (mergeAgain) {
|
390
|
148 return true;
|
|
149 }
|
440
|
150 REPCommand prev = sentMergedList.remove();
|
|
151 assert (prev.seq==command.seq);
|
390
|
152 if(sentMergedList.size()==0) {
|
|
153 merge_mode=false;
|
|
154 }
|
|
155 return false;
|
|
156 }
|
|
157
|
|
158 public void getMergeAgain(REPNode editor) {
|
|
159 LinkedList<REPCommand> returnCommand = new LinkedList<REPCommand>();
|
431
|
160 LinkedList<REPCommand> merge = new LinkedList<REPCommand>();
|
|
161 LinkedList<REPCommand> conflict = new LinkedList<REPCommand>();
|
|
162 for(REPCommand command : unMergedCmds) {
|
|
163 returnCommand.add(createUndo(command));
|
390
|
164 }
|
431
|
165 for(REPCommand command : unMergedCmds) {
|
390
|
166 if(command.eid == REP.MERGE_EID.id){
|
431
|
167 merge.addLast(command);
|
390
|
168 }
|
|
169 }
|
431
|
170 for(REPCommand command : unMergedCmds){
|
390
|
171 if(command.eid == eid){
|
|
172 command.eid = REP.MERGE_EID.id;
|
431
|
173 conflict.addLast(command);
|
390
|
174 }
|
|
175 }
|
431
|
176 unMergedCmds.clear();
|
|
177 returnCommand.addAll(merge);
|
|
178 returnCommand.addAll(conflict);
|
411
|
179 // int count = 0;
|
|
180 // for(REPCommand command: returnCommand) {
|
|
181 // switch(command.cmd) {
|
|
182 // case REPCMD_INSERT: count++; break;
|
|
183 // case REPCMD_DELETE: count--; break;
|
|
184 // default: assert false;
|
|
185 // }
|
|
186 // }
|
421
|
187 logger.writeLog("MergeAgain ret="+returnCommand.size());
|
411
|
188 // +" increment="+count);
|
431
|
189 mergeAgain = false;
|
390
|
190 optimizedSend(editor, returnCommand);
|
|
191 }
|
|
192
|
|
193 public boolean isFinished() {
|
|
194 if(unMergedCmds.size() > 0) return false;
|
|
195 if(sentMergedList.size() > 0) return false;
|
|
196 return true;
|
|
197 }
|
|
198
|
|
199 public boolean isMerging() {
|
|
200 return merge_mode;
|
|
201 }
|
|
202
|
|
203 public void startMerge(REPCommand cmd) {
|
431
|
204 logger.writeLog("START MERGE command ="+cmd+" and top of unMergedCmds = "+ unMergedCmds.getLast());
|
390
|
205 merge_mode = true;
|
|
206 }
|
|
207
|
|
208 public void mergeAck() {
|
|
209 }
|
|
210
|
|
211
|
|
212
|
|
213 }
|