Lucene.Net  3.0.3
Lucene.Net is a port of the Lucene search engine library, written in C# and targeted at .NET runtime users.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Pages
Lock.cs
Go to the documentation of this file.
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 using System;
19 using Lucene.Net.Support;
20 
21 namespace Lucene.Net.Store
22 {
23 
24  /// <summary>An interprocess mutex lock.
25  /// <p/>Typical use might look like:<code>
26  /// new Lock.With(directory.makeLock("my.lock")) {
27  /// public Object doBody() {
28  /// <i>... code to execute while locked ...</i>
29  /// }
30  /// }.run();
31  /// </code>
32  /// </summary>
33  /// <seealso cref="Directory.MakeLock(String)" />
34  public abstract class Lock
35  {
36 
37  /// <summary>How long <see cref="Obtain(long)" /> waits, in milliseconds,
38  /// in between attempts to acquire the lock.
39  /// </summary>
40  public static long LOCK_POLL_INTERVAL = 1000;
41 
42  /// <summary>Pass this value to <see cref="Obtain(long)" /> to try
43  /// forever to obtain the lock.
44  /// </summary>
45  public const long LOCK_OBTAIN_WAIT_FOREVER = - 1;
46 
47  /// <summary>Attempts to obtain exclusive access and immediately return
48  /// upon success or failure.
49  /// </summary>
50  /// <returns> true iff exclusive access is obtained
51  /// </returns>
52  public abstract bool Obtain();
53 
54  /// <summary> If a lock obtain called, this failureReason may be set
55  /// with the "root cause" Exception as to why the lock was
56  /// not obtained.
57  /// </summary>
58  protected internal System.Exception failureReason;
59 
60  /// <summary>Attempts to obtain an exclusive lock within amount of
61  /// time given. Polls once per <see cref="LOCK_POLL_INTERVAL" />
62  /// (currently 1000) milliseconds until lockWaitTimeout is
63  /// passed.
64  /// </summary>
65  /// <param name="lockWaitTimeout">length of time to wait in
66  /// milliseconds or <see cref="LOCK_OBTAIN_WAIT_FOREVER" />
67  /// to retry forever
68  /// </param>
69  /// <returns> true if lock was obtained
70  /// </returns>
71  /// <throws> LockObtainFailedException if lock wait times out </throws>
72  /// <throws> IllegalArgumentException if lockWaitTimeout is </throws>
73  /// <summary> out of bounds
74  /// </summary>
75  /// <throws> IOException if obtain() throws IOException </throws>
76  public virtual bool Obtain(long lockWaitTimeout)
77  {
78  failureReason = null;
79  bool locked = Obtain();
80  if (lockWaitTimeout < 0 && lockWaitTimeout != LOCK_OBTAIN_WAIT_FOREVER)
81  throw new System.ArgumentException("lockWaitTimeout should be LOCK_OBTAIN_WAIT_FOREVER or a non-negative number (got " + lockWaitTimeout + ")");
82 
83  long maxSleepCount = lockWaitTimeout / LOCK_POLL_INTERVAL;
84  long sleepCount = 0;
85  while (!locked)
86  {
87  if (lockWaitTimeout != LOCK_OBTAIN_WAIT_FOREVER && sleepCount++ >= maxSleepCount)
88  {
89  System.String reason = "Lock obtain timed out: " + this.ToString();
90  if (failureReason != null)
91  {
92  reason += (": " + failureReason);
93  }
94  var e = failureReason != null
95  ? new LockObtainFailedException(reason, failureReason)
96  : new LockObtainFailedException(reason);
97  throw e;
98  }
99  try
100  {
101  System.Threading.Thread.Sleep(TimeSpan.FromMilliseconds(LOCK_POLL_INTERVAL));
102  }
103  catch (System.Threading.ThreadInterruptedException)
104  {
105  throw;
106  }
107  locked = Obtain();
108  }
109  return locked;
110  }
111 
112  /// <summary>Releases exclusive access. </summary>
113  public abstract void Release();
114 
115  /// <summary>Returns true if the resource is currently locked. Note that one must
116  /// still call <see cref="Obtain()" /> before using the resource.
117  /// </summary>
118  public abstract bool IsLocked();
119 
120 
121  /// <summary>Utility class for executing code with exclusive access. </summary>
122  public abstract class With
123  {
124  private Lock lock_Renamed;
125  private long lockWaitTimeout;
126 
127 
128  /// <summary>Constructs an executor that will grab the named lock. </summary>
129  protected With(Lock lock_Renamed, long lockWaitTimeout)
130  {
131  this.lock_Renamed = lock_Renamed;
132  this.lockWaitTimeout = lockWaitTimeout;
133  }
134 
135  /// <summary>Code to execute with exclusive access. </summary>
136  protected internal abstract System.Object DoBody();
137 
138  /// <summary>Calls <see cref="DoBody" /> while <i>lock</i> is obtained. Blocks if lock
139  /// cannot be obtained immediately. Retries to obtain lock once per second
140  /// until it is obtained, or until it has tried ten times. Lock is released when
141  /// <see cref="DoBody" /> exits.
142  /// </summary>
143  /// <throws> LockObtainFailedException if lock could not </throws>
144  /// <summary> be obtained
145  /// </summary>
146  /// <throws> IOException if <see cref="Lock.Obtain(long)" /> throws IOException </throws>
147  public virtual System.Object run()
148  {
149  bool locked = false;
150  try
151  {
152  locked = lock_Renamed.Obtain(lockWaitTimeout);
153  return DoBody();
154  }
155  finally
156  {
157  if (locked)
158  lock_Renamed.Release();
159  }
160  }
161  }
162  }
163 }