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); |
