1   /*
2    * Copyright 2017 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  
17  package com.linecorp.centraldogma.server.internal.storage.repository;
18  
19  import static java.util.Objects.requireNonNull;
20  
21  import java.util.concurrent.CompletableFuture;
22  import java.util.concurrent.locks.Lock;
23  import java.util.concurrent.locks.ReentrantLock;
24  
25  import com.google.common.base.MoreObjects;
26  
27  import com.linecorp.centraldogma.server.storage.repository.Repository;
28  
29  // XXX(trustin): Consider using reflection or AOP so that it takes less effort to add more call types.
30  public abstract class CacheableCall<T> {
31  
32      private static final Lock[] locks;
33  
34      static {
35          locks = new Lock[8192];
36          for (int i = 0; i < locks.length; i++) {
37              locks[i] = new ReentrantLock();
38          }
39      }
40  
41      final Repository repo;
42  
43      protected CacheableCall(Repository repo) {
44          this.repo = requireNonNull(repo, "repo");
45      }
46  
47      public final Repository repo() {
48          return repo;
49      }
50  
51      public final Lock coarseGrainedLock() {
52          return locks[Math.abs(hashCode() % locks.length)];
53      }
54  
55      protected abstract int weigh(T value);
56  
57      public abstract CompletableFuture<T> execute();
58  
59      @Override
60      public int hashCode() {
61          return System.identityHashCode(repo);
62      }
63  
64      @Override
65      public boolean equals(Object obj) {
66          if (obj == null) {
67              return false;
68          }
69  
70          if (obj == this) {
71              return true;
72          }
73  
74          if (getClass() != obj.getClass()) {
75              return false;
76          }
77  
78          final CacheableCall<?> that = (CacheableCall<?>) obj;
79          return repo == that.repo;
80      }
81  
82      @Override
83      public final String toString() {
84          final MoreObjects.ToStringHelper helper =
85                  MoreObjects.toStringHelper(this)
86                             .add("repo", repo.parent().name() + '/' + repo.name());
87          toString(helper);
88          return helper.toString();
89      }
90  
91      protected abstract void toString(MoreObjects.ToStringHelper helper);
92  }