Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

DfsReader.java 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684
  1. /*
  2. * Copyright (C) 2008-2011, Google Inc.
  3. * Copyright (C) 2006-2008, Shawn O. Pearce <spearce@spearce.org>
  4. * and other copyright owners as documented in the project's IP log.
  5. *
  6. * This program and the accompanying materials are made available
  7. * under the terms of the Eclipse Distribution License v1.0 which
  8. * accompanies this distribution, is reproduced below, and is
  9. * available at http://www.eclipse.org/org/documents/edl-v10.php
  10. *
  11. * All rights reserved.
  12. *
  13. * Redistribution and use in source and binary forms, with or
  14. * without modification, are permitted provided that the following
  15. * conditions are met:
  16. *
  17. * - Redistributions of source code must retain the above copyright
  18. * notice, this list of conditions and the following disclaimer.
  19. *
  20. * - Redistributions in binary form must reproduce the above
  21. * copyright notice, this list of conditions and the following
  22. * disclaimer in the documentation and/or other materials provided
  23. * with the distribution.
  24. *
  25. * - Neither the name of the Eclipse Foundation, Inc. nor the
  26. * names of its contributors may be used to endorse or promote
  27. * products derived from this software without specific prior
  28. * written permission.
  29. *
  30. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  31. * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  32. * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  33. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  34. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  35. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  36. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  37. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  38. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  39. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  40. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  41. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  42. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  43. */
  44. package org.eclipse.jgit.internal.storage.dfs;
  45. import static org.eclipse.jgit.internal.storage.pack.PackExt.PACK;
  46. import static org.eclipse.jgit.lib.Constants.OBJECT_ID_LENGTH;
  47. import java.io.IOException;
  48. import java.security.MessageDigest;
  49. import java.text.MessageFormat;
  50. import java.util.ArrayList;
  51. import java.util.Arrays;
  52. import java.util.Collection;
  53. import java.util.Collections;
  54. import java.util.Comparator;
  55. import java.util.HashSet;
  56. import java.util.Iterator;
  57. import java.util.List;
  58. import java.util.Set;
  59. import java.util.zip.DataFormatException;
  60. import java.util.zip.Inflater;
  61. import org.eclipse.jgit.errors.IncorrectObjectTypeException;
  62. import org.eclipse.jgit.errors.MissingObjectException;
  63. import org.eclipse.jgit.errors.StoredObjectRepresentationNotAvailableException;
  64. import org.eclipse.jgit.internal.JGitText;
  65. import org.eclipse.jgit.internal.storage.file.BitmapIndexImpl;
  66. import org.eclipse.jgit.internal.storage.file.PackBitmapIndex;
  67. import org.eclipse.jgit.internal.storage.file.PackIndex;
  68. import org.eclipse.jgit.internal.storage.file.PackReverseIndex;
  69. import org.eclipse.jgit.internal.storage.pack.CachedPack;
  70. import org.eclipse.jgit.internal.storage.pack.ObjectReuseAsIs;
  71. import org.eclipse.jgit.internal.storage.pack.ObjectToPack;
  72. import org.eclipse.jgit.internal.storage.pack.PackOutputStream;
  73. import org.eclipse.jgit.internal.storage.pack.PackWriter;
  74. import org.eclipse.jgit.lib.AbbreviatedObjectId;
  75. import org.eclipse.jgit.lib.AnyObjectId;
  76. import org.eclipse.jgit.lib.AsyncObjectLoaderQueue;
  77. import org.eclipse.jgit.lib.AsyncObjectSizeQueue;
  78. import org.eclipse.jgit.lib.BitmapIndex;
  79. import org.eclipse.jgit.lib.BitmapIndex.BitmapBuilder;
  80. import org.eclipse.jgit.lib.Constants;
  81. import org.eclipse.jgit.lib.InflaterCache;
  82. import org.eclipse.jgit.lib.ObjectId;
  83. import org.eclipse.jgit.lib.ObjectLoader;
  84. import org.eclipse.jgit.lib.ObjectReader;
  85. import org.eclipse.jgit.lib.ProgressMonitor;
  86. import org.eclipse.jgit.util.BlockList;
  87. /**
  88. * Reader to access repository content through.
  89. * <p>
  90. * See the base {@link ObjectReader} documentation for details. Notably, a
  91. * reader is not thread safe.
  92. */
  93. public final class DfsReader extends ObjectReader implements ObjectReuseAsIs {
  94. /** Temporary buffer large enough for at least one raw object id. */
  95. final byte[] tempId = new byte[OBJECT_ID_LENGTH];
  96. /** Database this reader loads objects from. */
  97. final DfsObjDatabase db;
  98. private Inflater inf;
  99. private DfsBlock block;
  100. private DeltaBaseCache baseCache;
  101. private DfsPackFile last;
  102. private boolean avoidUnreachable;
  103. DfsReader(DfsObjDatabase db) {
  104. this.db = db;
  105. }
  106. DfsReaderOptions getOptions() {
  107. return db.getReaderOptions();
  108. }
  109. DeltaBaseCache getDeltaBaseCache() {
  110. if (baseCache == null)
  111. baseCache = new DeltaBaseCache(this);
  112. return baseCache;
  113. }
  114. int getStreamFileThreshold() {
  115. return getOptions().getStreamFileThreshold();
  116. }
  117. @Override
  118. public ObjectReader newReader() {
  119. return new DfsReader(db);
  120. }
  121. @Override
  122. public void setAvoidUnreachableObjects(boolean avoid) {
  123. avoidUnreachable = avoid;
  124. }
  125. @Override
  126. public BitmapIndex getBitmapIndex() throws IOException {
  127. for (DfsPackFile pack : db.getPacks()) {
  128. PackBitmapIndex bitmapIndex = pack.getBitmapIndex(this);
  129. if (bitmapIndex != null)
  130. return new BitmapIndexImpl(bitmapIndex);
  131. }
  132. return null;
  133. }
  134. public Collection<CachedPack> getCachedPacksAndUpdate(
  135. BitmapBuilder needBitmap) throws IOException {
  136. for (DfsPackFile pack : db.getPacks()) {
  137. PackBitmapIndex bitmapIndex = pack.getBitmapIndex(this);
  138. if (needBitmap.removeAllOrNone(bitmapIndex))
  139. return Collections.<CachedPack> singletonList(
  140. new DfsCachedPack(pack));
  141. }
  142. return Collections.emptyList();
  143. }
  144. @Override
  145. public Collection<ObjectId> resolve(AbbreviatedObjectId id)
  146. throws IOException {
  147. if (id.isComplete())
  148. return Collections.singleton(id.toObjectId());
  149. boolean noGarbage = avoidUnreachable;
  150. HashSet<ObjectId> matches = new HashSet<ObjectId>(4);
  151. for (DfsPackFile pack : db.getPacks()) {
  152. if (noGarbage && pack.isGarbage())
  153. continue;
  154. pack.resolve(this, matches, id, 256);
  155. if (256 <= matches.size())
  156. break;
  157. }
  158. return matches;
  159. }
  160. @Override
  161. public boolean has(AnyObjectId objectId) throws IOException {
  162. if (last != null && last.hasObject(this, objectId))
  163. return true;
  164. boolean noGarbage = avoidUnreachable;
  165. for (DfsPackFile pack : db.getPacks()) {
  166. if (pack == last || (noGarbage && pack.isGarbage()))
  167. continue;
  168. if (pack.hasObject(this, objectId)) {
  169. last = pack;
  170. return true;
  171. }
  172. }
  173. return false;
  174. }
  175. @Override
  176. public ObjectLoader open(AnyObjectId objectId, int typeHint)
  177. throws MissingObjectException, IncorrectObjectTypeException,
  178. IOException {
  179. if (last != null) {
  180. ObjectLoader ldr = last.get(this, objectId);
  181. if (ldr != null)
  182. return ldr;
  183. }
  184. boolean noGarbage = avoidUnreachable;
  185. for (DfsPackFile pack : db.getPacks()) {
  186. if (pack == last || (noGarbage && pack.isGarbage()))
  187. continue;
  188. ObjectLoader ldr = pack.get(this, objectId);
  189. if (ldr != null) {
  190. last = pack;
  191. return ldr;
  192. }
  193. }
  194. if (typeHint == OBJ_ANY)
  195. throw new MissingObjectException(objectId.copy(), "unknown");
  196. throw new MissingObjectException(objectId.copy(), typeHint);
  197. }
  198. @Override
  199. public Set<ObjectId> getShallowCommits() {
  200. return Collections.emptySet();
  201. }
  202. private static final Comparator<FoundObject<?>> FOUND_OBJECT_SORT = new Comparator<FoundObject<?>>() {
  203. public int compare(FoundObject<?> a, FoundObject<?> b) {
  204. int cmp = a.packIndex - b.packIndex;
  205. if (cmp == 0)
  206. cmp = Long.signum(a.offset - b.offset);
  207. return cmp;
  208. }
  209. };
  210. private static class FoundObject<T extends ObjectId> {
  211. final T id;
  212. final DfsPackFile pack;
  213. final long offset;
  214. final int packIndex;
  215. FoundObject(T objectId, int packIdx, DfsPackFile pack, long offset) {
  216. this.id = objectId;
  217. this.pack = pack;
  218. this.offset = offset;
  219. this.packIndex = packIdx;
  220. }
  221. FoundObject(T objectId) {
  222. this.id = objectId;
  223. this.pack = null;
  224. this.offset = 0;
  225. this.packIndex = 0;
  226. }
  227. }
  228. private <T extends ObjectId> Iterable<FoundObject<T>> findAll(
  229. Iterable<T> objectIds) throws IOException {
  230. ArrayList<FoundObject<T>> r = new ArrayList<FoundObject<T>>();
  231. DfsPackFile[] packList = db.getPacks();
  232. if (packList.length == 0) {
  233. for (T t : objectIds)
  234. r.add(new FoundObject<T>(t));
  235. return r;
  236. }
  237. int lastIdx = 0;
  238. DfsPackFile lastPack = packList[lastIdx];
  239. boolean noGarbage = avoidUnreachable;
  240. OBJECT_SCAN: for (T t : objectIds) {
  241. try {
  242. long p = lastPack.findOffset(this, t);
  243. if (0 < p) {
  244. r.add(new FoundObject<T>(t, lastIdx, lastPack, p));
  245. continue;
  246. }
  247. } catch (IOException e) {
  248. // Fall though and try to examine other packs.
  249. }
  250. for (int i = 0; i < packList.length; i++) {
  251. if (i == lastIdx)
  252. continue;
  253. DfsPackFile pack = packList[i];
  254. if (noGarbage && pack.isGarbage())
  255. continue;
  256. try {
  257. long p = pack.findOffset(this, t);
  258. if (0 < p) {
  259. r.add(new FoundObject<T>(t, i, pack, p));
  260. lastIdx = i;
  261. lastPack = pack;
  262. continue OBJECT_SCAN;
  263. }
  264. } catch (IOException e) {
  265. // Examine other packs.
  266. }
  267. }
  268. r.add(new FoundObject<T>(t));
  269. }
  270. Collections.sort(r, FOUND_OBJECT_SORT);
  271. last = lastPack;
  272. return r;
  273. }
  274. @Override
  275. public <T extends ObjectId> AsyncObjectLoaderQueue<T> open(
  276. Iterable<T> objectIds, final boolean reportMissing) {
  277. Iterable<FoundObject<T>> order;
  278. IOException error = null;
  279. try {
  280. order = findAll(objectIds);
  281. } catch (IOException e) {
  282. order = Collections.emptyList();
  283. error = e;
  284. }
  285. final Iterator<FoundObject<T>> idItr = order.iterator();
  286. final IOException findAllError = error;
  287. return new AsyncObjectLoaderQueue<T>() {
  288. private FoundObject<T> cur;
  289. public boolean next() throws MissingObjectException, IOException {
  290. if (idItr.hasNext()) {
  291. cur = idItr.next();
  292. return true;
  293. } else if (findAllError != null) {
  294. throw findAllError;
  295. } else {
  296. return false;
  297. }
  298. }
  299. public T getCurrent() {
  300. return cur.id;
  301. }
  302. public ObjectId getObjectId() {
  303. return cur.id;
  304. }
  305. public ObjectLoader open() throws IOException {
  306. if (cur.pack == null)
  307. throw new MissingObjectException(cur.id, "unknown");
  308. return cur.pack.load(DfsReader.this, cur.offset);
  309. }
  310. public boolean cancel(boolean mayInterruptIfRunning) {
  311. return true;
  312. }
  313. public void release() {
  314. // Nothing to clean up.
  315. }
  316. };
  317. }
  318. @Override
  319. public <T extends ObjectId> AsyncObjectSizeQueue<T> getObjectSize(
  320. Iterable<T> objectIds, final boolean reportMissing) {
  321. Iterable<FoundObject<T>> order;
  322. IOException error = null;
  323. try {
  324. order = findAll(objectIds);
  325. } catch (IOException e) {
  326. order = Collections.emptyList();
  327. error = e;
  328. }
  329. final Iterator<FoundObject<T>> idItr = order.iterator();
  330. final IOException findAllError = error;
  331. return new AsyncObjectSizeQueue<T>() {
  332. private FoundObject<T> cur;
  333. private long sz;
  334. public boolean next() throws MissingObjectException, IOException {
  335. if (idItr.hasNext()) {
  336. cur = idItr.next();
  337. if (cur.pack == null)
  338. throw new MissingObjectException(cur.id, "unknown");
  339. sz = cur.pack.getObjectSize(DfsReader.this, cur.offset);
  340. return true;
  341. } else if (findAllError != null) {
  342. throw findAllError;
  343. } else {
  344. return false;
  345. }
  346. }
  347. public T getCurrent() {
  348. return cur.id;
  349. }
  350. public ObjectId getObjectId() {
  351. return cur.id;
  352. }
  353. public long getSize() {
  354. return sz;
  355. }
  356. public boolean cancel(boolean mayInterruptIfRunning) {
  357. return true;
  358. }
  359. public void release() {
  360. // Nothing to clean up.
  361. }
  362. };
  363. }
  364. @Override
  365. public long getObjectSize(AnyObjectId objectId, int typeHint)
  366. throws MissingObjectException, IncorrectObjectTypeException,
  367. IOException {
  368. if (last != null) {
  369. long sz = last.getObjectSize(this, objectId);
  370. if (0 <= sz)
  371. return sz;
  372. }
  373. for (DfsPackFile pack : db.getPacks()) {
  374. if (pack == last)
  375. continue;
  376. long sz = pack.getObjectSize(this, objectId);
  377. if (0 <= sz) {
  378. last = pack;
  379. return sz;
  380. }
  381. }
  382. if (typeHint == OBJ_ANY)
  383. throw new MissingObjectException(objectId.copy(), "unknown");
  384. throw new MissingObjectException(objectId.copy(), typeHint);
  385. }
  386. public DfsObjectToPack newObjectToPack(AnyObjectId objectId, int type) {
  387. return new DfsObjectToPack(objectId, type);
  388. }
  389. private static final Comparator<DfsObjectToPack> OFFSET_SORT = new Comparator<DfsObjectToPack>() {
  390. public int compare(DfsObjectToPack a, DfsObjectToPack b) {
  391. return Long.signum(a.getOffset() - b.getOffset());
  392. }
  393. };
  394. public void selectObjectRepresentation(PackWriter packer,
  395. ProgressMonitor monitor, Iterable<ObjectToPack> objects)
  396. throws IOException, MissingObjectException {
  397. for (DfsPackFile pack : db.getPacks()) {
  398. List<DfsObjectToPack> tmp = findAllFromPack(pack, objects);
  399. if (tmp.isEmpty())
  400. continue;
  401. Collections.sort(tmp, OFFSET_SORT);
  402. PackReverseIndex rev = pack.getReverseIdx(this);
  403. DfsObjectRepresentation rep = new DfsObjectRepresentation(pack);
  404. for (DfsObjectToPack otp : tmp) {
  405. pack.representation(rep, otp.getOffset(), this, rev);
  406. otp.setOffset(0);
  407. packer.select(otp, rep);
  408. if (!otp.isFound()) {
  409. otp.setFound();
  410. monitor.update(1);
  411. }
  412. }
  413. }
  414. }
  415. private List<DfsObjectToPack> findAllFromPack(DfsPackFile pack,
  416. Iterable<ObjectToPack> objects) throws IOException {
  417. List<DfsObjectToPack> tmp = new BlockList<DfsObjectToPack>();
  418. PackIndex idx = pack.getPackIndex(this);
  419. for (ObjectToPack otp : objects) {
  420. long p = idx.findOffset(otp);
  421. if (0 < p) {
  422. otp.setOffset(p);
  423. tmp.add((DfsObjectToPack) otp);
  424. }
  425. }
  426. return tmp;
  427. }
  428. public void copyObjectAsIs(PackOutputStream out, ObjectToPack otp,
  429. boolean validate) throws IOException,
  430. StoredObjectRepresentationNotAvailableException {
  431. DfsObjectToPack src = (DfsObjectToPack) otp;
  432. src.pack.copyAsIs(out, src, validate, this);
  433. }
  434. public void writeObjects(PackOutputStream out, List<ObjectToPack> list)
  435. throws IOException {
  436. for (ObjectToPack otp : list)
  437. out.writeObject(otp);
  438. }
  439. public void copyPackAsIs(PackOutputStream out, CachedPack pack,
  440. boolean validate) throws IOException {
  441. ((DfsCachedPack) pack).copyAsIs(out, validate, this);
  442. }
  443. /**
  444. * Copy bytes from the window to a caller supplied buffer.
  445. *
  446. * @param pack
  447. * the file the desired window is stored within.
  448. * @param position
  449. * position within the file to read from.
  450. * @param dstbuf
  451. * destination buffer to copy into.
  452. * @param dstoff
  453. * offset within <code>dstbuf</code> to start copying into.
  454. * @param cnt
  455. * number of bytes to copy. This value may exceed the number of
  456. * bytes remaining in the window starting at offset
  457. * <code>pos</code>.
  458. * @return number of bytes actually copied; this may be less than
  459. * <code>cnt</code> if <code>cnt</code> exceeded the number of bytes
  460. * available.
  461. * @throws IOException
  462. * this cursor does not match the provider or id and the proper
  463. * window could not be acquired through the provider's cache.
  464. */
  465. int copy(DfsPackFile pack, long position, byte[] dstbuf, int dstoff, int cnt)
  466. throws IOException {
  467. if (cnt == 0)
  468. return 0;
  469. long length = pack.length;
  470. if (0 <= length && length <= position)
  471. return 0;
  472. int need = cnt;
  473. do {
  474. pin(pack, position);
  475. int r = block.copy(position, dstbuf, dstoff, need);
  476. position += r;
  477. dstoff += r;
  478. need -= r;
  479. if (length < 0)
  480. length = pack.length;
  481. } while (0 < need && position < length);
  482. return cnt - need;
  483. }
  484. void copyPackAsIs(DfsPackFile pack, long length, boolean validate,
  485. PackOutputStream out) throws IOException {
  486. MessageDigest md = null;
  487. if (validate) {
  488. md = Constants.newMessageDigest();
  489. byte[] buf = out.getCopyBuffer();
  490. pin(pack, 0);
  491. if (block.copy(0, buf, 0, 12) != 12) {
  492. pack.setInvalid();
  493. throw new IOException(JGitText.get().packfileIsTruncated);
  494. }
  495. md.update(buf, 0, 12);
  496. }
  497. long position = 12;
  498. long remaining = length - (12 + 20);
  499. while (0 < remaining) {
  500. pin(pack, position);
  501. int ptr = (int) (position - block.start);
  502. int n = (int) Math.min(block.size() - ptr, remaining);
  503. block.write(out, position, n, md);
  504. position += n;
  505. remaining -= n;
  506. }
  507. if (md != null) {
  508. byte[] buf = new byte[20];
  509. byte[] actHash = md.digest();
  510. pin(pack, position);
  511. if (block.copy(position, buf, 0, 20) != 20) {
  512. pack.setInvalid();
  513. throw new IOException(JGitText.get().packfileIsTruncated);
  514. }
  515. if (!Arrays.equals(actHash, buf)) {
  516. pack.setInvalid();
  517. throw new IOException(MessageFormat.format(
  518. JGitText.get().packfileCorruptionDetected,
  519. pack.getPackDescription().getFileName(PACK)));
  520. }
  521. }
  522. }
  523. /**
  524. * Inflate a region of the pack starting at {@code position}.
  525. *
  526. * @param pack
  527. * the file the desired window is stored within.
  528. * @param position
  529. * position within the file to read from.
  530. * @param dstbuf
  531. * destination buffer the inflater should output decompressed
  532. * data to.
  533. * @param headerOnly
  534. * if true the caller wants only {@code dstbuf.length} bytes.
  535. * @return updated <code>dstoff</code> based on the number of bytes
  536. * successfully inflated into <code>dstbuf</code>.
  537. * @throws IOException
  538. * this cursor does not match the provider or id and the proper
  539. * window could not be acquired through the provider's cache.
  540. * @throws DataFormatException
  541. * the inflater encountered an invalid chunk of data. Data
  542. * stream corruption is likely.
  543. */
  544. int inflate(DfsPackFile pack, long position, byte[] dstbuf,
  545. boolean headerOnly) throws IOException, DataFormatException {
  546. prepareInflater();
  547. pin(pack, position);
  548. block.setInput(inf, position);
  549. int dstoff = 0;
  550. for (;;) {
  551. int n = inf.inflate(dstbuf, dstoff, dstbuf.length - dstoff);
  552. if (n == 0) {
  553. if (headerOnly && dstoff == dstbuf.length)
  554. return dstoff;
  555. if (inf.needsInput()) {
  556. position += block.remaining(position);
  557. pin(pack, position);
  558. block.setInput(inf, position);
  559. continue;
  560. }
  561. if (inf.finished())
  562. return dstoff;
  563. throw new DataFormatException();
  564. }
  565. dstoff += n;
  566. }
  567. }
  568. DfsBlock quickCopy(DfsPackFile p, long pos, long cnt)
  569. throws IOException {
  570. pin(p, pos);
  571. if (block.contains(p.key, pos + (cnt - 1)))
  572. return block;
  573. return null;
  574. }
  575. Inflater inflater() {
  576. prepareInflater();
  577. return inf;
  578. }
  579. private void prepareInflater() {
  580. if (inf == null)
  581. inf = InflaterCache.get();
  582. else
  583. inf.reset();
  584. }
  585. void pin(DfsPackFile pack, long position) throws IOException {
  586. DfsBlock b = block;
  587. if (b == null || !b.contains(pack.key, position)) {
  588. // If memory is low, we may need what is in our window field to
  589. // be cleaned up by the GC during the get for the next window.
  590. // So we always clear it, even though we are just going to set
  591. // it again.
  592. block = null;
  593. block = pack.getOrLoadBlock(position, this);
  594. }
  595. }
  596. /** Release the current window cursor. */
  597. @Override
  598. public void release() {
  599. last = null;
  600. block = null;
  601. baseCache = null;
  602. try {
  603. InflaterCache.release(inf);
  604. } finally {
  605. inf = null;
  606. }
  607. }
  608. }