Mercurial > hg4j
comparison src/org/tmatesoft/hg/repo/Revlog.java @ 355:f2c11fe7f3e9
Newline filter shall respect whole stream when deciding whether to process line terminators, hence added stream preview functionality
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Tue, 06 Dec 2011 12:57:21 +0100 |
parents | 5f9073eabf06 |
children | 91d75e1bac9f |
comparison
equal
deleted
inserted
replaced
354:5f9073eabf06 | 355:f2c11fe7f3e9 |
---|---|
34 import org.tmatesoft.hg.core.HgInvalidRevisionException; | 34 import org.tmatesoft.hg.core.HgInvalidRevisionException; |
35 import org.tmatesoft.hg.core.Nodeid; | 35 import org.tmatesoft.hg.core.Nodeid; |
36 import org.tmatesoft.hg.internal.ArrayHelper; | 36 import org.tmatesoft.hg.internal.ArrayHelper; |
37 import org.tmatesoft.hg.internal.DataAccess; | 37 import org.tmatesoft.hg.internal.DataAccess; |
38 import org.tmatesoft.hg.internal.Experimental; | 38 import org.tmatesoft.hg.internal.Experimental; |
39 import org.tmatesoft.hg.internal.Preview; | |
39 import org.tmatesoft.hg.internal.RevlogStream; | 40 import org.tmatesoft.hg.internal.RevlogStream; |
40 import org.tmatesoft.hg.util.Adaptable; | 41 import org.tmatesoft.hg.util.Adaptable; |
41 import org.tmatesoft.hg.util.ByteChannel; | 42 import org.tmatesoft.hg.util.ByteChannel; |
42 import org.tmatesoft.hg.util.CancelSupport; | 43 import org.tmatesoft.hg.util.CancelSupport; |
43 import org.tmatesoft.hg.util.CancelledException; | 44 import org.tmatesoft.hg.util.CancelledException; |
45 import org.tmatesoft.hg.util.LogFacility; | |
44 import org.tmatesoft.hg.util.ProgressSupport; | 46 import org.tmatesoft.hg.util.ProgressSupport; |
45 | 47 |
46 | 48 |
47 /** | 49 /** |
48 * Base class for all Mercurial entities that are serialized in a so called revlog format (changelog, manifest, data files). | 50 * Base class for all Mercurial entities that are serialized in a so called revlog format (changelog, manifest, data files). |
176 */ | 178 */ |
177 protected void rawContent(int revision, ByteChannel sink) throws HgException, IOException, CancelledException, HgInvalidRevisionException { | 179 protected void rawContent(int revision, ByteChannel sink) throws HgException, IOException, CancelledException, HgInvalidRevisionException { |
178 if (sink == null) { | 180 if (sink == null) { |
179 throw new IllegalArgumentException(); | 181 throw new IllegalArgumentException(); |
180 } | 182 } |
181 ContentPipe insp = new ContentPipe(sink, 0); | 183 ContentPipe insp = new ContentPipe(sink, 0, repo.getContext().getLog()); |
182 insp.checkCancelled(); | 184 insp.checkCancelled(); |
183 content.iterate(revision, revision, true, insp); | 185 content.iterate(revision, revision, true, insp); |
184 insp.checkFailed(); | 186 insp.checkFailed(); |
185 } | 187 } |
186 | 188 |
594 } | 596 } |
595 | 597 |
596 protected static class ContentPipe extends ErrorHandlingInspector implements RevlogStream.Inspector, CancelSupport { | 598 protected static class ContentPipe extends ErrorHandlingInspector implements RevlogStream.Inspector, CancelSupport { |
597 private final ByteChannel sink; | 599 private final ByteChannel sink; |
598 private final int offset; | 600 private final int offset; |
601 private final LogFacility logFacility; | |
599 | 602 |
600 /** | 603 /** |
601 * @param _sink - cannot be <code>null</code> | 604 * @param _sink - cannot be <code>null</code> |
602 * @param seekOffset - when positive, orders to pipe bytes to the sink starting from specified offset, not from the first byte available in DataAccess | 605 * @param seekOffset - when positive, orders to pipe bytes to the sink starting from specified offset, not from the first byte available in DataAccess |
606 * @param log optional facility to put warnings/debug messages into, may be null. | |
603 */ | 607 */ |
604 public ContentPipe(ByteChannel _sink, int seekOffset) { | 608 public ContentPipe(ByteChannel _sink, int seekOffset, LogFacility log) { |
605 assert _sink != null; | 609 assert _sink != null; |
606 sink = _sink; | 610 sink = _sink; |
607 setCancelSupport(CancelSupport.Factory.get(_sink)); | 611 setCancelSupport(CancelSupport.Factory.get(_sink)); |
608 offset = seekOffset; | 612 offset = seekOffset; |
613 logFacility = log; | |
609 } | 614 } |
610 | 615 |
611 protected void prepare(int revisionNumber, DataAccess da) throws HgException, IOException { | 616 protected void prepare(int revisionNumber, DataAccess da) throws HgException, IOException { |
612 if (offset > 0) { // save few useless reset/rewind operations | 617 if (offset > 0) { // save few useless reset/rewind operations |
613 da.seek(offset); | 618 da.seek(offset); |
616 | 621 |
617 public void next(int revisionNumber, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, DataAccess da) { | 622 public void next(int revisionNumber, int actualLen, int baseRevision, int linkRevision, int parent1Revision, int parent2Revision, byte[] nodeid, DataAccess da) { |
618 try { | 623 try { |
619 prepare(revisionNumber, da); // XXX perhaps, prepare shall return DA (sliced, if needed) | 624 prepare(revisionNumber, da); // XXX perhaps, prepare shall return DA (sliced, if needed) |
620 final ProgressSupport progressSupport = ProgressSupport.Factory.get(sink); | 625 final ProgressSupport progressSupport = ProgressSupport.Factory.get(sink); |
621 ByteBuffer buf = ByteBuffer.allocate(512); | 626 ByteBuffer buf = ByteBuffer.allocate(actualLen > 8192 ? 8192 : actualLen); |
622 progressSupport.start(da.length()); | 627 Preview p = getAdapter(sink, Preview.class); |
628 if (p != null) { | |
629 progressSupport.start(2 * da.length()); | |
630 while (!da.isEmpty()) { | |
631 checkCancelled(); | |
632 da.readBytes(buf); | |
633 p.preview(buf); | |
634 buf.clear(); | |
635 } | |
636 da.reset(); | |
637 prepare(revisionNumber, da); | |
638 progressSupport.worked(da.length()); | |
639 buf.clear(); | |
640 } else { | |
641 progressSupport.start(da.length()); | |
642 } | |
623 while (!da.isEmpty()) { | 643 while (!da.isEmpty()) { |
624 checkCancelled(); | 644 checkCancelled(); |
625 da.readBytes(buf); | 645 da.readBytes(buf); |
626 buf.flip(); | 646 buf.flip(); // post: position == 0 |
627 // XXX I may not rely on returned number of bytes but track change in buf position instead. | 647 // XXX I may not rely on returned number of bytes but track change in buf position instead. |
628 int consumed = sink.write(buf); | 648 |
629 // FIXME in fact, bad sink implementation (that consumes no bytes) would result in endless loop. Need to account for this | 649 int consumed = sink.write(buf); |
630 buf.compact(); | 650 if ((consumed == 0 || consumed != buf.position()) && logFacility != null) { |
651 logFacility.warn(getClass(), "Bad data sink when reading revision %d. Reported %d bytes consumed, byt actually read %d", revisionNumber, consumed, buf.position()); | |
652 } | |
653 if (buf.position() == 0) { | |
654 throw new HgBadStateException("Bad sink implementation (consumes no bytes) results in endless loop"); | |
655 } | |
656 buf.compact(); // ensure (a) there's space for new (b) data starts at 0 | |
631 progressSupport.worked(consumed); | 657 progressSupport.worked(consumed); |
632 } | 658 } |
633 progressSupport.done(); // XXX shall specify whether #done() is invoked always or only if completed successfully. | 659 progressSupport.done(); // XXX shall specify whether #done() is invoked always or only if completed successfully. |
634 } catch (IOException ex) { | 660 } catch (IOException ex) { |
635 recordFailure(ex); | 661 recordFailure(ex); |