diff src/org/tmatesoft/hg/repo/HgDataFile.java @ 134:afac8ddc5dd2

Keep record if we tried and found no metadata for a given revision
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Wed, 16 Feb 2011 21:51:32 +0100
parents 4a948ec83980
children 3959bffb14e9
line wrap: on
line diff
--- a/src/org/tmatesoft/hg/repo/HgDataFile.java	Wed Feb 16 20:59:39 2011 +0100
+++ b/src/org/tmatesoft/hg/repo/HgDataFile.java	Wed Feb 16 21:51:32 2011 +0100
@@ -43,7 +43,7 @@
 	// slashes, unix-style?
 	// repo location agnostic, just to give info to user, not to access real storage
 	private final Path path;
-	private Metadata metadata;
+	private Metadata metadata; // get initialized on first access to file content.
 	
 	/*package-local*/HgDataFile(HgRepository hgRepo, Path filePath, RevlogStream content) {
 		super(hgRepo, content);
@@ -100,11 +100,20 @@
 			revision = content.revisionCount() - 1; // FIXME maxRevision.
 		}
 		byte[] data = super.content(revision);
-		if (data.length < 4 || (data[0] != 1 && data[1] != 10)) {
+		if (metadata == null) {
+			metadata = new Metadata();
+		}
+		if (metadata.none(revision)) {
+			// although not very reasonable when data is byte array, this check might
+			// get handy when there's a stream/channel to avoid useless reads and rewinds.
 			return data;
 		}
 		int toSkip = 0;
-		if (metadata == null || !metadata.known(revision)) {
+		if (!metadata.known(revision)) {
+			if (data.length < 4 || (data[0] != 1 && data[1] != 10)) {
+				metadata.recordNone(revision);
+				return data;
+			}
 			int lastEntryStart = 2;
 			int lastColon = -1;
 			ArrayList<MetadataEntry> _metadata = new ArrayList<MetadataEntry>();
@@ -133,9 +142,6 @@
 				}
 			}
 			_metadata.trimToSize();
-			if (metadata == null) {
-				metadata = new Metadata();
-			}
 			metadata.add(revision, lastEntryStart, _metadata);
 			toSkip = lastEntryStart;
 		} else {
@@ -187,10 +193,11 @@
 	}
 
 	public boolean isCopy() {
-		if (metadata == null) {
+		if (metadata == null || !metadata.checked(0)) {
+			// content() always initializes metadata.
 			content(0); // FIXME expensive way to find out metadata, distinct RevlogStream.Iterator would be better.
 		}
-		if (metadata == null || !metadata.known(0)) {
+		if (!metadata.known(0)) {
 			return false;
 		}
 		return metadata.find(0, "copy") != null;
@@ -229,9 +236,10 @@
 		/*package-local*/boolean matchKey(String key) {
 			return key.length() == valueStart && entry.startsWith(key);
 		}
-		public String key() {
-			return entry.substring(0, valueStart);
-		}
+//		uncomment once/if needed
+//		public String key() {
+//			return entry.substring(0, valueStart);
+//		}
 		public String value() {
 			return entry.substring(valueStart);
 		}
@@ -241,14 +249,44 @@
 		// XXX sparse array needed
 		private final TreeMap<Integer, Integer> offsets = new TreeMap<Integer, Integer>();
 		private final TreeMap<Integer, MetadataEntry[]> entries = new TreeMap<Integer, MetadataEntry[]>();
+		
+		private final Integer NONE = new Integer(-1); // do not duplicate -1 integers at least within single file (don't want statics)
+
+		// true when there's metadata for given revision
 		boolean known(int revision) {
+			Integer i = offsets.get(revision);
+			return i != null && NONE != i;
+		}
+
+		// true when revision has been checked for metadata presence.
+		public boolean checked(int revision) {
 			return offsets.containsKey(revision);
 		}
+
+		// true when revision has been checked and found not having any metadata
+		boolean none(int revision) {
+			Integer i = offsets.get(revision);
+			return i == NONE;
+		}
+
+		// mark revision as having no metadata.
+		void recordNone(int revision) {
+			Integer i = offsets.get(revision);
+			if (i == NONE) {
+				return; // already there
+			} 
+			if (i != null) {
+				throw new IllegalStateException(String.format("Trying to override Metadata state for revision %d (known offset: %d)", revision, i));
+			}
+			offsets.put(revision, NONE);
+		}
+
 		// since this is internal class, callers are supposed to ensure arg correctness (i.e. ask known() before)
 		int dataOffset(int revision) {
 			return offsets.get(revision);
 		}
 		void add(int revision, int dataOffset, Collection<MetadataEntry> e) {
+			assert !offsets.containsKey(revision);
 			offsets.put(revision, dataOffset);
 			entries.put(revision, e.toArray(new MetadataEntry[e.size()]));
 		}