2 * Copyright (C) 2009-2010, Google Inc.
3 * Copyright (C) 2009, Robin Rosenberg <robin.rosenberg@dewire.com>
4 * and other copyright owners as documented in the project's IP log.
6 * This program and the accompanying materials are made available
7 * under the terms of the Eclipse Distribution License v1.0 which
8 * accompanies this distribution, is reproduced below, and is
9 * available at http://www.eclipse.org/org/documents/edl-v10.php
11 * All rights reserved.
13 * Redistribution and use in source and binary forms, with or
14 * without modification, are permitted provided that the following
17 * - Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer.
20 * - Redistributions in binary form must reproduce the above
21 * copyright notice, this list of conditions and the following
22 * disclaimer in the documentation and/or other materials provided
23 * with the distribution.
25 * - Neither the name of the Eclipse Foundation, Inc. nor the
26 * names of its contributors may be used to endorse or promote
27 * products derived from this software without specific prior
30 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
31 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
32 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
33 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
34 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
35 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
36 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
37 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
38 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
39 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
40 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
41 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
42 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
45 package org
.eclipse
.jgit
.lib
;
47 import java
.io
.BufferedOutputStream
;
49 import java
.io
.FileOutputStream
;
50 import java
.io
.IOException
;
51 import java
.io
.OutputStream
;
52 import java
.util
.Arrays
;
54 import org
.eclipse
.jgit
.errors
.IncorrectObjectTypeException
;
55 import org
.eclipse
.jgit
.errors
.MissingObjectException
;
56 import org
.eclipse
.jgit
.revwalk
.RevObject
;
57 import org
.eclipse
.jgit
.revwalk
.RevWalk
;
59 public class ConcurrentRepackTest
extends RepositoryTestCase
{
60 public void setUp() throws Exception
{
61 WindowCacheConfig windowCacheConfig
= new WindowCacheConfig();
62 windowCacheConfig
.setPackedGitOpenFiles(1);
63 WindowCache
.reconfigure(windowCacheConfig
);
67 protected void tearDown() throws Exception
{
69 WindowCacheConfig windowCacheConfig
= new WindowCacheConfig();
70 WindowCache
.reconfigure(windowCacheConfig
);
73 public void testObjectInNewPack() throws IncorrectObjectTypeException
,
75 // Create a new object in a new pack, and test that it is present.
77 final Repository eden
= createBareRepository();
78 final RevObject o1
= writeBlob(eden
, "o1");
80 assertEquals(o1
.name(), parse(o1
).name());
83 public void testObjectMovedToNewPack1()
84 throws IncorrectObjectTypeException
, IOException
{
85 // Create an object and pack it. Then remove that pack and put the
86 // object into a different pack file, with some other object. We
87 // still should be able to access the objects.
89 final Repository eden
= createBareRepository();
90 final RevObject o1
= writeBlob(eden
, "o1");
91 final File
[] out1
= pack(eden
, o1
);
92 assertEquals(o1
.name(), parse(o1
).name());
94 final RevObject o2
= writeBlob(eden
, "o2");
97 // Force close, and then delete, the old pack.
102 // Now here is the interesting thing. Will git figure the new
103 // object exists in the new pack, and not the old one.
105 assertEquals(o2
.name(), parse(o2
).name());
106 assertEquals(o1
.name(), parse(o1
).name());
109 public void testObjectMovedWithinPack()
110 throws IncorrectObjectTypeException
, IOException
{
111 // Create an object and pack it.
113 final Repository eden
= createBareRepository();
114 final RevObject o1
= writeBlob(eden
, "o1");
115 final File
[] out1
= pack(eden
, o1
);
116 assertEquals(o1
.name(), parse(o1
).name());
118 // Force close the old pack.
122 // Now overwrite the old pack in place. This method of creating a
123 // different pack under the same file name is partially broken. We
124 // should also have a different file name because the list of objects
125 // within the pack has been modified.
127 final RevObject o2
= writeBlob(eden
, "o2");
128 final PackWriter pw
= new PackWriter(eden
, NullProgressMonitor
.INSTANCE
);
133 // Try the old name, then the new name. The old name should cause the
134 // pack to reload when it opens and the index and pack mismatch.
136 assertEquals(o1
.name(), parse(o1
).name());
137 assertEquals(o2
.name(), parse(o2
).name());
140 public void testObjectMovedToNewPack2()
141 throws IncorrectObjectTypeException
, IOException
{
142 // Create an object and pack it. Then remove that pack and put the
143 // object into a different pack file, with some other object. We
144 // still should be able to access the objects.
146 final Repository eden
= createBareRepository();
147 final RevObject o1
= writeBlob(eden
, "o1");
148 final File
[] out1
= pack(eden
, o1
);
149 assertEquals(o1
.name(), parse(o1
).name());
151 final ObjectLoader load1
= db
.openBlob(o1
);
152 assertNotNull(load1
);
154 final RevObject o2
= writeBlob(eden
, "o2");
157 // Force close, and then delete, the old pack.
162 // Now here is the interesting thing... can the loader we made
163 // earlier still resolve the object, even though its underlying
164 // pack is gone, but the object still exists.
166 final ObjectLoader load2
= db
.openBlob(o1
);
167 assertNotNull(load2
);
168 assertNotSame(load1
, load2
);
170 final byte[] data2
= load2
.getCachedBytes();
171 final byte[] data1
= load1
.getCachedBytes();
172 assertNotNull(data2
);
173 assertNotNull(data1
);
174 assertNotSame(data1
, data2
); // cache should be per-pack, not per object
175 assertTrue(Arrays
.equals(data1
, data2
));
176 assertEquals(load2
.getType(), load1
.getType());
179 private static void whackCache() {
180 final WindowCacheConfig config
= new WindowCacheConfig();
181 config
.setPackedGitOpenFiles(1);
182 WindowCache
.reconfigure(config
);
185 private RevObject
parse(final AnyObjectId id
)
186 throws MissingObjectException
, IOException
{
187 return new RevWalk(db
).parseAny(id
);
190 private File
[] pack(final Repository src
, final RevObject
... list
)
192 final PackWriter pw
= new PackWriter(src
, NullProgressMonitor
.INSTANCE
);
193 for (final RevObject o
: list
) {
197 final ObjectId name
= pw
.computeName();
198 final File packFile
= fullPackFileName(name
, ".pack");
199 final File idxFile
= fullPackFileName(name
, ".idx");
200 final File
[] files
= new File
[] { packFile
, idxFile
};
205 private static void write(final File
[] files
, final PackWriter pw
)
207 final long begin
= files
[0].getParentFile().lastModified();
210 out
= new BufferedOutputStream(new FileOutputStream(files
[0]));
217 out
= new BufferedOutputStream(new FileOutputStream(files
[1]));
224 touch(begin
, files
[0].getParentFile());
227 private static void delete(final File
[] list
) {
228 final long begin
= list
[0].getParentFile().lastModified();
229 for (final File f
: list
) {
231 assertFalse(f
+ " was removed", f
.exists());
233 touch(begin
, list
[0].getParentFile());
236 private static void touch(final long begin
, final File dir
) {
237 while (begin
>= dir
.lastModified()) {
240 } catch (InterruptedException ie
) {
243 dir
.setLastModified(System
.currentTimeMillis());
247 private File
fullPackFileName(final ObjectId name
, final String suffix
) {
248 final File packdir
= new File(db
.getObjectsDirectory(), "pack");
249 return new File(packdir
, "pack-" + name
.name() + suffix
);
252 private RevObject
writeBlob(final Repository repo
, final String data
)
254 final RevWalk revWalk
= new RevWalk(repo
);
255 final byte[] bytes
= Constants
.encode(data
);
256 final ObjectWriter ow
= new ObjectWriter(repo
);
257 final ObjectId id
= ow
.writeBlob(bytes
);
260 fail("Object " + id
.name() + " should not exist in test repository");
261 } catch (MissingObjectException e
) {
264 return revWalk
.lookupBlob(id
);