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