Loading...
Searching...
No Matches
fileMonitor.C
Go to the documentation of this file.
1/*---------------------------------------------------------------------------*\
2 ========= |
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4 \\ / O peration |
5 \\ / A nd | www.openfoam.com
6 \\/ M anipulation |
7-------------------------------------------------------------------------------
8 Copyright (C) 2011-2016 OpenFOAM Foundation
9 Copyright (C) 2018-2023 OpenCFD Ltd.
10-------------------------------------------------------------------------------
11License
12 This file is part of OpenFOAM.
13
14 OpenFOAM is free software: you can redistribute it and/or modify it
15 under the terms of the GNU General Public License as published by
16 the Free Software Foundation, either version 3 of the License, or
17 (at your option) any later version.
18
19 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26
27\*---------------------------------------------------------------------------*/
28
29#include "fileMonitor.H"
30#include "error.H"
31#include "Enum.H"
32#include "defineDebugSwitch.H"
33#include "IOstreams.H"
34#include "Pstream.H"
35#include "PackedList.H"
36#include "PstreamReduceOps.H"
37#include "OSspecific.H"
38#include "IOobject.H" // for fileModificationSkew symbol
39
40#ifdef FOAM_USE_INOTIFY
41 #include <unistd.h>
42 #include <sys/inotify.h>
43 #include <sys/ioctl.h>
44 #include <errno.h>
45 #define EVENT_SIZE ( sizeof (struct inotify_event) )
46 #define EVENT_LEN (EVENT_SIZE + 16)
47 #define EVENT_BUF_LEN ( 1024 * EVENT_LEN )
48#endif
49
50// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
51
52const Foam::Enum
53<
55>
57({
58 { fileState::UNMODIFIED, "unmodified" },
59 { fileState::MODIFIED, "modified" },
60 { fileState::DELETED, "deleted" },
61});
62
63
64namespace Foam
66 defineDebugSwitchWithName(fileMonitor, "fileMonitor", 0);
68
69 //- Reduction operator for PackedList of fileState
70 struct reduceFileStates
71 {
72 unsigned int operator()(const unsigned int x, const unsigned int y)
73 const
74 {
75 // x,y are sets of 2bits representing fileState
76
77 unsigned int mask = 3u;
78 unsigned int shift = 0;
79 unsigned int result = 0;
80
81 while (mask)
82 {
83 // Combine state
84 unsigned int xState = (x & mask) >> shift;
85 unsigned int yState = (y & mask) >> shift;
86
87 // Combine and add to result. Combine is such that UNMODIFIED
88 // wins.
89 unsigned int state = min(xState, yState);
90 result |= (state << shift);
91
92 shift += 2;
93 mask <<= 2;
94 }
95 return result;
96 }
97 };
98
99 //- Combine operator for PackedList of fileState
101 {
102 void operator()(unsigned int& x, const unsigned int y) const
103 {
104 x = reduceFileStates()(x, y);
105 }
106 };
107
108
109
110 //- Internal tracking via stat(3p) or inotify(7)
112 {
113 public:
115 const bool useInotify_;
116
117 // For inotify
118
119 //- File descriptor for the inotify instance
120 int inotifyFd_;
122 //- Current watchIDs and corresponding directory id
125
126 // For stat
128 //- From watch descriptor to modified time
130
131
132
133 //- Initialise inotify
134 inline fileMonitorWatcher(const bool useInotify, const label sz = 20)
135 :
136 useInotify_(useInotify),
137 inotifyFd_(-1)
138 {
139 if (useInotify_)
140 {
141 #ifdef FOAM_USE_INOTIFY
142 inotifyFd_ = inotify_init();
143 dirWatches_.setCapacity(sz);
144 dirFiles_.setCapacity(sz);
145
146 if (inotifyFd_ < 0)
147 {
148 static bool hasWarned = false;
149 if (!hasWarned)
150 {
151 hasWarned = true;
153 << "Failed allocating an inotify descriptor : "
154 << string(strerror(errno)) << endl
155 << " Please increase the number of allowable "
156 << "inotify instances" << endl
157 << " (/proc/sys/fs/inotify/max_user_instances"
158 << " on Linux)" << endl
159 << " , switch off runTimeModifiable." << endl
160 << " or compile this file without "
161 << "FOAM_USE_INOTIFY"
162 << " to use time stamps instead of inotify." << endl
163 << " Continuing without additional file"
164 << " monitoring."
165 << endl;
166 }
167 }
168 #else
170 << "You selected inotify but this file was compiled"
171 << " without FOAM_USE_INOTIFY"
172 << " Please select another fileModification test method"
173 << exit(FatalError);
174 #endif
175 }
176 else
177 {
178 lastMod_.setCapacity(sz);
179 }
180 }
181
182 //- Remove all watches
183 inline ~fileMonitorWatcher()
184 {
185 #ifdef FOAM_USE_INOTIFY
186 if (useInotify_ && inotifyFd_ >= 0)
187 {
189 {
190 if (dirWatches_[i] >= 0)
191 {
192 if (inotify_rm_watch(inotifyFd_, int(dirWatches_[i])))
193 {
195 << "Failed deleting directory watch "
196 << dirWatches_[i] << endl;
197 }
198 }
199 }
200 }
201 #endif
202 }
203
204 inline bool addWatch(const label watchFd, const fileName& fName)
205 {
206 if (useInotify_)
207 {
208 if (inotifyFd_ < 0)
209 {
210 return false;
211 }
212
213 #ifdef FOAM_USE_INOTIFY
214 // Add/retrieve watch on directory containing file.
215 // Note that fName might be non-existing in special situations
216 // (master-only reading for IODictionaries)
217
218 const fileName dir = fName.path();
219
220 label dirWatchID = -1;
221 if (isDir(dir))
222 {
223 dirWatchID = inotify_add_watch
224 (
226 dir.c_str(),
227 IN_CLOSE_WRITE
228 );
229
230 if (dirWatchID < 0)
231 {
233 << "Failed adding watch " << watchFd
234 << " to directory " << fName << " due to "
235 << string(strerror(errno))
236 << exit(FatalError);
237 }
238 }
239
240 if (watchFd < dirWatches_.size() && dirWatches_[watchFd] != -1)
241 {
242 // Reuse of watchFd : should have dir watchID set to -1.
244 << "Problem adding watch " << watchFd
245 << " to file " << fName
246 << abort(FatalError);
247 }
248
249 dirWatches_(watchFd) = dirWatchID;
250 dirFiles_(watchFd) = fName.name();
251 #endif
252 }
253 else
254 {
255 if (watchFd < lastMod_.size() && lastMod_[watchFd] != 0)
256 {
257 // Reuse of watchFd : should have lastMod set to 0.
259 << "Problem adding watch " << watchFd
260 << " to file " << fName
261 << abort(FatalError);
262 }
263
264 lastMod_(watchFd) = highResLastModified(fName);
265 }
266
267 return true;
268 }
269
270 inline bool removeWatch(const label watchFd)
271 {
272 if (useInotify_)
273 {
274 if (inotifyFd_ < 0)
275 {
276 return false;
277 }
278
279 dirWatches_[watchFd] = -1;
280 }
281 else
282 {
283 lastMod_[watchFd] = 0;
284 }
285 return true;
286 }
287
288 };
289}
290
291
292// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
293
294void Foam::fileMonitor::checkFiles() const
295{
296 if (useInotify_)
297 {
298 #ifdef FOAM_USE_INOTIFY
299 // Large buffer for lots of events
300 char buffer[EVENT_BUF_LEN];
301
302 while (true)
303 {
304 struct timeval zeroTimeout = {0, 0};
305
306 //- Pre-allocated structure containing file descriptors
307 fd_set fdSet;
308 // Add notify descriptor to select fd_set
309 FD_ZERO(&fdSet);
310 FD_SET(watcher_->inotifyFd_, &fdSet);
311
312 int ready = select
313 (
314 watcher_->inotifyFd_+1, // num filedescriptors in fdSet
315 &fdSet, // fdSet with only inotifyFd
316 nullptr, // No writefds
317 nullptr, // No errorfds
318 &zeroTimeout // eNo timeout
319 );
320
321 if (ready < 0)
322 {
324 << "Problem in issuing select."
325 << abort(FatalError);
326 }
327 else if (FD_ISSET(watcher_->inotifyFd_, &fdSet))
328 {
329 // Read events
330 ssize_t nBytes = ::read
331 (
332 watcher_->inotifyFd_,
333 buffer,
334 EVENT_BUF_LEN
335 );
336
337 if (nBytes < 0)
338 {
340 << "read of " << watcher_->inotifyFd_
341 << " failed with " << label(nBytes)
342 << abort(FatalError);
343 }
344
345 // Go through buffer, consuming events
346 int i = 0;
347 while (i < nBytes)
348 {
349 const struct inotify_event* inotifyEvent =
350 reinterpret_cast<const struct inotify_event*>
351 (
352 &buffer[i]
353 );
354
355 //Pout<< "watchFd:" << inotifyEvent->wd << nl
356 // << "mask:" << inotifyEvent->mask << nl
357 // << endl;
358 //Pout<< "file:" << fileName(inotifyEvent->name) << endl;
359 //Pout<< "len:" << inotifyEvent->len << endl;
360
361 if
362 (
363 (inotifyEvent->mask & IN_CLOSE_WRITE)
364 && inotifyEvent->len
365 )
366 {
367 // Search for file
368 forAll(watcher_->dirWatches_, i)
369 {
370 label id = watcher_->dirWatches_[i];
371 if
372 (
373 id == inotifyEvent->wd
374 && inotifyEvent->name == watcher_->dirFiles_[i]
375 )
376 {
377 // Correct directory and name
378 localState_[i] = MODIFIED;
379 }
380 }
381 }
382
383 i += EVENT_SIZE + inotifyEvent->len;
384 }
385 }
386 else
387 {
388 // No data
389 return;
390 }
391 }
392 #endif
393 }
394 else
395 {
396 forAll(watcher_->lastMod_, watchFd)
397 {
398 double oldTime = watcher_->lastMod_[watchFd];
399
400 if (oldTime != 0)
401 {
402 const fileName& fName = watchFile_[watchFd];
403 double newTime = highResLastModified(fName);
404
405 if (newTime == 0)
406 {
407 localState_[watchFd] = DELETED;
408 }
409 else
410 {
411 if (newTime > (oldTime + IOobject::fileModificationSkew))
412 {
413 localState_[watchFd] = MODIFIED;
414 }
415 else
416 {
417 localState_[watchFd] = UNMODIFIED;
418 }
419 }
420 }
421 }
422 }
423}
424
425
426// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
427
428
429Foam::fileMonitor::fileMonitor(const bool useInotify)
430:
431 useInotify_(useInotify),
432 localState_(20),
433 state_(20),
434 watchFile_(20),
435 freeWatchFds_(2),
436 watcher_(new fileMonitorWatcher(useInotify_, 20))
437{}
438
439
440// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
441
443{}
444
445
446// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
447
448// Note: fName might not exist (on slaves if in master-only mode for
449// regIOobject)
450Foam::label Foam::fileMonitor::addWatch(const fileName& fName)
451{
452 if (debug)
454 Pout<< "fileMonitor : adding watch on file " << fName << endl;
455 }
456
457 label watchFd = state_.size();
458
459 if (!freeWatchFds_.empty())
460 {
461 watchFd = freeWatchFds_.back();
462 freeWatchFds_.pop_back();
463 }
464
465 watcher_->addWatch(watchFd, fName);
466
467 if (debug)
468 {
469 Pout<< "fileMonitor : added watch " << watchFd << " on file "
470 << fName << endl;
471 }
472
473 if (watchFd < 0)
474 {
476 << "could not add watch for file " << fName << endl;
477 }
478 else
479 {
480 localState_(watchFd) = UNMODIFIED;
481 state_(watchFd) = UNMODIFIED;
482 watchFile_(watchFd) = fName;
483 }
484 return watchFd;
485}
486
487
488bool Foam::fileMonitor::removeWatch(const label watchFd)
489{
490 if (debug)
491 {
492 Pout<< "fileMonitor : removing watch " << watchFd << " on file "
493 << watchFile_[watchFd] << endl;
494 }
495
496 freeWatchFds_.push_uniq(watchFd);
497
498 return watcher_->removeWatch(watchFd);
500
501
502const Foam::fileName& Foam::fileMonitor::getFile(const label watchFd) const
503{
504 return watchFile_[watchFd];
505}
506
507
509const
510{
511 return state_[watchFd];
512}
517 const bool masterOnly,
518 const bool syncPar
519) const
520{
521 if (Pstream::master() || !masterOnly)
522 {
523 // Update the localState_
524 checkFiles();
525 }
527 if (syncPar)
528 {
529 // Pack local state (might be on master only)
530 PackedList<2> stats(state_.size(), MODIFIED);
531 if (Pstream::master() || !masterOnly)
532 {
533 forAll(state_, watchFd)
534 {
535 stats.set
536 (
537 watchFd,
538 static_cast<unsigned int>(localState_[watchFd])
539 );
540 }
541 }
542
543
544 // Scatter or reduce to synchronise state
545 if (masterOnly)
546 {
547 // Broadcast
548 if (stats.storage().size() == 1)
549 {
550 Pstream::broadcast(stats.storage()[0]);
551 }
552 else
553 {
555 }
556 }
557 else
558 {
559 // Reduce
560 if (stats.storage().size() == 1)
561 {
562 // Optimisation valid for most cases.
563 reduce(stats.storage()[0], reduceFileStates());
564 }
565 else
566 {
568 (
569 stats.storage(),
571 );
572 }
573 }
574
575
576 // Update synchronised state
577 forAll(state_, watchFd)
578 {
579 // Assign synchronised state
580 unsigned int stat = stats[watchFd];
581 state_[watchFd] = fileState(stat);
582
583 if (!masterOnly)
584 {
585 // Give warning for inconsistent state
586 if (state_[watchFd] != localState_[watchFd])
587 {
588 if (debug)
589 {
590 Pout<< "fileMonitor : Delaying reading "
591 << watchFile_[watchFd]
592 << " due to inconsistent "
593 "file time-stamps between processors"
594 << endl;
595 }
596
598 << "Delaying reading " << watchFile_[watchFd]
599 << " due to inconsistent "
600 "file time-stamps between processors" << endl;
601 }
602 }
603 }
604 }
605 else
606 {
607 state_ = localState_;
608 }
609}
610
611
612void Foam::fileMonitor::setUnmodified(const label watchFd)
613{
614 state_[watchFd] = UNMODIFIED;
615 localState_[watchFd] = UNMODIFIED;
616
617 if (!useInotify_)
618 {
619 watcher_->lastMod_[watchFd] = highResLastModified(watchFile_[watchFd]);
620 }
621}
622
624// ************************************************************************* //
Useful combination of include files which define Sin, Sout and Serr and the use of IO streams general...
scalar y
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
Inter-processor communication reduction functions.
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition DynamicList.H:68
Enum is a wrapper around a list of names/values that represent particular enumeration (or int) values...
Definition Enum.H:57
static float fileModificationSkew
Time skew (seconds) for file modification checks.
Definition IOobject.H:363
A dynamic list of packed unsigned integers, with the number of bits per item specified by the <Width>...
Definition PackedList.H:146
const List< block_type > & storage() const noexcept
Return the underlying storage blocks.
Definition PackedList.H:569
bool set(const label i, unsigned int val=~0u)
Set value at index i, default value set is the max_value.
static void listCombineGather(UList< T > &values, CombineOp cop, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Forwards to Pstream::listGather with an in-place cop.
void size(const label n)
Older name for setAddressableSize.
Definition UList.H:118
static bool master(const label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
Definition UPstream.H:1714
@ broadcast
broadcast [MPI]
Definition UPstream.H:189
Internal tracking via stat(3p) or inotify(7).
fileMonitorWatcher(const bool useInotify, const label sz=20)
Initialise inotify.
DynamicList< double > lastMod_
From watch descriptor to modified time.
int inotifyFd_
File descriptor for the inotify instance.
DynamicList< label > dirWatches_
Current watchIDs and corresponding directory id.
bool addWatch(const label watchFd, const fileName &fName)
DynamicList< fileName > dirFiles_
~fileMonitorWatcher()
Remove all watches.
bool removeWatch(const label watchFd)
Checking for changes to files.
Definition fileMonitor.H:62
fileState getState(const label watchFd) const
Check state using handle.
label addWatch(const fileName &)
Add file to watch. Return watch descriptor.
void setUnmodified(const label watchFd)
Reset state (e.g. after having read it) using handle.
~fileMonitor()
Destructor.
const fileName & getFile(const label watchFd) const
Get name of file being watched.
void updateStates(const bool masterOnly, const bool syncPar) const
Check state of all files. Updates state_.
static int debug
Named/registered debug switch: 'fileMonitor'.
static const Enum< fileState > fileStateNames_
Definition fileMonitor.H:77
fileState
Enumeration defining the file state.
Definition fileMonitor.H:71
bool removeWatch(const label watchFd)
Remove file to watch. Return true if successful.
A class for handling file names.
Definition fileName.H:75
static std::string path(const std::string &str)
Return directory path name (part before last /).
Definition fileNameI.H:169
static std::string name(const std::string &str)
Return basename (part beyond last /), including its extension.
Definition fileNameI.H:192
A class for handling character strings derived from std::string.
Definition string.H:76
Info<< "Creating field kinetic energy K\n"<< endl;volScalarField K("K", 0.5 *magSqr(U));if(U.nOldTimes()){ volVectorField *Uold=&U.oldTime();volScalarField *Kold=&K.oldTime(); *Kold==0.5 *magSqr(*Uold);while(Uold->nOldTimes()) { Uold=&Uold-> oldTime()
Macro definitions for debug switches.
#define registerDebugSwitchWithName(Type, Tag, Name)
Define the debug information, lookup as Name.
#define defineDebugSwitchWithName(Type, Name, Value)
Define the debug information, lookup as Name.
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition error.H:600
#define WarningInFunction
Report a warning using Foam::Warning.
List< bool > select(const label n, const labelUList &locations)
Construct a selection list of bools (all false) with the given pre-size, subsequently add specified l...
Definition BitOps.C:139
Namespace for handling debugging switches.
Definition debug.C:45
Namespace for OpenFOAM.
bool read(const char *buf, int32_t &val)
Same as readInt32.
Definition int32.H:127
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
void reduce(T &value, BinaryOp bop, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Reduce inplace (cf. MPI Allreduce).
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition hashSets.C:26
errorManip< error > abort(error &err)
Definition errorManip.H:139
double highResLastModified(const fileName &, const bool followLink=true)
Return time of last file modification.
Definition POSIX.C:948
error FatalError
Error stream (stdout output on all processes), with additional 'FOAM FATAL ERROR' header text and sta...
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition errorManip.H:125
bool isDir(const fileName &name, const bool followLink=true)
Does the name exist as a DIRECTORY in the file system?
Definition POSIX.C:862
#define forAll(list, i)
Loop across all elements in list.
Definition stdFoam.H:299
Combine operator for PackedList of fileState.
Definition fileMonitor.C:98
void operator()(unsigned int &x, const unsigned int y) const
Definition fileMonitor.C:99
Reduction operator for PackedList of fileState.
Definition fileMonitor.C:66
unsigned int operator()(const unsigned int x, const unsigned int y) const
Definition fileMonitor.C:67