001: /*
002: * This file or a portion of this file is licensed under the terms of
003: * the Globus Toolkit Public License, found in file ../GTPL, or at
004: * http://www.globus.org/toolkit/download/license.html. This notice must
005: * appear in redistributions of this file, with or without modification.
006: *
007: * Redistributions of this Software, with or without modification, must
008: * reproduce the GTPL in: (1) the Software, or (2) the Documentation or
009: * some other similar material which is provided with the Software (if
010: * any).
011: *
012: * Copyright 1999-2004 University of Chicago and The University of
013: * Southern California. All rights reserved.
014: */
015: package org.griphyn.vdl.util;
016:
017: import org.griphyn.vdl.util.*;
018: import java.util.*;
019: import java.io.*;
020:
021: /**
022: * @author Jens-S. Vöckler
023: * @author Yong Zhao
024: * @version $Revision: 50 $
025: *
026: * @see java.io.File
027: */
028: public class LockHelper {
029: /**
030: * The suffix to use for the regular lock file.
031: */
032: public static final String LOCK_SUFFIX = ".lock";
033:
034: /**
035: * The initial timeout to use when retrying with exponential backoff.
036: */
037: private long m_timeout;
038:
039: /**
040: * The number of retries to attempt obtaining a lock.
041: */
042: private int m_retries;
043:
044: /**
045: * default ctor.
046: */
047: public LockHelper() {
048: this .m_timeout = 250;
049: this .m_retries = 10;
050: }
051:
052: /**
053: * ctor.
054: */
055: public LockHelper(long timeout, int retries) {
056: this .m_timeout = timeout;
057: this .m_retries = retries;
058: }
059:
060: /**
061: * Creates a file-based lock file in an NFS secure fashion. Do not use
062: * this function for locking, use {@link #lockFile(String)} instead.
063: * One exception is to use this method for test-and-set locking.
064: *
065: * @param filename is the file to create a lockfile for
066: * @return the representation of the lock file, or <code>null</code>
067: * in case of error.
068: */
069: public File createLock(String filename) {
070: // create local names from basename
071: File result = null;
072: File lock = new File(filename + LockHelper.LOCK_SUFFIX);
073:
074: // exclusively create new file
075: boolean created = false;
076: try {
077: created = lock.createNewFile();
078: } catch (IOException ioe) {
079: Logging.instance().log(
080: "lock",
081: 0,
082: "while creating lock " + lock.getPath() + ": "
083: + ioe.getMessage());
084: created = false; // make extra sure
085: }
086:
087: // if the lock was created, continue
088: if (created) {
089: // postcondition: file was created
090: Logging.instance().log("lock", 2,
091: "created lock " + lock.getPath());
092: LockFileSet.instance().add(lock);
093: lock.setLastModified(System.currentTimeMillis()); // force NFS
094: result = lock;
095: } else {
096: // unable to rename file to lock file: lock exists
097: Logging.instance().log("lock", 1,
098: "lock " + lock.getPath() + " already exists");
099: }
100:
101: // may be null
102: return result;
103: }
104:
105: /**
106: * Locks a file using an empty lockfile. This method repeatedly retries
107: * to lock a file, and gives up after a few seconds.
108: *
109: * @param filename is the basename of the file to lock.
110: * @return true, if the file was locked successfully, false otherwise.
111: */
112: public boolean lockFile(String filename) {
113: long timeout = this .m_timeout;
114:
115: // do five retries
116: for (int i = 0; i < this .m_retries; ++i) {
117: File lock = this .createLock(filename);
118: if (lock == null) {
119: // lock is busy, try again later
120: Logging.instance()
121: .log(
122: "lock",
123: 1,
124: "file " + filename + " is busy, "
125: + "sleeping "
126: + Long.toString(timeout)
127: + " ms " + "(retry "
128: + Integer.toString(i) + ')');
129: try {
130: Thread.sleep(timeout);
131: } catch (InterruptedException ie) {
132: // ignore, as usual
133: }
134: timeout <<= 1;
135: } else {
136: // we got the lock, go ahead, and write our pid into it
137: // FIXME: we don't have a pid in Java (in Windows)
138: return true;
139: }
140: }
141:
142: // postcondition: timeout out after retries
143: Logging.instance().log(
144: "default",
145: 0,
146: "unable to lock " + filename
147: + ", still busy, giving up!");
148: return false;
149: }
150:
151: /**
152: * Releases a lock file from its basename.
153: * @param filename is the name of the basename of the file to unlock.
154: * The locking extension will be added internally.
155: * @return true, if the lock was removed successfully, false otherwise.
156: */
157: public boolean unlockFile(String filename) {
158: File lock = new File(filename + LockHelper.LOCK_SUFFIX);
159: LockFileSet.instance().remove(lock);
160:
161: boolean result = lock.delete();
162: if (result)
163: Logging.instance().log("lock", 2,
164: "removed lock " + lock.getPath());
165: return result;
166: }
167: }
|