public void get()

in application/org.openjdk.jmc.joverflow/src/main/java/org/openjdk/jmc/joverflow/heap/parser/CachedReadBuffer.java [149:249]


	public void get(long pos, byte[] buf, int numBytesToRead) throws IOException {
		if (DEBUG_PERF) {
			lastReadPos = pos;
			numReads++;
		}
		int numBytesLeft = numBytesToRead;
		int posInBuf = 0;
		while (numBytesLeft > 0) {
			int pageIdxInFile = (int) (pos >> PAGE_SIZE_MAGNITUDE);
			Page page = pageIdxInFileToPage[pageIdxInFile];

			if (page == null) {
				page = leastRecentlyUsed;
				if (pass == 2) {
					// This improves performance a bit by reducing the number of swaps by 3% or so.
					// We try to find a page which is both close to LRU and from which enough
					// bytes have been read to reasonably expect that no more will be read in the
					// future. That it works depends on the fact that JOverflow, during both
					// of its heap scans (overall and detailed), generally does not read the
					// same byte in the heap dump more than once. The exception are char[] arrays
					// shared by several String instances, but that doesn't happen very often.
					Page candidate = page;
					int threshold = PAGE_SIZE * 4 / 5;
					for (int i = 0; i < numPagesInPool / 8; i++) {
						int candidateBytes = numBytesReadFromFilePage[candidate.pageIdxInFile];
						if (candidateBytes > threshold) {
							page = candidate;
							break;
						} else {
							candidate = candidate.next;
							if (candidate == null) {
								break;
							}
						}
					}
					if (DEBUG_PERF && page != leastRecentlyUsed) {
						numChanges++;
					}
				}
				pageIdxInFileToPage[page.pageIdxInFile] = null;
				page.fill(pos & PAGE_START_MASK, pageIdxInFile);
				numPageSwaps++;
				pageIdxInFileToPage[pageIdxInFile] = page;
			}

			// Update the linked list
			if (page != mostRecentlyUsed) {
				if (DEBUG) {
					checkListConsistency(page);
				}
				// We use not the same page as on previous call. It becomes most-recently used.
				Page oldPreviousPage = page.previous;
				Page oldNextPage = page.next;
				page.previous = mostRecentlyUsed;
				// Deal with pointers in/to old Page instance that has just been reused
				if (oldPreviousPage != null) {
					oldPreviousPage.next = oldNextPage;
				}
				if (oldNextPage != null) {
					oldNextPage.previous = oldPreviousPage;
				}

				mostRecentlyUsed.next = page;
				mostRecentlyUsed = page;
				if (page == leastRecentlyUsed) {
					leastRecentlyUsed = leastRecentlyUsed.next;
				}
				page.next = null;

				if (DEBUG) {
					checkListConsistency(page);
				}
			}

			int startPosInPage = (int) (pos - page.startPosInFile);
			int numBytesToEndOfPage = (PAGE_SIZE - startPosInPage);
			int numBytesToCopy = (numBytesLeft < numBytesToEndOfPage) ? numBytesLeft : numBytesToEndOfPage;
			System.arraycopy(buffer, page.startPosInBuffer + startPosInPage, buf, posInBuf, numBytesToCopy);
			numBytesReadFromFilePage[pageIdxInFile] += numBytesToCopy;
			numBytesLeft -= numBytesToCopy;
			if (numBytesLeft > 0) {
				posInBuf += numBytesToCopy;
				pos += numBytesToCopy;
			}

			if (numBytesToCopy == PAGE_SIZE) {
				// If we read the whole page, we will not get back to it any time soon.
				// Thus it's the best candidate for reuse, and we declare it LRU.
				// Note that previously this page was declared MRU.
				Page oldPreviousPage = page.previous;
				page.previous = null;
				page.next = leastRecentlyUsed;
				leastRecentlyUsed = page;
				mostRecentlyUsed = oldPreviousPage;
				mostRecentlyUsed.next = null;
				if (DEBUG) {
					checkListConsistency(page);
				}
			}
		}
	}