Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

MergedReftableTest.java 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. /*
  2. * Copyright (C) 2017, Google Inc.
  3. * and other copyright owners as documented in the project's IP log.
  4. *
  5. * This program and the accompanying materials are made available
  6. * under the terms of the Eclipse Distribution License v1.0 which
  7. * accompanies this distribution, is reproduced below, and is
  8. * available at http://www.eclipse.org/org/documents/edl-v10.php
  9. *
  10. * All rights reserved.
  11. *
  12. * Redistribution and use in source and binary forms, with or
  13. * without modification, are permitted provided that the following
  14. * conditions are met:
  15. *
  16. * - Redistributions of source code must retain the above copyright
  17. * notice, this list of conditions and the following disclaimer.
  18. *
  19. * - Redistributions in binary form must reproduce the above
  20. * copyright notice, this list of conditions and the following
  21. * disclaimer in the documentation and/or other materials provided
  22. * with the distribution.
  23. *
  24. * - Neither the name of the Eclipse Foundation, Inc. nor the
  25. * names of its contributors may be used to endorse or promote
  26. * products derived from this software without specific prior
  27. * written permission.
  28. *
  29. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  30. * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  31. * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  32. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  33. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  34. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  35. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  36. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  37. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  38. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  39. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  40. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  41. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  42. */
  43. package org.eclipse.jgit.internal.storage.reftable;
  44. import static org.eclipse.jgit.lib.Constants.HEAD;
  45. import static org.eclipse.jgit.lib.Constants.MASTER;
  46. import static org.eclipse.jgit.lib.Constants.OBJECT_ID_LENGTH;
  47. import static org.eclipse.jgit.lib.Constants.R_HEADS;
  48. import static org.eclipse.jgit.lib.Ref.Storage.NEW;
  49. import static org.eclipse.jgit.lib.Ref.Storage.PACKED;
  50. import static org.junit.Assert.assertEquals;
  51. import static org.junit.Assert.assertFalse;
  52. import static org.junit.Assert.assertNull;
  53. import static org.junit.Assert.assertTrue;
  54. import java.io.ByteArrayOutputStream;
  55. import java.io.IOException;
  56. import java.util.ArrayList;
  57. import java.util.Arrays;
  58. import java.util.Collection;
  59. import java.util.Collections;
  60. import java.util.HashMap;
  61. import java.util.List;
  62. import java.util.Map;
  63. import org.eclipse.jgit.internal.storage.io.BlockSource;
  64. import org.eclipse.jgit.lib.ObjectId;
  65. import org.eclipse.jgit.lib.ObjectIdRef;
  66. import org.eclipse.jgit.lib.Ref;
  67. import org.eclipse.jgit.lib.RefComparator;
  68. import org.eclipse.jgit.lib.SymbolicRef;
  69. import org.junit.Test;
  70. public class MergedReftableTest {
  71. @Test
  72. public void noTables() throws IOException {
  73. MergedReftable mr = merge(new byte[0][]);
  74. try (RefCursor rc = mr.allRefs()) {
  75. assertFalse(rc.next());
  76. }
  77. try (RefCursor rc = mr.seekRef(HEAD)) {
  78. assertFalse(rc.next());
  79. }
  80. try (RefCursor rc = mr.seekRefsWithPrefix(R_HEADS)) {
  81. assertFalse(rc.next());
  82. }
  83. }
  84. @Test
  85. public void oneEmptyTable() throws IOException {
  86. MergedReftable mr = merge(write());
  87. try (RefCursor rc = mr.allRefs()) {
  88. assertFalse(rc.next());
  89. }
  90. try (RefCursor rc = mr.seekRef(HEAD)) {
  91. assertFalse(rc.next());
  92. }
  93. try (RefCursor rc = mr.seekRefsWithPrefix(R_HEADS)) {
  94. assertFalse(rc.next());
  95. }
  96. }
  97. @Test
  98. public void twoEmptyTables() throws IOException {
  99. MergedReftable mr = merge(write(), write());
  100. try (RefCursor rc = mr.allRefs()) {
  101. assertFalse(rc.next());
  102. }
  103. try (RefCursor rc = mr.seekRef(HEAD)) {
  104. assertFalse(rc.next());
  105. }
  106. try (RefCursor rc = mr.seekRefsWithPrefix(R_HEADS)) {
  107. assertFalse(rc.next());
  108. }
  109. }
  110. @SuppressWarnings("boxing")
  111. @Test
  112. public void oneTableScan() throws IOException {
  113. List<Ref> refs = new ArrayList<>();
  114. for (int i = 1; i <= 567; i++) {
  115. refs.add(ref(String.format("refs/heads/%03d", i), i));
  116. }
  117. MergedReftable mr = merge(write(refs));
  118. try (RefCursor rc = mr.allRefs()) {
  119. for (Ref exp : refs) {
  120. assertTrue("has " + exp.getName(), rc.next());
  121. Ref act = rc.getRef();
  122. assertEquals(exp.getName(), act.getName());
  123. assertEquals(exp.getObjectId(), act.getObjectId());
  124. assertEquals(1, act.getUpdateIndex());
  125. }
  126. assertFalse(rc.next());
  127. }
  128. }
  129. @Test
  130. public void deleteIsHidden() throws IOException {
  131. List<Ref> delta1 = Arrays.asList(
  132. ref("refs/heads/apple", 1),
  133. ref("refs/heads/master", 2));
  134. List<Ref> delta2 = Arrays.asList(delete("refs/heads/apple"));
  135. MergedReftable mr = merge(write(delta1), write(delta2));
  136. try (RefCursor rc = mr.allRefs()) {
  137. assertTrue(rc.next());
  138. assertEquals("refs/heads/master", rc.getRef().getName());
  139. assertEquals(id(2), rc.getRef().getObjectId());
  140. assertEquals(1, rc.getRef().getUpdateIndex());
  141. assertFalse(rc.next());
  142. }
  143. }
  144. @Test
  145. public void twoTableSeek() throws IOException {
  146. List<Ref> delta1 = Arrays.asList(
  147. ref("refs/heads/apple", 1),
  148. ref("refs/heads/master", 2));
  149. List<Ref> delta2 = Arrays.asList(ref("refs/heads/banana", 3));
  150. MergedReftable mr = merge(write(delta1), write(delta2));
  151. try (RefCursor rc = mr.seekRef("refs/heads/master")) {
  152. assertTrue(rc.next());
  153. assertEquals("refs/heads/master", rc.getRef().getName());
  154. assertEquals(id(2), rc.getRef().getObjectId());
  155. assertFalse(rc.next());
  156. assertEquals(1, rc.getRef().getUpdateIndex());
  157. }
  158. }
  159. @Test
  160. public void twoTableById() throws IOException {
  161. List<Ref> delta1 = Arrays.asList(
  162. ref("refs/heads/apple", 1),
  163. ref("refs/heads/master", 2));
  164. List<Ref> delta2 = Arrays.asList(ref("refs/heads/banana", 3));
  165. MergedReftable mr = merge(write(delta1), write(delta2));
  166. try (RefCursor rc = mr.byObjectId(id(2))) {
  167. assertTrue(rc.next());
  168. assertEquals("refs/heads/master", rc.getRef().getName());
  169. assertEquals(id(2), rc.getRef().getObjectId());
  170. assertEquals(1, rc.getRef().getUpdateIndex());
  171. assertFalse(rc.next());
  172. }
  173. }
  174. @SuppressWarnings("boxing")
  175. @Test
  176. public void fourTableScan() throws IOException {
  177. List<Ref> base = new ArrayList<>();
  178. for (int i = 1; i <= 567; i++) {
  179. base.add(ref(String.format("refs/heads/%03d", i), i));
  180. }
  181. List<Ref> delta1 = Arrays.asList(
  182. ref("refs/heads/next", 4),
  183. ref(String.format("refs/heads/%03d", 55), 4096));
  184. List<Ref> delta2 = Arrays.asList(
  185. delete("refs/heads/next"),
  186. ref(String.format("refs/heads/%03d", 55), 8192));
  187. List<Ref> delta3 = Arrays.asList(
  188. ref("refs/heads/master", 4242),
  189. ref(String.format("refs/heads/%03d", 42), 5120),
  190. ref(String.format("refs/heads/%03d", 98), 6120));
  191. List<Ref> expected = merge(base, delta1, delta2, delta3);
  192. MergedReftable mr = merge(
  193. write(base),
  194. write(delta1),
  195. write(delta2),
  196. write(delta3));
  197. try (RefCursor rc = mr.allRefs()) {
  198. for (Ref exp : expected) {
  199. assertTrue("has " + exp.getName(), rc.next());
  200. Ref act = rc.getRef();
  201. assertEquals(exp.getName(), act.getName());
  202. assertEquals(exp.getObjectId(), act.getObjectId());
  203. assertEquals(1, rc.getRef().getUpdateIndex());
  204. }
  205. assertFalse(rc.next());
  206. }
  207. }
  208. @Test
  209. public void scanDuplicates() throws IOException {
  210. List<Ref> delta1 = Arrays.asList(
  211. ref("refs/heads/apple", 1),
  212. ref("refs/heads/banana", 2));
  213. List<Ref> delta2 = Arrays.asList(
  214. ref("refs/heads/apple", 3),
  215. ref("refs/heads/apple", 4));
  216. MergedReftable mr = merge(write(delta1, 1000), write(delta2, 2000));
  217. try (RefCursor rc = mr.allRefs()) {
  218. assertTrue(rc.next());
  219. assertEquals("refs/heads/apple", rc.getRef().getName());
  220. assertEquals(id(3), rc.getRef().getObjectId());
  221. assertEquals(2000, rc.getRef().getUpdateIndex());
  222. assertTrue(rc.next());
  223. assertEquals("refs/heads/banana", rc.getRef().getName());
  224. assertEquals(id(2), rc.getRef().getObjectId());
  225. assertEquals(1000, rc.getRef().getUpdateIndex());
  226. assertFalse(rc.next());
  227. }
  228. }
  229. @Test
  230. public void scanIncludeDeletes() throws IOException {
  231. List<Ref> delta1 = Arrays.asList(ref("refs/heads/next", 4));
  232. List<Ref> delta2 = Arrays.asList(delete("refs/heads/next"));
  233. List<Ref> delta3 = Arrays.asList(ref("refs/heads/master", 8));
  234. MergedReftable mr = merge(write(delta1), write(delta2), write(delta3));
  235. mr.setIncludeDeletes(true);
  236. try (RefCursor rc = mr.allRefs()) {
  237. assertTrue(rc.next());
  238. Ref r = rc.getRef();
  239. assertEquals("refs/heads/master", r.getName());
  240. assertEquals(id(8), r.getObjectId());
  241. assertEquals(1, rc.getRef().getUpdateIndex());
  242. assertTrue(rc.next());
  243. r = rc.getRef();
  244. assertEquals("refs/heads/next", r.getName());
  245. assertEquals(NEW, r.getStorage());
  246. assertNull(r.getObjectId());
  247. assertEquals(1, rc.getRef().getUpdateIndex());
  248. assertFalse(rc.next());
  249. }
  250. }
  251. @SuppressWarnings("boxing")
  252. @Test
  253. public void oneTableSeek() throws IOException {
  254. List<Ref> refs = new ArrayList<>();
  255. for (int i = 1; i <= 567; i++) {
  256. refs.add(ref(String.format("refs/heads/%03d", i), i));
  257. }
  258. MergedReftable mr = merge(write(refs));
  259. for (Ref exp : refs) {
  260. try (RefCursor rc = mr.seekRef(exp.getName())) {
  261. assertTrue("has " + exp.getName(), rc.next());
  262. Ref act = rc.getRef();
  263. assertEquals(exp.getName(), act.getName());
  264. assertEquals(exp.getObjectId(), act.getObjectId());
  265. assertEquals(1, act.getUpdateIndex());
  266. assertFalse(rc.next());
  267. }
  268. }
  269. }
  270. @Test
  271. public void missedUpdate() throws IOException {
  272. ByteArrayOutputStream buf = new ByteArrayOutputStream();
  273. ReftableWriter writer = new ReftableWriter(buf)
  274. .setMinUpdateIndex(1)
  275. .setMaxUpdateIndex(3)
  276. .begin();
  277. writer.writeRef(ref("refs/heads/a", 1), 1);
  278. writer.writeRef(ref("refs/heads/c", 3), 3);
  279. writer.finish();
  280. byte[] base = buf.toByteArray();
  281. byte[] delta = write(Arrays.asList(
  282. ref("refs/heads/b", 2),
  283. ref("refs/heads/c", 4)),
  284. 2);
  285. MergedReftable mr = merge(base, delta);
  286. try (RefCursor rc = mr.allRefs()) {
  287. assertTrue(rc.next());
  288. assertEquals("refs/heads/a", rc.getRef().getName());
  289. assertEquals(id(1), rc.getRef().getObjectId());
  290. assertEquals(1, rc.getRef().getUpdateIndex());
  291. assertTrue(rc.next());
  292. assertEquals("refs/heads/b", rc.getRef().getName());
  293. assertEquals(id(2), rc.getRef().getObjectId());
  294. assertEquals(2, rc.getRef().getUpdateIndex());
  295. assertTrue(rc.next());
  296. assertEquals("refs/heads/c", rc.getRef().getName());
  297. assertEquals(id(3), rc.getRef().getObjectId());
  298. assertEquals(3, rc.getRef().getUpdateIndex());
  299. }
  300. }
  301. @Test
  302. public void compaction() throws IOException {
  303. List<Ref> delta1 = Arrays.asList(
  304. ref("refs/heads/next", 4),
  305. ref("refs/heads/master", 1));
  306. List<Ref> delta2 = Arrays.asList(delete("refs/heads/next"));
  307. List<Ref> delta3 = Arrays.asList(ref("refs/heads/master", 8));
  308. ByteArrayOutputStream out = new ByteArrayOutputStream();
  309. ReftableCompactor compactor = new ReftableCompactor(out);
  310. compactor.addAll(Arrays.asList(
  311. read(write(delta1)),
  312. read(write(delta2)),
  313. read(write(delta3))));
  314. compactor.compact();
  315. byte[] table = out.toByteArray();
  316. ReftableReader reader = read(table);
  317. try (RefCursor rc = reader.allRefs()) {
  318. assertTrue(rc.next());
  319. Ref r = rc.getRef();
  320. assertEquals("refs/heads/master", r.getName());
  321. assertEquals(id(8), r.getObjectId());
  322. assertFalse(rc.next());
  323. }
  324. }
  325. @Test
  326. public void versioningSymbolicReftargetMoves() throws IOException {
  327. Ref master = ref(MASTER, 100);
  328. List<Ref> delta1 = Arrays.asList(master, sym(HEAD, MASTER));
  329. List<Ref> delta2 = Arrays.asList(ref(MASTER, 200));
  330. MergedReftable mr = merge(write(delta1, 1), write(delta2, 2));
  331. Ref head = mr.exactRef(HEAD);
  332. assertEquals(head.getUpdateIndex(), 1);
  333. Ref masterRef = mr.exactRef(MASTER);
  334. assertEquals(masterRef.getUpdateIndex(), 2);
  335. }
  336. @Test
  337. public void versioningSymbolicRefMoves() throws IOException {
  338. Ref branchX = ref("refs/heads/branchX", 200);
  339. List<Ref> delta1 = Arrays.asList(ref(MASTER, 100), branchX,
  340. sym(HEAD, MASTER));
  341. List<Ref> delta2 = Arrays.asList(sym(HEAD, "refs/heads/branchX"));
  342. List<Ref> delta3 = Arrays.asList(sym(HEAD, MASTER));
  343. MergedReftable mr = merge(write(delta1, 1), write(delta2, 2),
  344. write(delta3, 3));
  345. Ref head = mr.exactRef(HEAD);
  346. assertEquals(head.getUpdateIndex(), 3);
  347. Ref masterRef = mr.exactRef(MASTER);
  348. assertEquals(masterRef.getUpdateIndex(), 1);
  349. Ref branchRef = mr.exactRef(MASTER);
  350. assertEquals(branchRef.getUpdateIndex(), 1);
  351. }
  352. @Test
  353. public void versioningResolveRef() throws IOException {
  354. List<Ref> delta1 = Arrays.asList(sym(HEAD, "refs/heads/tmp"),
  355. sym("refs/heads/tmp", MASTER), ref(MASTER, 100));
  356. List<Ref> delta2 = Arrays.asList(ref(MASTER, 200));
  357. List<Ref> delta3 = Arrays.asList(ref(MASTER, 300));
  358. MergedReftable mr = merge(write(delta1, 1), write(delta2, 2),
  359. write(delta3, 3));
  360. Ref head = mr.exactRef(HEAD);
  361. Ref resolvedHead = mr.resolve(head);
  362. assertEquals(resolvedHead.getObjectId(), id(300));
  363. assertEquals("HEAD has not moved", resolvedHead.getUpdateIndex(), 1);
  364. Ref master = mr.exactRef(MASTER);
  365. Ref resolvedMaster = mr.resolve(master);
  366. assertEquals(resolvedMaster.getObjectId(), id(300));
  367. assertEquals("master also has update index",
  368. resolvedMaster.getUpdateIndex(), 3);
  369. }
  370. private static MergedReftable merge(byte[]... table) {
  371. List<ReftableReader> stack = new ArrayList<>(table.length);
  372. for (byte[] b : table) {
  373. stack.add(read(b));
  374. }
  375. return new MergedReftable(stack);
  376. }
  377. private static ReftableReader read(byte[] table) {
  378. return new ReftableReader(BlockSource.from(table));
  379. }
  380. private static Ref ref(String name, int id) {
  381. return new ObjectIdRef.PeeledNonTag(PACKED, name, id(id));
  382. }
  383. private static Ref sym(String name, String target) {
  384. return new SymbolicRef(name, newRef(target));
  385. }
  386. private static Ref newRef(String name) {
  387. return new ObjectIdRef.Unpeeled(NEW, name, null);
  388. }
  389. private static Ref delete(String name) {
  390. return new ObjectIdRef.Unpeeled(NEW, name, null);
  391. }
  392. private static ObjectId id(int i) {
  393. byte[] buf = new byte[OBJECT_ID_LENGTH];
  394. buf[0] = (byte) (i & 0xff);
  395. buf[1] = (byte) ((i >>> 8) & 0xff);
  396. buf[2] = (byte) ((i >>> 16) & 0xff);
  397. buf[3] = (byte) (i >>> 24);
  398. return ObjectId.fromRaw(buf);
  399. }
  400. private byte[] write(Ref... refs) throws IOException {
  401. return write(Arrays.asList(refs));
  402. }
  403. private byte[] write(Collection<Ref> refs) throws IOException {
  404. return write(refs, 1);
  405. }
  406. private byte[] write(Collection<Ref> refs, long updateIndex)
  407. throws IOException {
  408. ByteArrayOutputStream buffer = new ByteArrayOutputStream();
  409. new ReftableWriter(buffer)
  410. .setMinUpdateIndex(updateIndex)
  411. .setMaxUpdateIndex(updateIndex)
  412. .begin()
  413. .sortAndWriteRefs(refs)
  414. .finish();
  415. return buffer.toByteArray();
  416. }
  417. @SafeVarargs
  418. private static List<Ref> merge(List<Ref>... tables) {
  419. Map<String, Ref> expect = new HashMap<>();
  420. for (List<Ref> t : tables) {
  421. for (Ref r : t) {
  422. if (r.getStorage() == NEW && r.getObjectId() == null) {
  423. expect.remove(r.getName());
  424. } else {
  425. expect.put(r.getName(), r);
  426. }
  427. }
  428. }
  429. List<Ref> expected = new ArrayList<>(expect.values());
  430. Collections.sort(expected, RefComparator.INSTANCE);
  431. return expected;
  432. }
  433. }