Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

DfsReftableDatabase.java 7.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. /*
  2. * Copyright (C) 2017, Google Inc. and others
  3. *
  4. * This program and the accompanying materials are made available under the
  5. * terms of the Eclipse Distribution License v. 1.0 which is available at
  6. * https://www.eclipse.org/org/documents/edl-v10.php.
  7. *
  8. * SPDX-License-Identifier: BSD-3-Clause
  9. */
  10. package org.eclipse.jgit.internal.storage.dfs;
  11. import java.io.IOException;
  12. import java.util.Arrays;
  13. import java.util.HashSet;
  14. import java.util.List;
  15. import java.util.Map;
  16. import java.util.Set;
  17. import java.util.TreeSet;
  18. import java.util.concurrent.locks.Lock;
  19. import java.util.concurrent.locks.ReentrantLock;
  20. import org.eclipse.jgit.annotations.Nullable;
  21. import org.eclipse.jgit.internal.storage.reftable.MergedReftable;
  22. import org.eclipse.jgit.internal.storage.reftable.ReftableConfig;
  23. import org.eclipse.jgit.internal.storage.reftable.ReftableDatabase;
  24. import org.eclipse.jgit.lib.BatchRefUpdate;
  25. import org.eclipse.jgit.lib.NullProgressMonitor;
  26. import org.eclipse.jgit.lib.ObjectId;
  27. import org.eclipse.jgit.lib.Ref;
  28. import org.eclipse.jgit.revwalk.RevWalk;
  29. import org.eclipse.jgit.transport.ReceiveCommand;
  30. import org.eclipse.jgit.util.RefList;
  31. import org.eclipse.jgit.util.RefMap;
  32. /**
  33. * A {@link org.eclipse.jgit.internal.storage.dfs.DfsRefDatabase} that uses
  34. * reftable for storage.
  35. * <p>
  36. * A {@code DfsRefDatabase} instance is thread-safe.
  37. * <p>
  38. * Implementors may wish to use
  39. * {@link org.eclipse.jgit.internal.storage.dfs.DfsPackDescription#getMaxUpdateIndex()}
  40. * as the primary key identifier for a
  41. * {@link org.eclipse.jgit.internal.storage.pack.PackExt#REFTABLE} only pack
  42. * description, ensuring that when there are competing transactions one wins,
  43. * and one will fail.
  44. */
  45. public class DfsReftableDatabase extends DfsRefDatabase {
  46. final ReftableDatabase reftableDatabase;
  47. private DfsReader ctx;
  48. private DfsReftableStack stack;
  49. /**
  50. * Initialize the reference database for a repository.
  51. *
  52. * @param repo
  53. * the repository this database instance manages references for.
  54. */
  55. protected DfsReftableDatabase(DfsRepository repo) {
  56. super(repo);
  57. reftableDatabase = new ReftableDatabase() {
  58. @Override
  59. public MergedReftable openMergedReftable() throws IOException {
  60. Lock l = DfsReftableDatabase.this.getLock();
  61. l.lock();
  62. try {
  63. return new MergedReftable(stack().readers());
  64. } finally {
  65. l.unlock();
  66. }
  67. }
  68. };
  69. stack = null;
  70. }
  71. /** {@inheritDoc} */
  72. @Override
  73. public boolean hasVersioning() {
  74. return true;
  75. }
  76. /** {@inheritDoc} */
  77. @Override
  78. public boolean performsAtomicTransactions() {
  79. return true;
  80. }
  81. /** {@inheritDoc} */
  82. @Override
  83. public BatchRefUpdate newBatchUpdate() {
  84. DfsObjDatabase odb = getRepository().getObjectDatabase();
  85. return new DfsReftableBatchRefUpdate(this, odb);
  86. }
  87. /**
  88. * Get configuration to write new reftables with.
  89. *
  90. * @return configuration to write new reftables with.
  91. */
  92. public ReftableConfig getReftableConfig() {
  93. return new ReftableConfig(getRepository());
  94. }
  95. /**
  96. * Get the lock protecting this instance's state.
  97. *
  98. * @return the lock protecting this instance's state.
  99. */
  100. protected ReentrantLock getLock() {
  101. return reftableDatabase.getLock();
  102. }
  103. /**
  104. * Whether to compact reftable instead of extending the stack depth.
  105. *
  106. * @return {@code true} if commit of a new small reftable should try to
  107. * replace a prior small reftable by performing a compaction,
  108. * instead of extending the stack depth.
  109. */
  110. protected boolean compactDuringCommit() {
  111. return true;
  112. }
  113. /**
  114. * Obtain a handle to the stack of reftables. Must hold lock.
  115. *
  116. * @return (possibly cached) handle to the stack.
  117. * @throws java.io.IOException
  118. * if tables cannot be opened.
  119. */
  120. protected DfsReftableStack stack() throws IOException {
  121. if (!getLock().isLocked()) {
  122. throw new IllegalStateException("most hold lock to access stack"); //$NON-NLS-1$
  123. }
  124. DfsObjDatabase odb = getRepository().getObjectDatabase();
  125. if (ctx == null) {
  126. ctx = odb.newReader();
  127. }
  128. if (stack == null) {
  129. stack = DfsReftableStack.open(ctx, Arrays.asList(odb.getReftables()));
  130. }
  131. return stack;
  132. }
  133. @Override
  134. public boolean isNameConflicting(String refName) throws IOException {
  135. return reftableDatabase.isNameConflicting(refName, new TreeSet<>(), new HashSet<>());
  136. }
  137. /** {@inheritDoc} */
  138. @Override
  139. public Ref exactRef(String name) throws IOException {
  140. return reftableDatabase.exactRef(name);
  141. }
  142. /** {@inheritDoc} */
  143. @Override
  144. public Map<String, Ref> getRefs(String prefix) throws IOException {
  145. List<Ref> refs = reftableDatabase.getRefsByPrefix(prefix);
  146. RefList.Builder<Ref> builder = new RefList.Builder<>(refs.size());
  147. for (Ref r : refs) {
  148. builder.add(r);
  149. }
  150. return new RefMap(prefix, builder.toRefList(), RefList.emptyList(),
  151. RefList.emptyList());
  152. }
  153. /** {@inheritDoc} */
  154. @Override
  155. public List<Ref> getRefsByPrefix(String prefix) throws IOException {
  156. return reftableDatabase.getRefsByPrefix(prefix);
  157. }
  158. /** {@inheritDoc} */
  159. @Override
  160. public List<Ref> getRefsByPrefixWithExclusions(String include, Set<String> excludes)
  161. throws IOException {
  162. return reftableDatabase.getRefsByPrefixWithExclusions(include, excludes);
  163. }
  164. /** {@inheritDoc} */
  165. @Override
  166. public Set<Ref> getTipsWithSha1(ObjectId id) throws IOException {
  167. if (!getReftableConfig().isIndexObjects()) {
  168. return super.getTipsWithSha1(id);
  169. }
  170. return reftableDatabase.getTipsWithSha1(id);
  171. }
  172. /** {@inheritDoc} */
  173. @Override
  174. public boolean hasFastTipsWithSha1() throws IOException {
  175. return reftableDatabase.hasFastTipsWithSha1();
  176. }
  177. /** {@inheritDoc} */
  178. @Override
  179. public Ref peel(Ref ref) throws IOException {
  180. Ref oldLeaf = ref.getLeaf();
  181. if (oldLeaf.isPeeled() || oldLeaf.getObjectId() == null) {
  182. return ref;
  183. }
  184. return recreate(ref, doPeel(oldLeaf), hasVersioning());
  185. }
  186. @Override
  187. boolean exists() throws IOException {
  188. DfsObjDatabase odb = getRepository().getObjectDatabase();
  189. return odb.getReftables().length > 0;
  190. }
  191. @Override
  192. void clearCache() {
  193. ReentrantLock l = getLock();
  194. l.lock();
  195. try {
  196. if (ctx != null) {
  197. ctx.close();
  198. ctx = null;
  199. }
  200. reftableDatabase.clearCache();
  201. if (stack != null) {
  202. stack.close();
  203. stack = null;
  204. }
  205. } finally {
  206. l.unlock();
  207. }
  208. }
  209. /** {@inheritDoc} */
  210. @Override
  211. protected boolean compareAndPut(Ref oldRef, @Nullable Ref newRef)
  212. throws IOException {
  213. ReceiveCommand cmd = ReftableDatabase.toCommand(oldRef, newRef);
  214. try (RevWalk rw = new RevWalk(getRepository())) {
  215. rw.setRetainBody(false);
  216. newBatchUpdate().setAllowNonFastForwards(true).addCommand(cmd)
  217. .execute(rw, NullProgressMonitor.INSTANCE);
  218. }
  219. switch (cmd.getResult()) {
  220. case OK:
  221. return true;
  222. case REJECTED_OTHER_REASON:
  223. throw new IOException(cmd.getMessage());
  224. case LOCK_FAILURE:
  225. default:
  226. return false;
  227. }
  228. }
  229. /** {@inheritDoc} */
  230. @Override
  231. protected boolean compareAndRemove(Ref oldRef) throws IOException {
  232. return compareAndPut(oldRef, null);
  233. }
  234. /** {@inheritDoc} */
  235. @Override
  236. protected RefCache scanAllRefs() throws IOException {
  237. throw new UnsupportedOperationException();
  238. }
  239. @Override
  240. void stored(Ref ref) {
  241. // Unnecessary; DfsReftableBatchRefUpdate calls clearCache().
  242. }
  243. @Override
  244. void removed(String refName) {
  245. // Unnecessary; DfsReftableBatchRefUpdate calls clearCache().
  246. }
  247. /** {@inheritDoc} */
  248. @Override
  249. protected void cachePeeledState(Ref oldLeaf, Ref newLeaf) {
  250. // Do not cache peeled state in reftable.
  251. }
  252. }