IDEs like Eclipse offer up the settings in WindowCacheConfig to the user as a global set of options that are configured for the entire JVM process, not per-repository, as the cache is shared across the entire JVM. The limit on how much we are willing to allocate for an object buffer is similar to the limit on how much we can use for data caches, allocating that much space impacts the entire JVM and not just a single repository, so it should be a global limit. Change-Id: I22eafb3e223bf8dea57ece82cd5df8bfe5badebc Signed-off-by: Shawn O. Pearce <spearce@spearce.org>tags/v0.9.1
WindowCursor curs) throws IOException { | WindowCursor curs) throws IOException { | ||||
wrapped.selectObjectRepresentation(packer, otp, curs); | wrapped.selectObjectRepresentation(packer, otp, curs); | ||||
} | } | ||||
@Override | |||||
int getStreamFileThreshold() { | |||||
return wrapped.getStreamFileThreshold(); | |||||
} | |||||
} | } |
abstract FileObjectDatabase newCachedFileObjectDatabase(); | abstract FileObjectDatabase newCachedFileObjectDatabase(); | ||||
abstract int getStreamFileThreshold(); | |||||
static class AlternateHandle { | static class AlternateHandle { | ||||
final FileObjectDatabase db; | final FileObjectDatabase db; | ||||
options.getObjectDirectory(), // | options.getObjectDirectory(), // | ||||
options.getAlternateObjectDirectories(), // | options.getAlternateObjectDirectories(), // | ||||
getFS()); | getFS()); | ||||
getListenerList().addConfigChangedListener(objectDatabase); | |||||
if (objectDatabase.exists()) { | if (objectDatabase.exists()) { | ||||
final String repositoryFormatVersion = getConfig().getString( | final String repositoryFormatVersion = getConfig().getString( |
import org.eclipse.jgit.JGitText; | import org.eclipse.jgit.JGitText; | ||||
import org.eclipse.jgit.errors.PackMismatchException; | import org.eclipse.jgit.errors.PackMismatchException; | ||||
import org.eclipse.jgit.events.ConfigChangedEvent; | |||||
import org.eclipse.jgit.events.ConfigChangedListener; | |||||
import org.eclipse.jgit.lib.AbbreviatedObjectId; | import org.eclipse.jgit.lib.AbbreviatedObjectId; | ||||
import org.eclipse.jgit.lib.AnyObjectId; | import org.eclipse.jgit.lib.AnyObjectId; | ||||
import org.eclipse.jgit.lib.Config; | import org.eclipse.jgit.lib.Config; | ||||
import org.eclipse.jgit.lib.Constants; | import org.eclipse.jgit.lib.Constants; | ||||
import org.eclipse.jgit.lib.CoreConfig; | |||||
import org.eclipse.jgit.lib.ObjectDatabase; | import org.eclipse.jgit.lib.ObjectDatabase; | ||||
import org.eclipse.jgit.lib.ObjectId; | import org.eclipse.jgit.lib.ObjectId; | ||||
import org.eclipse.jgit.lib.ObjectInserter; | import org.eclipse.jgit.lib.ObjectInserter; | ||||
* searched (recursively through all alternates) before the slow half is | * searched (recursively through all alternates) before the slow half is | ||||
* considered. | * considered. | ||||
*/ | */ | ||||
public class ObjectDirectory extends FileObjectDatabase implements | |||||
ConfigChangedListener { | |||||
public class ObjectDirectory extends FileObjectDatabase { | |||||
private static final PackList NO_PACKS = new PackList(-1, -1, new PackFile[0]); | private static final PackList NO_PACKS = new PackList(-1, -1, new PackFile[0]); | ||||
/** Maximum number of candidates offered as resolutions of abbreviation. */ | /** Maximum number of candidates offered as resolutions of abbreviation. */ | ||||
private final AtomicReference<AlternateHandle[]> alternates; | private final AtomicReference<AlternateHandle[]> alternates; | ||||
private int streamFileThreshold; | |||||
/** | /** | ||||
* Initialize a reference to an on-disk object directory. | * Initialize a reference to an on-disk object directory. | ||||
* | * | ||||
alt[i] = openAlternate(alternatePaths[i]); | alt[i] = openAlternate(alternatePaths[i]); | ||||
alternates.set(alt); | alternates.set(alt); | ||||
} | } | ||||
onConfigChanged(new ConfigChangedEvent()); | |||||
} | |||||
public void onConfigChanged(ConfigChangedEvent event) { | |||||
CoreConfig core = config.get(CoreConfig.KEY); | |||||
streamFileThreshold = core.getStreamFileThreshold(); | |||||
} | } | ||||
/** | /** | ||||
FileObjectDatabase newCachedFileObjectDatabase() { | FileObjectDatabase newCachedFileObjectDatabase() { | ||||
return new CachedObjectDirectory(this); | return new CachedObjectDirectory(this); | ||||
} | } | ||||
@Override | |||||
int getStreamFileThreshold() { | |||||
return streamFileThreshold; | |||||
} | |||||
} | } |
private static volatile WindowCache cache; | private static volatile WindowCache cache; | ||||
private static volatile int streamFileThreshold; | |||||
static { | static { | ||||
reconfigure(new WindowCacheConfig()); | reconfigure(new WindowCacheConfig()); | ||||
} | } | ||||
if (oc != null) | if (oc != null) | ||||
oc.removeAll(); | oc.removeAll(); | ||||
cache = nc; | cache = nc; | ||||
streamFileThreshold = cfg.getStreamFileThreshold(); | |||||
UnpackedObjectCache.reconfigure(cfg); | UnpackedObjectCache.reconfigure(cfg); | ||||
} | } | ||||
static int getStreamFileThreshold() { | |||||
return streamFileThreshold; | |||||
} | |||||
static WindowCache getInstance() { | static WindowCache getInstance() { | ||||
return cache; | return cache; | ||||
} | } |
package org.eclipse.jgit.storage.file; | package org.eclipse.jgit.storage.file; | ||||
import org.eclipse.jgit.lib.Config; | import org.eclipse.jgit.lib.Config; | ||||
import org.eclipse.jgit.lib.ObjectLoader; | |||||
/** Configuration parameters for {@link WindowCache}. */ | /** Configuration parameters for {@link WindowCache}. */ | ||||
public class WindowCacheConfig { | public class WindowCacheConfig { | ||||
private int deltaBaseCacheLimit; | private int deltaBaseCacheLimit; | ||||
private int streamFileThreshold; | |||||
/** Create a default configuration. */ | /** Create a default configuration. */ | ||||
public WindowCacheConfig() { | public WindowCacheConfig() { | ||||
packedGitOpenFiles = 128; | packedGitOpenFiles = 128; | ||||
packedGitWindowSize = 8 * KB; | packedGitWindowSize = 8 * KB; | ||||
packedGitMMAP = false; | packedGitMMAP = false; | ||||
deltaBaseCacheLimit = 10 * MB; | deltaBaseCacheLimit = 10 * MB; | ||||
streamFileThreshold = ObjectLoader.STREAM_THRESHOLD; | |||||
} | } | ||||
/** | /** | ||||
deltaBaseCacheLimit = newLimit; | deltaBaseCacheLimit = newLimit; | ||||
} | } | ||||
/** @return the size threshold beyond which objects must be streamed. */ | |||||
public int getStreamFileThreshold() { | |||||
return streamFileThreshold; | |||||
} | |||||
/** | |||||
* @param newLimit | |||||
* new byte limit for objects that must be streamed. Objects | |||||
* smaller than this size can be obtained as a contiguous byte | |||||
* array, while objects bigger than this size require using an | |||||
* {@link org.eclipse.jgit.lib.ObjectStream}. | |||||
*/ | |||||
public void setStreamFileThreshold(final int newLimit) { | |||||
streamFileThreshold = newLimit; | |||||
} | |||||
/** | /** | ||||
* Update properties by setting fields from the configuration. | * Update properties by setting fields from the configuration. | ||||
* <p> | * <p> | ||||
setPackedGitWindowSize(rc.getInt("core", null, "packedgitwindowsize", getPackedGitWindowSize())); | setPackedGitWindowSize(rc.getInt("core", null, "packedgitwindowsize", getPackedGitWindowSize())); | ||||
setPackedGitMMAP(rc.getBoolean("core", null, "packedgitmmap", isPackedGitMMAP())); | setPackedGitMMAP(rc.getBoolean("core", null, "packedgitmmap", isPackedGitMMAP())); | ||||
setDeltaBaseCacheLimit(rc.getInt("core", null, "deltabasecachelimit", getDeltaBaseCacheLimit())); | setDeltaBaseCacheLimit(rc.getInt("core", null, "deltabasecachelimit", getDeltaBaseCacheLimit())); | ||||
long maxMem = Runtime.getRuntime().maxMemory(); | |||||
long sft = rc.getLong("core", null, "streamfilethreshold", getStreamFileThreshold()); | |||||
sft = Math.min(sft, maxMem / 4); // don't use more than 1/4 of the heap | |||||
sft = Math.min(sft, Integer.MAX_VALUE); // cannot exceed array length | |||||
setStreamFileThreshold((int) sft); | |||||
} | } | ||||
} | } |
} | } | ||||
int getStreamFileThreshold() { | int getStreamFileThreshold() { | ||||
if (db == null) | |||||
return ObjectLoader.STREAM_THRESHOLD; | |||||
return db.getStreamFileThreshold(); | |||||
return WindowCache.getStreamFileThreshold(); | |||||
} | } | ||||
/** Release the current window cursor. */ | /** Release the current window cursor. */ |