# HG changeset patch # User Artem Tikhomirov # Date 1365690426 -7200 # Node ID e4ee4bf4c7d0f95c525547c5cfb1709bd1c0bf94 # Parent 36853bb80a3535a321af36d9cb3901e8550254ce Let session context control creation of Path instances diff -r 36853bb80a35 -r e4ee4bf4c7d0 src/org/tmatesoft/hg/core/HgCloneCommand.java --- a/src/org/tmatesoft/hg/core/HgCloneCommand.java Thu Apr 11 16:07:17 2013 +0200 +++ b/src/org/tmatesoft/hg/core/HgCloneCommand.java Thu Apr 11 16:27:06 2013 +0200 @@ -146,6 +146,7 @@ private final ProgressSupport progressSupport; private final CancelSupport cancelSupport; private final SessionContext ctx; + private final Path.Source pathFactory; private FileOutputStream indexFile; private String filename; // human-readable name of the file being written, for log/exception purposes @@ -174,6 +175,7 @@ progressSupport = progress; cancelSupport = cancel; revlogDataZip = new RevlogCompressor(sessionCtx); + pathFactory = ctx.getPathFactory(); } public void initEmptyRepository() throws IOException { @@ -243,7 +245,7 @@ try { revlogHeader.offset(0).baseRevision(-1); revisionSequence.clear(); - fncacheFile.add(Path.create(name)); + fncacheFile.add(pathFactory.path(name)); File file = new File(hgDir, filename = storagePathHelper.rewrite(name).toString()); file.getParentFile().mkdirs(); indexFile = new FileOutputStream(file); diff -r 36853bb80a35 -r e4ee4bf4c7d0 src/org/tmatesoft/hg/core/HgLogCommand.java --- a/src/org/tmatesoft/hg/core/HgLogCommand.java Thu Apr 11 16:07:17 2013 +0200 +++ b/src/org/tmatesoft/hg/core/HgLogCommand.java Thu Apr 11 16:27:06 2013 +0200 @@ -230,7 +230,8 @@ * @return this for convenience */ public HgLogCommand file(String file, boolean followCopyRename) { - return file(Path.create(repo.getToRepoPathHelper().rewrite(file)), followCopyRename); + Path.Source ps = repo.getSessionContext().getPathFactory(); + return file(ps.path(repo.getToRepoPathHelper().rewrite(file)), followCopyRename); } /** @@ -238,7 +239,8 @@ * @return this for convenience */ public HgLogCommand file(String file, boolean followCopyRename, boolean followFileAncestry) { - return file(Path.create(repo.getToRepoPathHelper().rewrite(file)), followCopyRename, followFileAncestry); + Path.Source ps = repo.getSessionContext().getPathFactory(); + return file(ps.path(repo.getToRepoPathHelper().rewrite(file)), followCopyRename, followFileAncestry); } /** diff -r 36853bb80a35 -r e4ee4bf4c7d0 src/org/tmatesoft/hg/core/HgRepoFacade.java --- a/src/org/tmatesoft/hg/core/HgRepoFacade.java Thu Apr 11 16:07:17 2013 +0200 +++ b/src/org/tmatesoft/hg/core/HgRepoFacade.java Thu Apr 11 16:27:06 2013 +0200 @@ -36,7 +36,7 @@ * @author Artem Tikhomirov * @author TMate Software Ltd. */ -public class HgRepoFacade { +public class HgRepoFacade implements SessionContext.Source { private HgRepository repo; private final SessionContext context; @@ -97,6 +97,10 @@ } return repo; } + + public SessionContext getSessionContext() { + return context; + } public HgLogCommand createLogCommand() { return new HgLogCommand(repo/*, getCommandContext()*/); diff -r 36853bb80a35 -r e4ee4bf4c7d0 src/org/tmatesoft/hg/core/SessionContext.java --- a/src/org/tmatesoft/hg/core/SessionContext.java Thu Apr 11 16:07:17 2013 +0200 +++ b/src/org/tmatesoft/hg/core/SessionContext.java Thu Apr 11 16:27:06 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2012 TMate Software Ltd + * Copyright (c) 2011-2013 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 @@ -17,6 +17,7 @@ package org.tmatesoft.hg.core; import org.tmatesoft.hg.util.LogFacility; +import org.tmatesoft.hg.util.Path; /** * Access to objects that might need to be shared between various distinct operations ran during the same working session @@ -47,6 +48,25 @@ // e.g. when there's standalone Caches and WritableSessionProperties objects /** + * Provide a factory to create {@link Path} objects. + * + * Occasionally, there's a need to construct a {@link Path} object from a string/byte data + * kept in mercurial control files. Generally, default implementation (with {@link Path#create(CharSequence)} + * is enough, however, if there's a need to control number of string objects in memory (i.e. prevent duplicates), + * default implementation might need to be replaced with more sophisticated (e.g. using weak references or + * just a huge hash set). + * + * @return factory to construct Path objects, never null + */ + public Path.Source getPathFactory() { + return new Path.Source() { + public Path path(CharSequence p) { + return Path.create(p); + } + }; + } + + /** * Providers of the context may implement */ public interface Source { diff -r 36853bb80a35 -r e4ee4bf4c7d0 src/org/tmatesoft/hg/internal/SubrepoManager.java --- a/src/org/tmatesoft/hg/internal/SubrepoManager.java Thu Apr 11 16:07:17 2013 +0200 +++ b/src/org/tmatesoft/hg/internal/SubrepoManager.java Thu Apr 11 16:27:06 2013 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011-2012 TMate Software Ltd + * Copyright (c) 2011-2013 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 @@ -81,6 +81,7 @@ String line; LinkedList res = new LinkedList(); HgInternals hgRepoInternal = new HgInternals(repo); + final Path.Source pathFactory = repo.getSessionContext().getPathFactory(); while ((line = br.readLine()) != null) { int sep = line.indexOf('='); if (sep == -1) { @@ -109,7 +110,7 @@ // // apparently, key value can't end with '/', `hg commit` fails if it does: // abort: path ends in directory separator: fourth/ - Path p = Path.create(key.charAt(key.length()-1) == '/' ? key : key + '/'); + Path p = pathFactory.path(key.charAt(key.length()-1) == '/' ? key : key + '/'); String revValue = substate.get(key); HgSubrepoLocation loc = hgRepoInternal.newSubrepo(p, value, kind, revValue == null ? null : Nodeid.fromAscii(revValue)); res.add(loc); diff -r 36853bb80a35 -r e4ee4bf4c7d0 src/org/tmatesoft/hg/repo/HgDataFile.java --- a/src/org/tmatesoft/hg/repo/HgDataFile.java Thu Apr 11 16:07:17 2013 +0200 +++ b/src/org/tmatesoft/hg/repo/HgDataFile.java Thu Apr 11 16:27:06 2013 +0200 @@ -401,7 +401,8 @@ */ public Path getCopySourceName() throws HgRuntimeException { if (isCopy()) { - return Path.create(metadata.find(0, "copy")); + Path.Source ps = getRepo().getSessionContext().getPathFactory(); + return ps.path(metadata.find(0, "copy")); } throw new UnsupportedOperationException(); // XXX REVISIT, think over if Exception is good (clients would check isCopy() anyway, perhaps null is sufficient?) } diff -r 36853bb80a35 -r e4ee4bf4c7d0 src/org/tmatesoft/hg/repo/HgManifest.java --- a/src/org/tmatesoft/hg/repo/HgManifest.java Thu Apr 11 16:07:17 2013 +0200 +++ b/src/org/tmatesoft/hg/repo/HgManifest.java Thu Apr 11 16:27:06 2013 +0200 @@ -194,7 +194,7 @@ manifestLast = manifestFirst; manifestFirst = x; } - content.iterate(manifestFirst, manifestLast, true, new ManifestParser(inspector, encodingHelper)); + content.iterate(manifestFirst, manifestLast, true, new ManifestParser(inspector)); } /** @@ -214,7 +214,7 @@ throw new IllegalArgumentException(); } int[] manifestRevs = toManifestRevisionIndexes(revisionIndexes, inspector); - content.iterate(manifestRevs, true, new ManifestParser(inspector, encodingHelper)); + content.iterate(manifestRevs, true, new ManifestParser(inspector)); } // @@ -399,18 +399,16 @@ * of the String, but these are only for unique Strings (Paths) (3020 in the example above). Besides, I save * useless char[] and byte->char conversions. */ - private static class PathProxy { + private final class PathProxy { private byte[] data; private int start; private final int hash, length; private Path result; - private final EncodingHelper encHelper; - public PathProxy(byte[] data, int start, int length, EncodingHelper eh) { + public PathProxy(byte[] data, int start, int length) { this.data = data; this.start = start; this.length = length; - this.encHelper = eh; // copy from String.hashCode(). In fact, not necessarily match result of String(data).hashCode // just need some nice algorithm here @@ -448,7 +446,8 @@ public Path freeze() { if (result == null) { - result = Path.create(encHelper.fromManifest(data, start, length)); + Path.Source pathFactory = HgManifest.this.getRepo().getSessionContext().getPathFactory(); + result = pathFactory.path(HgManifest.this.encodingHelper.fromManifest(data, start, length)); // release reference to bigger data array, make a copy of relevant part only // use original bytes, not those from String above to avoid cache misses due to different encodings byte[] d = new byte[length]; @@ -460,19 +459,17 @@ } } - private static class ManifestParser implements RevlogStream.Inspector, Lifecycle { + private class ManifestParser implements RevlogStream.Inspector, Lifecycle { private final Inspector inspector; private IdentityPool nodeidPool, thisRevPool; private final IdentityPool fnamePool; private byte[] nodeidLookupBuffer = new byte[20]; // get reassigned each time new Nodeid is added to pool private final ProgressSupport progressHelper; private IterateControlMediator iterateControl; - private final EncodingHelper encHelper; - public ManifestParser(Inspector delegate, EncodingHelper eh) { + public ManifestParser(Inspector delegate) { assert delegate != null; inspector = delegate; - encHelper = eh; nodeidPool = new IdentityPool(); fnamePool = new IdentityPool(); thisRevPool = new IdentityPool(); @@ -496,7 +493,7 @@ int x = i; for( ; data[i] != '\n' && i < actualLen; i++) { if (fname == null && data[i] == 0) { - PathProxy px = fnamePool.unify(new PathProxy(data, x, i - x, encHelper)); + PathProxy px = fnamePool.unify(new PathProxy(data, x, i - x)); // if (cached = fnamePool.unify(px))== px then cacheMiss, else cacheHit // cpython 0..10k: hits: 15 989 152, misses: 3020 fname = px.freeze(); diff -r 36853bb80a35 -r e4ee4bf4c7d0 src/org/tmatesoft/hg/repo/HgRepository.java --- a/src/org/tmatesoft/hg/repo/HgRepository.java Thu Apr 11 16:07:17 2013 +0200 +++ b/src/org/tmatesoft/hg/repo/HgRepository.java Thu Apr 11 16:27:06 2013 +0200 @@ -266,7 +266,7 @@ public HgDataFile getFileNode(String path) { CharSequence nPath = normalizePath.rewrite(path); - Path p = Path.create(nPath); + Path p = sessionContext.getPathFactory().path(nPath); return getFileNode(p); }