/*::.
==================================================================================================================================
=================================================¦ Copyright © 2002 Allen Baker ¦=================================================
+------------------------------+
File: FileLockingProtocol.java
Originator: Allen Baker (2002.03.02)
LayoutRev: 5
================================================================================================================================== */
/*.
==========================================================================================
Package
------------------------------------------------------------------------------------------ */
package cosmicabyss.com.lib;
/*.
==========================================================================================
Imports
------------------------------------------------------------------------------------------ */
import java.io.*;
import java.util.*;
/*::
======================================================================================================================== *//**
Instances of this class implement a cooperative file-locking protocol. A cooperative file-locking protocol is used to
control access to a shared resource. In a cooperative file-locking protocol, the participating programs use a lock file
as a token that gives permission to the holder of the token to access the shared resource. The holder of the token is
the program that creates the lock file. When the holder of the token is done, it deletes the lock file.<P>
When a program wants to access the shared resource, it checks to see if the lock file exists. If it does, the program
must wait to access the shared resource. If the lock file does not exist, the program creates it and accesses the shared
resource. While the lock file exists, other programs are prevented from accessing the shared resource. When the program
is done accessing the shared resource, it deletes the lock file and in so doing, allows another program to access the
shared resource.<P>
<I> Note: Using the Standard Java SDK method createNewFile() from within getLock() is the key to making this whole
FileLockingProtocol class work because it is an <B>atomic operation</B>. In other words, two processes cannot both call
createNewFile() at the same time and both succeed. CreateNewFile() atomically creates a new, empty file if and only if
the file does not yet exist. <B>The check for the existence of the file and the creation of the file if it does not
exist are a single operation that is atomic with respect to all other filesystem activities that might affect the
file</B>. </I>
<P>
<DL>
<DT>
<B>
Example usage:
</B>
<DD>
<BLOCKQUOTE>
<PRE id="unindent">
this snippet will try for up to 5 seconds to obtain a
lock by creating the lock file "/lock.file". Then, after
accessing the shared resource, it releases the lock by
deleting the lock file.
FileLockingProtocol locker = new FileLockingProtocol("/lock.file",5);
if (locker.getLock())
{
System.out.println("obtained lock; accessing shared resource");
locker.releaseLock();
}
else
{
System.out.println("cannot obtain lock; cannot access shared resource");
}
</PRE>
</BLOCKQUOTE>
</DD>
</DT>
<DT>
<B>
View Source:
</B>
<DD>
<A href="FileLockingProtocol.java.html">
FileLockingProtocol.java
</A>
</DD>
</DT>
<DT>
<B>
Author:
</B>
<DD>
<A href="mailto:sourcecode.v01@cosmicabyss.com">
Allen Baker
</A>
</DD>
</DT>
</DL>
*//*
======================================================================================================================== */
public class FileLockingProtocol
{
/*: :METHOD:000:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method create a object that can be used to get and release a lock file.
<P><B>Implementation: </B><A HREF="FileLockingProtocol.java.html#000">View source</A>
@param
pLockFileName is the name of the file that will be used as a lock file.
@param
pMaxSecondsToWait is the maximum amount of time to wait (in seconds) for the lock file to become
available for creation before giving up on a getLock() attempt.
*//*
---------------------------------------------------------------------------------------------------- */
public <Type> FileLockingProtocol(Type pLockFileName, int pMaxSecondsToWait)
{
mLockFileName = XString.toXString(pLockFileName);
mMaxSecondsToWait = pMaxSecondsToWait;
}
/*: :METHOD:001:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method gets the lock file that controls access to a shared resource.<P>
This method will poll for an opportunity to create the lock file. It will continue polling up to the
pMaxSecondsToWait that was passed into the constructor.
Its polling interval is a function of pMaxSecondsToWait. The minimum polling interval is 1 second
and the maximum polling interval is 5 minutes.
At pMaxSecondsToWait above 1min, the polling interval is 1/60th of pMaxSecondsToWait in
milliseconds. The "inc" column of this table gives the polling interval for some sample
pMaxSecondsToWait.
<BLOCKQUOTE>
<PRE id="unindent">
wait pMaxSecondsToWait wait in ms wait/60 inc in ms inc
-----+-----------------+-----------+--------+-----------+------
1sec 1 1000 16 1000 1sec
30sec 30 30000 500 1000 1sec
1min 60 60000 1000 1000 1sec
2min 120 120000 2000 2000 2sec
30min 1800 1800000 30000 30000 30sec
1hr 3600 3600000 60000 60000 1min
2hr 7200 7200000 120000 120000 2min
4hr 14400 14400000 240000 240000 4min
5hr 18000 18000000 300000 300000 5min
8hr 28800 28800000 480000 300000 5min
16hr 57600 57600000 960000 300000 5min
32hr 115200 115200000 1920000 300000 5min
</PRE>
</BLOCKQUOTE>
<P><B>Implementation: </B><A HREF="FileLockingProtocol.java.html#001">View source</A>
@return
True if the lock was obtained, false otherwise.
*//*
---------------------------------------------------------------------------------------------------- */
public boolean getLock() throws IOException
{
/*.
==========================================================================================
If this object already owns the lock file, then just return true.
------------------------------------------------------------------------------------------ */
if (mLockFileOwner)
{
return true;
}
/*.
==========================================================================================
Convert to milliseconds: the amount of time to poll (total polling time) before giving up
------------------------------------------------------------------------------------------ */
int maxMillisecondsToWait;
maxMillisecondsToWait = mMaxSecondsToWait * 1000;
/*.
==========================================================================================
Compute the frequency of the polls. Polls will occur every 1/60th of the total polling
time. However, the most frequently that polls can occur is once every 1000ms or every 1
second (no faster than once every 1 sec). The least frequently is once every 300000ms or
once every 5 minutes (no slower than once every 5min).
------------------------------------------------------------------------------------------ */
int millisecondsBetweenPolls;
millisecondsBetweenPolls = maxMillisecondsToWait / 60;
millisecondsBetweenPolls = UMath.max(1000, millisecondsBetweenPolls);
millisecondsBetweenPolls = UMath.min(300000,millisecondsBetweenPolls);
/*.
==========================================================================================
Go through the process of trying to create the lock file.
------------------------------------------------------------------------------------------ */
long startTime = System.currentTimeMillis();
mLockFile = new File(mLockFileName.string());
while (true)
{
/*.
==========================================================================================
Using createNewFile() is the key to making this whole FileLockingProtocol class work
because it is an atomic operation. In other words, two processes cannot both call
createNewFile() at the same time and both succeed. CreateNewFile() atomically creates a
new, empty file named by this abstract pathname if and only if a file with this name does
not yet exist. The check for the existence of the file and the creation of the file if it
does not exist are a single operation that is atomic with respect to all other filesystem
activities that might affect the file.
------------------------------------------------------------------------------------------ */
if (mLockFile.createNewFile())
{
mLockFileOwner = true;
return true;
}
if ((System.currentTimeMillis() - startTime) > maxMillisecondsToWait)
{
return false;
}
Util.sleep(millisecondsBetweenPolls);
}
}
/*: :METHOD:002:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method deletes the lock file and in so doing, allows another program to access the shared
resource.
<P><B>Implementation: </B><A HREF="FileLockingProtocol.java.html#002">View source</A>
*//*
---------------------------------------------------------------------------------------------------- */
public void releaseLock()
{
/*.
==========================================================================================
Only delete the file if we actually own it.
------------------------------------------------------------------------------------------ */
if (mLockFileOwner)
{
mLockFile.delete();
mLockFileOwner = false;
}
}
/*: :METHOD:003:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method forcably deletes the lock file and in so doing, allows another program to access the
shared resource. This method violates the protocol and should be used only to delete the file after
a program that created it crashed without deleting it.
<P><B>Implementation: </B><A HREF="FileLockingProtocol.java.html#003">View source</A>
*//*
---------------------------------------------------------------------------------------------------- */
public void forceReleaseLock() throws Exception
{
mLockFile = new File(mLockFileName.string());
mLockFile.delete();
mLockFileOwner = false;
}
/*:.
==============================================================================================================
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@[ Protected ]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
============================================================================================================== */
/*:.
==============================================================================================================
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@[ Private ]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
============================================================================================================== */
/*.
==========================================================================================
------------------------------------------------------------------------------------------ */
private boolean mLockFileOwner = false;
private XString mLockFileName;
private File mLockFile;
private int mMaxSecondsToWait;
/*:.
==============================================================================================================
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@[ Inner Classes ]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
============================================================================================================== */
/*:.
==============================================================================================================
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@[ Public Static Methods ]@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
============================================================================================================== */
/*: :METHOD:004:BOOKMARK:
====================================================================================================
[][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][][]
==================================================================================================== *//**
This method allows the FileLockingProtocol class file to be unit tested as a stand-alone
application. It's the method that's called when the class is invoked from the command line by using
the java application launcher - "java". Main() is not a required method, but the practice of putting
one in each class and wrapping class test code within it allows easy unit testing of the class; and
main does not need to be removed when testing is complete.
<P>
<DL>
<DT>
<B>
Command line usage:
</B>
<DD>
Java com.hp.ces.provision.FileLockingProtocol
</DD>
</DT>
</DL>
<P><B>Implementation: </B><A HREF="FileLockingProtocol.java.html#004">View source</A>
@param
pArgs contains the command line arguments with which the class was invoked as an application.
*//*
---------------------------------------------------------------------------------------------------- */
public static void main(String[] pArgs) throws Exception
{
FileLockingProtocol locker = new FileLockingProtocol(new XString("/lock.file"),5);
if (locker.getLock())
{
System.out.println("obtained lock; accessing shared resource");
locker.releaseLock();
}
else
{
System.out.println("cannot obtain lock; cannot access shared resource");
}
}
} // class FileLockingProtocol
Copyright © 2012 Allen Baker
|