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
casacore::LockFile::addReqId
void addReqId()
Add the request id of this process to the list.
casacore::LockFile::itsFileIO
FiledesIO * itsFileIO
Definition: LockFile.h:321
casacore::FileLocker::hasLock
Bool hasLock(LockType=Write) const
Test if the process has a lock for read or write on the file.
Definition: FileLocker.h:154
casacore::LockFile::itsHostId
uInt itsHostId
Definition: LockFile.h:329
casacore::LockFile::itsCanIO
CanonicalIO * itsCanIO
Definition: LockFile.h:322
casacore::FileLocker::canLock
Bool canLock(LockType=Write)
Test if the file can be locked for read or write.
casacore::LockFile::itsUseLocker
FileLocker itsUseLocker
Definition: LockFile.h:320
casacore::LockFile::getInfo
void getInfo(MemoryIO &info)
Get the request id's and the info from the lock file.
casacore::Time
date and time enquiry functions, with some operations.
Definition: Time.h:88
casacore::LockFile::itsLocker
FileLocker itsLocker
Definition: LockFile.h:319
casacore::LockFile::convReqId
void convReqId(const uChar *buffer, uInt leng)
Convert the request id from canonical to local format.
casacore::LockFile::itsLastTime
Time itsLastTime
Definition: LockFile.h:326
casacore::LockFile::canLock
Bool canLock(FileLocker::LockType=FileLocker::Write)
Test if the file can be locked for read or write.
Definition: LockFile.h:356
casacore::LockFile::~LockFile
~LockFile()
The destructor does not delete the file, because it is not known when the last process using the lock...
casacore::LockFile::showLock
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.
casacore::LockFile
Class to handle file locking and synchronization.
Definition: LockFile.h:172
casacore::uChar
unsigned char uChar
Definition: aipstype.h:47
casacore::FileLocker::LockType
LockType
Define the possible lock types.
Definition: FileLocker.h:95
casacore::CanonicalIO
Class for IO in canonical format.
Definition: CanonicalIO.h:74
casacore::MemoryIO
Class for IO to a memory buffer.
Definition: MemoryIO.h:125
casacore::LockFile::getReqId
void getReqId()
Get the request list from the file.
casacore::LockFile::itsAddToList
Bool itsAddToList
Definition: LockFile.h:324
casacore::FiledesIO
Class for unbuffered IO on a file.
Definition: FiledesIO.h:89
casacore::LockFile::isMultiUsed
Bool isMultiUsed()
Is the file associated with the LockFile object in use in another process?
casacore::LockFile::itsWritable
Bool itsWritable
Definition: LockFile.h:323
casacore::FileLocker::lastMessage
String lastMessage() const
Get the message belonging to the last error.
casacore::LockFile::itsInspectCount
Int itsInspectCount
Definition: LockFile.h:333
casacore::LockFile::lastError
int lastError() const
Get the last error.
Definition: LockFile.h:364
casacore::LockFile::itsReqId
Block< Int > itsReqId
Definition: LockFile.h:330
casacore::LockFile::acquire
Bool acquire(FileLocker::LockType=FileLocker::Write, uInt nattempts=0)
Acquire a read or write lock.
Definition: LockFile.h:339
casacore::LockFile::acquire
Bool acquire(MemoryIO *info, FileLocker::LockType type, uInt nattempts)
casacore::FileLocker::Write
@ Write
Acquire a write lock.
Definition: FileLocker.h:99
casacore::False
const Bool False
Definition: aipstype.h:44
casacore::uInt
unsigned int uInt
Definition: aipstype.h:51
casacore::LockFile::lastMessage
String lastMessage() const
Get the message belonging to the last error.
Definition: LockFile.h:368
casacore::LockFile::release
Bool release()
Release a lock and write the information (if given) into the lock file.
Definition: LockFile.h:348
casacore::LockFile::name
const String & name() const
Get the name of the lock file.
Definition: LockFile.h:372
casacore::LockFile::removeReqId
void removeReqId()
Remove the request id of this process from the list (and all the ones before it).
casacore::FileLocker::lastError
int lastError() const
Get the last error.
Definition: FileLocker.h:162
casacore::Int
int Int
Definition: aipstype.h:50
casacore
this file contains all the compiler specific defines
Definition: mainpage.dox:28
casacore::LockFile::putInfo
void putInfo(const MemoryIO &info) const
Put the info into the file (after the request id's).
casacore::True
const Bool True
Definition: aipstype.h:43
casacore::LockFile::putReqId
void putReqId(int fd) const
Put the request list into the file.
casacore::LockFile::LockFile
LockFile(const LockFile &)
The copy constructor cannot be used (its semantics are too difficult).
casacore::LockFile::release
Bool release(const MemoryIO *info)
casacore::LockFile::inspect
Bool inspect(Bool always=False)
Inspect if another process wants to access the file (i.e.
casacore::LockFile::itsInterval
double itsInterval
Definition: LockFile.h:325
casacore::LockFile::reqIds
const Block< Int > & reqIds() const
Get the block of request id's.
Definition: LockFile.h:376
casacore::String
String: the storage and methods of handling collections of characters.
Definition: String.h:223
casacore::FileLocker
Class to handle file locking.
Definition: FileLocker.h:92
casacore::LockFile::LockFile
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.
casacore::Bool
bool Bool
Define the standard types used by Casacore.
Definition: aipstype.h:42
casacore::Block< Int >
casacore::LockFile::operator=
LockFile & operator=(const LockFile &)
Assignment cannot be used (its semantics are too difficult).
casacore::LockFile::getInt
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.
casacore::LockFile::hasLock
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
casacore::LockFile::itsName
String itsName
Definition: LockFile.h:327
casacore::LockFile::itsPid
uInt itsPid
Definition: LockFile.h:328
casacore::LockFile::getNrReqId
Int getNrReqId() const
Get the number of request id's.