diff src/org/tmatesoft/hg/internal/RevlogStream.java @ 608:e1b29756f901

Clean, organize and resolve some TODOs and FIXMEs: minor refactorings and comments
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Tue, 07 May 2013 21:27:51 +0200
parents 66f1cc23b906
children 65c01508f002
line wrap: on
line diff
--- a/src/org/tmatesoft/hg/internal/RevlogStream.java	Tue May 07 16:52:46 2013 +0200
+++ b/src/org/tmatesoft/hg/internal/RevlogStream.java	Tue May 07 21:27:51 2013 +0200
@@ -50,6 +50,8 @@
  */
 public class RevlogStream {
 
+	static final int INLINEDATA = 1 << 16;
+
 	/*
 	 * makes sense for index with inline data only - actual offset of the record in the .i file (record entry + revision * record size))
 	 * 
@@ -63,7 +65,7 @@
 	private boolean inline = false;
 	private final File indexFile;
 	private File dataFile;
-	private final DataAccessProvider dataAccess;
+	private final Internals repo;
 	// keeps last complete revision we've read. Note, this cached revision doesn't help
 	// for subsequent #iterate() calls with the same revision (Inspector needs more data than 
 	// we currently cache here, perhaps, we shall cache everything it wants to cover same 
@@ -77,14 +79,10 @@
 	private List<Observer> observers;
 	private boolean shallDropDerivedCaches = false;
 
-	// if we need anything else from HgRepo, might replace DAP parameter with HgRepo and query it for DAP.
-	public RevlogStream(DataAccessProvider dap, File indexFile) {
-		this.dataAccess = dap;
+	public RevlogStream(Internals hgRepo, File indexFile) {
+		repo = hgRepo;
 		this.indexFile = indexFile;
-		// TODO in fact, shall ask Internals for an instance (there we'll decide whether to use
-		// one monitor per multiple files or an instance per file; and let SessionContext pass
-		// alternative implementation)
-		changeTracker = new RevlogChangeMonitor(indexFile);
+		changeTracker = repo.getRevlogTracker(indexFile);
 	}
 
 	/**
@@ -94,18 +92,22 @@
 	/*package*/ DataAccess getIndexStream(boolean shortRead) {
 		// shortRead hint helps  to avoid mmap files when only 
 		// few bytes are to be read (i.e. #dataLength())
+		DataAccessProvider dataAccess = repo.getDataAccess();
 		return dataAccess.createReader(indexFile, shortRead);
 	}
 
 	/*package*/ DataAccess getDataStream() {
+		DataAccessProvider dataAccess = repo.getDataAccess();
 		return dataAccess.createReader(getDataFile(), false);
 	}
 	
 	/*package*/ DataSerializer getIndexStreamWriter() {
+		DataAccessProvider dataAccess = repo.getDataAccess();
 		return dataAccess.createWriter(indexFile, true);
 	}
 	
 	/*package*/ DataSerializer getDataStreamWriter() {
+		DataAccessProvider dataAccess = repo.getDataAccess();
 		return dataAccess.createWriter(getDataFile(), true);
 	}
 	
@@ -301,14 +303,12 @@
 		HgInternals.checkRevlogRange(start, end, indexSize-1);
 		// XXX may cache [start .. end] from index with a single read (pre-read)
 		
-		ReaderN1 r = new ReaderN1(needData, inspector, dataAccess.shallMergePatches());
+		ReaderN1 r = new ReaderN1(needData, inspector, repo.shallMergePatches());
 		try {
 			r.start(end - start + 1, getLastRevisionRead());
 			r.range(start, end);
 		} catch (IOException ex) {
 			throw new HgInvalidControlFileException(String.format("Failed reading [%d..%d]", start, end), ex, indexFile);
-		} catch (HgInvalidControlFileException ex) {
-			throw ex;
 		} finally {
 			CachedRevision cr = r.finish();
 			setLastRevisionRead(cr);
@@ -334,7 +334,7 @@
 			throw new HgInvalidRevisionException(String.format("Can't iterate [%d, %d] in range [0..%d]", sortedRevisions[0], sortedRevisions[sortedRevisions.length - 1], indexSize), null, sortedRevisions[sortedRevisions.length - 1]);
 		}
 
-		ReaderN1 r = new ReaderN1(needData, inspector, dataAccess.shallMergePatches());
+		ReaderN1 r = new ReaderN1(needData, inspector, repo.shallMergePatches());
 		try {
 			r.start(sortedRevisions.length, getLastRevisionRead());
 			for (int i = 0; i < sortedRevisions.length; ) {
@@ -354,10 +354,7 @@
 			}
 		} catch (IOException ex) {
 			final int c = sortedRevisions.length;
-			throw new HgInvalidControlFileException(String.format("Failed reading %d revisions in [%d; %d]",c, sortedRevisions[0], sortedRevisions[c-1]), ex, indexFile);
-		} catch (HgInvalidControlFileException ex) {
-			// TODO post-1.0 fill HgRuntimeException with appropriate file (either index or data, depending on error source)
-			throw ex;
+			throw new HgInvalidControlFileException(String.format("Failed reading %d revisions in [%d; %d]", c, sortedRevisions[0], sortedRevisions[c-1]), ex, indexFile);
 		} finally {
 			CachedRevision cr = r.finish();
 			setLastRevisionRead(cr);
@@ -488,7 +485,6 @@
 			}
 			int versionField = da.readInt();
 			da.readInt(); // just to skip next 4 bytes of offset + flags
-			final int INLINEDATA = 1 << 16;
 			inline = (versionField & INLINEDATA) != 0;
 			IntVector resBases, resOffsets = null;
 			int entryCountGuess = Internals.ltoi(da.longLength() / REVLOGV1_RECORD_SIZE);
@@ -592,7 +588,7 @@
 		// next are transient values, for range() use only
 		private final Inflater inflater = new Inflater();
 		// can share buffer between instances of InflaterDataAccess as I never read any two of them in parallel
-		private final byte[] inflaterBuffer = new byte[10 * 1024]; // TODO consider using DAP.DEFAULT_FILE_BUFFER
+		private final byte[] inflaterBuffer = new byte[10 * 1024]; // TODO [post-1.1] consider using DAP.DEFAULT_FILE_BUFFER
 		private final byte[] nodeidBuf = new byte[20];
 		// revlog record fields
 		private long offset;
@@ -829,9 +825,22 @@
 
 	
 	public interface Inspector {
-		// XXX boolean retVal to indicate whether to continue?
-		// TODO specify nodeid and data length, and reuse policy (i.e. if revlog stream doesn't reuse nodeid[] for each call)
-		// implementers shall not invoke DataAccess.done(), it's accomplished by #iterate at appropraite moment
+		/**
+		 * XXX boolean retVal to indicate whether to continue?
+		 * 
+		 * Implementers shall not invoke DataAccess.done(), it's accomplished by #iterate at appropriate moment
+		 * 
+		 * @param revisionIndex absolute index of revision in revlog being iterated
+		 * @param actualLen length of the user data at this revision
+		 * @param baseRevision last revision known to hold complete revision (other hold patches). 
+		 *        if baseRevision != revisionIndex, data for this revision is a result of a sequence of patches
+		 * @param linkRevision index of corresponding changeset revision
+		 * @param parent1Revision index of first parent revision in this revlog, or {@link HgRepository#NO_REVISION}
+		 * @param parent2Revision index of second parent revision in this revlog, or {@link HgRepository#NO_REVISION}
+		 * @param nodeid 20-byte buffer, shared between invocations 
+		 * @param data access to revision content of actualLen size, or <code>null</code> if no data has been requested with 
+		 *        {@link RevlogStream#iterate(int[], boolean, Inspector)}
+		 */
 		void next(int revisionIndex, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[/*20*/] nodeid, DataAccess data);
 	}