ENH: fileMonitor : monitor directory, not file

Some editors (emacs) rename file at startup to the backup version. Hence
watching the original file tells one nothing.
This commit is contained in:
mattijs
2010-08-29 02:42:20 +01:00
parent a2fa56ec83
commit 1a6db8cdfa
4 changed files with 152 additions and 100 deletions

View File

@ -31,6 +31,7 @@ Class
#include "Pstream.H" #include "Pstream.H"
#include "PackedList.H" #include "PackedList.H"
#include "PstreamReduceOps.H" #include "PstreamReduceOps.H"
#include "OSspecific.H"
#ifdef FOAM_USE_STAT #ifdef FOAM_USE_STAT
# include "OSspecific.H" # include "OSspecific.H"
@ -112,50 +113,104 @@ namespace Foam
#ifdef FOAM_USE_STAT #ifdef FOAM_USE_STAT
//- From watch descriptor to modified time //- From watch descriptor to modified time
HashTable<label, time_t> lastMod; DynamicList<time_t> lastMod_;
//- initialize HashTable size //- initialize HashTable size
inline fileMonitorWatcher(const label sz = 20) inline fileMonitorWatcher(const label sz = 20)
: :
lastMod(sz) lastMod_(sz)
{} {}
inline label addWatch(const fileName& fName) inline bool addWatch(const label watchFd, const fileName& fName)
{ {
const label watchFd = lastMod.size(); if (watchFd < lastMod_.size() && lastMod_[watchFd] != 0)
lastMod.insert(watchFd, lastModified(fName)); {
return watchFd; // Reuse of watchFd : should have lastMod set to 0.
FatalErrorIn("addWatch(const label, const fileName&)")
<< "Problem adding watch " << watchFd
<< " to file " << fName
<< abort(FatalError);
}
lastMod_(watchFd) = lastModified(fName);
return true;
} }
inline bool removeWatch(const label watchFd) inline bool removeWatch(const label watchFd)
{ {
return lastMod.erase(watchFd); lastMod_[watchFd] = 0;
return true;
} }
#else #else
//- File descriptor for the inotify instance //- File descriptor for the inotify instance
int fd; int fd;
//- initialize inotify //- Current watchIDs and corresponding directory id
inline fileMonitorWatcher(const label dummy = 0) DynamicList<label> dirWatches_;
DynamicList<fileName> dirFiles_;
//- initialise inotify
inline fileMonitorWatcher(const label sz = 20)
: :
fd(inotify_init()) fd(inotify_init()),
dirWatches_(sz),
dirFiles_(sz)
{} {}
inline label addWatch(const fileName& fName) //- remove all watches
inline ~fileMonitorWatcher()
{ {
return inotify_add_watch forAll(dirWatches_, i)
{
if (dirWatches_[i] >= 0)
{
if (inotify_rm_watch(fd, int(dirWatches_[i])))
{
WarningIn("fileMonitor::~fileMonitor()")
<< "Failed deleting directory watch "
<< dirWatches_[i] << endl;
}
}
}
}
inline bool addWatch(const label watchFd, const fileName& fName)
{
// Add/retrieve watch on directory containing file
label dirWatchID = inotify_add_watch
( (
fd, fd,
fName.c_str(), fName.path().c_str(),
// IN_ALL_EVENTS IN_CLOSE_WRITE
IN_CLOSE_WRITE | IN_DELETE_SELF //| IN_MODIFY
); );
if (dirWatchID < 0)
{
FatalErrorIn("addWatch(const label, const fileName&)")
<< "Failed adding watch " << watchFd
<< " to directory " << fName
<< exit(FatalError);
}
if (watchFd < dirWatches_.size() && dirWatches_[watchFd] != -1)
{
// Reuse of watchFd : should have dir watchID set to -1.
FatalErrorIn("addWatch(const label, const fileName&)")
<< "Problem adding watch " << watchFd
<< " to file " << fName
<< abort(FatalError);
}
dirWatches_(watchFd) = dirWatchID;
dirFiles_(watchFd) = fName.name();
return true;
} }
inline bool removeWatch(const label watchFd) inline bool removeWatch(const label watchFd)
{ {
return inotify_rm_watch(fd, int(watchFd)) == 0; dirWatches_[watchFd] = -1;
return true;
} }
#endif #endif
@ -169,32 +224,30 @@ namespace Foam
void Foam::fileMonitor::checkFiles() const void Foam::fileMonitor::checkFiles() const
{ {
#ifdef FOAM_USE_STAT #ifdef FOAM_USE_STAT
for forAll(watcher_->lastMod_, watchFd)
(
HashTable<label, time_t>::iterator iter = watcher_->lastMod.begin();
iter != watcher_->lastMod.end();
++iter
)
{ {
const label watchFd = iter.key(); time_t oldTime = watcher_->lastMod_[watchFd];
const fileName& fName = watchFile_[watchFd];
time_t newTime = lastModified(fName);
if (newTime == 0) if (oldTime != 0)
{ {
state_.set(watchFd, DELETED); const fileName& fName = watchFile_[watchFd];
} time_t newTime = lastModified(fName);
else
{ if (newTime == 0)
time_t oldTime = iter();
if (newTime > (oldTime + regIOobject::fileModificationSkew))
{ {
iter() = newTime; state_[watchFd] = DELETED;
state_.set(watchFd, MODIFIED);
} }
else else
{ {
state_.set(watchFd, UNMODIFIED); if (newTime > (oldTime + regIOobject::fileModificationSkew))
{
watcher_->lastMod_[watchFd] = newTime;
state_[watchFd] = MODIFIED;
}
else
{
state_[watchFd] = UNMODIFIED;
}
} }
} }
} }
@ -250,26 +303,30 @@ void Foam::fileMonitor::checkFiles() const
&buffer[i] &buffer[i]
); );
// Pout<< "mask:" << inotifyEvent->mask << nl //Pout<< "watchFd:" << inotifyEvent->wd << nl
// << "watchFd:" << inotifyEvent->wd << nl // << "mask:" << inotifyEvent->mask << nl
// << "watchName:" << watchFile_[inotifyEvent->wd] << endl; // << endl;
//Pout<< "file:" << fileName(inotifyEvent->name) << endl;
//Pout<< "len:" << inotifyEvent->len << endl;
if (inotifyEvent->mask % IN_DELETE_SELF) if ((inotifyEvent->mask & IN_CLOSE_WRITE) && inotifyEvent->len)
{ {
Map<fileState>::iterator iter = // Search for file
state_.find(label(inotifyEvent->wd)); forAll(watcher_->dirWatches_, i)
iter() = DELETED; {
} label id = watcher_->dirWatches_[i];
else if if
( (
//(inotifyEvent->mask % IN_MODIFY) id == inotifyEvent->wd
(inotifyEvent->mask % IN_CLOSE_WRITE) && inotifyEvent->name == watcher_->dirFiles_[i]
) )
{ {
Map<fileState>::iterator iter = // Correct directory and name
state_.find(label(inotifyEvent->wd)); state_[i] = MODIFIED;
iter() = MODIFIED; }
}
} }
i += EVENT_SIZE + inotifyEvent->len; i += EVENT_SIZE + inotifyEvent->len;
} }
} }
@ -289,6 +346,7 @@ Foam::fileMonitor::fileMonitor()
: :
state_(20), state_(20),
watchFile_(20), watchFile_(20),
freeWatchFds_(2),
watcher_(new fileMonitorWatcher(20)) watcher_(new fileMonitorWatcher(20))
{} {}
@ -296,24 +354,27 @@ Foam::fileMonitor::fileMonitor()
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::fileMonitor::~fileMonitor() Foam::fileMonitor::~fileMonitor()
{ {}
// Remove watch on any remaining files
List<label> watchFds(state_.toc());
forAll(watchFds, i)
{
removeWatch(watchFds[i]);
}
delete watcher_;
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
Foam::label Foam::fileMonitor::addWatch(const fileName& fName) Foam::label Foam::fileMonitor::addWatch(const fileName& fName)
{ {
const label watchFd = watcher_->addWatch(fName); label watchFd;
label sz = freeWatchFds_.size();
if (sz)
{
watchFd = freeWatchFds_[sz-1];
freeWatchFds_.setSize(sz-1);
}
else
{
watchFd = state_.size();
}
watcher_->addWatch(watchFd, fName);
if (debug) if (debug)
{ {
@ -328,8 +389,8 @@ Foam::label Foam::fileMonitor::addWatch(const fileName& fName)
} }
else else
{ {
state_.insert(watchFd, UNMODIFIED); state_(watchFd) = UNMODIFIED;
watchFile_.insert(watchFd, fName); watchFile_(watchFd) = fName;
} }
return watchFd; return watchFd;
} }
@ -343,8 +404,7 @@ bool Foam::fileMonitor::removeWatch(const label watchFd)
<< watchFile_[watchFd] << endl; << watchFile_[watchFd] << endl;
} }
state_.erase(watchFd); freeWatchFds_.append(watchFd);
watchFile_.erase(watchFd);
return watcher_->removeWatch(watchFd); return watcher_->removeWatch(watchFd);
} }
@ -369,10 +429,9 @@ void Foam::fileMonitor::updateStates(const bool syncPar) const
if (syncPar) if (syncPar)
{ {
PackedList<2> stats(state_.size()); PackedList<2> stats(state_.size());
label i = 0; forAll(state_, watchFd)
forAllConstIter(Map<fileState>, state_, iter)
{ {
stats[i++] = static_cast<unsigned int>(iter()); stats[watchFd] = static_cast<unsigned int>(state_[watchFd]);
} }
// Save local state for warning message below // Save local state for warning message below
PackedList<2> thisProcStats(stats); PackedList<2> thisProcStats(stats);
@ -391,26 +450,24 @@ void Foam::fileMonitor::updateStates(const bool syncPar) const
); );
} }
i = 0; forAll(state_, watchFd)
forAllIter(Map<fileState>, state_, iter)
{ {
if (thisProcStats[i] != UNMODIFIED) if (thisProcStats[watchFd] != UNMODIFIED)
{ {
if (stats[i] == UNMODIFIED) if (stats[watchFd] == UNMODIFIED)
{ {
WarningIn("fileMonitor::updateStates(const bool) const") WarningIn("fileMonitor::updateStates(const bool) const")
<< "Delaying reading " << watchFile_[iter.key()] << "Delaying reading " << watchFile_[watchFd]
<< " due to inconsistent " << " due to inconsistent "
"file time-stamps between processors" "file time-stamps between processors"
<< endl; << endl;
} }
else else
{ {
unsigned int stat = stats[i]; unsigned int stat = stats[watchFd];
iter() = fileState(stat); state_[watchFd] = fileState(stat);
} }
} }
i++;
} }
} }
} }
@ -419,19 +476,9 @@ void Foam::fileMonitor::updateStates(const bool syncPar) const
void Foam::fileMonitor::setUnmodified(const label watchFd) void Foam::fileMonitor::setUnmodified(const label watchFd)
{ {
#ifdef FOAM_USE_STAT #ifdef FOAM_USE_STAT
watcher_->lastMod[watchFd] = lastModified(watchFile_[watchFd]); watcher_->lastMod_[watchFd] = lastModified(watchFile_[watchFd]);
#endif #endif
state_[watchFd] = UNMODIFIED;
Map<fileState>::iterator iter = state_.find(watchFd);
if (iter == state_.end())
{
FatalErrorIn("fileMonitor::setUnmodified(const label)")
<< "Illegal watchFd " << watchFd
<< abort(FatalError);
}
iter() = UNMODIFIED;
} }

View File

@ -33,10 +33,6 @@ Note
Compiling with FOAM_USE_STAT (or if /usr/include/sys/inotify.h Compiling with FOAM_USE_STAT (or if /usr/include/sys/inotify.h
does not exist) uses the stat function call. does not exist) uses the stat function call.
- works fine except when a file is deleted and recreated:
it stops monitoring the file!
(does work though if the file gets moved)
SourceFiles SourceFiles
fileMonitor.C fileMonitor.C
@ -46,9 +42,9 @@ SourceFiles
#define fileMonitor_H #define fileMonitor_H
#include <sys/types.h> #include <sys/types.h>
#include "Map.H"
#include "NamedEnum.H" #include "NamedEnum.H"
#include "className.H" #include "className.H"
#include "DynamicList.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -83,13 +79,16 @@ private:
// Private data // Private data
//- State for all watchFds //- State for all watchFds
mutable Map<fileState> state_; mutable DynamicList<fileState> state_;
//- From watch descriptor to filename //- Filename for all watchFds
HashTable<fileName, label> watchFile_; DynamicList<fileName> watchFile_;
//- Free watchFds
DynamicList<label> freeWatchFds_;
//- Watch mechanism (stat or inotify) //- Watch mechanism (stat or inotify)
mutable fileMonitorWatcher *watcher_; mutable autoPtr<fileMonitorWatcher> watcher_;
// Private Member Functions // Private Member Functions

View File

@ -371,6 +371,11 @@ Foam::Time::Time
Foam::Time::~Time() Foam::Time::~Time()
{ {
if (controlDict_.watchIndex() != -1)
{
removeWatch(controlDict_.watchIndex());
}
// destroy function objects first // destroy function objects first
functionObjects_.clear(); functionObjects_.clear();
} }

View File

@ -184,6 +184,7 @@ void Foam::Time::readDict()
if (!runTimeModifiable_ && controlDict_.watchIndex() != -1) if (!runTimeModifiable_ && controlDict_.watchIndex() != -1)
{ {
removeWatch(controlDict_.watchIndex()); removeWatch(controlDict_.watchIndex());
controlDict_.watchIndex() = -1;
} }
} }