Skip to content

Commit

Permalink
Enriched FileSystemAbstraction
Browse files Browse the repository at this point in the history
* renamed renameFile to move and added CopyOptions
* added lastModifiedTime
  • Loading branch information
fickludd committed Sep 11, 2016
1 parent ab43aec commit ec29b7c
Show file tree
Hide file tree
Showing 13 changed files with 116 additions and 27 deletions.
Expand Up @@ -33,6 +33,8 @@
import java.io.Writer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.file.CopyOption;
import java.nio.file.Files;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
Expand Down Expand Up @@ -133,8 +135,13 @@ public void deleteRecursively( File directory ) throws IOException
}

@Override
public boolean renameFile( File from, File to ) throws IOException
public boolean move( File from, File to, CopyOption... copyOptions ) throws IOException
{
if ( copyOptions.length > 0 )
{
Files.move( from.toPath(), to.toPath(), copyOptions );
return true; // will throw if failure
}
return FileUtils.renameFile( from, to );
}

Expand Down Expand Up @@ -195,6 +202,12 @@ public void truncate( File path, long size ) throws IOException
FileUtils.truncateFile( path, size );
}

@Override
public long lastModifiedTime( File file )
{
return file.lastModified();
}

protected StoreFileChannel getStoreFileChannel( FileChannel channel )
{
return new StoreFileChannel( channel );
Expand Down
Expand Up @@ -30,16 +30,21 @@
import java.io.Writer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.file.CopyOption;
import java.nio.file.DirectoryStream;
import java.nio.file.FileSystem;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Stream;

import static java.nio.file.StandardCopyOption.ATOMIC_MOVE;
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;

/**
* This FileSystemAbstract implementation delegates all calls to a given {@link FileSystem} implementation.
* This is useful for testing with arbitrary 3rd party file systems, such as Jimfs.
Expand Down Expand Up @@ -165,9 +170,9 @@ public void deleteRecursively( File directory ) throws IOException
}

@Override
public boolean renameFile( File from, File to ) throws IOException
public boolean move( File from, File to, CopyOption... copyOptions ) throws IOException
{
Files.move( path( from ), path( to ) );
Files.move( path( from ), path( to ), copyOptions );
return true;
}

Expand Down Expand Up @@ -241,7 +246,7 @@ private void copyRecursively( Path source, Path target ) throws IOException
else
{
Files.copy( sourcePath, targetPath,
StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES );
REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES );
}
}
}
Expand Down Expand Up @@ -271,4 +276,10 @@ public void truncate( File path, long size ) throws IOException
channel.truncate( size );
}
}

@Override
public long lastModifiedTime( File file ) throws IOException
{
return Files.getLastModifiedTime( path( file ) ).toMillis();
}
}
Expand Up @@ -28,6 +28,7 @@
import java.io.Reader;
import java.io.Writer;
import java.nio.charset.Charset;
import java.nio.file.CopyOption;
import java.util.function.Function;
import java.util.zip.ZipOutputStream;

Expand Down Expand Up @@ -57,7 +58,7 @@ public interface FileSystemAbstraction

void deleteRecursively( File directory ) throws IOException;

boolean renameFile( File from, File to ) throws IOException;
boolean move( File from, File to, CopyOption... copyOptions ) throws IOException;

File[] listFiles( File directory );

Expand All @@ -75,6 +76,8 @@ public interface FileSystemAbstraction

void truncate( File path, long size ) throws IOException;

long lastModifiedTime( File file ) throws IOException;

interface ThirdPartyFileSystem extends Closeable
{
void close();
Expand Down
Expand Up @@ -32,6 +32,7 @@
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.nio.charset.Charset;
import java.nio.file.CopyOption;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
Expand Down Expand Up @@ -68,10 +69,10 @@ public StoreChannel open( File fileName, String mode ) throws IOException
return AdversarialFileChannel.wrap( (StoreFileChannel) delegate.open( fileName, mode ), adversary );
}

public boolean renameFile( File from, File to ) throws IOException
public boolean move( File from, File to, CopyOption... copyOptions ) throws IOException
{
adversary.injectFailure( FileNotFoundException.class, SecurityException.class );
return delegate.renameFile( from, to );
return delegate.move( from, to, copyOptions );
}

public OutputStream openAsOutputStream( File fileName, boolean append ) throws IOException
Expand Down Expand Up @@ -204,6 +205,14 @@ public void truncate( File path, long size ) throws IOException
delegate.truncate( path, size );
}

@Override
public long lastModifiedTime( File file ) throws IOException
{
adversary.injectFailure( FileNotFoundException.class, IOException.class, SecurityException.class,
NullPointerException.class );
return delegate.lastModifiedTime( file );
}

private <K extends ThirdPartyFileSystem> ThirdPartyFileSystem adversarialProxy(
final ThirdPartyFileSystem fileSystem,
Class<K> clazz )
Expand Down
Expand Up @@ -19,6 +19,7 @@
*/
package org.neo4j.graphdb.mockfs;

import java.awt.image.ConvolveOp;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
Expand All @@ -27,6 +28,7 @@
import java.io.Reader;
import java.io.Writer;
import java.nio.charset.Charset;
import java.nio.file.CopyOption;
import java.util.function.Function;

import org.neo4j.io.fs.FileSystemAbstraction;
Expand Down Expand Up @@ -79,9 +81,15 @@ public void truncate( File path, long size ) throws IOException
}

@Override
public boolean renameFile( File from, File to ) throws IOException
public long lastModifiedTime( File file ) throws IOException
{
return delegate.renameFile( from, to );
return delegate.lastModifiedTime( file );
}

@Override
public boolean move( File from, File to, CopyOption... copyOptions ) throws IOException
{
return delegate.move( from, to, copyOptions );
}

@Override
Expand Down
Expand Up @@ -40,6 +40,9 @@
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.nio.charset.Charset;
import java.nio.file.CopyOption;
import java.nio.file.StandardCopyOption;
import java.time.Clock;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
Expand Down Expand Up @@ -70,6 +73,8 @@

public class EphemeralFileSystemAbstraction implements FileSystemAbstraction
{
private Clock clock;

interface Positionable
{
long pos();
Expand All @@ -84,6 +89,12 @@ interface Positionable

public EphemeralFileSystemAbstraction()
{
this( Clock.systemUTC() );
}

public EphemeralFileSystemAbstraction( Clock clock )
{
this.clock = clock;
this.files = new ConcurrentHashMap<>();
initCurrentWorkingDirectory();
}
Expand Down Expand Up @@ -280,7 +291,7 @@ public synchronized StoreChannel create( File fileName ) throws IOException
+ "' (The system cannot find the path specified)" );
}

EphemeralFileData data = new EphemeralFileData();
EphemeralFileData data = new EphemeralFileData( clock );
free( files.put( canonicalFile( fileName ), data ) );
return new StoreFileChannel(
new EphemeralFileChannel( data, new FileStillOpenException( fileName.getPath() ) ) );
Expand Down Expand Up @@ -369,15 +380,25 @@ public void deleteRecursively( File directory ) throws IOException
}

@Override
public boolean renameFile( File from, File to ) throws IOException
public boolean move( File from, File to, CopyOption... copyOptions ) throws IOException
{
from = canonicalFile( from );
to = canonicalFile( to );

boolean replaceExisting = false;
for ( CopyOption op : copyOptions )
{
if ( op == StandardCopyOption.REPLACE_EXISTING )
{
replaceExisting = true;
}
}

if ( !files.containsKey( from ) )
{
throw new IOException( "'" + from + "' doesn't exist" );
}
if ( files.containsKey( to ) )
if ( !replaceExisting && files.containsKey( to ) )
{
throw new IOException( "'" + to + "' already exists" );
}
Expand Down Expand Up @@ -592,6 +613,17 @@ public void truncate( File file, long size ) throws IOException
data.truncate( size );
}

@Override
public long lastModifiedTime( File file ) throws IOException
{
EphemeralFileData data = files.get( canonicalFile( file ) );
if ( data == null )
{
throw new FileNotFoundException( "File " + file + " not found" );
}
return data.lastModified;
}

@SuppressWarnings( "serial" )
private static class FileStillOpenException extends Exception
{
Expand Down Expand Up @@ -844,16 +876,20 @@ protected byte[] initialValue()
private int size;
private int forcedSize;
private int locked;
private Clock clock;
private long lastModified;

public EphemeralFileData()
public EphemeralFileData( Clock clock )
{
this( new DynamicByteBuffer() );
this( new DynamicByteBuffer(), clock );
}

private EphemeralFileData( DynamicByteBuffer data )
private EphemeralFileData( DynamicByteBuffer data, Clock clock )
{
this.fileAsBuffer = data;
this.forcedBuffer = data.copy();
this.clock = clock;
this.lastModified = clock.millis();
}

int read( Positionable fc, ByteBuffer dst )
Expand Down Expand Up @@ -905,12 +941,13 @@ synchronized int write( Positionable fc, ByteBuffer src )
}

size = newSize;
lastModified = clock.millis();
return wanted;
}

synchronized EphemeralFileData copy()
{
EphemeralFileData copy = new EphemeralFileData( fileAsBuffer.copy() );
EphemeralFileData copy = new EphemeralFileData( fileAsBuffer.copy(), clock );
copy.size = size;
return copy;
}
Expand Down
Expand Up @@ -28,6 +28,7 @@
import java.io.Reader;
import java.io.Writer;
import java.nio.charset.Charset;
import java.nio.file.CopyOption;

import org.neo4j.io.fs.FileSystemAbstraction;
import org.neo4j.io.fs.StoreChannel;
Expand Down Expand Up @@ -88,10 +89,10 @@ public void mkdirs( File fileName ) throws IOException
}

@Override
public boolean renameFile( File from, File to ) throws IOException
public boolean move( File from, File to, CopyOption... copyOptions ) throws IOException
{
ensureHasSpace();
return super.renameFile( from, to );
return super.move( from, to, copyOptions );
}

public void runOutOfDiskSpace( boolean outOfSpace )
Expand Down
Expand Up @@ -27,6 +27,7 @@
import java.io.Reader;
import java.io.Writer;
import java.nio.charset.Charset;
import java.nio.file.CopyOption;
import java.util.function.Function;

import org.neo4j.io.fs.FileSystemAbstraction;
Expand Down Expand Up @@ -125,9 +126,9 @@ public void deleteRecursively( File directory ) throws IOException
}

@Override
public boolean renameFile( File from, File to ) throws IOException
public boolean move( File from, File to, CopyOption... copyOptions ) throws IOException
{
return chooseFileSystem( from ).renameFile( from, to );
return chooseFileSystem( from ).move( from, to, copyOptions );
}

@Override
Expand Down Expand Up @@ -179,6 +180,12 @@ public void truncate( File path, long size ) throws IOException
chooseFileSystem( path ).truncate( path, size );
}

@Override
public long lastModifiedTime( File file ) throws IOException
{
return chooseFileSystem( file ).lastModifiedTime( file );
}

private FileSystemAbstraction chooseFileSystem( File file )
{
return file.equals( specialFile ) ? specialFileSystem : defaultFileSystem;
Expand Down
Expand Up @@ -264,7 +264,7 @@ private void write()
fileSystem.deleteFile( oldFile );
try
{
if ( fileSystem.fileExists( file ) && !fileSystem.renameFile( file, oldFile ) )
if ( fileSystem.fileExists( file ) && !fileSystem.move( file, oldFile ) )
{
throw new RuntimeException( "Couldn't rename " + file + " -> " + oldFile );
}
Expand All @@ -277,7 +277,7 @@ private void write()
// Rename the .tmp file to the current name
try
{
if ( !fileSystem.renameFile( tmpFile, this.file ) )
if ( !fileSystem.move( tmpFile, this.file ) )
{
throw new RuntimeException( "Couldn't rename " + tmpFile + " -> " + file );
}
Expand Down
Expand Up @@ -175,7 +175,7 @@ public void renameLogFiles( File storeDir ) throws IOException
final String oldName = file.getName();
final long version = getLegacyLogVersion( oldName );
final String newName = DEFAULT_NAME + DEFAULT_VERSION_SUFFIX + version;
fs.renameFile( file, new File( file.getParent(), newName ) );
fs.move( file, new File( file.getParent(), newName ) );
}

deleteUnusedLogFiles( storeDir );
Expand Down

0 comments on commit ec29b7c

Please sign in to comment.