You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

DhtReader.java 20KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698
  1. /*
  2. * Copyright (C) 2011, Google Inc.
  3. * and other copyright owners as documented in the project's IP log.
  4. *
  5. * This program and the accompanying materials are made available
  6. * under the terms of the Eclipse Distribution License v1.0 which
  7. * accompanies this distribution, is reproduced below, and is
  8. * available at http://www.eclipse.org/org/documents/edl-v10.php
  9. *
  10. * All rights reserved.
  11. *
  12. * Redistribution and use in source and binary forms, with or
  13. * without modification, are permitted provided that the following
  14. * conditions are met:
  15. *
  16. * - Redistributions of source code must retain the above copyright
  17. * notice, this list of conditions and the following disclaimer.
  18. *
  19. * - Redistributions in binary form must reproduce the above
  20. * copyright notice, this list of conditions and the following
  21. * disclaimer in the documentation and/or other materials provided
  22. * with the distribution.
  23. *
  24. * - Neither the name of the Eclipse Foundation, Inc. nor the
  25. * names of its contributors may be used to endorse or promote
  26. * products derived from this software without specific prior
  27. * written permission.
  28. *
  29. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  30. * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  31. * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  32. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  33. * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  34. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  35. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  36. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  37. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  38. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  39. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  40. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  41. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  42. */
  43. package org.eclipse.jgit.storage.dht;
  44. import static org.eclipse.jgit.lib.Constants.OBJ_COMMIT;
  45. import static org.eclipse.jgit.lib.Constants.OBJ_TREE;
  46. import java.io.IOException;
  47. import java.io.PrintWriter;
  48. import java.io.StringWriter;
  49. import java.lang.reflect.Field;
  50. import java.lang.reflect.Modifier;
  51. import java.util.ArrayList;
  52. import java.util.Collection;
  53. import java.util.Collections;
  54. import java.util.LinkedHashMap;
  55. import java.util.List;
  56. import java.util.Map;
  57. import java.util.concurrent.TimeoutException;
  58. import java.util.zip.Inflater;
  59. import org.eclipse.jgit.errors.IncorrectObjectTypeException;
  60. import org.eclipse.jgit.errors.MissingObjectException;
  61. import org.eclipse.jgit.errors.StoredObjectRepresentationNotAvailableException;
  62. import org.eclipse.jgit.generated.storage.dht.proto.GitStore.CachedPackInfo;
  63. import org.eclipse.jgit.lib.AbbreviatedObjectId;
  64. import org.eclipse.jgit.lib.AnyObjectId;
  65. import org.eclipse.jgit.lib.AsyncObjectLoaderQueue;
  66. import org.eclipse.jgit.lib.AsyncObjectSizeQueue;
  67. import org.eclipse.jgit.lib.InflaterCache;
  68. import org.eclipse.jgit.lib.ObjectId;
  69. import org.eclipse.jgit.lib.ObjectLoader;
  70. import org.eclipse.jgit.lib.ObjectReader;
  71. import org.eclipse.jgit.lib.ProgressMonitor;
  72. import org.eclipse.jgit.revwalk.ObjectWalk;
  73. import org.eclipse.jgit.revwalk.RevCommit;
  74. import org.eclipse.jgit.revwalk.RevObject;
  75. import org.eclipse.jgit.revwalk.RevWalk;
  76. import org.eclipse.jgit.storage.dht.spi.Context;
  77. import org.eclipse.jgit.storage.dht.spi.Database;
  78. import org.eclipse.jgit.storage.dht.spi.ObjectIndexTable;
  79. import org.eclipse.jgit.storage.pack.CachedPack;
  80. import org.eclipse.jgit.storage.pack.ObjectReuseAsIs;
  81. import org.eclipse.jgit.storage.pack.ObjectToPack;
  82. import org.eclipse.jgit.storage.pack.PackOutputStream;
  83. import org.eclipse.jgit.storage.pack.PackWriter;
  84. /**
  85. * ObjectReader implementation for DHT based repositories.
  86. * <p>
  87. * This class is public only to expose its unique statistics for runtime
  88. * performance reporting. Applications should always prefer to use the more
  89. * generic base class, {@link ObjectReader}.
  90. */
  91. public class DhtReader extends ObjectReader implements ObjectReuseAsIs {
  92. private final DhtRepository repository;
  93. private final RepositoryKey repo;
  94. private final Database db;
  95. private final DhtReaderOptions readerOptions;
  96. private final DhtInserterOptions inserterOptions;
  97. private final Statistics stats;
  98. private final RecentInfoCache recentInfo;
  99. private final RecentChunks recentChunks;
  100. private final DeltaBaseCache deltaBaseCache;
  101. private Collection<CachedPack> cachedPacks;
  102. private Inflater inflater;
  103. private Prefetcher prefetcher;
  104. DhtReader(DhtObjDatabase objdb) {
  105. this.repository = objdb.getRepository();
  106. this.repo = objdb.getRepository().getRepositoryKey();
  107. this.db = objdb.getDatabase();
  108. this.readerOptions = objdb.getReaderOptions();
  109. this.inserterOptions = objdb.getInserterOptions();
  110. this.stats = new Statistics();
  111. this.recentInfo = new RecentInfoCache(getOptions());
  112. this.recentChunks = new RecentChunks(this);
  113. this.deltaBaseCache = new DeltaBaseCache(this);
  114. }
  115. /** @return describes how this DhtReader has performed. */
  116. public Statistics getStatistics() {
  117. return stats;
  118. }
  119. Database getDatabase() {
  120. return db;
  121. }
  122. RepositoryKey getRepositoryKey() {
  123. return repo;
  124. }
  125. DhtReaderOptions getOptions() {
  126. return readerOptions;
  127. }
  128. DhtInserterOptions getInserterOptions() {
  129. return inserterOptions;
  130. }
  131. RecentInfoCache getRecentInfoCache() {
  132. return recentInfo;
  133. }
  134. DeltaBaseCache getDeltaBaseCache() {
  135. return deltaBaseCache;
  136. }
  137. Inflater inflater() {
  138. if (inflater == null)
  139. inflater = InflaterCache.get();
  140. else
  141. inflater.reset();
  142. return inflater;
  143. }
  144. @Override
  145. public void release() {
  146. recentChunks.clear();
  147. endPrefetch();
  148. InflaterCache.release(inflater);
  149. inflater = null;
  150. super.release();
  151. }
  152. @Override
  153. public ObjectReader newReader() {
  154. return new DhtReader(repository.getObjectDatabase());
  155. }
  156. @Override
  157. public boolean has(AnyObjectId objId, int typeHint) throws IOException {
  158. if (objId instanceof RefDataUtil.IdWithChunk)
  159. return true;
  160. if (recentChunks.has(repo, objId))
  161. return true;
  162. if (repository.getRefDatabase().findChunk(objId) != null)
  163. return true;
  164. return !find(objId).isEmpty();
  165. }
  166. @Override
  167. public ObjectLoader open(AnyObjectId objId, int typeHint)
  168. throws MissingObjectException, IncorrectObjectTypeException,
  169. IOException {
  170. ObjectLoader ldr = recentChunks.open(repo, objId, typeHint);
  171. if (ldr != null)
  172. return ldr;
  173. ChunkAndOffset p = getChunk(objId, typeHint, false);
  174. ldr = PackChunk.read(p.chunk, p.offset, this, typeHint);
  175. recentChunk(p.chunk);
  176. return ldr;
  177. }
  178. @Override
  179. public <T extends ObjectId> AsyncObjectLoaderQueue<T> open(
  180. Iterable<T> objectIds, boolean reportMissing) {
  181. return new OpenQueue<T>(this, objectIds, reportMissing);
  182. }
  183. @Override
  184. public long getObjectSize(AnyObjectId objectId, int typeHint)
  185. throws MissingObjectException, IncorrectObjectTypeException,
  186. IOException {
  187. for (ObjectInfo info : find(objectId))
  188. return info.getSize();
  189. throw missing(objectId, typeHint);
  190. }
  191. @Override
  192. public <T extends ObjectId> AsyncObjectSizeQueue<T> getObjectSize(
  193. Iterable<T> objectIds, boolean reportMissing) {
  194. return new SizeQueue<T>(this, objectIds, reportMissing);
  195. }
  196. @Override
  197. public void walkAdviceBeginCommits(RevWalk rw, Collection<RevCommit> roots)
  198. throws IOException {
  199. endPrefetch();
  200. // Don't assign the prefetcher right away. Delay until its
  201. // configured as push might invoke our own methods that may
  202. // try to call back into the active prefetcher.
  203. //
  204. Prefetcher p = new Prefetcher(this, OBJ_COMMIT);
  205. p.push(this, roots);
  206. prefetcher = p;
  207. }
  208. @Override
  209. public void walkAdviceBeginTrees(ObjectWalk ow, RevCommit min, RevCommit max)
  210. throws IOException {
  211. endPrefetch();
  212. // Don't assign the prefetcher right away. Delay until its
  213. // configured as push might invoke our own methods that may
  214. // try to call back into the active prefetcher.
  215. //
  216. Prefetcher p = new Prefetcher(this, OBJ_TREE);
  217. p.push(this, min.getTree(), max.getTree());
  218. prefetcher = p;
  219. }
  220. @Override
  221. public void walkAdviceEnd() {
  222. endPrefetch();
  223. }
  224. void recentChunk(PackChunk chunk) {
  225. recentChunks.put(chunk);
  226. }
  227. ChunkAndOffset getChunkGently(AnyObjectId objId) {
  228. return recentChunks.find(repo, objId);
  229. }
  230. ChunkAndOffset getChunk(AnyObjectId objId, int typeHint, boolean checkRecent)
  231. throws DhtException, MissingObjectException {
  232. if (checkRecent) {
  233. ChunkAndOffset r = recentChunks.find(repo, objId);
  234. if (r != null)
  235. return r;
  236. }
  237. ChunkKey key;
  238. if (objId instanceof RefDataUtil.IdWithChunk)
  239. key = ((RefDataUtil.IdWithChunk) objId).getChunkKey();
  240. else
  241. key = repository.getRefDatabase().findChunk(objId);
  242. if (key != null) {
  243. PackChunk chunk = load(key);
  244. if (chunk != null && chunk.hasIndex()) {
  245. int pos = chunk.findOffset(repo, objId);
  246. if (0 <= pos)
  247. return new ChunkAndOffset(chunk, pos);
  248. }
  249. // The hint above is stale. Fall through and do a
  250. // more exhaustive lookup to find the object.
  251. }
  252. if (prefetcher != null) {
  253. ChunkAndOffset r = prefetcher.find(repo, objId);
  254. if (r != null)
  255. return r;
  256. }
  257. for (ObjectInfo link : find(objId)) {
  258. PackChunk chunk;
  259. if (prefetcher != null) {
  260. chunk = prefetcher.get(link.getChunkKey());
  261. if (chunk == null) {
  262. chunk = load(link.getChunkKey());
  263. if (chunk == null)
  264. continue;
  265. if (prefetcher.isType(typeHint))
  266. prefetcher.push(chunk.getMeta());
  267. }
  268. } else {
  269. chunk = load(link.getChunkKey());
  270. if (chunk == null)
  271. continue;
  272. }
  273. return new ChunkAndOffset(chunk, link.getOffset());
  274. }
  275. throw missing(objId, typeHint);
  276. }
  277. ChunkKey findChunk(AnyObjectId objId) throws DhtException {
  278. if (objId instanceof RefDataUtil.IdWithChunk)
  279. return ((RefDataUtil.IdWithChunk) objId).getChunkKey();
  280. ChunkKey key = repository.getRefDatabase().findChunk(objId);
  281. if (key != null)
  282. return key;
  283. ChunkAndOffset r = recentChunks.find(repo, objId);
  284. if (r != null)
  285. return r.chunk.getChunkKey();
  286. for (ObjectInfo link : find(objId))
  287. return link.getChunkKey();
  288. return null;
  289. }
  290. static MissingObjectException missing(AnyObjectId objId, int typeHint) {
  291. ObjectId id = objId.copy();
  292. if (typeHint != OBJ_ANY)
  293. return new MissingObjectException(id, typeHint);
  294. return new MissingObjectException(id, DhtText.get().objectTypeUnknown);
  295. }
  296. PackChunk getChunk(ChunkKey key) throws DhtException {
  297. PackChunk chunk = recentChunks.get(key);
  298. if (chunk != null)
  299. return chunk;
  300. chunk = load(key);
  301. if (chunk != null)
  302. return chunk;
  303. throw new DhtMissingChunkException(key);
  304. }
  305. @Override
  306. public Collection<ObjectId> resolve(AbbreviatedObjectId id)
  307. throws IOException {
  308. // Because ObjectIndexKey requires at least 4 leading digits
  309. // don't resolve anything that is shorter than 4 digits.
  310. //
  311. if (id.length() < 4)
  312. return Collections.emptySet();
  313. throw new DhtException.TODO("resolve abbreviations");
  314. }
  315. public DhtObjectToPack newObjectToPack(RevObject obj) {
  316. return new DhtObjectToPack(obj);
  317. }
  318. @SuppressWarnings("unchecked")
  319. public void selectObjectRepresentation(PackWriter packer,
  320. ProgressMonitor monitor, Iterable<ObjectToPack> objects)
  321. throws IOException, MissingObjectException {
  322. Iterable itr = objects;
  323. new RepresentationSelector(packer, this, monitor).select(itr);
  324. }
  325. private void endPrefetch() {
  326. prefetcher = null;
  327. }
  328. @SuppressWarnings("unchecked")
  329. public void writeObjects(PackOutputStream out, List<ObjectToPack> objects)
  330. throws IOException {
  331. prefetcher = new Prefetcher(this, 0);
  332. try {
  333. List itr = objects;
  334. new ObjectWriter(this, prefetcher).plan(itr);
  335. for (ObjectToPack otp : objects)
  336. out.writeObject(otp);
  337. } finally {
  338. endPrefetch();
  339. }
  340. }
  341. public void copyObjectAsIs(PackOutputStream out, ObjectToPack otp,
  342. boolean validate) throws IOException,
  343. StoredObjectRepresentationNotAvailableException {
  344. DhtObjectToPack obj = (DhtObjectToPack) otp;
  345. try {
  346. PackChunk chunk = recentChunks.get(obj.chunk);
  347. if (chunk == null) {
  348. chunk = prefetcher.get(obj.chunk);
  349. if (chunk == null) {
  350. // This should never happen during packing, it implies
  351. // the fetch plan was incorrect. Unfortunately that can
  352. // occur if objects need to be recompressed on the fly.
  353. //
  354. stats.access(obj.chunk).cntCopyObjectAsIs_PrefetchMiss++;
  355. chunk = getChunk(obj.chunk);
  356. }
  357. if (!chunk.isFragment())
  358. recentChunk(chunk);
  359. }
  360. chunk.copyObjectAsIs(out, obj, validate, this);
  361. } catch (DhtMissingChunkException missingChunk) {
  362. stats.access(missingChunk.getChunkKey()).cntCopyObjectAsIs_InvalidChunk++;
  363. throw new StoredObjectRepresentationNotAvailableException(otp);
  364. }
  365. }
  366. public Collection<CachedPack> getCachedPacks() throws IOException {
  367. if (cachedPacks == null) {
  368. Collection<CachedPackInfo> info;
  369. Collection<CachedPack> packs;
  370. try {
  371. info = db.repository().getCachedPacks(repo);
  372. } catch (TimeoutException e) {
  373. throw new DhtTimeoutException(e);
  374. }
  375. packs = new ArrayList<CachedPack>(info.size());
  376. for (CachedPackInfo i : info)
  377. packs.add(new DhtCachedPack(i));
  378. cachedPacks = packs;
  379. }
  380. return cachedPacks;
  381. }
  382. public void copyPackAsIs(PackOutputStream out, CachedPack pack,
  383. boolean validate) throws IOException {
  384. ((DhtCachedPack) pack).copyAsIs(out, validate, this);
  385. }
  386. private List<ObjectInfo> find(AnyObjectId obj) throws DhtException {
  387. List<ObjectInfo> info = recentInfo.get(obj);
  388. if (info != null)
  389. return info;
  390. stats.cntObjectIndex_Load++;
  391. ObjectIndexKey idxKey = ObjectIndexKey.create(repo, obj);
  392. Context opt = Context.READ_REPAIR;
  393. Sync<Map<ObjectIndexKey, Collection<ObjectInfo>>> sync = Sync.create();
  394. db.objectIndex().get(opt, Collections.singleton(idxKey), sync);
  395. try {
  396. Collection<ObjectInfo> m;
  397. m = sync.get(getOptions().getTimeout()).get(idxKey);
  398. if (m == null || m.isEmpty())
  399. return Collections.emptyList();
  400. info = new ArrayList<ObjectInfo>(m);
  401. ObjectInfo.sort(info);
  402. recentInfo.put(obj, info);
  403. return info;
  404. } catch (InterruptedException e) {
  405. throw new DhtTimeoutException(e);
  406. } catch (TimeoutException e) {
  407. throw new DhtTimeoutException(e);
  408. }
  409. }
  410. private PackChunk load(ChunkKey chunkKey) throws DhtException {
  411. if (0 == stats.access(chunkKey).cntReader_Load++
  412. && readerOptions.isTrackFirstChunkLoad())
  413. stats.access(chunkKey).locReader_Load = new Throwable("first");
  414. Context opt = Context.READ_REPAIR;
  415. Sync<Collection<PackChunk.Members>> sync = Sync.create();
  416. db.chunk().get(opt, Collections.singleton(chunkKey), sync);
  417. try {
  418. Collection<PackChunk.Members> c = sync.get(getOptions()
  419. .getTimeout());
  420. if (c.isEmpty())
  421. return null;
  422. if (c instanceof List)
  423. return ((List<PackChunk.Members>) c).get(0).build();
  424. return c.iterator().next().build();
  425. } catch (InterruptedException e) {
  426. throw new DhtTimeoutException(e);
  427. } catch (TimeoutException e) {
  428. throw new DhtTimeoutException(e);
  429. }
  430. }
  431. static class ChunkAndOffset {
  432. final PackChunk chunk;
  433. final int offset;
  434. ChunkAndOffset(PackChunk chunk, int offset) {
  435. this.chunk = chunk;
  436. this.offset = offset;
  437. }
  438. }
  439. /** How this DhtReader has performed since creation. */
  440. public static class Statistics {
  441. private final Map<ChunkKey, ChunkAccess> chunkAccess = new LinkedHashMap<ChunkKey, ChunkAccess>();
  442. ChunkAccess access(ChunkKey chunkKey) {
  443. ChunkAccess ca = chunkAccess.get(chunkKey);
  444. if (ca == null) {
  445. ca = new ChunkAccess(chunkKey);
  446. chunkAccess.put(chunkKey, ca);
  447. }
  448. return ca;
  449. }
  450. /**
  451. * Number of sequential {@link ObjectIndexTable} lookups made by the
  452. * reader. These were made without the support of batch lookups.
  453. */
  454. public int cntObjectIndex_Load;
  455. /** Cycles detected in delta chains during OBJ_REF_DELTA reads. */
  456. public int deltaChainCycles;
  457. int recentChunks_Hits;
  458. int recentChunks_Miss;
  459. int deltaBaseCache_Hits;
  460. int deltaBaseCache_Miss;
  461. /** @return ratio of recent chunk hits, [0.00,1.00]. */
  462. public double getRecentChunksHitRatio() {
  463. int total = recentChunks_Hits + recentChunks_Miss;
  464. return ((double) recentChunks_Hits) / total;
  465. }
  466. /** @return ratio of delta base cache hits, [0.00,1.00]. */
  467. public double getDeltaBaseCacheHitRatio() {
  468. int total = deltaBaseCache_Hits + deltaBaseCache_Miss;
  469. return ((double) deltaBaseCache_Hits) / total;
  470. }
  471. /**
  472. * @return collection of chunk accesses made by the application code
  473. * against this reader. The collection's iterator has no
  474. * relevant order.
  475. */
  476. public Collection<ChunkAccess> getChunkAccess() {
  477. return chunkAccess.values();
  478. }
  479. @Override
  480. public String toString() {
  481. StringBuilder b = new StringBuilder();
  482. b.append("DhtReader.Statistics:\n");
  483. b.append(" ");
  484. if (recentChunks_Hits != 0 || recentChunks_Miss != 0)
  485. ratio(b, "recentChunks", getRecentChunksHitRatio());
  486. if (deltaBaseCache_Hits != 0 || deltaBaseCache_Miss != 0)
  487. ratio(b, "deltaBaseCache", getDeltaBaseCacheHitRatio());
  488. appendFields(this, b);
  489. b.append("\n");
  490. for (ChunkAccess ca : getChunkAccess()) {
  491. b.append(" ");
  492. b.append(ca.toString());
  493. b.append("\n");
  494. }
  495. return b.toString();
  496. }
  497. @SuppressWarnings("boxing")
  498. static void ratio(StringBuilder b, String name, double value) {
  499. b.append(String.format(" %s=%.2f%%", name, value * 100.0));
  500. }
  501. static void appendFields(Object obj, StringBuilder b) {
  502. try {
  503. for (Field field : obj.getClass().getDeclaredFields()) {
  504. String n = field.getName();
  505. if (field.getType() == Integer.TYPE
  506. && (field.getModifiers() & Modifier.PUBLIC) != 0) {
  507. int v = field.getInt(obj);
  508. if (0 < v)
  509. b.append(' ').append(n).append('=').append(v);
  510. }
  511. }
  512. } catch (IllegalArgumentException e) {
  513. throw new RuntimeException(e);
  514. } catch (IllegalAccessException e) {
  515. throw new RuntimeException(e);
  516. }
  517. }
  518. /** Summary describing how a chunk was accessed. */
  519. public static final class ChunkAccess {
  520. /** Chunk this access block describes. */
  521. public final ChunkKey chunkKey;
  522. /**
  523. * Number of times chunk was loaded sequentially. Incremented when
  524. * the reader had to load the chunk on demand with no cache or
  525. * prefetcher support.
  526. */
  527. public int cntReader_Load;
  528. Throwable locReader_Load;
  529. /**
  530. * Number of times the prefetcher loaded from the database.
  531. * Incremented each time the prefetcher asked for the chunk from the
  532. * underlying database (which might have its own distributed cache,
  533. * or not).
  534. */
  535. public int cntPrefetcher_Load;
  536. /**
  537. * Number of times the prefetcher ordering was wrong. Incremented if
  538. * a reader wants a chunk but the prefetcher didn't have it ready at
  539. * the time of request. This indicates a bad prefetching plan as the
  540. * chunk should have been listed earlier in the prefetcher's list.
  541. */
  542. public int cntPrefetcher_OutOfOrder;
  543. /**
  544. * Number of times the reader had to stall to wait for a chunk that
  545. * is currently being prefetched to finish loading and become ready.
  546. * This indicates the prefetcher may have fetched other chunks first
  547. * (had the wrong order), or does not have a deep enough window to
  548. * hide these loads from the application.
  549. */
  550. public int cntPrefetcher_WaitedForLoad;
  551. /**
  552. * Number of times the reader asked the prefetcher for the same
  553. * chunk after it was already consumed from the prefetcher. This
  554. * indicates the reader has walked back on itself and revisited a
  555. * chunk again.
  556. */
  557. public int cntPrefetcher_Revisited;
  558. /**
  559. * Number of times the reader needed this chunk to copy an object
  560. * as-is into a pack stream, but the prefetcher didn't have it
  561. * ready. This correlates with {@link #cntPrefetcher_OutOfOrder} or
  562. * {@link #cntPrefetcher_Revisited}.
  563. */
  564. public int cntCopyObjectAsIs_PrefetchMiss;
  565. /**
  566. * Number of times the reader tried to copy an object from this
  567. * chunk, but discovered the chunk was corrupt or did not contain
  568. * the object as expected.
  569. */
  570. public int cntCopyObjectAsIs_InvalidChunk;
  571. ChunkAccess(ChunkKey key) {
  572. chunkKey = key;
  573. }
  574. @Override
  575. public String toString() {
  576. StringBuilder b = new StringBuilder();
  577. b.append(chunkKey).append('[');
  578. appendFields(this, b);
  579. b.append(" ]");
  580. if (locReader_Load != null) {
  581. StringWriter sw = new StringWriter();
  582. locReader_Load.printStackTrace(new PrintWriter(sw));
  583. b.append(sw);
  584. }
  585. return b.toString();
  586. }
  587. }
  588. }
  589. }