001: /**
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright
003: * notice. All rights reserved.
004: */package com.tc.util;
005:
006: import com.tc.io.TCFile;
007: import com.tc.io.TCFileChannel;
008: import com.tc.io.TCFileLock;
009: import com.tc.io.TCRandomFileAccess;
010: import com.tc.logging.TCLogger;
011: import com.tc.logging.TCLogging;
012: import com.tc.util.startuplock.FileNotCreatedException;
013: import com.tc.util.startuplock.LocationNotCreatedException;
014:
015: import java.io.FileNotFoundException;
016: import java.io.IOException;
017: import java.nio.channels.OverlappingFileLockException;
018:
019: /**
020: * Class for testing if it is safe to startup a process on a specified directory (i.e. will it corrupt a db)
021: */
022: public class StartupLock {
023: private static final TCLogger logger = TCLogging
024: .getLogger(StartupLock.class);
025: private final TCFile location;
026: private TCFileLock lock;
027: private TCFileChannel channel;
028: private boolean blocking;
029:
030: public StartupLock(TCFile location) {
031: this .location = location;
032: }
033:
034: public synchronized void release() {
035: try {
036: if (lock != null) {
037: try {
038: this .lock.release();
039: blocking = false;
040: } catch (IOException e) {
041: logger.error(e);
042: }
043: }
044:
045: if (channel != null) {
046: try {
047: channel.close();
048: } catch (IOException e) {
049: logger.error(e);
050: }
051: }
052: } finally {
053: lock = null;
054: channel = null;
055: }
056: }
057:
058: public synchronized boolean canProceed(
059: TCRandomFileAccess randomFileAccess, boolean block)
060: throws LocationNotCreatedException, FileNotCreatedException {
061: // Get a file channel for the file
062:
063: TCFile tcFile = location.createNewTCFile(location,
064: "startup.lck");
065:
066: ensureLocationExists();
067: ensureFileExists(tcFile);
068:
069: try {
070: channel = randomFileAccess.getChannel(tcFile, "rw");
071: } catch (FileNotFoundException fnfe) {
072: throw new TCAssertionError(fnfe);
073: }
074:
075: try {
076: if (block) {
077: blocking = true;
078: lock = channel.lock();
079: blocking = false;
080: } else {
081: lock = channel.tryLock();
082: }
083: } catch (OverlappingFileLockException e) {
084: // File is already locked in this thread or virtual machine
085: } catch (IOException ioe) {
086: throw new TCDataFileLockingException(
087: "Unable to acquire file lock on '"
088: + tcFile.getFile().getAbsolutePath()
089: + "'. Aborting Terracotta server startup.");
090: } finally {
091: blocking = false;
092: }
093:
094: Assert.eval(tcFile.exists());
095:
096: return lock != null;
097: }
098:
099: public boolean isBlocking() {
100: return this .blocking;
101: }
102:
103: private void ensureFileExists(TCFile file)
104: throws FileNotCreatedException {
105: if (!file.exists()) {
106: try {
107: file.createNewFile();
108: } catch (IOException e) {
109: throw new FileNotCreatedException(
110: "Could not create file for startup lock: "
111: + file
112: + ". Please ensure that this file can be created.");
113: }
114: Assert.eval(file.exists());
115: }
116: }
117:
118: private void ensureLocationExists()
119: throws LocationNotCreatedException {
120: if (!location.exists()) {
121: try {
122: location.forceMkdir();
123: } catch (IOException e) {
124: throw new LocationNotCreatedException(
125: "Could not create location for startup lock: "
126: + location
127: + ". Please ensure that this directory can be created.");
128: }
129: }
130: }
131: }
|