1   /*
2    * Copyright 2019 LINE Corporation
3    *
4    * LINE Corporation licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package com.linecorp.centraldogma.server.internal.storage.repository.git;
17  
18  import static com.linecorp.centraldogma.server.internal.storage.repository.RepositoryCache.logger;
19  
20  import java.util.List;
21  import java.util.Objects;
22  import java.util.concurrent.CompletableFuture;
23  
24  import javax.annotation.Nullable;
25  
26  import org.eclipse.jgit.attributes.Attribute;
27  import org.eclipse.jgit.diff.DiffEntry;
28  import org.eclipse.jgit.revwalk.RevTree;
29  import org.eclipse.jgit.treewalk.filter.TreeFilter;
30  
31  import com.google.common.base.MoreObjects.ToStringHelper;
32  
33  import com.linecorp.centraldogma.server.storage.repository.AbstractCacheableCall;
34  
35  final class CacheableCompareTreesCall extends AbstractCacheableCall<List<DiffEntry>> {
36  
37      private static final int SHA1_LEN = 20;
38  
39      private final GitRepository repo;
40      @Nullable
41      private final RevTree treeA;
42      @Nullable
43      private final RevTree treeB;
44      private final int hashCode;
45  
46      CacheableCompareTreesCall(GitRepository repo, @Nullable RevTree treeA, @Nullable RevTree treeB) {
47          super(repo);
48          this.repo = repo;
49  
50          this.treeA = treeA;
51          this.treeB = treeB;
52          hashCode = Objects.hash(treeA, treeB) * 31 + System.identityHashCode(repo);
53      }
54  
55      @Override
56      public int weigh(List<DiffEntry> value) {
57          int weight = SHA1_LEN * 2;
58          for (DiffEntry e : value) {
59              if (e.getOldId() != null) {
60                  weight += SHA1_LEN;
61              }
62              if (e.getNewId() != null) {
63                  weight += SHA1_LEN;
64              }
65              if (e.getOldPath() != null) {
66                  weight += e.getOldPath().length();
67              }
68              if (e.getNewPath() != null) {
69                  weight += e.getNewPath().length();
70              }
71              final Attribute attr = e.getDiffAttribute();
72              if (attr != null) {
73                  if (attr.getKey() != null) {
74                      weight += attr.getKey().length();
75                  }
76                  if (attr.getValue() != null) {
77                      weight += attr.getValue().length();
78                  }
79              }
80          }
81          return weight;
82      }
83  
84      /**
85       * Never invoked because {@link GitRepository} produces the value of this call.
86       */
87      @Override
88      public CompletableFuture<List<DiffEntry>> execute() {
89          logger.debug("Cache miss: {}", this);
90          final List<DiffEntry> diffEntries = repo.blockingCompareTreesUncached(treeA, treeB, TreeFilter.ALL);
91          return CompletableFuture.completedFuture(diffEntries);
92      }
93  
94      @Override
95      public int hashCode() {
96          return hashCode;
97      }
98  
99      @Override
100     public boolean equals(Object o) {
101         if (!super.equals(o)) {
102             return false;
103         }
104 
105         final CacheableCompareTreesCall that = (CacheableCompareTreesCall) o;
106         return Objects.equals(treeA, that.treeA) &&
107                Objects.equals(treeB, that.treeB);
108     }
109 
110     @Override
111     protected void toString(ToStringHelper helper) {
112         helper.add("treeA", treeA != null ? treeA.getName() : null)
113               .add("treeB", treeB != null ? treeB.getName() : null);
114     }
115 }