1
2
3
4
5
6
7
8
9
10
11 package org.eclipse.jgit.internal.storage.file;
12
13 import static org.eclipse.jgit.lib.Ref.Storage.PACKED;
14 import static org.junit.Assert.assertEquals;
15 import static org.junit.Assert.assertThrows;
16 import static org.junit.Assert.assertTrue;
17
18 import java.io.File;
19 import java.io.FileNotFoundException;
20 import java.io.IOException;
21 import java.nio.file.Files;
22 import java.nio.file.Path;
23 import java.util.Collections;
24 import java.util.List;
25 import java.util.stream.Collectors;
26
27 import org.eclipse.jgit.internal.storage.file.FileReftableStack.Segment;
28 import org.eclipse.jgit.internal.storage.reftable.MergedReftable;
29 import org.eclipse.jgit.internal.storage.reftable.RefCursor;
30 import org.eclipse.jgit.lib.Config;
31 import org.eclipse.jgit.lib.ObjectId;
32 import org.eclipse.jgit.lib.ObjectIdRef;
33 import org.eclipse.jgit.lib.Ref;
34 import org.eclipse.jgit.util.FileUtils;
35 import org.junit.After;
36 import org.junit.Before;
37 import org.junit.Test;
38
39 public class FileReftableStackTest {
40
41 private static Ref newRef(String name, ObjectId id) {
42 return new ObjectIdRef.PeeledNonTag(PACKED, name, id);
43 }
44
45 private File reftableDir;
46
47 @Before
48 public void setup() throws Exception {
49 reftableDir = FileUtils.createTempDir("rtstack", "", null);
50 }
51
52 @After
53 public void tearDown() throws Exception {
54 if (reftableDir != null) {
55 FileUtils.delete(reftableDir, FileUtils.RECURSIVE);
56 }
57 }
58
59 void writeBranches(FileReftableStack stack, String template, int start,
60 int N) throws IOException {
61 for (int i = 0; i < N; i++) {
62 while (true) {
63 final long next = stack.getMergedReftable().maxUpdateIndex()
64 + 1;
65
66 String name = String.format(template,
67 Integer.valueOf(start + i));
68 Ref r = newRef(name, ObjectId.zeroId());
69 boolean ok = stack.addReftable(rw -> {
70 rw.setMinUpdateIndex(next).setMaxUpdateIndex(next).begin()
71 .writeRef(r);
72 });
73 if (ok) {
74 break;
75 }
76 }
77 }
78 }
79
80 public void testCompaction(int N) throws Exception {
81 try (FileReftableStack stack = new FileReftableStack(
82 new File(reftableDir, "refs"), reftableDir, null,
83 () -> new Config())) {
84 writeBranches(stack, "refs/heads/branch%d", 0, N);
85 MergedReftable table = stack.getMergedReftable();
86 for (int i = 1; i < N; i++) {
87 String name = String.format("refs/heads/branch%d",
88 Integer.valueOf(i));
89 RefCursor c = table.seekRef(name);
90 assertTrue(c.next());
91 assertEquals(ObjectId.zeroId(), c.getRef().getObjectId());
92 }
93
94 List<String> files = Files.list(reftableDir.toPath())
95 .map(Path::getFileName).map(Path::toString)
96 .collect(Collectors.toList());
97 Collections.sort(files);
98
99 assertTrue(files.size() < 20);
100
101 FileReftableStack.CompactionStats stats = stack.getStats();
102 assertEquals(0, stats.failed);
103 assertTrue(stats.attempted < N);
104 assertTrue(stats.refCount < FileReftableStack.log(N) * N);
105 }
106 }
107
108 @Test
109 public void testCompaction9() throws Exception {
110 testCompaction(9);
111 }
112
113 @Test
114 public void testCompaction1024() throws Exception {
115 testCompaction(1024);
116 }
117
118 @SuppressWarnings({ "resource", "unused" })
119 @Test
120 public void missingReftable() throws Exception {
121 try (FileReftableStack stack = new FileReftableStack(
122 new File(reftableDir, "refs"), reftableDir, null,
123 () -> new Config())) {
124 outer: for (int i = 0; i < 10; i++) {
125 final long next = stack.getMergedReftable().maxUpdateIndex()
126 + 1;
127 String name = String.format("branch%d", Integer.valueOf(i));
128 Ref r = newRef(name, ObjectId.zeroId());
129 boolean ok = stack.addReftable(rw -> {
130 rw.setMinUpdateIndex(next).setMaxUpdateIndex(next).begin()
131 .writeRef(r);
132 });
133 assertTrue(ok);
134
135 List<Path> files = Files.list(reftableDir.toPath())
136 .collect(Collectors.toList());
137 for (int j = 0; j < files.size(); j++) {
138 Path f = files.get(j);
139 Path fileName = f.getFileName();
140 if (fileName != null
141 && fileName.toString().endsWith(".ref")) {
142 Files.delete(f);
143 break outer;
144 }
145 }
146 }
147 }
148 assertThrows(FileNotFoundException.class,
149 () -> new FileReftableStack(new File(reftableDir, "refs"),
150 reftableDir, null, () -> new Config()));
151 }
152
153 @Test
154 public void testSegments() {
155 long in[] = { 1024, 1024, 1536, 100, 64, 50, 25, 24 };
156 List<Segment> got = FileReftableStack.segmentSizes(in);
157 Segment want[] = { new Segment(0, 3, 10, 3584),
158 new Segment(3, 5, 6, 164), new Segment(5, 6, 5, 50),
159 new Segment(6, 8, 4, 49), };
160 assertEquals(got.size(), want.length);
161 for (int i = 0; i < want.length; i++) {
162 assertTrue(want[i].equals(got.get(i)));
163 }
164 }
165
166 @Test
167 public void testLog2() throws Exception {
168 assertEquals(10, FileReftableStack.log(1024));
169 assertEquals(10, FileReftableStack.log(1025));
170 assertEquals(10, FileReftableStack.log(2047));
171 }
172 }