Mercurial > jhg
comparison src/org/tmatesoft/hg/internal/RevlogStream.java @ 398:c76c57f6b961
Merge fixed for issue 24 and issue 26 from smartgit3 branch
author | Artem Tikhomirov <tikhomirov.artem@gmail.com> |
---|---|
date | Thu, 23 Feb 2012 21:53:21 +0100 |
parents | 0ae53c32ecef 5e95b0da26f2 |
children | 6c22bdc0bdfd |
comparison
equal
deleted
inserted
replaced
396:0ae53c32ecef | 398:c76c57f6b961 |
---|---|
486 streamOffset = (int) offset; | 486 streamOffset = (int) offset; |
487 streamDataAccess = daData; | 487 streamDataAccess = daData; |
488 daData.seek(streamOffset); | 488 daData.seek(streamOffset); |
489 } | 489 } |
490 final boolean patchToPrevious = baseRevision != i; // the only way I found to tell if it's a patch | 490 final boolean patchToPrevious = baseRevision != i; // the only way I found to tell if it's a patch |
491 if (streamDataAccess.isEmpty()) { | 491 if (streamDataAccess.isEmpty() || compressedLen == 0) { |
492 userDataAccess = new DataAccess(); // empty | 492 userDataAccess = new DataAccess(); // empty |
493 } else { | 493 } else { |
494 final byte firstByte = streamDataAccess.readByte(); | 494 final byte firstByte = streamDataAccess.readByte(); |
495 if (firstByte == 0x78 /* 'x' */) { | 495 if (firstByte == 0x78 /* 'x' */) { |
496 inflater.reset(); | 496 inflater.reset(); |
497 userDataAccess = new InflaterDataAccess(streamDataAccess, streamOffset, compressedLen, patchToPrevious ? -1 : actualLen, inflater, inflaterBuffer); | 497 userDataAccess = new InflaterDataAccess(streamDataAccess, streamOffset, compressedLen, patchToPrevious ? -1 : actualLen, inflater, inflaterBuffer); |
498 } else if (firstByte == 0x75 /* 'u' */) { | 498 } else if (firstByte == 0x75 /* 'u' */) { |
499 userDataAccess = new FilterDataAccess(streamDataAccess, streamOffset+1, compressedLen-1); | 499 userDataAccess = new FilterDataAccess(streamDataAccess, streamOffset+1, compressedLen-1); |
500 } else { | 500 } else { |
501 // XXX Python impl in fact throws exception when there's not 'x', 'u' or '0' | 501 // XXX Python impl in fact throws exception when there's not 'x', 'u' or '0' but I don't see reason not to return data as is |
502 // but I don't see reason not to return data as is | 502 // |
503 // although firstByte is already read from the streamDataAccess, FilterDataAccess#readByte would seek to | |
504 // initial offset before first attempt to read a byte | |
503 userDataAccess = new FilterDataAccess(streamDataAccess, streamOffset, compressedLen); | 505 userDataAccess = new FilterDataAccess(streamDataAccess, streamOffset, compressedLen); |
504 } | 506 } |
505 } | 507 } |
506 // XXX | 508 // userDataAccess is revision content, either complete revision, patch of a previous content, or an empty patch |
507 if (patchToPrevious && !userDataAccess.isEmpty() /* Issue 22, empty patch to an empty base revision*/) { | 509 if (patchToPrevious) { |
508 // this is a patch | 510 // this is a patch |
509 patch.read(userDataAccess); | 511 if (userDataAccess.isEmpty()) { |
510 userDataAccess.done(); | 512 // Issue 22, empty patch to an empty base revision |
511 // | 513 // Issue 24, empty patch to non-empty base revision |
512 // it shall be reset at the end of prev iteration, when it got assigned from userDataAccess | 514 // empty patch modifies nothing, use content of a previous revision (shall present - it's a patch here) |
513 // however, actual userDataAccess and lastUserData may share Inflater object, which needs to be reset | 515 // |
514 // Alternatively, userDataAccess.done() above may be responsible to reset Inflater (if it's InflaterDataAccess) | 516 assert lastUserData.length() == actualLen; // with no patch, data size shall be the same |
515 lastUserData.reset(); | 517 userDataAccess = lastUserData; |
516 // final long startMeasuring = System.currentTimeMillis(); // TIMING | 518 } else { |
517 byte[] userData = patch.apply(lastUserData, actualLen); | 519 patch.read(userDataAccess); |
518 // applyTime += (System.currentTimeMillis() - startMeasuring); // TIMING | 520 userDataAccess.done(); |
519 patch.clear(); // do not keep any reference, allow byte[] data to be gc'd | 521 // |
520 userDataAccess = new ByteArrayDataAccess(userData); | 522 // it shall be reset at the end of prev iteration, when it got assigned from userDataAccess |
523 // however, actual userDataAccess and lastUserData may share Inflater object, which needs to be reset | |
524 // Alternatively, userDataAccess.done() above may be responsible to reset Inflater (if it's InflaterDataAccess) | |
525 lastUserData.reset(); | |
526 // final long startMeasuring = System.currentTimeMillis(); // TIMING | |
527 byte[] userData = patch.apply(lastUserData, actualLen); | |
528 // applyTime += (System.currentTimeMillis() - startMeasuring); // TIMING | |
529 patch.clear(); // do not keep any reference, allow byte[] data to be gc'd | |
530 userDataAccess = new ByteArrayDataAccess(userData); | |
531 } | |
521 } | 532 } |
522 } else { | 533 } else { |
523 if (inline) { | 534 if (inline) { |
524 daIndex.skip(compressedLen); | 535 daIndex.skip(compressedLen); |
525 } | 536 } |
535 } | 546 } |
536 } | 547 } |
537 if (userDataAccess != null) { | 548 if (userDataAccess != null) { |
538 userDataAccess.reset(); // not sure this is necessary here, as lastUserData would get reset anyway before next use. | 549 userDataAccess.reset(); // not sure this is necessary here, as lastUserData would get reset anyway before next use. |
539 } | 550 } |
540 if (lastUserData != null) { | 551 if (lastUserData != null && lastUserData != userDataAccess /* empty patch case, reuse of recent data in actual revision */) { |
552 // release lastUserData only if we didn't reuse it in actual revision due to empty patch: | |
553 // empty patch means we have previous revision and didn't alter it with a patch, hence use lastUserData for userDataAccess above | |
541 lastUserData.done(); | 554 lastUserData.done(); |
542 } | 555 } |
543 lastUserData = userDataAccess; | 556 lastUserData = userDataAccess; |
544 } | 557 } |
545 lastRevisionRead = end; | 558 lastRevisionRead = end; |