casacore
LockFile.h
Go to the documentation of this file.
1 //# LockFile.h: Class to handle file locking and synchronization
2 //# Copyright (C) 1997,1998,1999,2000,2001,2002
3 //# Associated Universities, Inc. Washington DC, USA.
4 //#
5 //# This library is free software; you can redistribute it and/or modify it
6 //# under the terms of the GNU Library General Public License as published by
7 //# the Free Software Foundation; either version 2 of the License, or (at your
8 //# option) any later version.
9 //#
10 //# This library is distributed in the hope that it will be useful, but WITHOUT
11 //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 //# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
13 //# License for more details.
14 //#
15 //# You should have received a copy of the GNU Library General Public License
16 //# along with this library; if not, write to the Free Software Foundation,
17 //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
18 //#
19 //# Correspondence concerning AIPS++ should be addressed as follows:
20 //# Internet email: aips2-request@nrao.edu.
21 //# Postal address: AIPS++ Project Office
22 //# National Radio Astronomy Observatory
23 //# 520 Edgemont Road
24 //# Charlottesville, VA 22903-2475 USA
25 //#
26 //# $Id$
27 
28 #ifndef CASA_LOCKFILE_H
29 #define CASA_LOCKFILE_H
30 
31 
32 //# Includes
33 #include <casacore/casa/aips.h>
34 #include <casacore/casa/IO/FileLocker.h>
35 #include <casacore/casa/OS/Time.h>
36 #include <casacore/casa/Containers/Block.h>
37 #include <casacore/casa/BasicSL/String.h>
38 #include <sys/types.h>
39 
40 namespace casacore { //# NAMESPACE CASACORE - BEGIN
41 
42 //# Forward declarations
43 class FiledesIO;
44 class MemoryIO;
45 class CanonicalIO;
46 
47 
48 // <summary>
49 // Class to handle file locking and synchronization.
50 // </summary>
51 
52 // <use visibility=export>
53 
54 // <reviewed reviewer="UNKNOWN" date="before2004/08/25" tests="tLockFile" demos="">
55 // </reviewed>
56 
57 // <prerequisite>
58 // <li> class <linkto class=FileLocker>FileLocker</linkto>
59 // <li> class <linkto class=MemoryIO>MemoryIO</linkto>
60 // </prerequisite>
61 
62 // <synopsis>
63 // This class handles file locking by means of a special lock file
64 // which serves as the locking mechanism for another file or
65 // group of files. It is for instance used to lock a table in
66 // the Casacore Table System.
67 // <p>
68 // The lock file has in principle world read/write access, so every
69 // process accessing the main file can write information in it.
70 // The lock file contains the following information (in canonical format):
71 // <ul>
72 // <li> A request list indicating which processes want to acquire a lock.
73 // The process holding the lock can inspect this list to decide if it
74 // should release its lock. An interval can be defined to be sure
75 // that the list is not inspected too often.
76 // A user can choose not to add to this list, because it incurs some
77 // overhead to write the list. However, that should only be done when
78 // one is sure that another process cannot keep a lock forever.
79 // <li> Some information telling if the state of the main file has changed.
80 // The information can be used by a process to synchronize its
81 // internal buffers with the new contents of the file(s).
82 // E.g. a table could store one or more counters in it, which can be
83 // used to determine if the table has to refresh its caches.
84 // This information is passed as a MemoryIO object and is opaque
85 // for the <src>LockFile</src> class. It is simply handled as a
86 // stream of bytes.
87 // </ul>
88 // <p>
89 // Acquiring a lock works as follows:
90 // <ul>
91 // <li> Class <linkto class=FileLocker>FileLocker</linkto> is used
92 // to do one attempt to acquire a read or write lock.
93 // <li> If it fails and multiple attempts have to be done, the
94 // request is added to the request list in the lock file to tell
95 // the process holding the lock that another process needs a lock.
96 // <li> Other attempts (with 1 second intervals) will be done until the
97 // lock is acquired or until the maximum number of attempts is reached.
98 // <li> The lock request is removed from the request list.
99 // <li> When the lock was acquired, the synchronization info is read
100 // from the lock file.
101 // </ul>
102 // Releasing a lock writes the synchronization info into the lock file
103 // and tells <src>FileLocker</src> to release the lock.
104 // <p>
105 // When the lock file cannot be opened as read/write, it is opened as
106 // readonly. It means that the request list cannot be stored in it,
107 // so the process has no way to tell the other processes it wants
108 // access to the file. It has to wait until the lock is released.
109 // <br> In principle a lock file should always be there. However, it
110 // is possible (with a constructor option) that there is no lock file.
111 // In that case each lock request succeeds without doing actual locking.
112 // This mode is needed to be able to handle readonly tables containing
113 // no lock file.
114 // <p>
115 // After each write the <src>fsync</src> function is called to make
116 // sure that the contents of the file are written to disk. This is
117 // necessary for correct file synchronization in NFS.
118 // However, at the moment this feature is switched off, because it
119 // degraded performance severely.
120 // <p>
121 // Apart from the read/write lock handling, the <src>LockFile</src>
122 // also contains a mechanism to detect if a file is opened by another
123 // process. This can be used to test if a process can safely delete the file.
124 // For this purpose it sets another read lock when the file gets opened.
125 // The function <src>isMultiUsed</src> tests this lock to see if the file is
126 // used in other processes.
127 // <br> This lock is also used to tell if the file is permanently locked.
128 // If that is the case, the locked block is 2 bytes instead of 1.
129 // <p>
130 // When in the same process multiple LockFile objects are created for the same
131 // file, deleting one object releases all locks on the file, thus also the
132 // locks held by the other LockFile objects. This behaviour is due to the way
133 // file locking is working on UNIX machines (certainly on Solaris 2.6).
134 // One can use the test program tLockFile to test for this behaviour.
135 // </synopsis>
136 
137 // <example>
138 // <srcblock>
139 // // Create/open the lock file (with 1 sec inspection interval).
140 // // Acquire the lock and get the synchronization info.
141 // LockFile lock ("file.name", 1);
142 // MemoryIO syncInfo;
143 // if (! lock.acquire (syncInfo)) {
144 // throw (AipsError ("Locking failed: " + lock.message()));
145 // }
146 // while (...) {
147 // ... do something with the table files ...
148 // // Test if another process needs the files.
149 // // If so, synchronize files and release lock.
150 // if (lock.inspect()) {
151 // do fsync for all other files
152 // syncInfo.seek (0);
153 // syncInfo.write (...);
154 // lock.release (syncInfo);
155 // // At this point another process can grab the lock.
156 // // Reacquire the lock
157 // lock.acquire (syncInfo);
158 // throw (AipsError ("Locking failed: " + lock.message()));
159 // }
160 // }
161 // }
162 // </srcblock>
163 // </example>
164 
165 // <motivation>
166 // Make it possible to lock and synchronize tables in an easy and
167 // efficient way.
168 // </motivation>
169 
170 
171 class LockFile
172 {
173 public:
174  // Create or open the lock file with the given name.
175  // It is created if create=True or if the file does not exist yet.
176  // The interval (in seconds) defines how often function <src>inspect</src>
177  // inspects the request list in the lock file.
178  // An interval&gt;0 means that it is only inspected if the last inspect
179  // was at least <src>inspectInterval</src> seconds ago.
180  // An interval&lt;=0 means that <src>inspect</src> always inspects
181  // the request list.
182  // <br>When addToRequestList=False, function <src>acquire</src> does not
183  // add the request to the lock file when a lock cannot be acquired.
184  // This may result in better performance, but should be used with care.
185  // <br> If <src>create==True</src>, a new lock file will always be created.
186  // Otherwise it will be created if it does not exist yet.
187  // <br> If <src>mustExist==False</src>, it is allowed that the LockFile
188  // does not exist and cannot be created either.
189  // <br> The seqnr is used to set the offset where LockFile will use 2 bytes
190  // to set the locks on. Only in special cases it should be other than 0.
191  // At the moment the offset is 2*seqnr.
192  // <br> The <src>permLocking</src> argument is used to indicate if
193  // permanent locking will be used. If so, it'll indicate so. In that
194  // way showLock() can find out if if table is permanently locked.
195  // <br> The <src>noLocking</src> argument is used to indicate that
196  // no locking is needed. It means that acquiring a lock always succeeds.
197  explicit LockFile (const String& fileName, double inspectInterval = 0,
198  Bool create = False, Bool addToRequestList = True,
199  Bool mustExist = True, uInt seqnr = 0,
200  Bool permLocking = False, Bool noLocking = False);
201 
202  // The destructor does not delete the file, because it is not known
203  // when the last process using the lock file will stop.
204  // For the table system this is no problem, because the lock file
205  // is contained in the directory of the table, thus deleted when
206  // the table gets deleted.
208 
209  // Is the file associated with the LockFile object in use in
210  // another process?
212 
213  // Acquire a read or write lock.
214  // It reads the information (if the <src>info</src> argument is given)
215  // from the lock file. The user is responsible for interpreting the
216  // information (e.g. converting from canonical to local format).
217  // The seek pointer in the <src>MemoryIO</src> object is set to 0,
218  // so the user can simply start reading the pointer.
219  // <br>The argument <src>nattempts</src> tells how often it is
220  // attempted (with 1 second intervals) to acquire the lock if
221  // it does not succeed.
222  // 0 means forever, while 1 means do not retry.
223  // <group>
226  uInt nattempts = 0);
227  Bool acquire (MemoryIO* info, FileLocker::LockType type, uInt nattempts);
228  // </group>
229 
230  // Release a lock and write the information (if given) into the lock file.
231  // The user is responsible for making the information machine-independent
232  // (e.g. converting from local to canonical format).
233  // <group>
234  Bool release();
235  Bool release (const MemoryIO& info);
236  Bool release (const MemoryIO* info);
237  // </group>
238 
239  // Inspect if another process wants to access the file (i.e. if the
240  // request list is not empty).
241  // It only inspects if the time passed since the last inspection
242  // exceeds the inspection interval as given in the constructor.
243  // If the time passed is too short, False is returned (indicating
244  // that no access is needed).
245  // If <src>always==True</src>, no test on inspection interval is done,
246  // so the inspect is always done.
247  Bool inspect (Bool always=False);
248 
249  // Test if the file can be locked for read or write.
251 
252  // Test if the process has a lock for read or write on the file.
254 
255  // Get the last error.
256  int lastError() const;
257 
258  // Get the message belonging to the last error.
259  String lastMessage() const;
260 
261  // Get the name of the lock file.
262  const String& name() const;
263 
264  // Get the block of request id's.
265  const Block<Int>& reqIds() const;
266 
267  // Get the request id's and the info from the lock file.
268  void getInfo (MemoryIO& info);
269 
270  // Put the info into the file (after the request id's).
271  void putInfo (const MemoryIO& info) const;
272 
273  // Tell if another process holds a read or write lock on the given file
274  // or has the file opened. It returns:
275  // <br> 3 if write-locked elsewhere.
276  // <br> 2 if read-locked elsewhere.
277  // <br> 1 if opened elsewhere.
278  // <br> 0 if locked nor opened.
279  // <br>It fills in the PID of the process having the file locked or opened.
280  // <br>If locked, it also tells if it is permanently locked.
281  // <br>An exception is thrown if the file does not exist or cannot
282  // be opened.
283  static uInt showLock (uInt& pid, Bool& permLocked, const String& fileName);
284 
285 private:
286  // The copy constructor cannot be used (its semantics are too difficult).
287  LockFile (const LockFile&);
288 
289  // Assignment cannot be used (its semantics are too difficult).
291 
292  // Get an Int from the buffer at the given offset and convert
293  // it from canonical to local format.
294  // If the buffer is too short (i.e. does not contain the value),
295  // a zero value is returned.
296  Int getInt (const uChar* buffer, uInt leng, uInt offset) const;
297 
298  // Add the request id of this process to the list.
299  void addReqId();
300 
301  // Remove the request id of this process from the list
302  // (and all the ones before it).
303  void removeReqId();
304 
305  // Get the request list from the file.
306  void getReqId();
307 
308  // Put the request list into the file.
309  void putReqId (int fd) const;
310 
311  // Convert the request id from canonical to local format.
312  void convReqId (const uChar* buffer, uInt leng);
313 
314  // Get the number of request id's.
315  Int getNrReqId() const;
316 
317 
318  //# The member variables.
323  Bool itsWritable; //# lock file is writable?
324  Bool itsAddToList; //# Should acquire add to request list?
325  double itsInterval; //# interval between inspections
326  Time itsLastTime; //# time of last inspection
327  String itsName; //# Name of lock file
330  Block<Int> itsReqId; //# Id's of processes requesting lock
331  //# First value contains #req id's
332  //# Thereafter pid, hostid
333  Int itsInspectCount; //# The number of times inspect() has
334  //# been called since the last elapsed
335  //# time check.
336 };
337 
338 
340 {
341  return acquire (0, type, nattempts);
342 }
344  uInt nattempts)
345 {
346  return acquire (&info, type, nattempts);
347 }
349 {
350  return release (0);
351 }
352 inline Bool LockFile::release (const MemoryIO& info)
353 {
354  return release (&info);
355 }
357 {
358  return (itsFileIO == 0 ? True : itsLocker.canLock (type));
359 }
361 {
362  return (itsFileIO == 0 ? True : itsLocker.hasLock (type));
363 }
364 inline int LockFile::lastError() const
365 {
366  return itsLocker.lastError();
367 }
369 {
370  return itsLocker.lastMessage();
371 }
372 inline const String& LockFile::name() const
373 {
374  return itsName;
375 }
376 inline const Block<Int>& LockFile::reqIds() const
377 {
378  return itsReqId;
379 }
380 
381 
382 
383 } //# NAMESPACE CASACORE - END
384 
385 #endif
int lastError() const
Get the last error.
Definition: FileLocker.h:162
Bool canLock(LockType=Write)
Test if the file can be locked for read or write.
Bool hasLock(LockType=Write) const
Test if the process has a lock for read or write on the file.
Definition: FileLocker.h:154
LockType
Define the possible lock types.
Definition: FileLocker.h:95
@ Write
Acquire a write lock.
Definition: FileLocker.h:99
String lastMessage() const
Get the message belonging to the last error.
Int getInt(const uChar *buffer, uInt leng, uInt offset) const
Get an Int from the buffer at the given offset and convert it from canonical to local format.
LockFile(const LockFile &)
The copy constructor cannot be used (its semantics are too difficult).
void putReqId(int fd) const
Put the request list into the file.
FileLocker itsLocker
Definition: LockFile.h:319
const Block< Int > & reqIds() const
Get the block of request id's.
Definition: LockFile.h:376
Bool isMultiUsed()
Is the file associated with the LockFile object in use in another process?
void convReqId(const uChar *buffer, uInt leng)
Convert the request id from canonical to local format.
Block< Int > itsReqId
Definition: LockFile.h:330
int lastError() const
Get the last error.
Definition: LockFile.h:364
CanonicalIO * itsCanIO
Definition: LockFile.h:322
void addReqId()
Add the request id of this process to the list.
Bool hasLock(FileLocker::LockType=FileLocker::Write) const
Test if the process has a lock for read or write on the file.
Definition: LockFile.h:360
const String & name() const
Get the name of the lock file.
Definition: LockFile.h:372
void putInfo(const MemoryIO &info) const
Put the info into the file (after the request id's).
Bool release()
Release a lock and write the information (if given) into the lock file.
Definition: LockFile.h:348
Bool canLock(FileLocker::LockType=FileLocker::Write)
Test if the file can be locked for read or write.
Definition: LockFile.h:356
Bool inspect(Bool always=False)
Inspect if another process wants to access the file (i.e.
FileLocker itsUseLocker
Definition: LockFile.h:320
~LockFile()
The destructor does not delete the file, because it is not known when the last process using the lock...
Int getNrReqId() const
Get the number of request id's.
static uInt showLock(uInt &pid, Bool &permLocked, const String &fileName)
Tell if another process holds a read or write lock on the given file or has the file opened.
LockFile(const String &fileName, double inspectInterval=0, Bool create=False, Bool addToRequestList=True, Bool mustExist=True, uInt seqnr=0, Bool permLocking=False, Bool noLocking=False)
Create or open the lock file with the given name.
FiledesIO * itsFileIO
Definition: LockFile.h:321
void getInfo(MemoryIO &info)
Get the request id's and the info from the lock file.
Bool acquire(MemoryIO *info, FileLocker::LockType type, uInt nattempts)
LockFile & operator=(const LockFile &)
Assignment cannot be used (its semantics are too difficult).
String lastMessage() const
Get the message belonging to the last error.
Definition: LockFile.h:368
void removeReqId()
Remove the request id of this process from the list (and all the ones before it).
Bool acquire(FileLocker::LockType=FileLocker::Write, uInt nattempts=0)
Acquire a read or write lock.
Definition: LockFile.h:339
double itsInterval
Definition: LockFile.h:325
Bool release(const MemoryIO *info)
void getReqId()
Get the request list from the file.
String: the storage and methods of handling collections of characters.
Definition: String.h:225
this file contains all the compiler specific defines
Definition: mainpage.dox:28
unsigned char uChar
Definition: aipstype.h:47
const Bool False
Definition: aipstype.h:44
unsigned int uInt
Definition: aipstype.h:51
int Int
Definition: aipstype.h:50
bool Bool
Define the standard types used by Casacore.
Definition: aipstype.h:42
const Bool True
Definition: aipstype.h:43