Skip to content

Commit

Permalink
Add PageCache.listExistingMappings.
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisvest committed Jan 30, 2018
1 parent 58e2f7a commit 93a31b6
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 28 deletions.
27 changes: 22 additions & 5 deletions community/io/src/main/java/org/neo4j/io/pagecache/PageCache.java
Expand Up @@ -24,6 +24,7 @@
import java.nio.file.NoSuchFileException; import java.nio.file.NoSuchFileException;
import java.nio.file.OpenOption; import java.nio.file.OpenOption;
import java.nio.file.StandardOpenOption; import java.nio.file.StandardOpenOption;
import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Stream; import java.util.stream.Stream;


Expand Down Expand Up @@ -69,7 +70,7 @@ public interface PageCache extends AutoCloseable
* If no mapping exist for this file, then returned {@link Optional} will report {@link Optional#isPresent()} * If no mapping exist for this file, then returned {@link Optional} will report {@link Optional#isPresent()}
* false. * false.
* <p> * <p>
* NOTE! User is responsible for closing the returned paged file. * <strong>NOTE:</strong> The calling code is responsible for closing the returned paged file, if any.
* *
* @param file The file to try to get the mapped paged file for. * @param file The file to try to get the mapped paged file for.
* @return {@link Optional} containing the {@link PagedFile} mapped by this {@link PageCache} for given file, or an * @return {@link Optional} containing the {@link PagedFile} mapped by this {@link PageCache} for given file, or an
Expand All @@ -78,11 +79,26 @@ public interface PageCache extends AutoCloseable
*/ */
Optional<PagedFile> getExistingMapping( File file ) throws IOException; Optional<PagedFile> getExistingMapping( File file ) throws IOException;


/** Flush all dirty pages */ /**
* List a snapshot of the current file mappings.
* <p>
* The mappings can change as soon as this method returns. However, the returned {@link PagedFile}s will remain
* valid even if they are closed elsewhere.
* <p>
* <strong>NOTE:</strong> The calling code is responsible for closing <em>all</em> the returned paged files.
*
* @throws IOException if page cache has been closed or page eviction problems occur.
*/
List<PagedFile> listExistingMappings() throws IOException;

/**
* Flush all dirty pages.
*/
void flushAndForce() throws IOException; void flushAndForce() throws IOException;


/** /**
* Flush all dirty pages, but limit the rate of IO as advised by the given IOPSLimiter. * Flush all dirty pages, but limit the rate of IO as advised by the given IOPSLimiter.
*
* @param limiter The {@link IOLimiter} that determines if pauses or sleeps should be injected into the flushing * @param limiter The {@link IOLimiter} that determines if pauses or sleeps should be injected into the flushing
* process to keep the IO rate down. * process to keep the IO rate down.
*/ */
Expand All @@ -92,21 +108,22 @@ public interface PageCache extends AutoCloseable
* Close the page cache to prevent any future mapping of files. * Close the page cache to prevent any future mapping of files.
* This also releases any internal resources, including the {@link PageSwapperFactory} through its * This also releases any internal resources, including the {@link PageSwapperFactory} through its
* {@link PageSwapperFactory#close() close} method. * {@link PageSwapperFactory#close() close} method.
*
* @throws IllegalStateException if not all files have been unmapped, with {@link PagedFile#close()}, prior to * @throws IllegalStateException if not all files have been unmapped, with {@link PagedFile#close()}, prior to
* closing the page cache. In this case, the page cache <em>WILL NOT</em> be considered to be successfully closed. * closing the page cache. In this case, the page cache <em>WILL NOT</em> be considered to be successfully closed.
* @throws RuntimeException if the {@link PageSwapperFactory#close()} method throws. In this case the page cache * @throws RuntimeException if the {@link PageSwapperFactory#close()} method throws. In this case the page cache
* <em>WILL BE</em> considered to have been closed successfully. * <em>WILL BE</em> considered to have been closed successfully.
**/ */
void close() throws IllegalStateException; void close() throws IllegalStateException;


/** /**
* The size in bytes of the pages managed by this cache. * The size in bytes of the pages managed by this cache.
**/ */
int pageSize(); int pageSize();


/** /**
* The max number of cached pages. * The max number of cached pages.
**/ */
int maxCachedPages(); int maxCachedPages();


/** /**
Expand Down
Expand Up @@ -24,6 +24,7 @@
import java.nio.file.CopyOption; import java.nio.file.CopyOption;
import java.nio.file.OpenOption; import java.nio.file.OpenOption;
import java.nio.file.StandardOpenOption; import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
Expand Down Expand Up @@ -476,6 +477,25 @@ private void assertNotMapped( File file, FileIsMappedException.Operation operati
} }
} }


@Override
public synchronized List<PagedFile> listExistingMappings() throws IOException
{
assertHealthy();
ensureThreadsInitialised();

List<PagedFile> list = new ArrayList<>();
FileMapping current = mappedFiles;

while ( current != null )
{
MuninnPagedFile pagedFile = current.pagedFile;
pagedFile.incrementRefCount();
list.add( pagedFile );
current = current.next;
}
return list;
}

/** /**
* Note: Must be called while synchronizing on the MuninnPageCache instance. * Note: Must be called while synchronizing on the MuninnPageCache instance.
*/ */
Expand Down
Expand Up @@ -27,6 +27,7 @@
import java.nio.file.NoSuchFileException; import java.nio.file.NoSuchFileException;
import java.nio.file.OpenOption; import java.nio.file.OpenOption;
import java.nio.file.StandardOpenOption; import java.nio.file.StandardOpenOption;
import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Stream; import java.util.stream.Stream;
Expand Down Expand Up @@ -83,6 +84,18 @@ public Optional<PagedFile> getExistingMapping( File file ) throws IOException
return optional; return optional;
} }


@Override
public List<PagedFile> listExistingMappings() throws IOException
{
adversary.injectFailure( IOException.class, SecurityException.class );
List<PagedFile> list = delegate.listExistingMappings();
for ( int i = 0; i < list.size(); i++ )
{
list.set( i, new AdversarialPagedFile( list.get( i ), adversary ) );
}
return list;
}

@Override @Override
public void flushAndForce() throws IOException public void flushAndForce() throws IOException
{ {
Expand Down
Expand Up @@ -22,6 +22,7 @@
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.OpenOption; import java.nio.file.OpenOption;
import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Stream; import java.util.stream.Stream;


Expand All @@ -45,6 +46,13 @@ public Optional<PagedFile> getExistingMapping( File file ) throws IOException
return delegate.getExistingMapping( file ); return delegate.getExistingMapping( file );
} }


@Override
public List<PagedFile> listExistingMappings() throws IOException
{
return delegate.listExistingMappings();
}

@Override
public int pageSize() public int pageSize()
{ {
return delegate.pageSize(); return delegate.pageSize();
Expand Down
Expand Up @@ -1151,29 +1151,6 @@ public void writeToPreviouslyBoundCursorAfterNextReturnsFalseMustThrow() throws
verifyOnWriteCursor( this::checkPreviouslyBoundWriteCursorAfterFailedNext ); verifyOnWriteCursor( this::checkPreviouslyBoundWriteCursorAfterFailedNext );
} }


@Test
public void tryMappedPagedFileShouldReportMappedFilePresent() throws Exception
{
PageCache cache = createStandardPageCache();
final File file = file( "a" );
try ( PagedFile pf = cache.map( file, filePageSize ) )
{
final Optional<PagedFile> optional = cache.getExistingMapping( file );
assertTrue( optional.isPresent() );
final PagedFile actual = optional.get();
assertThat( actual, sameInstance( pf ) );
actual.close();
}
}

@Test
public void tryMappedPagedFileShouldReportNonMappedFileNotPresent() throws Exception
{
PageCache cache = createStandardPageCache();
final Optional<PagedFile> dont_exist = cache.getExistingMapping( new File( "dont_exist" ) );
assertFalse( dont_exist.isPresent() );
}

private void verifyOnReadCursor( private void verifyOnReadCursor(
ThrowingConsumer<PageCursorAction,IOException> testTemplate ) throws IOException ThrowingConsumer<PageCursorAction,IOException> testTemplate ) throws IOException
{ {
Expand Down Expand Up @@ -1310,6 +1287,62 @@ private void checkPreviouslyBoundWriteCursorAfterFailedNext( PageCursorAction ac
} }
} }


@Test
public void tryMappedPagedFileShouldReportMappedFilePresent() throws Exception
{
configureStandardPageCache();
final File file = file( "a" );
try ( PagedFile pf = pageCache.map( file, filePageSize ) )
{
final Optional<PagedFile> optional = pageCache.getExistingMapping( file );
assertTrue( optional.isPresent() );
final PagedFile actual = optional.get();
assertThat( actual, sameInstance( pf ) );
actual.close();
}
}

@Test
public void tryMappedPagedFileShouldReportNonMappedFileNotPresent() throws Exception
{
configureStandardPageCache();
final Optional<PagedFile> dontExist = pageCache.getExistingMapping( new File( "dont_exist" ) );
assertFalse( dontExist.isPresent() );
}

@Test
public void mustListExistingMappings() throws Exception
{
configureStandardPageCache();
File f1 = existingFile( "1" );
File f2 = existingFile( "2" );
File f3 = existingFile( "3" ); // Not mapped at the time of calling listExistingMappings.
existingFile( "4" ); // Never mapped.
try ( PagedFile pf1 = pageCache.map( f1, filePageSize );
PagedFile pf2 = pageCache.map( f2, filePageSize ) )
{
pageCache.map( f3, filePageSize ).close();
List<PagedFile> existingMappings = pageCache.listExistingMappings();
assertThat( existingMappings.size(), is( 2 ) );
assertThat( existingMappings, containsInAnyOrder( pf1, pf2 ) );
for ( PagedFile existingMapping : existingMappings )
{
existingMapping.close();
}
}
}

@Test
public void listExistingMappingsMustThrowOnClosedPageCache() throws Exception
{
configureStandardPageCache();
T pc = pageCache;
pageCache = null;
pc.close();
expectedException.expect( IllegalStateException.class );
pc.listExistingMappings();
}

@Test( timeout = SHORT_TIMEOUT_MILLIS ) @Test( timeout = SHORT_TIMEOUT_MILLIS )
public void lastPageMustBeAccessibleWithNoGrowSpecified() throws IOException public void lastPageMustBeAccessibleWithNoGrowSpecified() throws IOException
{ {
Expand Down
Expand Up @@ -22,6 +22,7 @@
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.OpenOption; import java.nio.file.OpenOption;
import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Stream; import java.util.stream.Stream;


Expand Down Expand Up @@ -76,6 +77,12 @@ public Optional<PagedFile> getExistingMapping( File file ) throws IOException
return delegate.getExistingMapping( file ); return delegate.getExistingMapping( file );
} }


@Override
public List<PagedFile> listExistingMappings() throws IOException
{
return delegate.listExistingMappings();
}

@Override @Override
public void flushAndForce() throws IOException public void flushAndForce() throws IOException
{ {
Expand Down

0 comments on commit 93a31b6

Please sign in to comment.