Mercurial > hg4j
comparison 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 |
comparison
equal
deleted
inserted
replaced
133:4a948ec83980 | 134:afac8ddc5dd2 |
---|---|
41 | 41 |
42 // absolute from repo root? | 42 // absolute from repo root? |
43 // slashes, unix-style? | 43 // slashes, unix-style? |
44 // repo location agnostic, just to give info to user, not to access real storage | 44 // repo location agnostic, just to give info to user, not to access real storage |
45 private final Path path; | 45 private final Path path; |
46 private Metadata metadata; | 46 private Metadata metadata; // get initialized on first access to file content. |
47 | 47 |
48 /*package-local*/HgDataFile(HgRepository hgRepo, Path filePath, RevlogStream content) { | 48 /*package-local*/HgDataFile(HgRepository hgRepo, Path filePath, RevlogStream content) { |
49 super(hgRepo, content); | 49 super(hgRepo, content); |
50 path = filePath; | 50 path = filePath; |
51 } | 51 } |
98 public byte[] content(int revision) { | 98 public byte[] content(int revision) { |
99 if (revision == TIP) { | 99 if (revision == TIP) { |
100 revision = content.revisionCount() - 1; // FIXME maxRevision. | 100 revision = content.revisionCount() - 1; // FIXME maxRevision. |
101 } | 101 } |
102 byte[] data = super.content(revision); | 102 byte[] data = super.content(revision); |
103 if (data.length < 4 || (data[0] != 1 && data[1] != 10)) { | 103 if (metadata == null) { |
104 metadata = new Metadata(); | |
105 } | |
106 if (metadata.none(revision)) { | |
107 // although not very reasonable when data is byte array, this check might | |
108 // get handy when there's a stream/channel to avoid useless reads and rewinds. | |
104 return data; | 109 return data; |
105 } | 110 } |
106 int toSkip = 0; | 111 int toSkip = 0; |
107 if (metadata == null || !metadata.known(revision)) { | 112 if (!metadata.known(revision)) { |
113 if (data.length < 4 || (data[0] != 1 && data[1] != 10)) { | |
114 metadata.recordNone(revision); | |
115 return data; | |
116 } | |
108 int lastEntryStart = 2; | 117 int lastEntryStart = 2; |
109 int lastColon = -1; | 118 int lastColon = -1; |
110 ArrayList<MetadataEntry> _metadata = new ArrayList<MetadataEntry>(); | 119 ArrayList<MetadataEntry> _metadata = new ArrayList<MetadataEntry>(); |
111 String key = null, value = null; | 120 String key = null, value = null; |
112 for (int i = 2; i < data.length; i++) { | 121 for (int i = 2; i < data.length; i++) { |
131 lastEntryStart = i+1; | 140 lastEntryStart = i+1; |
132 break; | 141 break; |
133 } | 142 } |
134 } | 143 } |
135 _metadata.trimToSize(); | 144 _metadata.trimToSize(); |
136 if (metadata == null) { | |
137 metadata = new Metadata(); | |
138 } | |
139 metadata.add(revision, lastEntryStart, _metadata); | 145 metadata.add(revision, lastEntryStart, _metadata); |
140 toSkip = lastEntryStart; | 146 toSkip = lastEntryStart; |
141 } else { | 147 } else { |
142 toSkip = metadata.dataOffset(revision); | 148 toSkip = metadata.dataOffset(revision); |
143 } | 149 } |
185 int changelogRevision = getChangesetLocalRevision(getLocalRevision(nid)); | 191 int changelogRevision = getChangesetLocalRevision(getLocalRevision(nid)); |
186 return getRepo().getChangelog().getRevision(changelogRevision); | 192 return getRepo().getChangelog().getRevision(changelogRevision); |
187 } | 193 } |
188 | 194 |
189 public boolean isCopy() { | 195 public boolean isCopy() { |
190 if (metadata == null) { | 196 if (metadata == null || !metadata.checked(0)) { |
197 // content() always initializes metadata. | |
191 content(0); // FIXME expensive way to find out metadata, distinct RevlogStream.Iterator would be better. | 198 content(0); // FIXME expensive way to find out metadata, distinct RevlogStream.Iterator would be better. |
192 } | 199 } |
193 if (metadata == null || !metadata.known(0)) { | 200 if (!metadata.known(0)) { |
194 return false; | 201 return false; |
195 } | 202 } |
196 return metadata.find(0, "copy") != null; | 203 return metadata.find(0, "copy") != null; |
197 } | 204 } |
198 | 205 |
227 valueStart = key.length(); | 234 valueStart = key.length(); |
228 } | 235 } |
229 /*package-local*/boolean matchKey(String key) { | 236 /*package-local*/boolean matchKey(String key) { |
230 return key.length() == valueStart && entry.startsWith(key); | 237 return key.length() == valueStart && entry.startsWith(key); |
231 } | 238 } |
232 public String key() { | 239 // uncomment once/if needed |
233 return entry.substring(0, valueStart); | 240 // public String key() { |
234 } | 241 // return entry.substring(0, valueStart); |
242 // } | |
235 public String value() { | 243 public String value() { |
236 return entry.substring(valueStart); | 244 return entry.substring(valueStart); |
237 } | 245 } |
238 } | 246 } |
239 | 247 |
240 private static class Metadata { | 248 private static class Metadata { |
241 // XXX sparse array needed | 249 // XXX sparse array needed |
242 private final TreeMap<Integer, Integer> offsets = new TreeMap<Integer, Integer>(); | 250 private final TreeMap<Integer, Integer> offsets = new TreeMap<Integer, Integer>(); |
243 private final TreeMap<Integer, MetadataEntry[]> entries = new TreeMap<Integer, MetadataEntry[]>(); | 251 private final TreeMap<Integer, MetadataEntry[]> entries = new TreeMap<Integer, MetadataEntry[]>(); |
252 | |
253 private final Integer NONE = new Integer(-1); // do not duplicate -1 integers at least within single file (don't want statics) | |
254 | |
255 // true when there's metadata for given revision | |
244 boolean known(int revision) { | 256 boolean known(int revision) { |
257 Integer i = offsets.get(revision); | |
258 return i != null && NONE != i; | |
259 } | |
260 | |
261 // true when revision has been checked for metadata presence. | |
262 public boolean checked(int revision) { | |
245 return offsets.containsKey(revision); | 263 return offsets.containsKey(revision); |
246 } | 264 } |
265 | |
266 // true when revision has been checked and found not having any metadata | |
267 boolean none(int revision) { | |
268 Integer i = offsets.get(revision); | |
269 return i == NONE; | |
270 } | |
271 | |
272 // mark revision as having no metadata. | |
273 void recordNone(int revision) { | |
274 Integer i = offsets.get(revision); | |
275 if (i == NONE) { | |
276 return; // already there | |
277 } | |
278 if (i != null) { | |
279 throw new IllegalStateException(String.format("Trying to override Metadata state for revision %d (known offset: %d)", revision, i)); | |
280 } | |
281 offsets.put(revision, NONE); | |
282 } | |
283 | |
247 // since this is internal class, callers are supposed to ensure arg correctness (i.e. ask known() before) | 284 // since this is internal class, callers are supposed to ensure arg correctness (i.e. ask known() before) |
248 int dataOffset(int revision) { | 285 int dataOffset(int revision) { |
249 return offsets.get(revision); | 286 return offsets.get(revision); |
250 } | 287 } |
251 void add(int revision, int dataOffset, Collection<MetadataEntry> e) { | 288 void add(int revision, int dataOffset, Collection<MetadataEntry> e) { |
289 assert !offsets.containsKey(revision); | |
252 offsets.put(revision, dataOffset); | 290 offsets.put(revision, dataOffset); |
253 entries.put(revision, e.toArray(new MetadataEntry[e.size()])); | 291 entries.put(revision, e.toArray(new MetadataEntry[e.size()])); |
254 } | 292 } |
255 String find(int revision, String key) { | 293 String find(int revision, String key) { |
256 for (MetadataEntry me : entries.get(revision)) { | 294 for (MetadataEntry me : entries.get(revision)) { |