diff options
Diffstat (limited to 'org.eclipse.jgit')
9 files changed, 328 insertions, 9 deletions
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/AlternateRepositoryDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/AlternateRepositoryDatabase.java index 311839e430..f8570a4203 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/AlternateRepositoryDatabase.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/AlternateRepositoryDatabase.java @@ -1,4 +1,5 @@ /* + * Copyright (C) 2010, Constantine Plotnikov <constantine.plotnikov@gmail.com> * Copyright (C) 2009, Google Inc. * and other copyright owners as documented in the project's IP log. * @@ -130,4 +131,9 @@ public final class AlternateRepositoryDatabase extends ObjectDatabase { protected void closeAlternates(final ObjectDatabase[] alt) { // Do nothing; these belong to odb to close, not us. } + + @Override + public ObjectDatabase newCachedDatabase() { + return odb.newCachedDatabase(); + } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/CachedObjectDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CachedObjectDatabase.java new file mode 100644 index 0000000000..3dcea1636f --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CachedObjectDatabase.java @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2010, Constantine Plotnikov <constantine.plotnikov@gmail.com> + * Copyright (C) 2010, JetBrains s.r.o. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.eclipse.jgit.lib; + +import java.io.IOException; +import java.util.Collection; + +/** + * {@link ObjectDatabase} wrapper providing temporary lookup caching. + * <p> + * The base class for {@code ObjectDatabase}s that wrap other database instances + * and optimize querying for objects by caching some database dependent + * information. Instances of this class (or any of its subclasses) can be + * returned from the method {@link ObjectDatabase#newCachedDatabase()}. This + * class can be used in scenarios where the database does not change, or when + * changes in the database while some operation is in progress is an acceptable + * risk. + * <p> + * The default implementation delegates all requests to the wrapped database. + * The instance might be indirectly invalidated if the wrapped instance is + * closed. Closing the delegating instance does not implies closing the wrapped + * instance. For alternative databases, cached instances are used as well. + */ +public class CachedObjectDatabase extends ObjectDatabase { + /** + * The wrapped database instance + */ + protected final ObjectDatabase wrapped; + + /** + * Create the delegating database instance + * + * @param wrapped + * the wrapped object database + */ + public CachedObjectDatabase(ObjectDatabase wrapped) { + this.wrapped = wrapped; + } + + @Override + protected boolean hasObject1(AnyObjectId objectId) { + return wrapped.hasObject1(objectId); + } + + @Override + protected ObjectLoader openObject1(WindowCursor curs, AnyObjectId objectId) + throws IOException { + return wrapped.openObject1(curs, objectId); + } + + @Override + protected boolean hasObject2(String objectName) { + return wrapped.hasObject2(objectName); + } + + @Override + protected ObjectDatabase[] loadAlternates() throws IOException { + ObjectDatabase[] loaded = wrapped.getAlternates(); + ObjectDatabase[] result = new ObjectDatabase[loaded.length]; + for (int i = 0; i < loaded.length; i++) { + result[i] = loaded[i].newCachedDatabase(); + } + return result; + } + + @Override + protected ObjectLoader openObject2(WindowCursor curs, String objectName, + AnyObjectId objectId) throws IOException { + return wrapped.openObject2(curs, objectName, objectId); + } + + @Override + void openObjectInAllPacks1(Collection<PackedObjectLoader> out, + WindowCursor curs, AnyObjectId objectId) throws IOException { + wrapped.openObjectInAllPacks1(out, curs, objectId); + } + + @Override + protected boolean tryAgain1() { + return wrapped.tryAgain1(); + } + + @Override + public ObjectDatabase newCachedDatabase() { + // Note that "this" is not returned since subclasses might actually do something, + // on closeSelf() (for example closing database connections or open repositories). + // The situation might become even more tricky if we will consider alternates. + return wrapped.newCachedDatabase(); + } +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/CachedObjectDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CachedObjectDirectory.java new file mode 100644 index 0000000000..3724f84463 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/CachedObjectDirectory.java @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2010, Constantine Plotnikov <constantine.plotnikov@gmail.com> + * Copyright (C) 2010, JetBrains s.r.o. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.eclipse.jgit.lib; + +import java.io.File; +import java.io.IOException; + +/** + * The cached instance of an {@link ObjectDirectory}. + * <p> + * This class caches the list of loose objects in memory, so the file system is + * not queried with stat calls. + */ +public class CachedObjectDirectory extends CachedObjectDatabase { + /** + * The set that contains unpacked objects identifiers, it is created when + * the cached instance is created. + */ + private final ObjectIdSubclassMap<ObjectId> unpackedObjects = new ObjectIdSubclassMap<ObjectId>(); + + /** + * The constructor + * + * @param wrapped + * the wrapped database + */ + public CachedObjectDirectory(ObjectDirectory wrapped) { + super(wrapped); + File objects = wrapped.getDirectory(); + String[] fanout = objects.list(); + if (fanout == null) + fanout = new String[0]; + for (String d : fanout) { + if (d.length() != 2) + continue; + String[] entries = new File(objects, d).list(); + if (entries == null) + continue; + for (String e : entries) { + if (e.length() != Constants.OBJECT_ID_STRING_LENGTH - 2) + continue; + try { + unpackedObjects.add(ObjectId.fromString(d + e)); + } catch (IllegalArgumentException notAnObject) { + // ignoring the file that does not represent loose object + } + } + } + } + + @Override + protected ObjectLoader openObject2(WindowCursor curs, String objectName, + AnyObjectId objectId) throws IOException { + if (unpackedObjects.get(objectId) == null) + return null; + return super.openObject2(curs, objectName, objectId); + } + + @Override + protected boolean hasObject1(AnyObjectId objectId) { + if (unpackedObjects.get(objectId) != null) + return true; // known to be loose + return super.hasObject1(objectId); + } + + @Override + protected boolean hasObject2(String name) { + return false; // loose objects were tested by hasObject1 + } +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java index 661371ca21..0d0c377f8f 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Config.java @@ -577,6 +577,43 @@ public class Config { } /** + * Remove all configuration values under a single section. + * + * @param section + * section name, e.g "branch" + * @param subsection + * optional subsection value, e.g. a branch name + */ + public void unsetSection(String section, String subsection) { + State src, res; + do { + src = state.get(); + res = unsetSection(src, section, subsection); + } while (!state.compareAndSet(src, res)); + } + + private State unsetSection(final State srcState, final String section, + final String subsection) { + final int max = srcState.entryList.size(); + final ArrayList<Entry> r = new ArrayList<Entry>(max); + + boolean lastWasMatch = false; + for (Entry e : srcState.entryList) { + if (e.match(section, subsection)) { + // Skip this record, it's for the section we are removing. + lastWasMatch = true; + continue; + } + + if (lastWasMatch && e.section == null && e.subsection == null) + continue; // skip this padding line in the section. + r.add(e); + } + + return newState(r); + } + + /** * Set a configuration value. * * <pre> @@ -715,9 +752,10 @@ public class Config { if (e.prefix == null || "".equals(e.prefix)) out.append('\t'); out.append(e.name); - if (e.value != null) { - if (MAGIC_EMPTY_VALUE != e.value) { - out.append(" = "); + if (MAGIC_EMPTY_VALUE != e.value) { + out.append(" ="); + if (e.value != null) { + out.append(' '); out.append(escapeValue(e.value)); } } @@ -1103,6 +1141,11 @@ public class Config { && eqIgnoreCase(name, aKey); } + boolean match(final String aSection, final String aSubsection) { + return eqIgnoreCase(section, aSection) + && eqSameCase(subsection, aSubsection); + } + private static boolean eqIgnoreCase(final String a, final String b) { if (a == null && b == null) return true; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectChecker.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectChecker.java index 82a8c38257..5906802d18 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectChecker.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectChecker.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008, Google Inc. + * Copyright (C) 2008-2010, Google Inc. * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> * and other copyright owners as documented in the project's IP log. * @@ -217,10 +217,10 @@ public class ObjectChecker { throw new CorruptObjectException("no tag header"); ptr = nextLF(raw, ptr); - if ((ptr = match(raw, ptr, tagger)) < 0) - throw new CorruptObjectException("no tagger header"); - if ((ptr = personIdent(raw, ptr)) < 0 || raw[ptr++] != '\n') - throw new CorruptObjectException("invalid tagger"); + if ((ptr = match(raw, ptr, tagger)) > 0) { + if ((ptr = personIdent(raw, ptr)) < 0 || raw[ptr++] != '\n') + throw new CorruptObjectException("invalid tagger"); + } } private static int lastPathChar(final int mode) { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectDatabase.java index 21b7b9dc93..7eac79fb78 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectDatabase.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectDatabase.java @@ -380,4 +380,16 @@ public abstract class ObjectDatabase { d.close(); } } + + /** + * Create a new cached database instance over this database. This instance might + * optimize queries by caching some information about database. So some modifications + * done after instance creation might fail to be noticed. + * + * @return new cached database instance + * @see CachedObjectDatabase + */ + public ObjectDatabase newCachedDatabase() { + return new CachedObjectDatabase(this); + } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectDirectory.java index a6fdbfae5c..a8d6dda066 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectDirectory.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectDirectory.java @@ -541,4 +541,9 @@ public class ObjectDirectory extends ObjectDatabase { return true; } } + + @Override + public ObjectDatabase newCachedDatabase() { + return new CachedObjectDirectory(this); + } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/IndexPack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/IndexPack.java index 6e0f228079..7c94767b49 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/IndexPack.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/IndexPack.java @@ -68,6 +68,7 @@ import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.InflaterCache; import org.eclipse.jgit.lib.MutableObjectId; import org.eclipse.jgit.lib.ObjectChecker; +import org.eclipse.jgit.lib.ObjectDatabase; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectIdSubclassMap; import org.eclipse.jgit.lib.ObjectLoader; @@ -130,6 +131,11 @@ public class IndexPack { private final Repository repo; + /** + * Object database used for loading existing objects + */ + private final ObjectDatabase objectDatabase; + private Inflater inflater; private final MessageDigest objectDigest; @@ -199,6 +205,7 @@ public class IndexPack { public IndexPack(final Repository db, final InputStream src, final File dstBase) throws IOException { repo = db; + objectDatabase = db.getObjectDatabase().newCachedDatabase(); in = src; inflater = InflaterCache.get(); readCurs = new WindowCursor(); @@ -350,6 +357,7 @@ public class IndexPack { InflaterCache.release(inflater); } finally { inflater = null; + objectDatabase.close(); } readCurs = WindowCursor.release(readCurs); @@ -756,7 +764,7 @@ public class IndexPack { } } - final ObjectLoader ldr = repo.openObject(readCurs, id); + final ObjectLoader ldr = objectDatabase.openObject(readCurs, id); if (ldr != null) { final byte[] existingData = ldr.getCachedBytes(); if (ldr.getType() != type || !Arrays.equals(data, existingData)) { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java index f041765b8a..c53bcf2601 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java @@ -373,6 +373,7 @@ public class TransportHttp extends HttpTransport implements WalkTransport, final HttpURLConnection httpOpen(final URL u) throws IOException { final Proxy proxy = HttpSupport.proxyFor(proxySelector, u); HttpURLConnection conn = (HttpURLConnection) u.openConnection(proxy); + conn.setUseCaches(false); conn.setRequestProperty(HDR_ACCEPT_ENCODING, ENCODING_GZIP); conn.setRequestProperty(HDR_PRAGMA, "no-cache");//$NON-NLS-1$ conn.setRequestProperty(HDR_USER_AGENT, userAgent); |