| // 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 java.util.stream.Collectors.toList; |
| |
| import com.google.gerrit.common.Nullable; |
| import com.google.gerrit.entities.Project; |
| import com.google.gerrit.proto.Protos; |
| import com.google.gerrit.server.cache.proto.Cache.TagSetHolderProto; |
| import com.google.gerrit.server.cache.serialize.CacheSerializer; |
| import java.util.Collection; |
| import org.eclipse.jgit.lib.Ref; |
| import org.eclipse.jgit.lib.Repository; |
| |
| public class TagSetHolder { |
| private final Object buildLock = new Object(); |
| private final Project.NameKey projectName; |
| |
| @Nullable private volatile TagSet tags; |
| |
| TagSetHolder(Project.NameKey projectName) { |
| this.projectName = projectName; |
| } |
| |
| Project.NameKey getProjectName() { |
| return projectName; |
| } |
| |
| TagSet getTagSet() { |
| return tags; |
| } |
| |
| void setTagSet(TagSet tags) { |
| this.tags = tags; |
| } |
| |
| public TagMatcher matcher(TagCache cache, Repository db, Collection<Ref> include) { |
| include = include.stream().filter(r -> !TagSet.skip(r)).collect(toList()); |
| |
| TagSet tags = this.tags; |
| if (tags == null) { |
| tags = build(cache, db); |
| } |
| |
| TagMatcher m = new TagMatcher(this, cache, db, include, tags, false); |
| tags.prepare(m); |
| if (!m.newRefs.isEmpty() || !m.lostRefs.isEmpty()) { |
| tags = rebuild(cache, db, tags, m); |
| |
| m = new TagMatcher(this, cache, db, include, tags, true); |
| tags.prepare(m); |
| } |
| return m; |
| } |
| |
| void rebuildForNewTags(TagCache cache, TagMatcher m) { |
| m.tags = rebuild(cache, m.db, m.tags, null); |
| m.mask.clear(); |
| m.newRefs.clear(); |
| m.lostRefs.clear(); |
| m.tags.prepare(m); |
| } |
| |
| private TagSet build(TagCache cache, Repository db) { |
| synchronized (buildLock) { |
| TagSet tags = this.tags; |
| if (tags == null) { |
| tags = new TagSet(projectName); |
| tags.build(db, null, null); |
| this.tags = tags; |
| cache.put(projectName, this); |
| } |
| return tags; |
| } |
| } |
| |
| private TagSet rebuild(TagCache cache, Repository db, TagSet old, TagMatcher m) { |
| synchronized (buildLock) { |
| TagSet cur = this.tags; |
| if (cur == old) { |
| cur = new TagSet(projectName); |
| cur.build(db, old, m); |
| this.tags = cur; |
| cache.put(projectName, this); |
| } |
| return cur; |
| } |
| } |
| |
| enum Serializer implements CacheSerializer<TagSetHolder> { |
| INSTANCE; |
| |
| @Override |
| public byte[] serialize(TagSetHolder object) { |
| TagSetHolderProto.Builder b = |
| TagSetHolderProto.newBuilder().setProjectName(object.projectName.get()); |
| TagSet tags = object.tags; |
| if (tags != null) { |
| b.setTags(tags.toProto()); |
| } |
| return Protos.toByteArray(b.build()); |
| } |
| |
| @Override |
| public TagSetHolder deserialize(byte[] in) { |
| TagSetHolderProto proto = Protos.parseUnchecked(TagSetHolderProto.parser(), in); |
| TagSetHolder holder = new TagSetHolder(Project.nameKey(proto.getProjectName())); |
| if (proto.hasTags()) { |
| holder.tags = TagSet.fromProto(proto.getTags()); |
| } |
| return holder; |
| } |
| } |
| } |