You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

RepositoryCacheTest.java 9.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. /*
  2. * Copyright (C) 2009, 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.lib;
  11. import static org.hamcrest.CoreMatchers.hasItem;
  12. import static org.hamcrest.MatcherAssert.assertThat;
  13. import static org.junit.Assert.assertEquals;
  14. import static org.junit.Assert.assertFalse;
  15. import static org.junit.Assert.assertNotNull;
  16. import static org.junit.Assert.assertNotSame;
  17. import static org.junit.Assert.assertSame;
  18. import static org.junit.Assert.assertTrue;
  19. import static org.junit.Assert.fail;
  20. import java.io.File;
  21. import java.io.IOException;
  22. import org.eclipse.jgit.errors.RepositoryNotFoundException;
  23. import org.eclipse.jgit.junit.RepositoryTestCase;
  24. import org.eclipse.jgit.lib.RepositoryCache.FileKey;
  25. import org.junit.Test;
  26. public class RepositoryCacheTest extends RepositoryTestCase {
  27. @Test
  28. public void testNonBareFileKey() throws IOException {
  29. File gitdir = db.getDirectory();
  30. File parent = gitdir.getParentFile();
  31. File other = new File(parent, "notagit");
  32. assertEqualsFile(gitdir, FileKey.exact(gitdir, db.getFS()).getFile());
  33. assertEqualsFile(parent, FileKey.exact(parent, db.getFS()).getFile());
  34. assertEqualsFile(other, FileKey.exact(other, db.getFS()).getFile());
  35. assertEqualsFile(gitdir, FileKey.lenient(gitdir, db.getFS()).getFile());
  36. assertEqualsFile(gitdir, FileKey.lenient(parent, db.getFS()).getFile());
  37. assertEqualsFile(other, FileKey.lenient(other, db.getFS()).getFile());
  38. }
  39. @Test
  40. public void testBareFileKey() throws IOException {
  41. Repository bare = createBareRepository();
  42. File gitdir = bare.getDirectory();
  43. File parent = gitdir.getParentFile();
  44. String name = gitdir.getName();
  45. assertTrue(name.endsWith(".git"));
  46. name = name.substring(0, name.length() - 4);
  47. assertEqualsFile(gitdir, FileKey.exact(gitdir, db.getFS()).getFile());
  48. assertEqualsFile(gitdir, FileKey.lenient(gitdir, db.getFS()).getFile());
  49. assertEqualsFile(gitdir,
  50. FileKey.lenient(new File(parent, name), db.getFS()).getFile());
  51. }
  52. @Test
  53. public void testFileKeyOpenExisting() throws IOException {
  54. try (Repository r = new FileKey(db.getDirectory(), db.getFS())
  55. .open(true)) {
  56. assertNotNull(r);
  57. assertEqualsFile(db.getDirectory(), r.getDirectory());
  58. }
  59. try (Repository r = new FileKey(db.getDirectory(), db.getFS())
  60. .open(false)) {
  61. assertNotNull(r);
  62. assertEqualsFile(db.getDirectory(), r.getDirectory());
  63. }
  64. }
  65. @Test
  66. public void testFileKeyOpenNew() throws IOException {
  67. File gitdir;
  68. try (Repository n = createRepository(true)) {
  69. gitdir = n.getDirectory();
  70. }
  71. recursiveDelete(gitdir);
  72. assertFalse(gitdir.exists());
  73. try {
  74. new FileKey(gitdir, db.getFS()).open(true);
  75. fail("incorrectly opened a non existant repository");
  76. } catch (RepositoryNotFoundException e) {
  77. assertEquals("repository not found: " + gitdir.getCanonicalPath(),
  78. e.getMessage());
  79. }
  80. final Repository o = new FileKey(gitdir, db.getFS()).open(false);
  81. assertNotNull(o);
  82. assertEqualsFile(gitdir, o.getDirectory());
  83. assertFalse(gitdir.exists());
  84. }
  85. @Test
  86. public void testCacheRegisterOpen() throws Exception {
  87. final File dir = db.getDirectory();
  88. RepositoryCache.register(db);
  89. assertSame(db, RepositoryCache.open(FileKey.exact(dir, db.getFS())));
  90. assertEquals(".git", dir.getName());
  91. final File parent = dir.getParentFile();
  92. assertSame(db, RepositoryCache.open(FileKey.lenient(parent, db.getFS())));
  93. }
  94. @Test
  95. public void testCacheOpen() throws Exception {
  96. final FileKey loc = FileKey.exact(db.getDirectory(), db.getFS());
  97. @SuppressWarnings("resource") // We are testing the close() method
  98. final Repository d2 = RepositoryCache.open(loc);
  99. assertNotSame(db, d2);
  100. assertSame(d2, RepositoryCache.open(FileKey.exact(loc.getFile(), db.getFS())));
  101. d2.close();
  102. d2.close();
  103. }
  104. @Test
  105. public void testGetRegisteredWhenEmpty() {
  106. assertEquals(0, RepositoryCache.getRegisteredKeys().size());
  107. }
  108. @Test
  109. public void testGetRegistered() {
  110. RepositoryCache.register(db);
  111. assertThat(RepositoryCache.getRegisteredKeys(),
  112. hasItem(FileKey.exact(db.getDirectory(), db.getFS())));
  113. assertEquals(1, RepositoryCache.getRegisteredKeys().size());
  114. }
  115. @Test
  116. public void testUnregister() {
  117. RepositoryCache.register(db);
  118. RepositoryCache
  119. .unregister(FileKey.exact(db.getDirectory(), db.getFS()));
  120. assertEquals(0, RepositoryCache.getRegisteredKeys().size());
  121. }
  122. @Test
  123. public void testRepositoryUsageCount() throws Exception {
  124. FileKey loc = FileKey.exact(db.getDirectory(), db.getFS());
  125. @SuppressWarnings("resource") // We are testing the close() method
  126. Repository d2 = RepositoryCache.open(loc);
  127. assertEquals(1, d2.useCnt.get());
  128. RepositoryCache.open(FileKey.exact(loc.getFile(), db.getFS()));
  129. assertEquals(2, d2.useCnt.get());
  130. d2.close();
  131. assertEquals(1, d2.useCnt.get());
  132. d2.close();
  133. assertEquals(0, d2.useCnt.get());
  134. }
  135. @Test
  136. public void testRepositoryUsageCountWithRegisteredRepository()
  137. throws IOException {
  138. @SuppressWarnings({"resource", "deprecation"}) // We are testing the close() method
  139. Repository repo = createRepository(false, false);
  140. assertEquals(1, repo.useCnt.get());
  141. RepositoryCache.register(repo);
  142. assertEquals(1, repo.useCnt.get());
  143. repo.close();
  144. assertEquals(0, repo.useCnt.get());
  145. }
  146. @Test
  147. public void testRepositoryNotUnregisteringWhenClosing() throws Exception {
  148. FileKey loc = FileKey.exact(db.getDirectory(), db.getFS());
  149. @SuppressWarnings("resource") // We are testing the close() method
  150. Repository d2 = RepositoryCache.open(loc);
  151. assertEquals(1, d2.useCnt.get());
  152. assertThat(RepositoryCache.getRegisteredKeys(),
  153. hasItem(FileKey.exact(db.getDirectory(), db.getFS())));
  154. assertEquals(1, RepositoryCache.getRegisteredKeys().size());
  155. d2.close();
  156. assertEquals(0, d2.useCnt.get());
  157. assertEquals(1, RepositoryCache.getRegisteredKeys().size());
  158. assertTrue(RepositoryCache.isCached(d2));
  159. }
  160. @Test
  161. public void testRepositoryUnregisteringWhenExpiredAndUsageCountNegative()
  162. throws Exception {
  163. @SuppressWarnings("resource") // We are testing the close() method
  164. Repository repoA = createBareRepository();
  165. RepositoryCache.register(repoA);
  166. assertEquals(1, RepositoryCache.getRegisteredKeys().size());
  167. assertTrue(RepositoryCache.isCached(repoA));
  168. // close the repo twice to make usage count negative
  169. repoA.close();
  170. repoA.close();
  171. // fake that repoA was closed more than 1 hour ago (default expiration
  172. // time)
  173. repoA.closedAt.set(System.currentTimeMillis() - 65 * 60 * 1000);
  174. RepositoryCache.clearExpired();
  175. assertEquals(0, RepositoryCache.getRegisteredKeys().size());
  176. }
  177. @Test
  178. public void testRepositoryUnregisteringWhenExpired() throws Exception {
  179. @SuppressWarnings({"resource", "deprecation"}) // We are testing the close() method
  180. Repository repoA = createRepository(true, false);
  181. @SuppressWarnings({"resource", "deprecation"}) // We are testing the close() method
  182. Repository repoB = createRepository(true, false);
  183. Repository repoC = createBareRepository();
  184. RepositoryCache.register(repoA);
  185. RepositoryCache.register(repoB);
  186. RepositoryCache.register(repoC);
  187. assertEquals(3, RepositoryCache.getRegisteredKeys().size());
  188. assertTrue(RepositoryCache.isCached(repoA));
  189. assertTrue(RepositoryCache.isCached(repoB));
  190. assertTrue(RepositoryCache.isCached(repoC));
  191. // fake that repoA was closed more than 1 hour ago (default expiration
  192. // time)
  193. repoA.close();
  194. repoA.closedAt.set(System.currentTimeMillis() - 65 * 60 * 1000);
  195. // close repoB but this one will not be expired
  196. repoB.close();
  197. assertEquals(3, RepositoryCache.getRegisteredKeys().size());
  198. assertTrue(RepositoryCache.isCached(repoA));
  199. assertTrue(RepositoryCache.isCached(repoB));
  200. assertTrue(RepositoryCache.isCached(repoC));
  201. RepositoryCache.clearExpired();
  202. assertEquals(2, RepositoryCache.getRegisteredKeys().size());
  203. assertFalse(RepositoryCache.isCached(repoA));
  204. assertTrue(RepositoryCache.isCached(repoB));
  205. assertTrue(RepositoryCache.isCached(repoC));
  206. }
  207. @Test
  208. public void testReconfigure() throws InterruptedException, IOException {
  209. @SuppressWarnings({"resource", "deprecation"}) // We are testing the close() method
  210. Repository repo = createRepository(false, false);
  211. RepositoryCache.register(repo);
  212. assertTrue(RepositoryCache.isCached(repo));
  213. repo.close();
  214. assertTrue(RepositoryCache.isCached(repo));
  215. // Actually, we would only need to validate that
  216. // WorkQueue.getExecutor().scheduleWithFixedDelay is called with proper
  217. // values but since we do not have a mock library, we test
  218. // reconfiguration from a black box perspective. I.e. reconfigure
  219. // expireAfter and cleanupDelay to 1 ms and wait until the Repository
  220. // is evicted to prove that reconfiguration worked.
  221. RepositoryCacheConfig config = new RepositoryCacheConfig();
  222. config.setExpireAfter(1);
  223. config.setCleanupDelay(1);
  224. config.install();
  225. // Instead of using a fixed waiting time, start with small and increase:
  226. // sleep 1, 2, 4, 8, 16, ..., 1024 ms
  227. // This wait will time out after 2048 ms
  228. for (int i = 0; i <= 10; i++) {
  229. Thread.sleep(1 << i);
  230. if (!RepositoryCache.isCached(repo)) {
  231. return;
  232. }
  233. }
  234. fail("Repository should have been evicted from cache");
  235. }
  236. }