Skip to content

Commit

Permalink
Introduced adversarial page cache
Browse files Browse the repository at this point in the history
Such page cache implementation is able to wrap the given page cache and
introduce some misbehaviour to exercise the user code. It can either throw
RuntimeExceptions/IOExceptions or return a page cursor with inconsistent
reads. Misbehaviour is controlled by the given Adversary.

Changed PageCacheRule to use the AdversarialPageCache.
  • Loading branch information
lutovich authored and chrisvest committed Mar 15, 2016
1 parent 0f99716 commit 725f841
Show file tree
Hide file tree
Showing 8 changed files with 712 additions and 324 deletions.
Expand Up @@ -279,9 +279,8 @@ public interface PageCursor extends AutoCloseable
* an equivalent io() call. In other words, the next call to next() will
* move the cursor to the starting page that was specified in the io() that
* produced the cursor.
* @throws IOException
*/
void rewind() throws IOException;
void rewind();

/**
* Moves the cursor to the next page, if any, and returns true when it is
Expand Down
@@ -0,0 +1,83 @@
/*
* Copyright (c) 2002-2016 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.adversaries.pagecache;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Objects;

import org.neo4j.adversaries.Adversary;
import org.neo4j.io.pagecache.PageCache;
import org.neo4j.io.pagecache.PagedFile;

/**
* A {@linkplain PageCache page cache} that wraps another page cache and an {@linkplain Adversary adversary} to provide
* a misbehaving page cache implementation for testing.
* <p>
* Depending on the adversary each operation can throw either {@link RuntimeException} like {@link SecurityException}
* or {@link IOException} like {@link FileNotFoundException}.
*/
@SuppressWarnings( "unchecked" )
public class AdversarialPageCache implements PageCache
{
private final PageCache delegate;
private final Adversary adversary;

public AdversarialPageCache( PageCache delegate, Adversary adversary )
{
this.delegate = Objects.requireNonNull( delegate );
this.adversary = Objects.requireNonNull( adversary );
}

@Override
public PagedFile map( File file, int pageSize ) throws IOException
{
adversary.injectFailure( FileNotFoundException.class, IOException.class, SecurityException.class );
PagedFile pagedFile = delegate.map( file, pageSize );
return new AdversarialPagedFile( pagedFile, adversary );
}

@Override
public void flushAndForce() throws IOException
{
adversary.injectFailure( FileNotFoundException.class, IOException.class, SecurityException.class );
delegate.flushAndForce();
}

@Override
public void close() throws IOException
{
adversary.injectFailure( FileNotFoundException.class, IOException.class, SecurityException.class );
delegate.close();
}

@Override
public int pageSize()
{
return delegate.pageSize();
}

@Override
public int maxCachedPages()
{
return delegate.maxCachedPages();
}
}
@@ -0,0 +1,94 @@
/*
* Copyright (c) 2002-2016 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.adversaries.pagecache;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Objects;

import org.neo4j.adversaries.Adversary;
import org.neo4j.io.pagecache.PageCursor;
import org.neo4j.io.pagecache.PagedFile;

/**
* A {@linkplain PagedFile paged file} that wraps another paged file and an {@linkplain Adversary adversary} to provide
* a misbehaving paged file implementation for testing.
* <p>
* Depending on the adversary each operation can throw either {@link RuntimeException} like {@link SecurityException}
* or {@link IOException} like {@link FileNotFoundException}.
*/
@SuppressWarnings( "unchecked" )
class AdversarialPagedFile implements PagedFile
{
private final PagedFile delegate;
private final Adversary adversary;

AdversarialPagedFile( PagedFile delegate, Adversary adversary )
{
this.delegate = Objects.requireNonNull( delegate );
this.adversary = Objects.requireNonNull( adversary );
}

@Override
public PageCursor io( long pageId, int pf_flags ) throws IOException
{
adversary.injectFailure( IllegalStateException.class );
PageCursor pageCursor = delegate.io( pageId, pf_flags );
if ( (pf_flags & PF_SHARED_LOCK) == PF_SHARED_LOCK )
{
return new AdversarialReadPageCursor( pageCursor, adversary );
}
return new AdversarialWritePageCursor( pageCursor, adversary );
}

@Override
public int pageSize()
{
return delegate.pageSize();
}

@Override
public void flushAndForce() throws IOException
{
adversary.injectFailure( FileNotFoundException.class, IOException.class, SecurityException.class );
delegate.flushAndForce();
}

@Override
public void force() throws IOException
{
adversary.injectFailure( IOException.class, SecurityException.class );
delegate.force();
}

@Override
public long getLastPageId() throws IOException
{
adversary.injectFailure( IllegalStateException.class );
return delegate.getLastPageId();
}

@Override
public void close() throws IOException
{
adversary.injectFailure( FileNotFoundException.class, IOException.class, SecurityException.class );
delegate.close();
}
}

0 comments on commit 725f841

Please sign in to comment.