1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 package org.eclipse.jgit.internal.storage.reftable;
45
46 import static org.eclipse.jgit.lib.Constants.OBJECT_ID_LENGTH;
47 import static org.eclipse.jgit.lib.Ref.Storage.NEW;
48 import static org.eclipse.jgit.lib.Ref.Storage.PACKED;
49 import static org.junit.Assert.assertEquals;
50 import static org.junit.Assert.assertFalse;
51 import static org.junit.Assert.assertTrue;
52
53 import java.io.ByteArrayOutputStream;
54 import java.io.IOException;
55 import java.util.Arrays;
56
57 import org.eclipse.jgit.internal.storage.io.BlockSource;
58 import org.eclipse.jgit.internal.storage.reftable.ReftableWriter.Stats;
59 import org.eclipse.jgit.lib.ObjectId;
60 import org.eclipse.jgit.lib.ObjectIdRef;
61 import org.eclipse.jgit.lib.Ref;
62 import org.junit.Test;
63
64 public class ReftableCompactorTest {
65 private static final String MASTER = "refs/heads/master";
66 private static final String NEXT = "refs/heads/next";
67
68 @Test
69 public void noTables() throws IOException {
70 ReftableCompactor compactor;
71 try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
72 compactor = new ReftableCompactor(out);
73 compactor.compact();
74 }
75 Stats stats = compactor.getStats();
76 assertEquals(0, stats.minUpdateIndex());
77 assertEquals(0, stats.maxUpdateIndex());
78 assertEquals(0, stats.refCount());
79 }
80
81 @Test
82 public void oneTable() throws IOException {
83 byte[] inTab;
84 try (ByteArrayOutputStream inBuf = new ByteArrayOutputStream()) {
85 ReftableWriter writer = new ReftableWriter(inBuf)
86 .setMinUpdateIndex(0)
87 .setMaxUpdateIndex(0)
88 .begin();
89
90 writer.writeRef(ref(MASTER, 1));
91 writer.finish();
92 inTab = inBuf.toByteArray();
93 }
94
95 byte[] outTab;
96 ReftableCompactor compactor;
97 try (ByteArrayOutputStream outBuf = new ByteArrayOutputStream()) {
98 compactor = new ReftableCompactor(outBuf);
99 compactor.tryAddFirst(read(inTab));
100 compactor.compact();
101 outTab = outBuf.toByteArray();
102 }
103 Stats stats = compactor.getStats();
104 assertEquals(0, stats.minUpdateIndex());
105 assertEquals(0, stats.maxUpdateIndex());
106 assertEquals(1, stats.refCount());
107
108 ReftableReader rr = read(outTab);
109 try (RefCursor rc = rr.allRefs()) {
110 assertTrue(rc.next());
111 assertEquals(MASTER, rc.getRef().getName());
112 assertEquals(id(1), rc.getRef().getObjectId());
113 assertEquals(0, rc.getRef().getUpdateIndex());
114 }
115 }
116
117 @Test
118 public void twoTablesOneRef() throws IOException {
119 byte[] inTab1;
120 try (ByteArrayOutputStream inBuf = new ByteArrayOutputStream()) {
121 ReftableWriter writer = new ReftableWriter(inBuf)
122 .setMinUpdateIndex(0)
123 .setMaxUpdateIndex(0)
124 .begin();
125
126 writer.writeRef(ref(MASTER, 1));
127 writer.finish();
128 inTab1 = inBuf.toByteArray();
129 }
130
131 byte[] inTab2;
132 try (ByteArrayOutputStream inBuf = new ByteArrayOutputStream()) {
133 ReftableWriter writer = new ReftableWriter(inBuf)
134 .setMinUpdateIndex(1)
135 .setMaxUpdateIndex(1)
136 .begin();
137
138 writer.writeRef(ref(MASTER, 2));
139 writer.finish();
140 inTab2 = inBuf.toByteArray();
141 }
142
143 byte[] outTab;
144 ReftableCompactor compactor;
145 try (ByteArrayOutputStream outBuf = new ByteArrayOutputStream()) {
146 compactor = new ReftableCompactor(outBuf);
147 compactor.addAll(Arrays.asList(read(inTab1), read(inTab2)));
148 compactor.compact();
149 outTab = outBuf.toByteArray();
150 }
151 Stats stats = compactor.getStats();
152 assertEquals(0, stats.minUpdateIndex());
153 assertEquals(1, stats.maxUpdateIndex());
154 assertEquals(1, stats.refCount());
155
156 ReftableReader rr = read(outTab);
157 try (RefCursor rc = rr.allRefs()) {
158 assertTrue(rc.next());
159 assertEquals(MASTER, rc.getRef().getName());
160 assertEquals(id(2), rc.getRef().getObjectId());
161 assertEquals(1, rc.getRef().getUpdateIndex());
162 }
163 }
164
165 @Test
166 public void twoTablesTwoRefs() throws IOException {
167 byte[] inTab1;
168 try (ByteArrayOutputStream inBuf = new ByteArrayOutputStream()) {
169 ReftableWriter writer = new ReftableWriter(inBuf)
170 .setMinUpdateIndex(0)
171 .setMaxUpdateIndex(0)
172 .begin();
173
174 writer.writeRef(ref(MASTER, 1));
175 writer.writeRef(ref(NEXT, 2));
176 writer.finish();
177 inTab1 = inBuf.toByteArray();
178 }
179
180 byte[] inTab2;
181 try (ByteArrayOutputStream inBuf = new ByteArrayOutputStream()) {
182 ReftableWriter writer = new ReftableWriter(inBuf)
183 .setMinUpdateIndex(1)
184 .setMaxUpdateIndex(1)
185 .begin();
186
187 writer.writeRef(ref(MASTER, 3));
188 writer.finish();
189 inTab2 = inBuf.toByteArray();
190 }
191
192 byte[] outTab;
193 ReftableCompactor compactor;
194 try (ByteArrayOutputStream outBuf = new ByteArrayOutputStream()) {
195 compactor = new ReftableCompactor(outBuf);
196 compactor.addAll(Arrays.asList(read(inTab1), read(inTab2)));
197 compactor.compact();
198 outTab = outBuf.toByteArray();
199 }
200 Stats stats = compactor.getStats();
201 assertEquals(0, stats.minUpdateIndex());
202 assertEquals(1, stats.maxUpdateIndex());
203 assertEquals(2, stats.refCount());
204
205 ReftableReader rr = read(outTab);
206 try (RefCursor rc = rr.allRefs()) {
207 assertTrue(rc.next());
208 assertEquals(MASTER, rc.getRef().getName());
209 assertEquals(id(3), rc.getRef().getObjectId());
210 assertEquals(1, rc.getRef().getUpdateIndex());
211
212 assertTrue(rc.next());
213 assertEquals(NEXT, rc.getRef().getName());
214 assertEquals(id(2), rc.getRef().getObjectId());
215 assertEquals(0, rc.getRef().getUpdateIndex());
216 }
217 }
218
219 @Test
220 public void twoTablesIncludeOneDelete() throws IOException {
221 byte[] inTab1;
222 try (ByteArrayOutputStream inBuf = new ByteArrayOutputStream()) {
223 ReftableWriter writer = new ReftableWriter(inBuf)
224 .setMinUpdateIndex(0)
225 .setMaxUpdateIndex(0)
226 .begin();
227
228 writer.writeRef(ref(MASTER, 1));
229 writer.finish();
230 inTab1 = inBuf.toByteArray();
231 }
232
233 byte[] inTab2;
234 try (ByteArrayOutputStream inBuf = new ByteArrayOutputStream()) {
235 ReftableWriter writer = new ReftableWriter(inBuf)
236 .setMinUpdateIndex(1)
237 .setMaxUpdateIndex(1)
238 .begin();
239
240 writer.writeRef(tombstone(MASTER));
241 writer.finish();
242 inTab2 = inBuf.toByteArray();
243 }
244
245 byte[] outTab;
246 ReftableCompactor compactor;
247 try (ByteArrayOutputStream outBuf = new ByteArrayOutputStream()) {
248 compactor = new ReftableCompactor(outBuf);
249 compactor.setIncludeDeletes(true);
250 compactor.addAll(Arrays.asList(read(inTab1), read(inTab2)));
251 compactor.compact();
252 outTab = outBuf.toByteArray();
253 }
254 Stats stats = compactor.getStats();
255 assertEquals(0, stats.minUpdateIndex());
256 assertEquals(1, stats.maxUpdateIndex());
257 assertEquals(1, stats.refCount());
258
259 ReftableReader rr = read(outTab);
260 try (RefCursor rc = rr.allRefs()) {
261 assertFalse(rc.next());
262 }
263 }
264
265 @Test
266 public void twoTablesNotIncludeOneDelete() throws IOException {
267 byte[] inTab1;
268 try (ByteArrayOutputStream inBuf = new ByteArrayOutputStream()) {
269 ReftableWriter writer = new ReftableWriter(inBuf)
270 .setMinUpdateIndex(0)
271 .setMaxUpdateIndex(0)
272 .begin();
273
274 writer.writeRef(ref(MASTER, 1));
275 writer.finish();
276 inTab1 = inBuf.toByteArray();
277 }
278
279 byte[] inTab2;
280 try (ByteArrayOutputStream inBuf = new ByteArrayOutputStream()) {
281 ReftableWriter writer = new ReftableWriter(inBuf)
282 .setMinUpdateIndex(1)
283 .setMaxUpdateIndex(1)
284 .begin();
285
286 writer.writeRef(tombstone(MASTER));
287 writer.finish();
288 inTab2 = inBuf.toByteArray();
289 }
290
291 byte[] outTab;
292 ReftableCompactor compactor;
293 try (ByteArrayOutputStream outBuf = new ByteArrayOutputStream()) {
294 compactor = new ReftableCompactor(outBuf);
295 compactor.setIncludeDeletes(false);
296 compactor.addAll(Arrays.asList(read(inTab1), read(inTab2)));
297 compactor.compact();
298 outTab = outBuf.toByteArray();
299 }
300 Stats stats = compactor.getStats();
301 assertEquals(0, stats.minUpdateIndex());
302 assertEquals(1, stats.maxUpdateIndex());
303 assertEquals(0, stats.refCount());
304
305 ReftableReader rr = read(outTab);
306 try (RefCursor rc = rr.allRefs()) {
307 assertFalse(rc.next());
308 }
309 }
310
311 private static Ref ref(String name, int id) {
312 return new ObjectIdRef.PeeledNonTag(PACKED, name, id(id));
313 }
314
315 private static Ref tombstone(String name) {
316 return new ObjectIdRef.Unpeeled(NEW, name, null);
317 }
318
319 private static ObjectId id(int i) {
320 byte[] buf = new byte[OBJECT_ID_LENGTH];
321 buf[0] = (byte) (i & 0xff);
322 buf[1] = (byte) ((i >>> 8) & 0xff);
323 buf[2] = (byte) ((i >>> 16) & 0xff);
324 buf[3] = (byte) (i >>> 24);
325 return ObjectId.fromRaw(buf);
326 }
327
328 private static ReftableReader read(byte[] table) {
329 return new ReftableReader(BlockSource.from(table));
330 }
331 }