diff options
Diffstat (limited to 'gerrit-server/src/main/java/com/google/gerrit/server/git/TagSet.java')
-rw-r--r-- | gerrit-server/src/main/java/com/google/gerrit/server/git/TagSet.java | 384 |
1 files changed, 0 insertions, 384 deletions
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/TagSet.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/TagSet.java deleted file mode 100644 index f131bc9856..0000000000 --- a/gerrit-server/src/main/java/com/google/gerrit/server/git/TagSet.java +++ /dev/null @@ -1,384 +0,0 @@ -// Copyright (C) 2011 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package com.google.gerrit.server.git; - -import static org.eclipse.jgit.lib.ObjectIdSerialization.readNotNull; -import static org.eclipse.jgit.lib.ObjectIdSerialization.writeNotNull; - -import com.google.gerrit.reviewdb.client.PatchSet; -import com.google.gerrit.reviewdb.client.Project; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.util.BitSet; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.atomic.AtomicReference; -import org.eclipse.jgit.errors.IncorrectObjectTypeException; -import org.eclipse.jgit.lib.AnyObjectId; -import org.eclipse.jgit.lib.Constants; -import org.eclipse.jgit.lib.ObjectId; -import org.eclipse.jgit.lib.ObjectIdOwnerMap; -import org.eclipse.jgit.lib.Ref; -import org.eclipse.jgit.lib.RefDatabase; -import org.eclipse.jgit.lib.Repository; -import org.eclipse.jgit.revwalk.RevCommit; -import org.eclipse.jgit.revwalk.RevSort; -import org.eclipse.jgit.revwalk.RevWalk; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -class TagSet { - private static final Logger log = LoggerFactory.getLogger(TagSet.class); - - private final Project.NameKey projectName; - private final Map<String, CachedRef> refs; - private final ObjectIdOwnerMap<Tag> tags; - - TagSet(Project.NameKey projectName) { - this.projectName = projectName; - this.refs = new HashMap<>(); - this.tags = new ObjectIdOwnerMap<>(); - } - - Tag lookupTag(AnyObjectId id) { - return tags.get(id); - } - - boolean updateFastForward(String refName, ObjectId oldValue, ObjectId newValue) { - CachedRef ref = refs.get(refName); - if (ref != null) { - // compareAndSet works on reference equality, but this operation - // wants to use object equality. Switch out oldValue with cur so the - // compareAndSet will function correctly for this operation. - // - ObjectId cur = ref.get(); - if (cur.equals(oldValue)) { - return ref.compareAndSet(cur, newValue); - } - } - return false; - } - - void prepare(TagMatcher m) { - @SuppressWarnings("resource") - RevWalk rw = null; - try { - for (Ref currentRef : m.include) { - if (currentRef.isSymbolic()) { - continue; - } - if (currentRef.getObjectId() == null) { - continue; - } - - CachedRef savedRef = refs.get(currentRef.getName()); - if (savedRef == null) { - // If the reference isn't known to the set, return null - // and force the caller to rebuild the set in a new copy. - m.newRefs.add(currentRef); - continue; - } - - // The reference has not been moved. It can be used as-is. - ObjectId savedObjectId = savedRef.get(); - if (currentRef.getObjectId().equals(savedObjectId)) { - m.mask.set(savedRef.flag); - continue; - } - - // Check on-the-fly to see if the branch still reaches the tag. - // This is very likely for a branch that fast-forwarded. - try { - if (rw == null) { - rw = new RevWalk(m.db); - rw.setRetainBody(false); - } - - RevCommit savedCommit = rw.parseCommit(savedObjectId); - RevCommit currentCommit = rw.parseCommit(currentRef.getObjectId()); - if (rw.isMergedInto(savedCommit, currentCommit)) { - // Fast-forward. Safely update the reference in-place. - savedRef.compareAndSet(savedObjectId, currentRef.getObjectId()); - m.mask.set(savedRef.flag); - continue; - } - - // The branch rewound. Walk the list of commits removed from - // the reference. If any matches to a tag, this has to be removed. - boolean err = false; - rw.reset(); - rw.markStart(savedCommit); - rw.markUninteresting(currentCommit); - rw.sort(RevSort.TOPO, true); - RevCommit c; - while ((c = rw.next()) != null) { - Tag tag = tags.get(c); - if (tag != null && tag.refFlags.get(savedRef.flag)) { - m.lostRefs.add(new TagMatcher.LostRef(tag, savedRef.flag)); - err = true; - } - } - if (!err) { - // All of the tags are still reachable. Update in-place. - savedRef.compareAndSet(savedObjectId, currentRef.getObjectId()); - m.mask.set(savedRef.flag); - } - - } catch (IOException err) { - // Defer a cache update until later. No conclusion can be made - // based on an exception reading from the repository storage. - log.warn("Error checking tags of " + projectName, err); - } - } - } finally { - if (rw != null) { - rw.close(); - } - } - } - - void build(Repository git, TagSet old, TagMatcher m) { - if (old != null && m != null && refresh(old, m)) { - return; - } - - try (TagWalk rw = new TagWalk(git)) { - rw.setRetainBody(false); - for (Ref ref : git.getRefDatabase().getRefs(RefDatabase.ALL).values()) { - if (skip(ref)) { - continue; - - } else if (isTag(ref)) { - // For a tag, remember where it points to. - addTag(rw, git.peel(ref)); - - } else { - // New reference to include in the set. - addRef(rw, ref); - } - } - - // Traverse the complete history. Copy any flags from a commit to - // all of its ancestors. This automatically updates any Tag object - // as the TagCommit and the stored Tag object share the same - // underlying bit set. - TagCommit c; - while ((c = (TagCommit) rw.next()) != null) { - BitSet mine = c.refFlags; - int pCnt = c.getParentCount(); - for (int pIdx = 0; pIdx < pCnt; pIdx++) { - ((TagCommit) c.getParent(pIdx)).refFlags.or(mine); - } - } - } catch (IOException e) { - log.warn("Error building tags for repository " + projectName, e); - } - } - - void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { - int refCnt = in.readInt(); - for (int i = 0; i < refCnt; i++) { - String name = in.readUTF(); - int flag = in.readInt(); - ObjectId id = readNotNull(in); - refs.put(name, new CachedRef(flag, id)); - } - - int tagCnt = in.readInt(); - for (int i = 0; i < tagCnt; i++) { - ObjectId id = readNotNull(in); - BitSet flags = (BitSet) in.readObject(); - tags.add(new Tag(id, flags)); - } - } - - void writeObject(ObjectOutputStream out) throws IOException { - out.writeInt(refs.size()); - for (Map.Entry<String, CachedRef> e : refs.entrySet()) { - out.writeUTF(e.getKey()); - out.writeInt(e.getValue().flag); - writeNotNull(out, e.getValue().get()); - } - - out.writeInt(tags.size()); - for (Tag tag : tags) { - writeNotNull(out, tag); - out.writeObject(tag.refFlags); - } - } - - private boolean refresh(TagSet old, TagMatcher m) { - if (m.newRefs.isEmpty()) { - // No new references is a simple update. Copy from the old set. - copy(old, m); - return true; - } - - // Only permit a refresh if all new references start from the tip of - // an existing references. This happens some of the time within a - // Gerrit Code Review server, perhaps about 50% of new references. - // Since a complete rebuild is so costly, try this approach first. - - Map<ObjectId, Integer> byObj = new HashMap<>(); - for (CachedRef r : old.refs.values()) { - ObjectId id = r.get(); - if (!byObj.containsKey(id)) { - byObj.put(id, r.flag); - } - } - - for (Ref newRef : m.newRefs) { - ObjectId id = newRef.getObjectId(); - if (id == null || refs.containsKey(newRef.getName())) { - continue; - } else if (!byObj.containsKey(id)) { - return false; - } - } - - copy(old, m); - - for (Ref newRef : m.newRefs) { - ObjectId id = newRef.getObjectId(); - if (id == null || refs.containsKey(newRef.getName())) { - continue; - } - - int srcFlag = byObj.get(id); - int newFlag = refs.size(); - refs.put(newRef.getName(), new CachedRef(newRef, newFlag)); - - for (Tag tag : tags) { - if (tag.refFlags.get(srcFlag)) { - tag.refFlags.set(newFlag); - } - } - } - - return true; - } - - private void copy(TagSet old, TagMatcher m) { - refs.putAll(old.refs); - - for (Tag srcTag : old.tags) { - BitSet mine = new BitSet(); - mine.or(srcTag.refFlags); - tags.add(new Tag(srcTag, mine)); - } - - for (TagMatcher.LostRef lost : m.lostRefs) { - Tag mine = tags.get(lost.tag); - if (mine != null) { - mine.refFlags.clear(lost.flag); - } - } - } - - private void addTag(TagWalk rw, Ref ref) { - ObjectId id = ref.getPeeledObjectId(); - if (id == null) { - id = ref.getObjectId(); - } - - if (!tags.contains(id)) { - BitSet flags; - try { - flags = ((TagCommit) rw.parseCommit(id)).refFlags; - } catch (IncorrectObjectTypeException notCommit) { - flags = new BitSet(); - } catch (IOException e) { - log.warn("Error on " + ref.getName() + " of " + projectName, e); - flags = new BitSet(); - } - tags.add(new Tag(id, flags)); - } - } - - private void addRef(TagWalk rw, Ref ref) { - try { - TagCommit commit = (TagCommit) rw.parseCommit(ref.getObjectId()); - rw.markStart(commit); - - int flag = refs.size(); - commit.refFlags.set(flag); - refs.put(ref.getName(), new CachedRef(ref, flag)); - } catch (IncorrectObjectTypeException notCommit) { - // No need to spam the logs. - // Quite many refs will point to non-commits. - // For instance, refs from refs/cache-automerge - // will often end up here. - } catch (IOException e) { - log.warn("Error on " + ref.getName() + " of " + projectName, e); - } - } - - static boolean skip(Ref ref) { - return ref.isSymbolic() || ref.getObjectId() == null || PatchSet.isChangeRef(ref.getName()); - } - - private static boolean isTag(Ref ref) { - return ref.getName().startsWith(Constants.R_TAGS); - } - - static final class Tag extends ObjectIdOwnerMap.Entry { - private final BitSet refFlags; - - Tag(AnyObjectId id, BitSet flags) { - super(id); - this.refFlags = flags; - } - - boolean has(BitSet mask) { - return refFlags.intersects(mask); - } - } - - private static final class CachedRef extends AtomicReference<ObjectId> { - private static final long serialVersionUID = 1L; - - final int flag; - - CachedRef(Ref ref, int flag) { - this(flag, ref.getObjectId()); - } - - CachedRef(int flag, ObjectId id) { - this.flag = flag; - set(id); - } - } - - private static final class TagWalk extends RevWalk { - TagWalk(Repository git) { - super(git); - } - - @Override - protected TagCommit createCommit(AnyObjectId id) { - return new TagCommit(id); - } - } - - private static final class TagCommit extends RevCommit { - final BitSet refFlags; - - TagCommit(AnyObjectId id) { - super(id); - refFlags = new BitSet(); - } - } -} |