1
2
3
4
5
6
7
8
9
10
11 package org.eclipse.jgit.internal.ketch;
12
13 import static org.eclipse.jgit.internal.ketch.KetchReplica.State.AHEAD;
14 import static org.eclipse.jgit.internal.ketch.KetchReplica.State.DIVERGENT;
15 import static org.eclipse.jgit.internal.ketch.KetchReplica.State.LAGGING;
16 import static org.eclipse.jgit.internal.ketch.KetchReplica.State.UNKNOWN;
17 import static org.eclipse.jgit.lib.Constants.OBJ_COMMIT;
18
19 import java.io.IOException;
20 import java.util.Collections;
21 import java.util.Map;
22
23 import org.eclipse.jgit.errors.MissingObjectException;
24 import org.eclipse.jgit.lib.AnyObjectId;
25 import org.eclipse.jgit.lib.ObjectId;
26 import org.eclipse.jgit.lib.Ref;
27 import org.eclipse.jgit.lib.Repository;
28 import org.eclipse.jgit.revwalk.RevCommit;
29 import org.eclipse.jgit.revwalk.RevWalk;
30 import org.eclipse.jgit.transport.ReceiveCommand;
31
32
33
34
35 class LagCheck implements AutoCloseable {
36 private final KetchReplica replica;
37 private final Repository repo;
38 private RevWalk rw;
39 private ObjectId remoteId;
40
41 LagCheck(KetchReplica replica, Repository repo) {
42 this.replica = replica;
43 this.repo = repo;
44 initRevWalk();
45 }
46
47 private void initRevWalk() {
48 if (rw != null) {
49 rw.close();
50 }
51
52 rw = new RevWalk(repo);
53 rw.setRetainBody(false);
54 }
55
56
57 @Override
58 public void close() {
59 if (rw != null) {
60 rw.close();
61 rw = null;
62 }
63 }
64
65 ObjectId getRemoteId() {
66 return remoteId;
67 }
68
69 KetchReplica.State check(ObjectId acceptId, ReceiveCommand acceptCmd) {
70 remoteId = acceptId;
71 if (remoteId == null) {
72
73 return UNKNOWN;
74 }
75
76 if (AnyObjectId.isEqual(remoteId, ObjectId.zeroId())) {
77
78 return LAGGING;
79 }
80
81 try {
82 RevCommit remote;
83 try {
84 remote = parseRemoteCommit(acceptCmd.getRefName());
85 } catch (RefGoneException gone) {
86
87 return LAGGING;
88 } catch (MissingObjectException notFound) {
89
90
91 return DIVERGENT;
92 }
93
94 RevCommit head = rw.parseCommit(acceptCmd.getNewId());
95 if (rw.isMergedInto(remote, head)) {
96 return LAGGING;
97 }
98
99
100 if (rw.isMergedInto(head, remote)) {
101 return AHEAD;
102 }
103 return DIVERGENT;
104 } catch (IOException err) {
105 KetchReplica.log.error(String.format(
106 "Cannot compare %s",
107 acceptCmd.getRefName()), err);
108 return UNKNOWN;
109 }
110 }
111
112 private RevCommit parseRemoteCommit(String refName)
113 throws IOException, MissingObjectException, RefGoneException {
114 try {
115 return rw.parseCommit(remoteId);
116 } catch (MissingObjectException notLocal) {
117
118 }
119
120 ReplicaFetchRequest fetch = new ReplicaFetchRequest(
121 Collections.singleton(refName),
122 Collections.<ObjectId> emptySet());
123 try {
124 replica.blockingFetch(repo, fetch);
125 } catch (IOException fetchErr) {
126 KetchReplica.log.error(String.format(
127 "Cannot fetch %s (%s) from %s",
128 remoteId.abbreviate(8).name(), refName,
129 replica.describeForLog()), fetchErr);
130 throw new MissingObjectException(remoteId, OBJ_COMMIT);
131 }
132
133 Map<String, Ref> adv = fetch.getRefs();
134 if (adv == null) {
135 throw new MissingObjectException(remoteId, OBJ_COMMIT);
136 }
137
138 Ref ref = adv.get(refName);
139 if (ref == null || ref.getObjectId() == null) {
140 throw new RefGoneException();
141 }
142
143 initRevWalk();
144 remoteId = ref.getObjectId();
145 return rw.parseCommit(remoteId);
146 }
147
148 private static class RefGoneException extends Exception {
149 private static final long serialVersionUID = 1L;
150 }
151 }