Mercurial > hg4j
diff src/org/tmatesoft/hg/repo/HgDataFile.java @ 277:74e7493a042a
Favor delegation over generalization
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Mon, 29 Aug 2011 23:14:59 +0200 |
parents | 6355ecda1f08 |
children | 981f9f50bb6c |
line wrap: on
line diff
--- a/src/org/tmatesoft/hg/repo/HgDataFile.java Mon Aug 29 22:15:12 2011 +0200 +++ b/src/org/tmatesoft/hg/repo/HgDataFile.java Mon Aug 29 23:14:59 2011 +0200 @@ -34,6 +34,7 @@ import org.tmatesoft.hg.core.Nodeid; import org.tmatesoft.hg.internal.DataAccess; import org.tmatesoft.hg.internal.FilterByteChannel; +import org.tmatesoft.hg.internal.FilterDataAccess; import org.tmatesoft.hg.internal.IntMap; import org.tmatesoft.hg.internal.RevlogStream; import org.tmatesoft.hg.util.ByteChannel; @@ -201,14 +202,14 @@ if (metadata == null) { metadata = new Metadata(); } - ContentPipe insp; + ErrorHandlingInspector insp; if (metadata.none(revision)) { insp = new ContentPipe(sink, 0); } else if (metadata.known(revision)) { insp = new ContentPipe(sink, metadata.dataOffset(revision)); } else { // do not know if there's metadata - insp = new MetadataContentPipe(sink, metadata, getPath()); + insp = new MetadataInspector(metadata, getPath(), new ContentPipe(sink, 0)); } insp.checkCancelled(); super.content.iterate(revision, revision, true, insp); @@ -409,28 +410,47 @@ } } - private static class MetadataContentPipe extends ContentPipe { - + private static class MetadataInspector extends ErrorHandlingInspector implements RevlogStream.Inspector { private final Metadata metadata; private final Path fname; // need this only for error reporting + private final RevlogStream.Inspector delegate; - public MetadataContentPipe(ByteChannel sink, Metadata _metadata, Path file) { - super(sink, 0); + public MetadataInspector(Metadata _metadata, Path file, RevlogStream.Inspector chain) { metadata = _metadata; fname = file; + delegate = chain; + setCancelSupport(CancelSupport.Factory.get(chain)); } - @Override - protected void prepare(int revisionNumber, DataAccess da) throws HgException, IOException { - final int daLength = da.length(); - if (daLength < 4 || da.readByte() != 1 || da.readByte() != 10) { - metadata.recordNone(revisionNumber); - da.reset(); - return; + public void next(int revisionNumber, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, DataAccess data) { + try { + final int daLength = data.length(); + if (daLength < 4 || data.readByte() != 1 || data.readByte() != 10) { + metadata.recordNone(revisionNumber); + data.reset(); + } else { + ArrayList<MetadataEntry> _metadata = new ArrayList<MetadataEntry>(); + int offset = parseMetadata(data, daLength, _metadata); + metadata.add(revisionNumber, offset, _metadata); + // da is in prepared state (i.e. we consumed all bytes up to metadata end). + // However, it's not safe to assume delegate won't call da.reset() for some reason, + // and we need to ensure predictable result. + data.reset(); + data = new FilterDataAccess(data, offset, daLength - offset); + } + if (delegate != null) { + delegate.next(revisionNumber, actualLen, baseRevision, linkRevision, parent1Revision, parent2Revision, nodeid, data); + } + } catch (IOException ex) { + recordFailure(ex); + } catch (HgDataStreamException ex) { + recordFailure(ex.setRevisionNumber(revisionNumber)); } + } + + private int parseMetadata(DataAccess data, final int daLength, ArrayList<MetadataEntry> _metadata) throws IOException, HgDataStreamException { int lastEntryStart = 2; int lastColon = -1; - ArrayList<MetadataEntry> _metadata = new ArrayList<MetadataEntry>(); // XXX in fact, need smth like ByteArrayBuilder, similar to StringBuilder, // which can't be used here because we can't convert bytes to chars as we read them // (there might be multi-byte encoding), and we need to collect all bytes before converting to string @@ -438,7 +458,7 @@ String key = null, value = null; boolean byteOne = false; for (int i = 2; i < daLength; i++) { - byte b = da.readByte(); + byte b = data.readByte(); if (b == '\n') { if (byteOne) { // i.e. \n follows 1 lastEntryStart = i+1; @@ -456,12 +476,12 @@ lastEntryStart = i+1; continue; } - // byteOne has to be consumed up to this line, if not jet, consume it + // byteOne has to be consumed up to this line, if not yet, consume it if (byteOne) { // insert 1 we've read on previous step into the byte builder bos.write(1); + byteOne = false; // fall-through to consume current byte - byteOne = false; } if (b == (int) ':') { assert value == null; @@ -474,11 +494,10 @@ bos.write(b); } } - metadata.add(revisionNumber, lastEntryStart, _metadata); - if (da.isEmpty() || !byteOne) { - throw new HgDataStreamException(fname, String.format("Metadata for revision %d is not closed properly", revisionNumber), null); + if (data.isEmpty() || !byteOne) { + throw new HgDataStreamException(fname, "Metadata is not closed properly", null); } - // da is in prepared state (i.e. we consumed all bytes up to metadata end). + return lastEntryStart; } } }