View Javadoc
1   /*
2    * Copyright (C) 2013, 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  
11  package org.eclipse.jgit.internal.storage.dfs;
12  
13  import static org.junit.Assert.assertEquals;
14  import static org.junit.Assert.assertFalse;
15  import static org.junit.Assert.assertSame;
16  import static org.junit.Assert.assertTrue;
17  
18  import java.io.IOException;
19  import java.nio.ByteBuffer;
20  import java.util.Arrays;
21  import java.util.Collection;
22  import java.util.HashSet;
23  import java.util.List;
24  import java.util.Set;
25  import java.util.zip.Deflater;
26  
27  import org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource;
28  import org.eclipse.jgit.internal.storage.pack.PackExt;
29  import org.eclipse.jgit.junit.JGitTestUtil;
30  import org.eclipse.jgit.junit.TestRng;
31  import org.eclipse.jgit.lib.AbbreviatedObjectId;
32  import org.eclipse.jgit.lib.Constants;
33  import org.eclipse.jgit.lib.ObjectId;
34  import org.eclipse.jgit.lib.ObjectInserter;
35  import org.eclipse.jgit.lib.ObjectLoader;
36  import org.eclipse.jgit.lib.ObjectReader;
37  import org.eclipse.jgit.util.IO;
38  import org.eclipse.jgit.util.RawParseUtils;
39  import org.junit.Before;
40  import org.junit.Test;
41  
42  public class DfsInserterTest {
43  	InMemoryRepository db;
44  
45  	@Before
46  	public void setUp() {
47  		db = new InMemoryRepository(new DfsRepositoryDescription("test"));
48  	}
49  
50  	@Test
51  	public void testInserterDiscardsPack() throws IOException {
52  		try (ObjectInserter ins = db.newObjectInserter()) {
53  			ins.insert(Constants.OBJ_BLOB, Constants.encode("foo"));
54  			ins.insert(Constants.OBJ_BLOB, Constants.encode("bar"));
55  			assertEquals(0, db.getObjectDatabase().listPacks().size());
56  		}
57  		assertEquals(0, db.getObjectDatabase().listPacks().size());
58  	}
59  
60  	@Test
61  	public void testReadFromInserterSmallObjects() throws IOException {
62  		try (ObjectInserter ins = db.newObjectInserter()) {
63  			ObjectId id1 = ins.insert(Constants.OBJ_BLOB,
64  					Constants.encode("foo"));
65  			ObjectId id2 = ins.insert(Constants.OBJ_BLOB,
66  					Constants.encode("bar"));
67  			assertEquals(0, db.getObjectDatabase().listPacks().size());
68  
69  			try (ObjectReader reader = ins.newReader()) {
70  				assertSame(ins, reader.getCreatedFromInserter());
71  				assertEquals("foo", readString(reader.open(id1)));
72  				assertEquals("bar", readString(reader.open(id2)));
73  				assertEquals(0, db.getObjectDatabase().listPacks().size());
74  				ins.flush();
75  				assertEquals(1, db.getObjectDatabase().listPacks().size());
76  			}
77  		}
78  	}
79  
80  	@Test
81  	public void testReadFromInserterLargerObjects() throws IOException {
82  		db.getObjectDatabase().getReaderOptions().setStreamFileThreshold(512);
83  		DfsBlockCache.reconfigure(new DfsBlockCacheConfig()
84  			.setBlockSize(512)
85  			.setBlockLimit(2048));
86  
87  		byte[] data = new TestRng(JGitTestUtil.getName()).nextBytes(8192);
88  		try (DfsInserter ins = (DfsInserter) db.newObjectInserter()) {
89  			ins.setCompressionLevel(Deflater.NO_COMPRESSION);
90  			ObjectId id1 = ins.insert(Constants.OBJ_BLOB, data);
91  			assertEquals(0, db.getObjectDatabase().listPacks().size());
92  
93  			try (ObjectReader reader = ins.newReader()) {
94  				assertSame(ins, reader.getCreatedFromInserter());
95  				assertTrue(Arrays.equals(data, readStream(reader.open(id1))));
96  				assertEquals(0, db.getObjectDatabase().listPacks().size());
97  			}
98  			ins.flush();
99  
100 		}
101 		List<DfsPackDescription> packs = db.getObjectDatabase().listPacks();
102 		assertEquals(1, packs.size());
103 		assertTrue(packs.get(0).getFileSize(PackExt.PACK) > 2048);
104 	}
105 
106 	@Test
107 	public void testReadFromFallback() throws IOException {
108 		try (ObjectInserter ins = db.newObjectInserter()) {
109 			ObjectId id1 = ins.insert(Constants.OBJ_BLOB,
110 					Constants.encode("foo"));
111 			ins.flush();
112 			ObjectId id2 = ins.insert(Constants.OBJ_BLOB,
113 					Constants.encode("bar"));
114 			assertEquals(1, db.getObjectDatabase().listPacks().size());
115 
116 			try (ObjectReader reader = ins.newReader()) {
117 				assertSame(ins, reader.getCreatedFromInserter());
118 				assertEquals("foo", readString(reader.open(id1)));
119 				assertEquals("bar", readString(reader.open(id2)));
120 				assertEquals(1, db.getObjectDatabase().listPacks().size());
121 			}
122 			ins.flush();
123 			assertEquals(2, db.getObjectDatabase().listPacks().size());
124 		}
125 	}
126 
127 	@Test
128 	public void testReaderResolve() throws IOException {
129 		try (ObjectInserter ins = db.newObjectInserter()) {
130 			ObjectId id1 = ins.insert(Constants.OBJ_BLOB,
131 					Constants.encode("foo"));
132 			ins.flush();
133 			ObjectId id2 = ins.insert(Constants.OBJ_BLOB,
134 					Constants.encode("bar"));
135 			String abbr1 = ObjectId.toString(id1).substring(0, 4);
136 			String abbr2 = ObjectId.toString(id2).substring(0, 4);
137 			assertFalse(abbr1.equals(abbr2));
138 
139 			try (ObjectReader reader = ins.newReader()) {
140 				assertSame(ins, reader.getCreatedFromInserter());
141 				Collection<ObjectId> objs;
142 				objs = reader.resolve(AbbreviatedObjectId.fromString(abbr1));
143 				assertEquals(1, objs.size());
144 				assertEquals(id1, objs.iterator().next());
145 
146 				objs = reader.resolve(AbbreviatedObjectId.fromString(abbr2));
147 				assertEquals(1, objs.size());
148 				assertEquals(id2, objs.iterator().next());
149 			}
150 		}
151 	}
152 
153 	@Test
154 	public void testGarbageSelectivelyVisible() throws IOException {
155 		ObjectId fooId;
156 		try (ObjectInserter ins = db.newObjectInserter()) {
157 			fooId = ins.insert(Constants.OBJ_BLOB, Constants.encode("foo"));
158 			ins.flush();
159 		}
160 		assertEquals(1, db.getObjectDatabase().listPacks().size());
161 
162 		// Make pack 0 garbage.
163 		db.getObjectDatabase().listPacks().get(0).setPackSource(PackSource.UNREACHABLE_GARBAGE);
164 
165 		// Default behavior should be that the database has foo, because we allow garbage objects.
166 		assertTrue(db.getObjectDatabase().has(fooId));
167 		// But we should not be able to see it if we pass the right args.
168 		assertFalse(db.getObjectDatabase().has(fooId, true));
169 	}
170 
171 	@Test
172 	public void testInserterIgnoresUnreachable() throws IOException {
173 		ObjectId fooId;
174 		try (ObjectInserter ins = db.newObjectInserter()) {
175 			fooId = ins.insert(Constants.OBJ_BLOB, Constants.encode("foo"));
176 			ins.flush();
177 			assertEquals(1, db.getObjectDatabase().listPacks().size());
178 
179 			// Make pack 0 garbage.
180 			db.getObjectDatabase().listPacks().get(0)
181 					.setPackSource(PackSource.UNREACHABLE_GARBAGE);
182 
183 			// We shouldn't be able to see foo because it's garbage.
184 			assertFalse(db.getObjectDatabase().has(fooId, true));
185 
186 			// But if we re-insert foo, it should become visible again.
187 			ins.insert(Constants.OBJ_BLOB, Constants.encode("foo"));
188 			ins.flush();
189 		}
190 		assertTrue(db.getObjectDatabase().has(fooId, true));
191 
192 		// Verify that we have a foo in both packs, and 1 of them is garbage.
193 		try (DfsReader reader = new DfsReader(db.getObjectDatabase())) {
194 			DfsPackFile packs[] = db.getObjectDatabase().getPacks();
195 			Set<PackSource> pack_sources = new HashSet<>();
196 
197 			assertEquals(2, packs.length);
198 
199 			pack_sources.add(packs[0].getPackDescription().getPackSource());
200 			pack_sources.add(packs[1].getPackDescription().getPackSource());
201 
202 			assertTrue(packs[0].hasObject(reader, fooId));
203 			assertTrue(packs[1].hasObject(reader, fooId));
204 			assertTrue(pack_sources.contains(PackSource.UNREACHABLE_GARBAGE));
205 			assertTrue(pack_sources.contains(PackSource.INSERT));
206 		}
207 	}
208 
209 	@Test
210 	public void testNoCheckExisting() throws IOException {
211 		byte[] contents = Constants.encode("foo");
212 		ObjectId fooId;
213 		try (ObjectInserter ins = db.newObjectInserter()) {
214 			fooId = ins.insert(Constants.OBJ_BLOB, contents);
215 			ins.flush();
216 		}
217 		assertEquals(1, db.getObjectDatabase().listPacks().size());
218 
219 		try (ObjectInserter ins = db.newObjectInserter()) {
220 			((DfsInserter) ins).checkExisting(false);
221 			assertEquals(fooId, ins.insert(Constants.OBJ_BLOB, contents));
222 			ins.flush();
223 		}
224 		assertEquals(2, db.getObjectDatabase().listPacks().size());
225 
226 		// Verify that we have a foo in both INSERT packs.
227 		try (DfsReader reader = new DfsReader(db.getObjectDatabase())) {
228 			DfsPackFile packs[] = db.getObjectDatabase().getPacks();
229 
230 			assertEquals(2, packs.length);
231 			DfsPackFile p1 = packs[0];
232 			assertEquals(PackSource.INSERT,
233 					p1.getPackDescription().getPackSource());
234 			assertTrue(p1.hasObject(reader, fooId));
235 
236 			DfsPackFile p2 = packs[1];
237 			assertEquals(PackSource.INSERT,
238 					p2.getPackDescription().getPackSource());
239 			assertTrue(p2.hasObject(reader, fooId));
240 		}
241 	}
242 
243 	private static String readString(ObjectLoader loader) throws IOException {
244 		return RawParseUtils.decode(readStream(loader));
245 	}
246 
247 	private static byte[] readStream(ObjectLoader loader) throws IOException {
248 		ByteBuffer bb = IO.readWholeStream(loader.openStream(), 64);
249 		byte[] buf = new byte[bb.remaining()];
250 		bb.get(buf);
251 		return buf;
252 	}
253 }