/* * ==================================================================== * Copyright (c) 2004-2012 TMate Software Ltd. All rights reserved. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at http://svnkit.com/license.html. * If newer versions of this license are posted there, you may use a * newer version instead, at your option. * ==================================================================== */ package org.tmatesoft.svn.core.internal.io.fs; import java.util.ArrayList; import java.util.Arrays; import org.tmatesoft.svn.core.SVNErrorCode; import org.tmatesoft.svn.core.SVNErrorMessage; import org.tmatesoft.svn.core.SVNException; import org.tmatesoft.svn.core.SVNNodeKind; import org.tmatesoft.svn.core.internal.wc.SVNErrorManager; import org.tmatesoft.svn.core.io.ISVNLocationEntryHandler; import org.tmatesoft.svn.core.io.ISVNLocationSegmentHandler; import org.tmatesoft.svn.core.io.SVNLocationEntry; import org.tmatesoft.svn.core.io.SVNLocationSegment; import org.tmatesoft.svn.core.io.SVNRepository; import org.tmatesoft.svn.util.SVNLogType; /** * @version 1.3 * @author TMate Software Ltd. */ public class FSLocationsFinder { private FSFS myFSFS; public FSLocationsFinder(FSFS fsfs) { myFSFS = fsfs; } public int traceNodeLocations(String path, long pegRevision, long[] revisions, ISVNLocationEntryHandler handler) throws SVNException { ArrayList locationEntries = new ArrayList(0); long[] locationRevs = new long[revisions.length]; long revision; Arrays.sort(revisions); for (int i = 0; i < revisions.length; ++i) { locationRevs[i] = revisions[revisions.length - (i + 1)]; } int count = 0; boolean isAncestor = false; for (count = 0; count < locationRevs.length && locationRevs[count] > pegRevision; ++count) { isAncestor = FSNodeHistory.checkAncestryOfPegPath(path, pegRevision, locationRevs[count], myFSFS); if (isAncestor) { break; } } if (count >= locationRevs.length) { return 0; } revision = isAncestor ? locationRevs[count] : pegRevision; FSRevisionRoot root = null; while (count < revisions.length) { long[] appearedRevision = new long[1]; root = myFSFS.createRevisionRoot(revision); SVNLocationEntry previousLocation = root.getPreviousLocation(path, appearedRevision); if (previousLocation == null) { break; } String previousPath = previousLocation.getPath(); long previousRevision = previousLocation.getRevision(); while ((count < revisions.length) && (locationRevs[count] >= appearedRevision[0])) { locationEntries.add(new SVNLocationEntry(locationRevs[count], path)); ++count; } while ((count < revisions.length) && locationRevs[count] > previousRevision) { ++count; } path = previousPath; revision = previousRevision; } if (root != null && revision != root.getRevision()) { root = myFSFS.createRevisionRoot(revision); } FSRevisionNode curNode = root.getRevisionNode(path); while (count < revisions.length) { root = myFSFS.createRevisionRoot(locationRevs[count]); if (root.checkNodeKind(path) == SVNNodeKind.NONE) { break; } FSRevisionNode currentNode = root.getRevisionNode(path); if (!curNode.getId().isRelated(currentNode.getId())) { break; } locationEntries.add(new SVNLocationEntry(locationRevs[count], path)); ++count; } for (count = 0; count < locationEntries.size(); count++) { if (handler != null) { handler.handleLocationEntry((SVNLocationEntry) locationEntries.get(count)); } } return count; } public long getNodeLocationSegments(String path, long pegRevision, long startRevision, long endRevision, ISVNLocationSegmentHandler handler) throws SVNException { long youngestRevision = SVNRepository.INVALID_REVISION; if (FSRepository.isInvalidRevision(pegRevision)) { pegRevision = youngestRevision = myFSFS.getYoungestRevision(); } if (FSRepository.isInvalidRevision(startRevision)) { if (FSRepository.isValidRevision(youngestRevision)) { startRevision = youngestRevision; } else { startRevision = myFSFS.getYoungestRevision(); } } if (FSRepository.isInvalidRevision(endRevision)) { endRevision = 0; } if (endRevision > startRevision) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.UNKNOWN, "End revision {0} must be less or equal to start revision {1}", new Object[] { new Long(endRevision), new Long(startRevision) }); SVNErrorManager.error(err, SVNLogType.FSFS); } if (pegRevision < startRevision) { SVNErrorMessage err = SVNErrorMessage.create(SVNErrorCode.UNKNOWN, "Peg revision {0} must be greater or equal to start revision {1}", new Object[] { new Long(pegRevision), new Long(startRevision) }); SVNErrorManager.error(err, SVNLogType.FSFS); } if (!path.startsWith("/")) { path = "/" + path; } long count = 0; long currentRevision = pegRevision; String currentPath = path; long[] appearedRevision = new long[1]; while (currentRevision >= endRevision) { long segmentStartRevision = endRevision; long segmentEndRevision = currentRevision; String segmentPath = currentPath; FSRevisionRoot root = myFSFS.createRevisionRoot(currentRevision); SVNLocationEntry previousLocation = root.getPreviousLocation(currentPath, appearedRevision); if (previousLocation == null) { segmentStartRevision = root.getNodeOriginRevision(currentPath); if (segmentStartRevision < endRevision) { segmentStartRevision = endRevision; } currentRevision = SVNRepository.INVALID_REVISION; } else { segmentStartRevision = appearedRevision[0]; currentPath = previousLocation.getPath(); currentRevision = previousLocation.getRevision(); } count += maybeCropAndSendSegment(segmentStartRevision, segmentEndRevision, startRevision, endRevision, segmentPath, handler); if (FSRepository.isInvalidRevision(currentRevision)) { break; } if (segmentStartRevision - currentRevision > 1) { count += maybeCropAndSendSegment(currentRevision + 1, segmentStartRevision - 1, startRevision, endRevision, null, handler); } } return count; } protected void reset(FSFS fsfs) { myFSFS = fsfs; } private long maybeCropAndSendSegment(long segmentStartRevision, long segmentEndRevision, long startRevision, long endRevision, String segmentPath, ISVNLocationSegmentHandler handler) throws SVNException { if (!(segmentStartRevision > startRevision || segmentEndRevision < endRevision)) { if (segmentStartRevision < endRevision) { segmentStartRevision = endRevision; } if (segmentEndRevision > startRevision) { segmentEndRevision = startRevision; } if (handler != null) { handler.handleLocationSegment(new SVNLocationSegment(segmentStartRevision, segmentEndRevision, segmentPath)); } return segmentEndRevision - segmentStartRevision + 1; } return 0; } }