use of org.neo4j.io.pagecache.context.CursorContext in project neo4j by neo4j.
the class MuninnPageCacheTest method mustFlushDirtyPagesOnEvictingLastPage.
@Test
void mustFlushDirtyPagesOnEvictingLastPage() throws Exception {
writeInitialDataTo(file("a"));
RecordingPageCacheTracer tracer = new RecordingPageCacheTracer();
RecordingPageCursorTracer cursorContext = new RecordingPageCursorTracer(tracer, "mustFlushDirtyPagesOnEvictingLastPage");
try (MuninnPageCache pageCache = createPageCache(fs, 2, blockCacheFlush(tracer));
PagedFile pagedFile = map(pageCache, file("a"), 8)) {
try (PageCursor cursor = pagedFile.io(1, PF_SHARED_WRITE_LOCK, new CursorContext(cursorContext))) {
assertTrue(cursor.next());
cursor.putLong(0L);
}
cursorContext.reportEvents();
assertNotNull(cursorContext.observe(Fault.class));
assertEquals(1, cursorContext.faults());
assertEquals(1, tracer.faults());
long clockArm = pageCache.evictPages(1, 0, tracer.beginPageEvictions(1));
assertThat(clockArm).isEqualTo(1L);
assertNotNull(tracer.observe(Evict.class));
ByteBuffer buf = readIntoBuffer("a");
assertThat(buf.getLong()).isEqualTo(x);
assertThat(buf.getLong()).isEqualTo(0L);
}
}
use of org.neo4j.io.pagecache.context.CursorContext in project neo4j by neo4j.
the class PageCacheTest method tracerMustBeNotifiedAboutPinUnpinFaultFlushAndEvictionEventsWhenWriting.
@Test
void tracerMustBeNotifiedAboutPinUnpinFaultFlushAndEvictionEventsWhenWriting() {
assertTimeoutPreemptively(ofMillis(SHORT_TIMEOUT_MILLIS), () -> {
long pagesToGenerate = 142;
DefaultPageCacheTracer tracer = new DefaultPageCacheTracer();
getPageCache(fs, maxPages, tracer);
long initialPins = tracer.pins();
long initialUnpins = tracer.unpins();
try (CursorContext cursorContext = new CursorContext(tracer.createPageCursorTracer("tracerMustBeNotifiedAboutPinUnpinFaultFlushAndEvictionEventsWhenWriting"));
PagedFile pagedFile = map(file("a"), filePageSize);
PageCursor cursor = pagedFile.io(0, PF_SHARED_WRITE_LOCK, cursorContext)) {
for (long i = 0; i < pagesToGenerate; i++) {
assertTrue(cursor.next());
assertThat(cursor.getCurrentPageId()).isEqualTo(i);
// This does not count as a pin
assertTrue(cursor.next(i));
assertThat(cursor.getCurrentPageId()).isEqualTo(i);
writeRecords(cursor);
}
// This counts as a single pin
assertTrue(cursor.next(0));
assertTrue(cursor.next(0));
}
assertThat(tracer.pins()).as("wrong count of pins").isEqualTo(pagesToGenerate + 1 + initialPins);
assertThat(tracer.unpins()).as("wrong count of unpins").isEqualTo(pagesToGenerate + 1 + initialUnpins);
// We might be unlucky and fault in the second next call, on the page
// we brought up in the first next call. That's why we assert that we
// have observed *at least* the countedPages number of faults.
long faults = tracer.faults();
assertThat(faults).as("wrong count of faults").isGreaterThanOrEqualTo(pagesToGenerate);
// Every page we move forward can put the freelist behind so the cache
// wants to evict more pages. Plus, every page fault we do could also
// block and get a page directly transferred to it, and these kinds of
// evictions can count in addition to the evictions we do when the
// cache is behind on keeping the freelist full.
assertThat(tracer.evictions()).as("wrong count of evictions").isGreaterThanOrEqualTo(pagesToGenerate - maxPages).isLessThanOrEqualTo(pagesToGenerate + faults);
// We use greaterThanOrEqualTo because we visit each page twice, and
// that leaves a small window wherein we can race with eviction, have
// the evictor flush the page, and then fault it back and mark it as
// dirty again.
// We also subtract 'maxPages' from the expected flush count, because
// vectored IO may coalesce all the flushes we do as part of unmapping
// the file, into a single flush.
long flushes = tracer.flushes();
long bytesWritten = tracer.bytesWritten();
assertThat(flushes).as("wrong count of flushes").isGreaterThanOrEqualTo(pagesToGenerate - maxPages);
assertThat(bytesWritten).as("wrong count of bytes written").isGreaterThanOrEqualTo(pagesToGenerate * filePageSize);
});
}
use of org.neo4j.io.pagecache.context.CursorContext in project neo4j by neo4j.
the class PageCacheTest method restartByShouldRetryMustCarryOverExistingPin.
@Test
void restartByShouldRetryMustCarryOverExistingPin() throws IOException {
DefaultPageCacheTracer tracer = new DefaultPageCacheTracer();
getPageCache(fs, maxPages, tracer);
generateFileWithRecords(file("a"), recordCount, recordSize);
try (PagedFile pagedFile = map(file("a"), filePageSize);
CursorContext cursorContext = new CursorContext(tracer.createPageCursorTracer("test"))) {
try (PageCursor reader = pagedFile.io(0, PF_SHARED_READ_LOCK, cursorContext)) {
assertTrue(reader.next());
// Cause the page under the reader cursor to be evicted.
try (PagedFile otherPagedFile = map(existingFile("b"), filePageSize);
PageCursor writer = otherPagedFile.io(0, PF_SHARED_WRITE_LOCK, cursorContext)) {
while (!reader.shouldRetry()) {
for (int i = 0; i < maxPages * 10; i++) {
assertTrue(writer.next(i));
}
}
}
}
}
// Then we should see pins and unpins pair up exactly.
assertThat(tracer.unpins()).isEqualTo(tracer.pins());
}
use of org.neo4j.io.pagecache.context.CursorContext in project neo4j by neo4j.
the class PageCacheTest method tracerMustBeNotifiedOfReadAndWritePins.
@Test
void tracerMustBeNotifiedOfReadAndWritePins() throws Exception {
final AtomicInteger writeCount = new AtomicInteger();
final AtomicInteger readCount = new AtomicInteger();
DefaultPageCacheTracer tracer = new DefaultPageCacheTracer();
DefaultPageCursorTracer pageCursorTracer = new DefaultPageCursorTracer(tracer, "test") {
@Override
public PinEvent beginPin(boolean writeLock, long filePageId, PageSwapper swapper) {
(writeLock ? writeCount : readCount).getAndIncrement();
return super.beginPin(writeLock, filePageId, swapper);
}
};
getPageCache(fs, maxPages, tracer);
generateFileWithRecords(file("a"), recordCount, recordSize);
int pinsForRead = 13;
int pinsForWrite = 42;
try (PagedFile pagedFile = map(file("a"), filePageSize)) {
try (PageCursor cursor = pagedFile.io(0, PF_SHARED_READ_LOCK, new CursorContext(pageCursorTracer))) {
for (int i = 0; i < pinsForRead; i++) {
assertTrue(cursor.next());
}
}
dirtyManyPages(pagedFile, pinsForWrite, new CursorContext(pageCursorTracer));
}
assertThat(readCount.get()).as("wrong read pin count").isEqualTo(pinsForRead);
assertThat(writeCount.get()).as("wrong write pin count").isEqualTo(pinsForWrite);
}
use of org.neo4j.io.pagecache.context.CursorContext in project neo4j by neo4j.
the class MuninnPageCacheTest method ableToEvictAllPageInAPageCache.
@Test
void ableToEvictAllPageInAPageCache() throws IOException {
writeInitialDataTo(file("a"));
RecordingPageCacheTracer tracer = new RecordingPageCacheTracer();
RecordingPageCursorTracer cursorContext = new RecordingPageCursorTracer(tracer, "ableToEvictAllPageInAPageCache");
try (MuninnPageCache pageCache = createPageCache(fs, 2, blockCacheFlush(tracer));
PagedFile pagedFile = map(pageCache, file("a"), 8);
CursorContext context = new CursorContext(cursorContext)) {
try (PageCursor cursor = pagedFile.io(0, PF_SHARED_READ_LOCK, context)) {
assertTrue(cursor.next());
}
try (PageCursor cursor = pagedFile.io(1, PF_SHARED_READ_LOCK, context)) {
assertTrue(cursor.next());
}
evictAllPages(pageCache);
}
}
Aggregations