From d3c6dfdbb5e6d268c45ddf261f941af1309649ba Mon Sep 17 00:00:00 2001 From: jprocter Date: Thu, 23 Mar 2006 11:41:09 +0000 Subject: [PATCH] locking for windows (XP) partly debugged. ClientsFileTest watchers do not behave perfectly yet. git-svn-id: https://svn.lifesci.dundee.ac.uk/svn/repository/trunk@201 be28352e-c001-0410-b1a7-c7978e42abec --- .../vamsas/client/simpleclient/ClientsFile.java | 15 ++-- src/org/vamsas/client/simpleclient/Lock.java | 92 +++++++++++++++++--- .../simpleclient/LockedFileOutputStream.java | 73 ++++++++++++++++ .../vamsas/client/simpleclient/SessionFile.java | 12 ++- .../client/simpleclient/SimpleClientAppdata.java | 3 +- .../vamsas/client/simpleclient/VamsasArchive.java | 2 +- 6 files changed, 171 insertions(+), 26 deletions(-) create mode 100644 src/org/vamsas/client/simpleclient/LockedFileOutputStream.java diff --git a/src/org/vamsas/client/simpleclient/ClientsFile.java b/src/org/vamsas/client/simpleclient/ClientsFile.java index 598bfdd..d8abd2b 100644 --- a/src/org/vamsas/client/simpleclient/ClientsFile.java +++ b/src/org/vamsas/client/simpleclient/ClientsFile.java @@ -43,8 +43,8 @@ public class ClientsFile extends ListFile { try { ClientHandle[] clients=null; if (this.fileLock.rafile.length()>0) { - ObjectInputStream is = new ObjectInputStream(new BufferedInputStream( - new java.io.FileInputStream(sessionFile))); + + ObjectInputStream is = new ObjectInputStream(fileLock.getBufferedInputStream(true)); Object o; o=is.readObject(); if (o!=null) { @@ -231,11 +231,14 @@ public class ClientsFile extends ListFile { File templist = backupSessionFile(); if (templist != null) { try { - fileLock.rafile.setLength(0); - ObjectOutputStream os = new ObjectOutputStream( - new BufferedOutputStream(new FileOutputStream(this.sessionFile))); + // fileLock.rafile.setLength(0); + ObjectOutputStream os = + new ObjectOutputStream(fileLock.getBufferedOutputStream(true)); + +// new BufferedOutputStream(new FileOutputStream(this.sessionFile))); + // new BufferedOutputStream(new FileOutputStream(this.fileLock.rafile.getFD()))); os.writeObject(clients); - os.close(); + os.close(); // close destroys lock! // All done - remove the backup. templist.delete(); templist = null; diff --git a/src/org/vamsas/client/simpleclient/Lock.java b/src/org/vamsas/client/simpleclient/Lock.java index dfc978e..b49cdf5 100644 --- a/src/org/vamsas/client/simpleclient/Lock.java +++ b/src/org/vamsas/client/simpleclient/Lock.java @@ -1,11 +1,16 @@ package org.vamsas.client.simpleclient; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.channels.FileLock; +import org.apache.commons.logging.LogFactory; + /** * transient object representing a file lock * This lock should hold for all processes interacting in a session. @@ -15,6 +20,7 @@ import java.nio.channels.FileLock; */ public class Lock { + org.apache.commons.logging.Log log = LogFactory.getLog(Lock.class); FileLock lock = null; RandomAccessFile rafile=null; /** @@ -29,21 +35,25 @@ public class Lock { try { if (!lockfile.exists()) if (!lockfile.createNewFile()) { + log.warn("Failed to create locked file "+lockfile); return; } lock = (rafile=new RandomAccessFile(lockfile,"rw")).getChannel().tryLock(); - if (lock==null || !lock.isValid()) + if (lock==null || !lock.isValid()) { // failed to get lock. Close the file channel + log.debug("failed to get lock for "+lockfile); rafile.getChannel().close(); + lock=null; + } } catch (FileNotFoundException e) { - System.err.println("Error! Couldn't create a lockfile at " - + lockfile.getAbsolutePath()); - e.printStackTrace(); + // + log.debug("Lock failed - normal behaviour for windows locking."); + //log.error("Error! Couldn't create a lockfile at " + // + lockfile.getAbsolutePath(), e); } catch (IOException e) { - System.err.println("Error! Problems with IO when creating a lock on " - + lockfile.getAbsolutePath()); - e.printStackTrace(); + log.error("Error! Problems with IO when creating a lock on " + + lockfile.getAbsolutePath(),e); } } @@ -55,19 +65,73 @@ public class Lock { } public void release() { try { - // TODO: verify that channel.close should be called after release() for rigourous locking. - if (lock!=null && lock.isValid()) - lock.release(); - if (rafile!=null && rafile.getChannel().isOpen()) - rafile.getChannel().close(); + // TODO: verify that channel.close should be called after release() for rigourous locking. + if (rafile!=null && rafile.getChannel()!=null) { + if (rafile.getChannel().isOpen()) { + if (lock!=null && lock.isValid()) + lock.release(); + if (rafile!=null && rafile.getChannel().isOpen()) + rafile.getChannel().close(); + } + } } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(System.err); + log.warn("Whilst releasing lock",e); } lock=null; rafile=null; } + /** + * gets Locked Stream for reading from + * @param atStart true to start reading at beginning of file. + * @return null if file not locked + * @throws IOException + */ + public FileInputStream getFileInputStream(boolean atStart) throws IOException { + if (!isLocked()) + return null; + if (atStart) + rafile.seek(0); + return new FileInputStream(rafile.getFD()); + } + /** + * gets Locked stream to write to + * FileInput always starts at the *end* of the file (after any truncation) + * @param clear true means file will be cleared to zero length + * @return null if file is not locked + * @throws IOException + */ + public FileOutputStream getFileOutputStream(boolean clear) throws IOException { + if (!isLocked()) + return null; + if (clear) + rafile.setLength(0); + rafile.seek(rafile.length()); + return new LockedFileOutputStream(rafile.getFD()); + } + /** + * return buffered output stream to locked file. + * @param clear - true means file is truncated to 0 length before writing + * @return + */ + public BufferedOutputStream getBufferedOutputStream(boolean clear) throws IOException { + FileOutputStream fos = getFileOutputStream(clear); + if (fos!=null) + return new BufferedOutputStream(fos); + return null; + } + + /** + * return buffered input stream for locked file. + * @param atStart - true means read from begining of file + * @return null if file is not locked. + */ + public BufferedInputStream getBufferedInputStream(boolean atStart) throws IOException { + FileInputStream fis = getFileInputStream(atStart); + if (fis!=null) + return new BufferedInputStream(fis); + return null; + } /* Explicitly release lock (probably don't need to do this!) * @see java.lang.Object#finalize() */ diff --git a/src/org/vamsas/client/simpleclient/LockedFileOutputStream.java b/src/org/vamsas/client/simpleclient/LockedFileOutputStream.java new file mode 100644 index 0000000..2c12974 --- /dev/null +++ b/src/org/vamsas/client/simpleclient/LockedFileOutputStream.java @@ -0,0 +1,73 @@ +/** + * + */ +package org.vamsas.client.simpleclient; + +import java.io.File; +import java.io.FileDescriptor; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; + +/** + * @author Jim + * + */ +public class LockedFileOutputStream extends FileOutputStream { + + /** + * @param file + * @throws FileNotFoundException + */ + public LockedFileOutputStream(File file) throws FileNotFoundException { + super(file); + // TODO Auto-generated constructor stub + } + + /** + * @param file + * @param append + * @throws FileNotFoundException + */ + public LockedFileOutputStream(File file, boolean append) + throws FileNotFoundException { + super(file, append); + // TODO Auto-generated constructor stub + } + + /** + * @param fdObj + */ + public LockedFileOutputStream(FileDescriptor fdObj) { + super(fdObj); + // TODO Auto-generated constructor stub + } + + /** + * @param name + * @throws FileNotFoundException + */ + public LockedFileOutputStream(String name) throws FileNotFoundException { + super(name); + // TODO Auto-generated constructor stub + } + + /** + * @param name + * @param append + * @throws FileNotFoundException + */ + public LockedFileOutputStream(String name, boolean append) + throws FileNotFoundException { + super(name, append); + // TODO Auto-generated constructor stub + } + /** + * closes - actually just flushes the stream instead. + */ + public void close() throws IOException { + // TODO Auto-generated method stub + super.flush(); + } + +} diff --git a/src/org/vamsas/client/simpleclient/SessionFile.java b/src/org/vamsas/client/simpleclient/SessionFile.java index 0eabf6d..d33f2f8 100644 --- a/src/org/vamsas/client/simpleclient/SessionFile.java +++ b/src/org/vamsas/client/simpleclient/SessionFile.java @@ -27,8 +27,10 @@ public class SessionFile { protected boolean lockFile(Lock extantlock) { if (fileLock!=null && !fileLock.isLocked()) { fileLock.release();// tidy up invalid lock + fileLock=null; } - fileLock=extantlock; + if (extantlock!=null) + fileLock=extantlock; return lockFile(); } @@ -60,11 +62,15 @@ public class SessionFile { } // TODO: see if we need to loop-wait for locks or they just block until // lock is made... + long tries=500; do { - if (fileLock!=null) + tries--; + if (fileLock!=null && !fileLock.isLocked()) fileLock.release(); fileLock = new Lock(sessionFile); // TODO: wait around if we can't get the lock. - } while (!fileLock.isLocked()); + } while (tries>0 && !fileLock.isLocked()); + if (!fileLock.isLocked()) + log.error("Failed to get lock for "+sessionFile); // fileLock = new Lock(sessionFile); return fileLock.isLocked(); } else diff --git a/src/org/vamsas/client/simpleclient/SimpleClientAppdata.java b/src/org/vamsas/client/simpleclient/SimpleClientAppdata.java index a2d8912..95362aa 100644 --- a/src/org/vamsas/client/simpleclient/SimpleClientAppdata.java +++ b/src/org/vamsas/client/simpleclient/SimpleClientAppdata.java @@ -343,8 +343,7 @@ public class SimpleClientAppdata implements IClientAppdata { apdfile.lockFile(); // LATER: Refactor these local AppDatastream IO stuff to their own class. JarOutputStream dstrm = - new JarOutputStream( - new BufferedOutputStream(new java.io.FileOutputStream(apdfile.sessionFile))); + new JarOutputStream(apdfile.fileLock.getBufferedOutputStream(true)); if (!clientOrUser) { newAppDataStream = dstrm; } else { diff --git a/src/org/vamsas/client/simpleclient/VamsasArchive.java b/src/org/vamsas/client/simpleclient/VamsasArchive.java index c485124..c58c5f3 100644 --- a/src/org/vamsas/client/simpleclient/VamsasArchive.java +++ b/src/org/vamsas/client/simpleclient/VamsasArchive.java @@ -533,7 +533,7 @@ public class VamsasArchive { rchive = new SessionFile(archive); if (!rchive.lockFile()) throw new IOException("Failed to get lock on file "+archive); - newarchive = new JarOutputStream(new BufferedOutputStream(new java.io.FileOutputStream(archive))); + newarchive = new JarOutputStream(rchive.fileLock.getBufferedOutputStream(true)); entries = new Hashtable(); } public void putVamsasDocument(VamsasDocument doc) throws IOException, -- 1.7.10.2