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