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