comparison src/org/tmatesoft/hg/internal/RevlogStream.java @ 606:5daa42067e7c

Avoid mmap files when only few bytes are to be read
author Artem Tikhomirov <tikhomirov.artem@gmail.com>
date Tue, 07 May 2013 14:16:35 +0200
parents cc7b0c4dc993
children 66f1cc23b906
comparison
equal deleted inserted replaced
605:c56edf42be64 606:5daa42067e7c
75 public RevlogStream(DataAccessProvider dap, File indexFile) { 75 public RevlogStream(DataAccessProvider dap, File indexFile) {
76 this.dataAccess = dap; 76 this.dataAccess = dap;
77 this.indexFile = indexFile; 77 this.indexFile = indexFile;
78 } 78 }
79 79
80 /*package*/ DataAccess getIndexStream() { 80 /**
81 // FIXME [1.1] must supply a hint that I'll need really few bytes of data (perhaps, at some offset) 81 * @param shortRead pass <code>true</code> to indicate intention to read few revisions only (as opposed to reading most of/complete revlog)
82 // to avoid mmap files when only few bytes are to be read (i.e. #dataLength()) 82 * @return never <code>null</code>, empty {@link DataAccess} if no stream is available
83 return dataAccess.createReader(indexFile); 83 */
84 /*package*/ DataAccess getIndexStream(boolean shortRead) {
85 // shortRead hint helps to avoid mmap files when only
86 // few bytes are to be read (i.e. #dataLength())
87 return dataAccess.createReader(indexFile, shortRead);
84 } 88 }
85 89
86 /*package*/ DataAccess getDataStream() { 90 /*package*/ DataAccess getDataStream() {
87 return dataAccess.createReader(getDataFile()); 91 return dataAccess.createReader(getDataFile(), false);
88 } 92 }
89 93
90 /*package*/ DataSerializer getIndexStreamWriter() { 94 /*package*/ DataSerializer getIndexStreamWriter() {
91 return dataAccess.createWriter(indexFile, true); 95 return dataAccess.createWriter(indexFile, true);
92 } 96 }
145 */ 149 */
146 public int dataLength(int revisionIndex) throws HgInvalidControlFileException, HgInvalidRevisionException { 150 public int dataLength(int revisionIndex) throws HgInvalidControlFileException, HgInvalidRevisionException {
147 // XXX in fact, use of iterate() instead of this implementation may be quite reasonable. 151 // XXX in fact, use of iterate() instead of this implementation may be quite reasonable.
148 // 152 //
149 revisionIndex = checkRevisionIndex(revisionIndex); 153 revisionIndex = checkRevisionIndex(revisionIndex);
150 DataAccess daIndex = getIndexStream(); 154 DataAccess daIndex = getIndexStream(true);
151 try { 155 try {
152 int recordOffset = getIndexOffsetInt(revisionIndex); 156 int recordOffset = getIndexOffsetInt(revisionIndex);
153 daIndex.seek(recordOffset + 12); // 6+2+4 157 daIndex.seek(recordOffset + 12); // 6+2+4
154 int actualLen = daIndex.readInt(); 158 int actualLen = daIndex.readInt();
155 return actualLen; 159 return actualLen;
166 * @throws HgInvalidControlFileException if attempt to read index file failed 170 * @throws HgInvalidControlFileException if attempt to read index file failed
167 * @throws HgInvalidRevisionException if revisionIndex argument doesn't represent a valid record in the revlog 171 * @throws HgInvalidRevisionException if revisionIndex argument doesn't represent a valid record in the revlog
168 */ 172 */
169 public byte[] nodeid(int revisionIndex) throws HgInvalidControlFileException, HgInvalidRevisionException { 173 public byte[] nodeid(int revisionIndex) throws HgInvalidControlFileException, HgInvalidRevisionException {
170 revisionIndex = checkRevisionIndex(revisionIndex); 174 revisionIndex = checkRevisionIndex(revisionIndex);
171 DataAccess daIndex = getIndexStream(); 175 DataAccess daIndex = getIndexStream(true);
172 try { 176 try {
173 int recordOffset = getIndexOffsetInt(revisionIndex); 177 int recordOffset = getIndexOffsetInt(revisionIndex);
174 daIndex.seek(recordOffset + 32); 178 daIndex.seek(recordOffset + 32);
175 byte[] rv = new byte[20]; 179 byte[] rv = new byte[20];
176 daIndex.readBytes(rv, 0, 20); 180 daIndex.readBytes(rv, 0, 20);
188 * @throws HgInvalidControlFileException if attempt to read index file failed 192 * @throws HgInvalidControlFileException if attempt to read index file failed
189 * @throws HgInvalidRevisionException if revisionIndex argument doesn't represent a valid record in the revlog 193 * @throws HgInvalidRevisionException if revisionIndex argument doesn't represent a valid record in the revlog
190 */ 194 */
191 public int linkRevision(int revisionIndex) throws HgInvalidControlFileException, HgInvalidRevisionException { 195 public int linkRevision(int revisionIndex) throws HgInvalidControlFileException, HgInvalidRevisionException {
192 revisionIndex = checkRevisionIndex(revisionIndex); 196 revisionIndex = checkRevisionIndex(revisionIndex);
193 DataAccess daIndex = getIndexStream(); 197 DataAccess daIndex = getIndexStream(true);
194 try { 198 try {
195 int recordOffset = getIndexOffsetInt(revisionIndex); 199 int recordOffset = getIndexOffsetInt(revisionIndex);
196 daIndex.seek(recordOffset + 20); 200 daIndex.seek(recordOffset + 20);
197 int linkRev = daIndex.readInt(); 201 int linkRev = daIndex.readInt();
198 return linkRev; 202 return linkRev;
224 * @throws HgInvalidControlFileException if attempt to read index file failed 228 * @throws HgInvalidControlFileException if attempt to read index file failed
225 */ 229 */
226 public int findRevisionIndex(Nodeid nodeid) throws HgInvalidControlFileException { 230 public int findRevisionIndex(Nodeid nodeid) throws HgInvalidControlFileException {
227 // XXX this one may be implemented with iterate() once there's mechanism to stop iterations 231 // XXX this one may be implemented with iterate() once there's mechanism to stop iterations
228 final int indexSize = revisionCount(); 232 final int indexSize = revisionCount();
229 DataAccess daIndex = getIndexStream(); 233 DataAccess daIndex = getIndexStream(false);
230 try { 234 try {
231 byte[] nodeidBuf = new byte[20]; 235 byte[] nodeidBuf = new byte[20];
232 for (int i = 0; i < indexSize; i++) { 236 for (int i = 0; i < indexSize; i++) {
233 daIndex.skip(8); 237 daIndex.skip(8);
234 int compressedLen = daIndex.readInt(); 238 int compressedLen = daIndex.readInt();
253 */ 257 */
254 public long newEntryOffset() { 258 public long newEntryOffset() {
255 if (revisionCount() == 0) { 259 if (revisionCount() == 0) {
256 return 0; 260 return 0;
257 } 261 }
258 DataAccess daIndex = getIndexStream(); 262 DataAccess daIndex = getIndexStream(true);
259 int lastRev = revisionCount() - 1; 263 int lastRev = revisionCount() - 1;
260 try { 264 try {
261 int recordOffset = getIndexOffsetInt(lastRev); 265 int recordOffset = getIndexOffsetInt(lastRev);
262 daIndex.seek(recordOffset); 266 daIndex.seek(recordOffset);
263 long value = daIndex.readLong(); 267 long value = daIndex.readLong();
419 423
420 private void initOutline() throws HgInvalidControlFileException { 424 private void initOutline() throws HgInvalidControlFileException {
421 if (outlineCached()) { 425 if (outlineCached()) {
422 return; 426 return;
423 } 427 }
424 DataAccess da = getIndexStream(); 428 DataAccess da = getIndexStream(false);
425 try { 429 try {
426 if (da.isEmpty()) { 430 if (da.isEmpty()) {
427 // do not fail with exception if stream is empty, it's likely intentional 431 // do not fail with exception if stream is empty, it's likely intentional
428 baseRevisions = new int[0]; 432 baseRevisions = new int[0];
429 // empty revlog, likely to be populated, indicate we start with a single file 433 // empty revlog, likely to be populated, indicate we start with a single file
549 inspector = insp; 553 inspector = insp;
550 mergePatches = usePatchMerge; 554 mergePatches = usePatchMerge;
551 } 555 }
552 556
553 public void start(int totalWork, CachedRevision cachedRevision) { 557 public void start(int totalWork, CachedRevision cachedRevision) {
554 daIndex = getIndexStream(); 558 daIndex = getIndexStream(totalWork <= 10);
555 if (needData && !inline) { 559 if (needData && !inline) {
556 daData = getDataStream(); 560 daData = getDataStream();
557 } 561 }
558 lifecycleListener = Adaptable.Factory.getAdapter(inspector, Lifecycle.class, null); 562 lifecycleListener = Adaptable.Factory.getAdapter(inspector, Lifecycle.class, null);
559 if (lifecycleListener != null) { 563 if (lifecycleListener != null) {