/*
* Copyright 2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using IndexWriter = Lucene.Net.Index.IndexWriter;
namespace Lucene.Net.Store
{
/// An interprocess mutex lock.
///
Typical use might look like:
/// new Lock.With(directory.makeLock("my.lock")) {
/// public Object doBody() {
/// ... code to execute while locked ...
/// }
/// }.Run();
///
///
///
/// Doug Cutting
///
/// $Id: Lock.cs,v 1.6 2005/10/31 00:37:06 dsd Exp $
///
///
///
public abstract class Lock
{
public static long LOCK_POLL_INTERVAL = 1000;
/// Attempts to obtain exclusive access and immediately return
/// upon success or failure.
///
/// true iff exclusive access is obtained
///
public abstract bool Obtain();
/// Attempts to obtain an exclusive lock within amount
/// of time given. Currently polls once per second until
/// lockWaitTimeout is passed.
///
/// length of time to wait in ms
///
/// true if lock was obtained
///
/// IOException if lock wait times out or obtain() throws an IOException
public virtual bool Obtain(long lockWaitTimeout)
{
int maxSleepCount = (int) (lockWaitTimeout / LOCK_POLL_INTERVAL);
int sleepCount = 0;
maxSleepCount = System.Math.Max (maxSleepCount, 1);
FSDirectory.Log ("Lock.Obtain timeout={0} maxsleepcount={1}", lockWaitTimeout, maxSleepCount);
bool locked = Obtain();
while (!locked)
{
if (sleepCount == maxSleepCount)
{
// Try and be a little more verbose on failure
string lockpath = this.ToString ();
System.Text.StringBuilder ex = new System.Text.StringBuilder();
ex.Append ("Lock obain timed out: ");
ex.Append (lockpath);
if (System.IO.File.Exists (lockpath)) {
System.IO.FileStream fs = System.IO.File.Open (lockpath, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read);
System.IO.StreamReader sr = new System.IO.StreamReader (fs);
string pid = sr.ReadToEnd ().Trim ();
sr.Close ();
fs.Close ();
ex.Append (" -- pid ").Append (pid);
if (System.IO.Directory.Exists ("/proc/" + pid))
ex.Append (" -- process exists");
else
ex.Append (" -- process does not exist, stale lockfile?");
} else {
ex.Append (" -- lock file doesn't exist!?");
}
throw new System.IO.IOException(ex.ToString ());
}
++sleepCount;
System.Threading.Thread.Sleep((int) LOCK_POLL_INTERVAL);
locked = Obtain();
}
return locked;
}
/// Releases exclusive access.
public abstract void Release();
/// Returns true if the resource is currently locked. Note that one must
/// still call {@link #Obtain()} before using the resource.
///
public abstract bool IsLocked();
/// Utility class for executing code with exclusive access.
public abstract class With
{
private Lock lock_Renamed;
private long lockWaitTimeout;
/// Constructs an executor that will grab the named lock.
/// Defaults lockWaitTimeout to Lock.COMMIT_LOCK_TIMEOUT.
///
/// Kept only to avoid breaking existing code.
///
public With(Lock lock_Renamed):this(lock_Renamed, IndexWriter.COMMIT_LOCK_TIMEOUT)
{
}
/// Constructs an executor that will grab the named lock.
public With(Lock lock_Renamed, long lockWaitTimeout)
{
this.lock_Renamed = lock_Renamed;
this.lockWaitTimeout = lockWaitTimeout;
}
/// Code to execute with exclusive access.
public abstract System.Object DoBody();
/// Calls {@link #doBody} while lock is obtained. Blocks if lock
/// cannot be obtained immediately. Retries to obtain lock once per second
/// until it is obtained, or until it has tried ten times. Lock is released when
/// {@link #doBody} exits.
///
public virtual System.Object Run()
{
bool locked = false;
try
{
locked = lock_Renamed.Obtain(lockWaitTimeout);
return DoBody();
}
finally
{
if (locked)
lock_Renamed.Release();
}
}
}
}
}