324
|
1 package rep.translator;
|
|
2
|
|
3 import java.util.Collection;
|
|
4 import java.util.Comparator;
|
|
5 import java.util.LinkedList;
|
326
|
6 import java.util.List;
|
324
|
7 import java.util.TreeSet;
|
|
8
|
|
9 import rep.Editor;
|
|
10 import rep.Forwarder;
|
|
11 import rep.REPCommand;
|
|
12 import rep.REP;
|
326
|
13 import rep.optimizers.REPCommandOptimizer;
|
324
|
14
|
|
15 public class TranslatorImpl implements Translator{
|
|
16 public int eid;
|
|
17 /*
|
|
18 * queue が5つもいるって、あまりに馬鹿げてる。
|
|
19 */
|
326
|
20 public REPCommandOptimizer optimizer;
|
|
21 private LinkedList<REPCommand> unMergedCmds;
|
324
|
22 public LinkedList<REPCommand> sentMergedList;
|
|
23 private LinkedList<REPCommand> mergeAgainList;
|
|
24 boolean merge_mode = false;
|
|
25
|
326
|
26 public TranslatorImpl(int _eid,REPCommandOptimizer opt){
|
324
|
27 eid = _eid;
|
326
|
28 optimizer = opt;
|
|
29 unMergedCmds = new LinkedList<REPCommand>();
|
324
|
30 mergeAgainList = new LinkedList<REPCommand>();
|
|
31 sentMergedList = new LinkedList<REPCommand>();
|
|
32 }
|
|
33
|
|
34 /**
|
|
35 * New command from an editor
|
|
36 * The command is sent to the next editor
|
|
37 * @param cmd
|
|
38 * @return translated command.
|
|
39 */
|
|
40 public REPCommand transSendCmd(REPCommand cmd){
|
327
|
41 assert(cmd.eid==eid);
|
326
|
42 unMergedCmds.add(cmd);
|
324
|
43
|
|
44 //マージ中にユーザから割り込みがあった場合
|
|
45 if(isMerging()){
|
|
46 mergeAgainList.add(cmd);
|
|
47 }
|
|
48
|
|
49 return cmd;
|
|
50 }
|
|
51 /**
|
325
|
52 * My command is returned from the session ring, and START_MERGE_ACK
|
|
53 * is returned. At this
|
|
54 * stage my writeQueue is empty, our editor is waiting for me.
|
324
|
55 * Start merge process.
|
|
56 * @param cmd
|
|
57 */
|
|
58 public boolean catchOwnCommand(Editor editor){
|
|
59 LinkedList<REPCommand> output = new LinkedList<REPCommand>();
|
|
60 LinkedList<REPCommand> cmds = new LinkedList<REPCommand>();
|
|
61 //スタック上にあるコマンドを全部undoコマンドにする
|
|
62 while ( !unMergedCmds.isEmpty() ){
|
326
|
63 REPCommand cmd0 = unMergedCmds.removeLast();
|
324
|
64 output.add( createUndo(cmd0) );
|
|
65 cmds.add(cmd0);
|
|
66 }
|
|
67
|
|
68 /* 必要な分だけソートして返却用のリストに追加 */
|
|
69 output.addAll( sortCmds(cmds) );
|
|
70
|
|
71 /* 残ったコマンドも再び実行させるが、まだマージされてないのでunMergedにも入れる */
|
|
72 output.addAll(cmds);
|
|
73 for(REPCommand c: cmds) {
|
|
74 output.add(c);
|
326
|
75 unMergedCmds.add(c);
|
324
|
76 }
|
326
|
77 return optimizedSend(editor,output);
|
324
|
78 }
|
|
79
|
326
|
80 /**
|
|
81 * Sent optimized merged command list
|
|
82 * @param editor
|
|
83 * @param output
|
|
84 * @return if any sent commands output
|
|
85 */
|
|
86 public boolean optimizedSend(Editor editor, LinkedList<REPCommand> output) {
|
|
87 List<REPCommand> output1 = optimizer.optimize(output);
|
|
88 if (output1.size()==0) {
|
|
89 merge_mode = false;
|
|
90 return false;
|
|
91 }
|
|
92 for(REPCommand c:output1) {
|
|
93 REPCommand m = new REPCommand(c);
|
|
94 m.setEID(REP.MERGE_EID.id);
|
|
95 m.setSEQID(editor.seq());
|
|
96 sentMergedList.add(m);
|
|
97 editor.send(m);
|
|
98 }
|
|
99 return true;
|
|
100 }
|
|
101
|
324
|
102 private REPCommand createUndo(REPCommand cmd){
|
|
103 REPCommand retCmd = new REPCommand(cmd);
|
|
104 if (cmd.cmd==REP.REPCMD_INSERT) retCmd.cmd=REP.REPCMD_DELETE;
|
|
105 else if (cmd.cmd==REP.REPCMD_DELETE) retCmd.cmd=REP.REPCMD_INSERT;
|
|
106 return retCmd;
|
|
107 }
|
|
108
|
|
109 class REPCommandComparator implements Comparator<REPCommand>{
|
|
110
|
|
111 public int compare(REPCommand o1, REPCommand o2) {
|
|
112
|
|
113 if ( o2.lineno > o1.lineno ) return 1;
|
|
114 else if ( o2.lineno < o1.lineno
|
|
115 || o2.eid > o1.eid )
|
|
116 return -1;
|
|
117
|
|
118 return 1;
|
|
119 }
|
|
120
|
|
121 }
|
|
122
|
|
123 private Collection<REPCommand> sortCmds(LinkedList<REPCommand> cmds) {
|
|
124 TreeSet<REPCommand> sortedCmds1 = new TreeSet<REPCommand>(new REPCommandComparator());
|
|
125 int top;
|
|
126 int prevEid=-1;
|
|
127 while ( -1 != (top=getPrecedence(cmds, prevEid+1)) ){
|
|
128 REPCommand tmp = cmds.remove(top);
|
|
129 sortedCmds1.add(tmp);
|
|
130 prevEid = tmp.eid;
|
|
131 }
|
|
132
|
|
133 return sortedCmds1;
|
|
134 }
|
|
135
|
|
136 /* search cmd. ordering by min EID that is lower lowEid and min SEQ. */
|
|
137 private int getPrecedence(LinkedList<REPCommand> cmds, int lowEid) {
|
|
138 int cEid, cSeq;
|
|
139 cEid=cSeq=Integer.MAX_VALUE;
|
|
140 int ret=-1;
|
|
141 for (int i=0; i<cmds.size(); i++){
|
|
142 REPCommand c = cmds.get(i);
|
|
143 if ( c.eid<lowEid ) continue;
|
|
144 else if ( c.eid>cEid ) continue;
|
|
145 else if ( c.eid==cEid ) {
|
|
146 if ( c.seq>cSeq ) continue;
|
|
147 cSeq=c.seq;
|
|
148 ret = i;
|
|
149 } else { /* tmp.eid<cEid */
|
|
150 cEid = c.eid;
|
|
151 cSeq = c.seq;
|
|
152 ret = i;
|
|
153 }
|
|
154 }
|
|
155 return ret;
|
|
156 }
|
|
157
|
|
158 /**
|
|
159 * Translate Command cmd that was received from SeMa.
|
|
160 * @param cmd the command to be translated.
|
|
161 * @return translated commannd.
|
|
162 */
|
|
163 public void transReceiveCmd(Forwarder nextEditor,REPCommand cmd){
|
|
164 assert (cmd.eid != eid);
|
|
165 // nop command の挿入は Editor 側で行って、こちら側ではやらない
|
326
|
166 unMergedCmds.add(cmd);
|
324
|
167 nextEditor.send(cmd);
|
|
168 }
|
|
169
|
|
170 public void setEid(int _eid){
|
|
171 eid = _eid;
|
|
172 }
|
|
173
|
|
174 public boolean checkMergeConflict(REPCommand command) {
|
326
|
175 REPCommand prev = sentMergedList.remove();
|
|
176 assert (prev.seq==command.seq);
|
324
|
177
|
|
178 if(mergeAgainList.size() > 0){
|
|
179 mergeAgainList.add(command);
|
326
|
180 return true;
|
324
|
181 }
|
326
|
182 if(sentMergedList.size()==0) {
|
|
183 merge_mode=false;
|
|
184 }
|
324
|
185 return false;
|
|
186 }
|
|
187
|
326
|
188 public void getMergeAgain(Editor editor) {
|
324
|
189 LinkedList<REPCommand> returnCommand = new LinkedList<REPCommand>();
|
|
190 for(int i = 0; i < mergeAgainList.size(); i++){
|
|
191 //eid = REP.MEGE_EID
|
|
192 returnCommand.add(createUndo(mergeAgainList.get(mergeAgainList.size() - i -1)));
|
|
193 }
|
|
194 for(REPCommand command : mergeAgainList){
|
|
195 if(command.eid == REP.MERGE_EID.id){
|
|
196 returnCommand.add(command);
|
|
197 }
|
|
198 }
|
|
199 for(REPCommand command : mergeAgainList){
|
|
200 if(command.eid == eid){
|
|
201 command.eid = REP.MERGE_EID.id;
|
|
202 returnCommand.add(command);
|
|
203 }
|
|
204 }
|
|
205 mergeAgainList.clear();
|
326
|
206 optimizedSend(editor, returnCommand);
|
324
|
207 }
|
|
208
|
|
209 public boolean isFinished() {
|
|
210 if(unMergedCmds.size() > 0) return false;
|
|
211 if(sentMergedList.size() > 0) return false;
|
|
212 return true;
|
|
213 }
|
|
214
|
|
215 public boolean isMerging() {
|
|
216 return merge_mode;
|
|
217 }
|
|
218
|
|
219 public void startMerge(REPCommand cmd) {
|
|
220 merge_mode = true;
|
|
221 }
|
|
222
|
|
223 public void mergeAck() {
|
|
224 }
|
|
225
|
|
226
|
|
227
|
|
228
|
|
229 }
|