Mercurial > jhg
changeset 431:12f668401613
FIXMEs: awkward API refactored, what need to be internal got hidden; public aspects got captured in slim interfaces
line wrap: on
line diff
--- a/cmdline/org/tmatesoft/hg/console/Main.java Thu Mar 29 18:48:23 2012 +0200 +++ b/cmdline/org/tmatesoft/hg/console/Main.java Thu Mar 29 20:54:04 2012 +0200 @@ -265,7 +265,7 @@ private void testTreeTraversal() throws Exception { File repoRoot = hgRepo.getWorkingDir(); Path.Source pathSrc = new Path.SimpleSource(new PathRewrite.Composite(new RelativePathRewrite(repoRoot), hgRepo.getToRepoPathHelper())); - FileWalker w = new FileWalker(new BasicSessionContext(null, null), repoRoot, pathSrc); + FileWalker w = new FileWalker(new BasicSessionContext(null), repoRoot, pathSrc); int count = 0; final long start = System.currentTimeMillis(); while (w.hasNext()) {
--- a/src/org/tmatesoft/hg/core/ChangesetTransformer.java Thu Mar 29 18:48:23 2012 +0200 +++ b/src/org/tmatesoft/hg/core/ChangesetTransformer.java Thu Mar 29 20:54:04 2012 +0200 @@ -18,6 +18,7 @@ import java.util.Set; +import org.tmatesoft.hg.internal.PathPool; import org.tmatesoft.hg.repo.HgChangelog; import org.tmatesoft.hg.repo.HgChangelog.RawChangeset; import org.tmatesoft.hg.repo.HgRepository; @@ -25,7 +26,6 @@ import org.tmatesoft.hg.util.Adaptable; import org.tmatesoft.hg.util.CancelSupport; import org.tmatesoft.hg.util.CancelledException; -import org.tmatesoft.hg.util.PathPool; import org.tmatesoft.hg.util.PathRewrite; import org.tmatesoft.hg.util.ProgressSupport; @@ -103,6 +103,7 @@ public Transformation(HgStatusCollector statusCollector, HgChangelog.ParentWalker pw) { // files listed in a changeset don't need their names to be rewritten (they are normalized already) + // pp serves as a cache for all filenames encountered and as a source for Path listed in the changeset PathPool pp = new PathPool(new PathRewrite.Empty()); statusCollector.setPathPool(pp); changeset = new HgChangeset(statusCollector, pp);
--- a/src/org/tmatesoft/hg/core/HgCloneCommand.java Thu Mar 29 18:48:23 2012 +0200 +++ b/src/org/tmatesoft/hg/core/HgCloneCommand.java Thu Mar 29 20:54:04 2012 +0200 @@ -147,7 +147,7 @@ public WriteDownMate(File destDir) { hgDir = new File(destDir, ".hg"); - implHelper = new Internals(new BasicSessionContext(null, null)); + implHelper = new Internals(new BasicSessionContext(null)); implHelper.setStorageConfig(1, STORE | FNCACHE | DOTENCODE); storagePathHelper = implHelper.buildDataFilesHelper(); }
--- a/src/org/tmatesoft/hg/core/HgFileRevision.java Thu Mar 29 18:48:23 2012 +0200 +++ b/src/org/tmatesoft/hg/core/HgFileRevision.java Thu Mar 29 20:54:04 2012 +0200 @@ -42,7 +42,9 @@ private Flags flags; // null unless set/extracted /** - * FIXME has to be public? + * New description of a file revision from a specific repository. + * + * <p>Although this constructor is public, and clients can use it to construct own file revisions to pass e.g. to commands, its use is discouraged. * * @param hgRepo repository * @param rev file revision
--- a/src/org/tmatesoft/hg/core/HgLogCommand.java Thu Mar 29 18:48:23 2012 +0200 +++ b/src/org/tmatesoft/hg/core/HgLogCommand.java Thu Mar 29 20:54:04 2012 +0200 @@ -323,7 +323,7 @@ HistoryNode[] go(HgDataFile fileNode) throws HgInvalidControlFileException { completeHistory = new HistoryNode[fileNode.getRevisionCount()]; commitRevisions = new int[completeHistory.length]; - fileNode.walk(0, TIP, this); + fileNode.indexWalk(0, TIP, this); return completeHistory; } };
--- a/src/org/tmatesoft/hg/core/HgManifestCommand.java Thu Mar 29 18:48:23 2012 +0200 +++ b/src/org/tmatesoft/hg/core/HgManifestCommand.java Thu Mar 29 20:54:04 2012 +0200 @@ -25,6 +25,7 @@ import java.util.LinkedList; import java.util.List; +import org.tmatesoft.hg.internal.PathPool; import org.tmatesoft.hg.repo.HgManifest; import org.tmatesoft.hg.repo.HgRepository; import org.tmatesoft.hg.repo.HgManifest.Flags; @@ -32,7 +33,6 @@ import org.tmatesoft.hg.util.CancelSupport; import org.tmatesoft.hg.util.CancelledException; import org.tmatesoft.hg.util.Path; -import org.tmatesoft.hg.util.PathPool; import org.tmatesoft.hg.util.PathRewrite;
--- a/src/org/tmatesoft/hg/core/HgRepoFacade.java Thu Mar 29 18:48:23 2012 +0200 +++ b/src/org/tmatesoft/hg/core/HgRepoFacade.java Thu Mar 29 20:54:04 2012 +0200 @@ -41,7 +41,7 @@ private final SessionContext context; public HgRepoFacade() { - this(new BasicSessionContext(null, null)); + this(new BasicSessionContext(null)); } public HgRepoFacade(SessionContext ctx) {
--- a/src/org/tmatesoft/hg/internal/BasicSessionContext.java Thu Mar 29 18:48:23 2012 +0200 +++ b/src/org/tmatesoft/hg/internal/BasicSessionContext.java Thu Mar 29 20:54:04 2012 +0200 @@ -21,8 +21,6 @@ import org.tmatesoft.hg.core.SessionContext; import org.tmatesoft.hg.util.LogFacility; -import org.tmatesoft.hg.util.PathPool; -import org.tmatesoft.hg.util.PathRewrite; /** * @@ -31,28 +29,19 @@ */ public class BasicSessionContext implements SessionContext { - private PathPool pathPool; private LogFacility logFacility; private final Map<String, Object> properties; - public BasicSessionContext(PathPool pathFactory, LogFacility log) { - this(null, pathFactory, log); + public BasicSessionContext(LogFacility log) { + this(null, log); } @SuppressWarnings("unchecked") - public BasicSessionContext(Map<String,?> propertyOverrides, PathPool pathFactory, LogFacility log) { - pathPool = pathFactory; + public BasicSessionContext(Map<String,?> propertyOverrides, LogFacility log) { logFacility = log; properties = propertyOverrides == null ? Collections.<String,Object>emptyMap() : (Map<String, Object>) propertyOverrides; } - public PathPool getPathPool() { - if (pathPool == null) { - pathPool = new PathPool(new PathRewrite.Empty()); - } - return pathPool; - } - public LogFacility getLog() { // e.g. for exceptions that we can't handle but log (e.g. FileNotFoundException when we've checked beforehand file.canRead() if (logFacility == null) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tmatesoft/hg/internal/IdentityPool.java Thu Mar 29 20:54:04 2012 +0200 @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2011 TMate Software Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * For information on how to redistribute this software under + * the terms of a license other than GNU General Public License + * contact TMate Software at support@hg4j.com + */ +package org.tmatesoft.hg.internal; + +import org.tmatesoft.hg.util.Convertor; +import org.tmatesoft.hg.util.DirectHashSet; + + +/** + * + * @author Artem Tikhomirov + * @author TMate Software Ltd. + */ +public class IdentityPool<T> implements Convertor<T> { + private final DirectHashSet<T> unify = new DirectHashSet<T>(); + + public IdentityPool() { + } + + public IdentityPool(int sizeHint) { + } + + public T mangle(T t) { + return unify(t); + } + + public T unify(T t) { + T rv = unify.get(t); + if (rv == null) { + // first time we see a new value + unify.put(t); + rv = t; + } + return rv; + } + + public boolean contains(T t) { + return unify.get(t) != null; + } + + public void record(T t) { + unify.put(t); + } + + public void clear() { + unify.clear(); + } + + public int size() { + return unify.size(); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(IdentityPool.class.getSimpleName()); + sb.append('@'); + sb.append(Integer.toString(System.identityHashCode(this))); + sb.append(' '); + sb.append(unify.toString()); + return sb.toString(); + } +}
--- a/src/org/tmatesoft/hg/internal/ManifestRevision.java Thu Mar 29 18:48:23 2012 +0200 +++ b/src/org/tmatesoft/hg/internal/ManifestRevision.java Thu Mar 29 20:54:04 2012 +0200 @@ -21,6 +21,7 @@ import org.tmatesoft.hg.core.Nodeid; import org.tmatesoft.hg.repo.HgManifest; +import org.tmatesoft.hg.util.Convertor; import org.tmatesoft.hg.util.Path; /** @@ -33,14 +34,14 @@ public final class ManifestRevision implements HgManifest.Inspector { private final TreeMap<Path, Nodeid> idsMap; private final TreeMap<Path, HgManifest.Flags> flagsMap; - private final Pool<Nodeid> idsPool; - private final Pool<Path> namesPool; + private final Convertor<Nodeid> idsPool; + private final Convertor<Path> namesPool; private Nodeid changeset; private int changelogRev; // optional pools for effective management of nodeids and filenames (they are likely // to be duplicated among different manifest revisions - public ManifestRevision(Pool<Nodeid> nodeidPool, Pool<Path> filenamePool) { + public ManifestRevision(Pool<Nodeid> nodeidPool, Convertor<Path> filenamePool) { idsPool = nodeidPool; namesPool = filenamePool; idsMap = new TreeMap<Path, Nodeid>(); @@ -75,10 +76,10 @@ public boolean next(Nodeid nid, Path fname, HgManifest.Flags flags) { if (namesPool != null) { - fname = namesPool.unify(fname); + fname = namesPool.mangle(fname); } if (idsPool != null) { - nid = idsPool.unify(nid); + nid = idsPool.mangle(nid); } idsMap.put(fname, nid); if (flags != HgManifest.Flags.RegularFile) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tmatesoft/hg/internal/PathPool.java Thu Mar 29 20:54:04 2012 +0200 @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2011-2012 TMate Software Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * For information on how to redistribute this software under + * the terms of a license other than GNU General Public License + * contact TMate Software at support@hg4j.com + */ +package org.tmatesoft.hg.internal; + +import java.lang.ref.SoftReference; +import java.util.WeakHashMap; + +import org.tmatesoft.hg.util.Convertor; +import org.tmatesoft.hg.util.Path; +import org.tmatesoft.hg.util.PathRewrite; + + +/** + * Produces path from strings and caches (weakly) result for reuse + * + * @author Artem Tikhomirov + * @author TMate Software Ltd. + */ +public class PathPool implements Path.Source, Convertor<Path> { + private final WeakHashMap<CharSequence, SoftReference<Path>> cache; + private final PathRewrite pathRewrite; + + public PathPool(PathRewrite rewrite) { + pathRewrite = rewrite; + cache = new WeakHashMap<CharSequence, SoftReference<Path>>(); + } + + /* + * (non-Javadoc) + * @see org.tmatesoft.hg.util.Path.Source#path(java.lang.CharSequence) + */ + public Path path(CharSequence p) { + if (p instanceof Path) { + return asPath((Path) p); + } + p = pathRewrite.rewrite(p); + return get(p, true); + } + + /* + * (non-Javadoc) + * @see org.tmatesoft.hg.util.Convertor#mangle(java.lang.Object) + */ + public Path mangle(Path p) { + return asPath(p); + } + + // pipes path object through cache to reuse instance, if possible + // TODO unify with Pool<Path> + private Path asPath(Path p) { + CharSequence s = pathRewrite.rewrite(p.toString()); + // rewrite string, not path to avoid use of Path object as key + // in case pathRewrite does nothing and returns supplied instance + // + Path cached = get(s, false); + if (cached == null) { + cache.put(s, new SoftReference<Path>(cached = p)); + } + return cached; + } + + // XXX what would be parent of an empty path? + // Path shall have similar functionality + public Path parent(Path path) { + if (path.length() == 0) { + throw new IllegalArgumentException(); + } + for (int i = path.length() - 2 /*if path represents a dir, trailing char is slash, skip*/; i >= 0; i--) { + if (path.charAt(i) == '/') { + return get(path.subSequence(0, i+1).toString(), true); + } + } + return get("", true); + } + + // invoke when path pool is no longer in use, to ease gc work + public void clear() { + cache.clear(); + } + + private Path get(CharSequence p, boolean create) { + SoftReference<Path> sr = cache.get(p); + Path path = sr == null ? null : sr.get(); + if (path == null) { + if (create) { + path = Path.create(p); + cache.put(p, new SoftReference<Path>(path)); + } else if (sr != null) { + // cached path no longer used, clear cache entry - do not wait for RefQueue to step in + cache.remove(p); + } + } + return path; + } +}
--- a/src/org/tmatesoft/hg/internal/Pool.java Thu Mar 29 18:48:23 2012 +0200 +++ b/src/org/tmatesoft/hg/internal/Pool.java Thu Mar 29 20:54:04 2012 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 TMate Software Ltd + * Copyright (c) 2011-2012 TMate Software Ltd * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,13 +18,15 @@ import java.util.HashMap; +import org.tmatesoft.hg.util.Convertor; + /** * Instance pooling. * * @author Artem Tikhomirov * @author TMate Software Ltd. */ -public class Pool<T> { +public class Pool<T> implements Convertor<T> { private final HashMap<T,T> unify; public Pool() { @@ -38,7 +40,11 @@ unify = new HashMap<T, T>(sizeHint * 4 / 3, 0.75f); } } - + + public T mangle(T t) { + return unify(t); + } + public T unify(T t) { T rv = unify.get(t); if (rv == null) {
--- a/src/org/tmatesoft/hg/internal/Pool2.java Thu Mar 29 18:48:23 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2011 TMate Software Ltd - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * For information on how to redistribute this software under - * the terms of a license other than GNU General Public License - * contact TMate Software at support@hg4j.com - */ -package org.tmatesoft.hg.internal; - -import org.tmatesoft.hg.util.DirectHashSet; - - -/** - * - * @author Artem Tikhomirov - * @author TMate Software Ltd. - */ -public class Pool2<T> { - private final DirectHashSet<T> unify = new DirectHashSet<T>(); - - public Pool2() { - } - - public Pool2(int sizeHint) { - } - - public T unify(T t) { - T rv = unify.get(t); - if (rv == null) { - // first time we see a new value - unify.put(t); - rv = t; - } - return rv; - } - - public boolean contains(T t) { - return unify.get(t) != null; - } - - public void record(T t) { - unify.put(t); - } - - public void clear() { - unify.clear(); - } - - public int size() { - return unify.size(); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append(Pool2.class.getSimpleName()); - sb.append('@'); - sb.append(Integer.toString(System.identityHashCode(this))); - sb.append(' '); - sb.append(unify.toString()); - return sb.toString(); - } -}
--- a/src/org/tmatesoft/hg/repo/HgDirstate.java Thu Mar 29 18:48:23 2012 +0200 +++ b/src/org/tmatesoft/hg/repo/HgDirstate.java Thu Mar 29 20:54:04 2012 +0200 @@ -34,7 +34,6 @@ import org.tmatesoft.hg.internal.EncodingHelper; import org.tmatesoft.hg.util.Pair; import org.tmatesoft.hg.util.Path; -import org.tmatesoft.hg.util.PathPool; import org.tmatesoft.hg.util.PathRewrite; @@ -53,7 +52,7 @@ private final HgRepository repo; private final File dirstateFile; - private final PathPool pathPool; + private final Path.Source pathPool; private final PathRewrite canonicalPathRewrite; private Map<Path, Record> normal; private Map<Path, Record> added; @@ -66,10 +65,10 @@ private Pair<Nodeid, Nodeid> parents; // canonicalPath may be null if we don't need to check for names other than in dirstate - /*package-local*/ HgDirstate(HgRepository hgRepo, File dirstate, PathPool pathPool, PathRewrite canonicalPath) { + /*package-local*/ HgDirstate(HgRepository hgRepo, File dirstate, Path.Source pathSource, PathRewrite canonicalPath) { repo = hgRepo; dirstateFile = dirstate; // XXX decide whether file names shall be kept local to reader (see #branches()) or passed from outside - this.pathPool = pathPool; + pathPool = pathSource; canonicalPathRewrite = canonicalPath; }
--- a/src/org/tmatesoft/hg/repo/HgInternals.java Thu Mar 29 18:48:23 2012 +0200 +++ b/src/org/tmatesoft/hg/repo/HgInternals.java Thu Mar 29 20:54:04 2012 +0200 @@ -33,7 +33,6 @@ import org.tmatesoft.hg.util.FileIterator; import org.tmatesoft.hg.util.FileWalker; import org.tmatesoft.hg.util.Path; -import org.tmatesoft.hg.util.PathPool; import org.tmatesoft.hg.util.PathRewrite; @@ -56,7 +55,7 @@ } public HgDirstate getDirstate() throws HgInvalidControlFileException { - return repo.loadDirstate(new PathPool(new PathRewrite.Empty())); + return repo.loadDirstate(new Path.SimpleSource()); } // tests @@ -70,7 +69,7 @@ } }; } - HgDirstate ds = new HgDirstate(repo, new File(repo.getRepositoryRoot(), "dirstate"), new PathPool(new PathRewrite.Empty()), canonicalPath); + HgDirstate ds = new HgDirstate(repo, new File(repo.getRepositoryRoot(), "dirstate"), new Path.SimpleSource(), canonicalPath); ds.read(repo.getImplHelper().buildFileNameEncodingHelper()); return ds; }
--- a/src/org/tmatesoft/hg/repo/HgLookup.java Thu Mar 29 18:48:23 2012 +0200 +++ b/src/org/tmatesoft/hg/repo/HgLookup.java Thu Mar 29 20:54:04 2012 +0200 @@ -143,7 +143,7 @@ private SessionContext getContext() { if (sessionContext == null) { - sessionContext = new BasicSessionContext(null, null); + sessionContext = new BasicSessionContext(null); } return sessionContext; }
--- a/src/org/tmatesoft/hg/repo/HgManifest.java Thu Mar 29 18:48:23 2012 +0200 +++ b/src/org/tmatesoft/hg/repo/HgManifest.java Thu Mar 29 20:54:04 2012 +0200 @@ -33,7 +33,7 @@ import org.tmatesoft.hg.internal.IntMap; import org.tmatesoft.hg.internal.IterateControlMediator; import org.tmatesoft.hg.internal.Lifecycle; -import org.tmatesoft.hg.internal.Pool2; +import org.tmatesoft.hg.internal.IdentityPool; import org.tmatesoft.hg.internal.RevlogStream; import org.tmatesoft.hg.util.CancelSupport; import org.tmatesoft.hg.util.Path; @@ -436,8 +436,8 @@ private static class ManifestParser implements RevlogStream.Inspector, Lifecycle { private final Inspector inspector; - private Pool2<Nodeid> nodeidPool, thisRevPool; - private final Pool2<PathProxy> fnamePool; + private IdentityPool<Nodeid> nodeidPool, thisRevPool; + private final IdentityPool<PathProxy> fnamePool; private byte[] nodeidLookupBuffer = new byte[20]; // get reassigned each time new Nodeid is added to pool private final ProgressSupport progressHelper; private IterateControlMediator iterateControl; @@ -447,9 +447,9 @@ assert delegate != null; inspector = delegate; encHelper = eh; - nodeidPool = new Pool2<Nodeid>(); - fnamePool = new Pool2<PathProxy>(); - thisRevPool = new Pool2<Nodeid>(); + nodeidPool = new IdentityPool<Nodeid>(); + fnamePool = new IdentityPool<PathProxy>(); + thisRevPool = new IdentityPool<Nodeid>(); progressHelper = ProgressSupport.Factory.get(delegate); } @@ -518,7 +518,7 @@ // (next manifest is likely to refer to most of them, although in specific cases // like commit in another branch a lot may be useless) nodeidPool.clear(); - Pool2<Nodeid> t = nodeidPool; + IdentityPool<Nodeid> t = nodeidPool; nodeidPool = thisRevPool; thisRevPool = t; iterateControl.checkCancelled();
--- a/src/org/tmatesoft/hg/repo/HgMergeState.java Thu Mar 29 18:48:23 2012 +0200 +++ b/src/org/tmatesoft/hg/repo/HgMergeState.java Thu Mar 29 20:54:04 2012 +0200 @@ -33,7 +33,6 @@ import org.tmatesoft.hg.internal.Pool; import org.tmatesoft.hg.util.Pair; import org.tmatesoft.hg.util.Path; -import org.tmatesoft.hg.util.PathPool; import org.tmatesoft.hg.util.PathRewrite; /** @@ -111,9 +110,8 @@ } try { ArrayList<Entry> result = new ArrayList<Entry>(); - // FIXME need to settle use of Pool<Path> and PathPool - // latter is pool that can create objects on demand, former is just cache - PathPool pathPool = new PathPool(new PathRewrite.Empty()); + // pipe (already normalized) names from mergestate through same pool of filenames as use manifest revisions + Path.Source pathPool = new Path.SimpleSource(new PathRewrite.Empty(), fnamePool); final ManifestRevision m1 = new ManifestRevision(nodeidPool, fnamePool); final ManifestRevision m2 = new ManifestRevision(nodeidPool, fnamePool); if (!wcp2.isNull()) { @@ -163,7 +161,6 @@ } entries = result.toArray(new Entry[result.size()]); br.close(); - pathPool.clear(); } catch (IOException ex) { throw new HgInvalidControlFileException("Merge state read failed", ex, f); }
--- a/src/org/tmatesoft/hg/repo/HgRepository.java Thu Mar 29 18:48:23 2012 +0200 +++ b/src/org/tmatesoft/hg/repo/HgRepository.java Thu Mar 29 20:54:04 2012 +0200 @@ -38,7 +38,6 @@ import org.tmatesoft.hg.util.CancelledException; import org.tmatesoft.hg.util.Pair; import org.tmatesoft.hg.util.Path; -import org.tmatesoft.hg.util.PathPool; import org.tmatesoft.hg.util.PathRewrite; import org.tmatesoft.hg.util.ProgressSupport; @@ -335,7 +334,7 @@ // XXX package-local, unless there are cases when required from outside (guess, working dir/revision walkers may hide dirstate access and no public visibility needed) // XXX consider passing Path pool or factory to produce (shared) Path instead of Strings - /*package-local*/ final HgDirstate loadDirstate(PathPool pathPool) throws HgInvalidControlFileException { + /*package-local*/ final HgDirstate loadDirstate(Path.Source pathFactory) throws HgInvalidControlFileException { PathRewrite canonicalPath = null; if (!impl.isCaseSensitiveFileSystem()) { canonicalPath = new PathRewrite() { @@ -345,7 +344,7 @@ } }; } - HgDirstate ds = new HgDirstate(this, new File(repoDir, "dirstate"), pathPool, canonicalPath); + HgDirstate ds = new HgDirstate(this, new File(repoDir, "dirstate"), pathFactory, canonicalPath); ds.read(impl.buildFileNameEncodingHelper()); return ds; }
--- a/src/org/tmatesoft/hg/repo/HgStatusCollector.java Thu Mar 29 18:48:23 2012 +0200 +++ b/src/org/tmatesoft/hg/repo/HgStatusCollector.java Thu Mar 29 20:54:04 2012 +0200 @@ -32,9 +32,8 @@ import org.tmatesoft.hg.internal.Pool; import org.tmatesoft.hg.util.CancelSupport; import org.tmatesoft.hg.util.CancelledException; +import org.tmatesoft.hg.util.Convertor; import org.tmatesoft.hg.util.Path; -import org.tmatesoft.hg.util.PathPool; -import org.tmatesoft.hg.util.PathRewrite; /** @@ -52,7 +51,7 @@ // no cache limit, but with cached nodeids and filenames - 1730+ // cache limit 100 - 19+ minutes to process 10000, and still working (too long, stopped) private final int cacheMaxSize = 50; // do not keep too much manifest revisions - private PathPool pathPool; + private Convertor<Path> pathPool; private final Pool<Nodeid> cacheNodes; private final Pool<Path> cacheFilenames; private final ManifestRevision emptyFakeState; @@ -161,9 +160,9 @@ /*package-local*/ ManifestRevision raw(int rev) throws HgInvalidControlFileException { return get(rev); } - /*package-local*/ PathPool getPathPool() { + /*package-local*/ Convertor<Path> getPathPool() { if (pathPool == null) { - pathPool = new PathPool(new PathRewrite.Empty()); + pathPool = cacheFilenames; } return pathPool; } @@ -171,8 +170,8 @@ /** * Allows sharing of a common path cache */ - public void setPathPool(PathPool pathPool) { - this.pathPool = pathPool; + public void setPathPool(Convertor<Path> pathConvertor) { + pathPool = pathConvertor; } /** @@ -293,7 +292,7 @@ Path copyTarget = r2fname; Path copyOrigin = getOriginIfCopy(repo, copyTarget, r1Files, rev1); if (copyOrigin != null) { - inspector.copied(getPathPool().path(copyOrigin) /*pipe through pool, just in case*/, copyTarget); + inspector.copied(getPathPool().mangle(copyOrigin) /*pipe through pool, just in case*/, copyTarget); } else { inspector.added(copyTarget); }
--- a/src/org/tmatesoft/hg/repo/HgWorkingCopyStatusCollector.java Thu Mar 29 18:48:23 2012 +0200 +++ b/src/org/tmatesoft/hg/repo/HgWorkingCopyStatusCollector.java Thu Mar 29 20:54:04 2012 +0200 @@ -37,17 +37,18 @@ import org.tmatesoft.hg.internal.FilterByteChannel; import org.tmatesoft.hg.internal.Internals; import org.tmatesoft.hg.internal.ManifestRevision; +import org.tmatesoft.hg.internal.PathPool; import org.tmatesoft.hg.internal.PathScope; import org.tmatesoft.hg.internal.Preview; import org.tmatesoft.hg.util.Adaptable; import org.tmatesoft.hg.util.ByteChannel; import org.tmatesoft.hg.util.CancelSupport; import org.tmatesoft.hg.util.CancelledException; +import org.tmatesoft.hg.util.Convertor; import org.tmatesoft.hg.util.FileInfo; import org.tmatesoft.hg.util.FileIterator; import org.tmatesoft.hg.util.FileWalker; import org.tmatesoft.hg.util.Path; -import org.tmatesoft.hg.util.PathPool; import org.tmatesoft.hg.util.PathRewrite; import org.tmatesoft.hg.util.RegularFileInfo; @@ -62,7 +63,7 @@ private final FileIterator repoWalker; private HgDirstate dirstate; private HgStatusCollector baseRevisionCollector; - private PathPool pathPool; + private Convertor<Path> pathPool; private ManifestRevision dirstateParentManifest; /** @@ -92,7 +93,7 @@ baseRevisionCollector = sc; } - /*package-local*/ PathPool getPathPool() { + /*package-local*/ Convertor<Path> getPathPool() { if (pathPool == null) { if (baseRevisionCollector == null) { pathPool = new PathPool(new PathRewrite.Empty()); @@ -103,8 +104,8 @@ return pathPool; } - public void setPathPool(PathPool pathPool) { - this.pathPool = pathPool; + public void setPathPool(Convertor<Path> pathConvertor) { + pathPool = pathConvertor; } /** @@ -113,7 +114,14 @@ */ public HgDirstate getDirstate() throws HgInvalidControlFileException { if (dirstate == null) { - dirstate = repo.loadDirstate(getPathPool()); + Convertor<Path> pp = getPathPool(); + Path.Source ps; + if (pp instanceof Path.Source) { + ps = (Path.Source) pp; + } else { + ps = new Path.SimpleSource(new PathRewrite.Empty(), pp); + } + dirstate = repo.loadDirstate(ps); } return dirstate; } @@ -206,7 +214,7 @@ while (repoWalker.hasNext()) { cs.checkCancelled(); repoWalker.next(); - final Path fname = getPathPool().path(repoWalker.name()); + final Path fname = getPathPool().mangle(repoWalker.name()); FileInfo f = repoWalker.file(); Path knownInDirstate; if (!f.exists()) { @@ -385,7 +393,7 @@ try { Path origin = HgStatusCollector.getOriginIfCopy(repo, fname, baseRevNames, baseRevision); if (origin != null) { - inspector.copied(getPathPool().path(origin), fname); + inspector.copied(getPathPool().mangle(origin), fname); return; } } catch (HgInvalidFileException ex) {
--- a/src/org/tmatesoft/hg/repo/Revlog.java Thu Mar 29 18:48:23 2012 +0200 +++ b/src/org/tmatesoft/hg/repo/Revlog.java Thu Mar 29 20:54:04 2012 +0200 @@ -290,7 +290,7 @@ * @throws HgRuntimeException subclass thereof to indicate issues with the library. <em>Runtime exception</em> */ @Experimental - public void walk(int start, int end, final Revlog.Inspector inspector) throws HgRuntimeException { + public void indexWalk(int start, int end, final Revlog.Inspector inspector) throws HgRuntimeException { int lastRev = getLastRevision(); if (start == TIP) { start = lastRev; @@ -387,7 +387,7 @@ // sequential = new Nodeid[revisionCount]; sorted = new Nodeid[revisionCount]; - Revlog.this.walk(0, TIP, this); + Revlog.this.indexWalk(0, TIP, this); Arrays.sort(sorted); sorted2natural = new int[revisionCount]; for (int i = 0; i < revisionCount; i++) { @@ -572,7 +572,7 @@ final int revisionCount = Revlog.this.getRevisionCount(); sequential = new Nodeid[revisionCount]; sorted = new Nodeid[revisionCount]; - Revlog.this.walk(0, TIP, this); + Revlog.this.indexWalk(0, TIP, this); // next is alternative to Arrays.sort(sorted), and build sorted2natural looking up each element of sequential in sorted. // the way sorted2natural was build is O(n*log n). final ArrayHelper ah = new ArrayHelper();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/tmatesoft/hg/util/Convertor.java Thu Mar 29 20:54:04 2012 +0200 @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2012 TMate Software Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * For information on how to redistribute this software under + * the terms of a license other than GNU General Public License + * contact TMate Software at support@hg4j.com + */ +package org.tmatesoft.hg.util; + +/** + * Transformations, e.g. unique instances + * + * @author Artem Tikhomirov + * @author TMate Software Ltd. + */ +public interface Convertor<T> { + T mangle(T t); +} \ No newline at end of file
--- a/src/org/tmatesoft/hg/util/Path.java Thu Mar 29 18:48:23 2012 +0200 +++ b/src/org/tmatesoft/hg/util/Path.java Thu Mar 29 20:54:04 2012 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 TMate Software Ltd + * Copyright (c) 2011-2012 TMate Software Ltd * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -187,24 +187,36 @@ * Factory for paths */ public interface Source { - Path path(String p); + Path path(CharSequence p); } - + /** * Straightforward {@link Source} implementation that creates new Path instance for each supplied string + * and optionally piping through a converter to get e.g. cached instance */ public static class SimpleSource implements Source { private final PathRewrite normalizer; + private final Convertor<Path> convertor; + + public SimpleSource() { + this(new PathRewrite.Empty(), null); + } public SimpleSource(PathRewrite pathRewrite) { - if (pathRewrite == null) { - throw new IllegalArgumentException(); - } - normalizer = pathRewrite; + this(pathRewrite, null); } - public Path path(String p) { - return Path.create(normalizer.rewrite(p)); + public SimpleSource(PathRewrite pathRewrite, Convertor<Path> pathConvertor) { + normalizer = pathRewrite; + convertor = pathConvertor; + } + + public Path path(CharSequence p) { + Path rv = Path.create(normalizer.rewrite(p)); + if (convertor != null) { + return convertor.mangle(rv); + } + return rv; } } }
--- a/src/org/tmatesoft/hg/util/PathPool.java Thu Mar 29 18:48:23 2012 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2011 TMate Software Ltd - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * For information on how to redistribute this software under - * the terms of a license other than GNU General Public License - * contact TMate Software at support@hg4j.com - */ -package org.tmatesoft.hg.util; - -import java.lang.ref.SoftReference; -import java.util.WeakHashMap; - - -/** - * Produces path from strings and caches result for reuse - * - * @author Artem Tikhomirov - * @author TMate Software Ltd. - */ -public class PathPool implements Path.Source { - private final WeakHashMap<String, SoftReference<Path>> cache; - private final PathRewrite pathRewrite; - - public PathPool(PathRewrite rewrite) { - pathRewrite = rewrite; - cache = new WeakHashMap<String, SoftReference<Path>>(); - } - - public Path path(String p) { - p = pathRewrite.rewrite(p).toString(); - return get(p, true); - } - - // pipes path object through cache to reuse instance, if possible - // TODO unify with Pool<Path> - public Path path(Path p) { - String s = pathRewrite.rewrite(p).toString(); - Path cached = get(s, false); - if (cached == null) { - cache.put(s, new SoftReference<Path>(cached = p)); - } - return cached; - } - - // XXX what would be parent of an empty path? - // Path shall have similar functionality - public Path parent(Path path) { - if (path.length() == 0) { - throw new IllegalArgumentException(); - } - for (int i = path.length() - 2 /*if path represents a dir, trailing char is slash, skip*/; i >= 0; i--) { - if (path.charAt(i) == '/') { - return get(path.subSequence(0, i+1).toString(), true); - } - } - return get("", true); - } - - // invoke when path pool is no longer in use, to ease gc work - public void clear() { - cache.clear(); - } - - private Path get(String p, boolean create) { - SoftReference<Path> sr = cache.get(p); - Path path = sr == null ? null : sr.get(); - if (path == null) { - if (create) { - path = Path.create(p); - cache.put(p, new SoftReference<Path>(path)); - } else if (sr != null) { - // cached path no longer used, clear cache entry - do not wait for RefQueue to step in - cache.remove(p); - } - } - return path; - } -}
--- a/test/org/tmatesoft/hg/test/MapTagsToFileRevisions.java Thu Mar 29 18:48:23 2012 +0200 +++ b/test/org/tmatesoft/hg/test/MapTagsToFileRevisions.java Thu Mar 29 20:54:04 2012 +0200 @@ -119,7 +119,7 @@ // final long start_3 = System.nanoTime(); final Map<Nodeid, Nodeid> changesetToNodeid_3 = new HashMap<Nodeid, Nodeid>(); - fileNode.walk(0, TIP, new HgDataFile.RevisionInspector() { + fileNode.indexWalk(0, TIP, new HgDataFile.RevisionInspector() { public void next(int fileRevisionIndex, Nodeid revision, int linkedRevisionIndex) { changesetToNodeid_3.put(clog.getRevision(linkedRevisionIndex), revision); @@ -360,7 +360,7 @@ repository.getManifest().walkFileRevisions(targetPath, collectFileRevAtCset,tagLocalRevs); final long start2a = System.nanoTime(); - fileNode.walk(0, lastRev, new HgDataFile.RevisionInspector() { + fileNode.indexWalk(0, lastRev, new HgDataFile.RevisionInspector() { public void next(int fileRevisionIndex, Nodeid fileRevision, int changesetRevisionIndex) { List<String> associatedTags = new LinkedList<String>();
--- a/test/org/tmatesoft/hg/test/StatusOutputParser.java Thu Mar 29 18:48:23 2012 +0200 +++ b/test/org/tmatesoft/hg/test/StatusOutputParser.java Thu Mar 29 20:54:04 2012 +0200 @@ -23,9 +23,9 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.tmatesoft.hg.internal.PathPool; import org.tmatesoft.hg.repo.HgStatusCollector; import org.tmatesoft.hg.util.Path; -import org.tmatesoft.hg.util.PathPool; import org.tmatesoft.hg.util.PathRewrite; /**
--- a/test/org/tmatesoft/hg/test/TestAuxUtilities.java Thu Mar 29 18:48:23 2012 +0200 +++ b/test/org/tmatesoft/hg/test/TestAuxUtilities.java Thu Mar 29 20:54:04 2012 +0200 @@ -219,14 +219,14 @@ @Test public void testRevlogInspectors() throws Exception { // TODO move to better place HgRepository repository = Configuration.get().find("branches-1"); // any repo - repository.getChangelog().walk(0, TIP, new HgChangelog.RevisionInspector() { + repository.getChangelog().indexWalk(0, TIP, new HgChangelog.RevisionInspector() { public void next(int localRevision, Nodeid revision, int linkedRevision) { Assert.assertEquals(localRevision, linkedRevision); } }); final HgDataFile fileNode = repository.getFileNode("file1"); - fileNode.walk(0, TIP, new HgDataFile.RevisionInspector() { + fileNode.indexWalk(0, TIP, new HgDataFile.RevisionInspector() { int i = 0; public void next(int localRevision, Nodeid revision, int linkedRevision) { @@ -235,7 +235,7 @@ Assert.assertEquals(fileNode.getRevision(localRevision), revision); } }); - fileNode.walk(0, TIP, new HgDataFile.ParentInspector() { + fileNode.indexWalk(0, TIP, new HgDataFile.ParentInspector() { int i = 0; Nodeid[] all = new Nodeid[fileNode.getRevisionCount()];
--- a/test/org/tmatesoft/hg/test/TestByteChannel.java Thu Mar 29 18:48:23 2012 +0200 +++ b/test/org/tmatesoft/hg/test/TestByteChannel.java Thu Mar 29 20:54:04 2012 +0200 @@ -98,7 +98,7 @@ public void testWorkingCopyFileAccess() throws Exception { final File repoDir = TestIncoming.initEmptyTempRepo("testWorkingCopyFileAccess"); final Map<String, ?> props = Collections.singletonMap(Internals.CFG_PROPERTY_REVLOG_STREAM_CACHE, false); - repo = new HgLookup(new BasicSessionContext(props, null, null)).detect(repoDir); + repo = new HgLookup(new BasicSessionContext(props, null)).detect(repoDir); File f1 = new File(repoDir, "file1"); final String c1 = "First", c2 = "Second", c3 = "Third"; ByteArrayChannel ch;
--- a/test/org/tmatesoft/hg/test/TestIncoming.java Thu Mar 29 18:48:23 2012 +0200 +++ b/test/org/tmatesoft/hg/test/TestIncoming.java Thu Mar 29 20:54:04 2012 +0200 @@ -135,7 +135,7 @@ static File initEmptyTempRepo(String dirName) throws IOException { File dest = createEmptyDir(dirName); - Internals implHelper = new Internals(new BasicSessionContext(null, null, null)); + Internals implHelper = new Internals(new BasicSessionContext(null)); implHelper.setStorageConfig(1, STORE | FNCACHE | DOTENCODE); implHelper.initEmptyRepository(new File(dest, ".hg")); return dest;
--- a/test/org/tmatesoft/hg/test/TestStorePath.java Thu Mar 29 18:48:23 2012 +0200 +++ b/test/org/tmatesoft/hg/test/TestStorePath.java Thu Mar 29 20:54:04 2012 +0200 @@ -54,7 +54,7 @@ public TestStorePath() { propertyOverrides.put("hg.consolelog.debug", true); - internals = new Internals(new BasicSessionContext(propertyOverrides, null, null)); + internals = new Internals(new BasicSessionContext(propertyOverrides, null)); internals.setStorageConfig(1, 0x7); storePathHelper = internals.buildDataFilesHelper(); }