|
a/src/index/rclmonrcv.cpp |
|
b/src/index/rclmonrcv.cpp |
|
... |
|
... |
100 |
RclMonEvent ev;
|
100 |
RclMonEvent ev;
|
101 |
if (m_mon->getEvent(ev, 0)) {
|
101 |
if (m_mon->getEvent(ev, 0)) {
|
102 |
if (ev.m_etyp != RclMonEvent::RCLEVT_NONE)
|
102 |
if (ev.m_etyp != RclMonEvent::RCLEVT_NONE)
|
103 |
m_queue->pushEvent(ev);
|
103 |
m_queue->pushEvent(ev);
|
104 |
} else {
|
104 |
} else {
|
105 |
MONDEB(("rclMonRcvRun: no event pending\n"));
|
105 |
MONDEB("rclMonRcvRun: no event pending\n");
|
106 |
break;
|
106 |
break;
|
107 |
}
|
107 |
}
|
108 |
}
|
108 |
}
|
109 |
if (!m_mon || !m_mon->ok())
|
109 |
if (!m_mon || !m_mon->ok())
|
110 |
return FsTreeWalker::FtwError;
|
110 |
return FsTreeWalker::FtwError;
|
|
... |
|
... |
208 |
}
|
208 |
}
|
209 |
}
|
209 |
}
|
210 |
}
|
210 |
}
|
211 |
|
211 |
|
212 |
// Forever wait for monitoring events and add them to queue:
|
212 |
// Forever wait for monitoring events and add them to queue:
|
213 |
MONDEB(("rclMonRcvRun: waiting for events. q->ok() %d\n", queue->ok()));
|
213 |
MONDEB("rclMonRcvRun: waiting for events. q->ok(): " << queue->ok() <<
|
|
|
214 |
std::endl);
|
214 |
while (queue->ok() && mon->ok()) {
|
215 |
while (queue->ok() && mon->ok()) {
|
215 |
RclMonEvent ev;
|
216 |
RclMonEvent ev;
|
216 |
// Note: I could find no way to get the select
|
217 |
// Note: I could find no way to get the select
|
217 |
// call to return when a signal is delivered to the process
|
218 |
// call to return when a signal is delivered to the process
|
218 |
// (it goes to the main thread, from which I tried to close or
|
219 |
// (it goes to the main thread, from which I tried to close or
|
|
... |
|
... |
262 |
// Utility routine used by both the fam/gamin and inotify versions to get
|
263 |
// Utility routine used by both the fam/gamin and inotify versions to get
|
263 |
// rid of the id-path translation for a moved dir
|
264 |
// rid of the id-path translation for a moved dir
|
264 |
bool eraseWatchSubTree(map<int, string>& idtopath, const string& top)
|
265 |
bool eraseWatchSubTree(map<int, string>& idtopath, const string& top)
|
265 |
{
|
266 |
{
|
266 |
bool found = false;
|
267 |
bool found = false;
|
267 |
MONDEB(("Clearing map for [%s]\n", top.c_str()));
|
268 |
MONDEB("Clearing map for [" << top << "]\n");
|
268 |
map<int,string>::iterator it = idtopath.begin();
|
269 |
map<int,string>::iterator it = idtopath.begin();
|
269 |
while (it != idtopath.end()) {
|
270 |
while (it != idtopath.end()) {
|
270 |
if (it->second.find(top) == 0) {
|
271 |
if (it->second.find(top) == 0) {
|
271 |
found = true;
|
272 |
found = true;
|
272 |
idtopath.erase(it++);
|
273 |
idtopath.erase(it++);
|
|
... |
|
... |
360 |
{
|
361 |
{
|
361 |
if (!ok())
|
362 |
if (!ok())
|
362 |
return false;
|
363 |
return false;
|
363 |
bool ret = false;
|
364 |
bool ret = false;
|
364 |
|
365 |
|
365 |
MONDEB(("RclFAM::addWatch: adding %s\n", path.c_str()));
|
366 |
MONDEB("RclFAM::addWatch: adding " << path << std::endl);
|
366 |
|
367 |
|
367 |
// It happens that the following call block forever.
|
368 |
// It happens that the following call block forever.
|
368 |
// We'd like to be able to at least terminate on a signal here, but
|
369 |
// We'd like to be able to at least terminate on a signal here, but
|
369 |
// gamin forever retries its write call on EINTR, so it's not even useful
|
370 |
// gamin forever retries its write call on EINTR, so it's not even useful
|
370 |
// to unblock signals. SIGALRM is not used by the main thread, so at least
|
371 |
// to unblock signals. SIGALRM is not used by the main thread, so at least
|
|
... |
|
... |
399 |
// Return EVT_NONE for bad event to keep queue processing going
|
400 |
// Return EVT_NONE for bad event to keep queue processing going
|
400 |
bool RclFAM::getEvent(RclMonEvent& ev, int msecs)
|
401 |
bool RclFAM::getEvent(RclMonEvent& ev, int msecs)
|
401 |
{
|
402 |
{
|
402 |
if (!ok())
|
403 |
if (!ok())
|
403 |
return false;
|
404 |
return false;
|
404 |
MONDEB(("RclFAM::getEvent:\n"));
|
405 |
MONDEB("RclFAM::getEvent:\n");
|
405 |
|
406 |
|
406 |
fd_set readfds;
|
407 |
fd_set readfds;
|
407 |
int fam_fd = FAMCONNECTION_GETFD(&m_conn);
|
408 |
int fam_fd = FAMCONNECTION_GETFD(&m_conn);
|
408 |
FD_ZERO(&readfds);
|
409 |
FD_ZERO(&readfds);
|
409 |
FD_SET(fam_fd, &readfds);
|
410 |
FD_SET(fam_fd, &readfds);
|
410 |
|
411 |
|
411 |
MONDEB(("RclFAM::getEvent: select. fam_fd is %d\n", fam_fd));
|
412 |
MONDEB("RclFAM::getEvent: select. fam_fd is " << fam_fd << std::endl);
|
412 |
// Fam / gamin is sometimes a bit slow to send events. Always add
|
413 |
// Fam / gamin is sometimes a bit slow to send events. Always add
|
413 |
// a little timeout, because if we fail to retrieve enough events,
|
414 |
// a little timeout, because if we fail to retrieve enough events,
|
414 |
// we risk deadlocking in addwatch()
|
415 |
// we risk deadlocking in addwatch()
|
415 |
if (msecs == 0)
|
416 |
if (msecs == 0)
|
416 |
msecs = 2;
|
417 |
msecs = 2;
|
|
... |
|
... |
424 |
LOGERR("RclFAM::getEvent: select failed, errno " << (errno) << "\n" );
|
425 |
LOGERR("RclFAM::getEvent: select failed, errno " << (errno) << "\n" );
|
425 |
close();
|
426 |
close();
|
426 |
return false;
|
427 |
return false;
|
427 |
} else if (ret == 0) {
|
428 |
} else if (ret == 0) {
|
428 |
// timeout
|
429 |
// timeout
|
429 |
MONDEB(("RclFAM::getEvent: select timeout\n"));
|
430 |
MONDEB("RclFAM::getEvent: select timeout\n");
|
430 |
return false;
|
431 |
return false;
|
431 |
}
|
432 |
}
|
432 |
|
433 |
|
433 |
MONDEB(("RclFAM::getEvent: select returned %d\n", ret));
|
434 |
MONDEB("RclFAM::getEvent: select returned " << ret << std::endl);
|
434 |
|
435 |
|
435 |
if (!FD_ISSET(fam_fd, &readfds))
|
436 |
if (!FD_ISSET(fam_fd, &readfds))
|
436 |
return false;
|
437 |
return false;
|
437 |
|
438 |
|
438 |
// ?? 2011/03/15 gamin v0.1.10. There is initially a single null
|
439 |
// ?? 2011/03/15 gamin v0.1.10. There is initially a single null
|
439 |
// byte on the connection so the first select always succeeds. If
|
440 |
// byte on the connection so the first select always succeeds. If
|
440 |
// we then call FAMNextEvent we stall. Using FAMPending works
|
441 |
// we then call FAMNextEvent we stall. Using FAMPending works
|
441 |
// around the issue, but we did not need this in the past and this
|
442 |
// around the issue, but we did not need this in the past and this
|
442 |
// is most weird.
|
443 |
// is most weird.
|
443 |
if (FAMPending(&m_conn) <= 0) {
|
444 |
if (FAMPending(&m_conn) <= 0) {
|
444 |
MONDEB(("RclFAM::getEvent: FAMPending says no events\n"));
|
445 |
MONDEB("RclFAM::getEvent: FAMPending says no events\n");
|
445 |
return false;
|
446 |
return false;
|
446 |
}
|
447 |
}
|
447 |
|
448 |
|
448 |
MONDEB(("RclFAM::getEvent: call FAMNextEvent\n"));
|
449 |
MONDEB("RclFAM::getEvent: call FAMNextEvent\n");
|
449 |
FAMEvent fe;
|
450 |
FAMEvent fe;
|
450 |
if (FAMNextEvent(&m_conn, &fe) < 0) {
|
451 |
if (FAMNextEvent(&m_conn, &fe) < 0) {
|
451 |
LOGERR("RclFAM::getEvent: FAMNextEvent failed, errno " << (errno) << "\n" );
|
452 |
LOGERR("RclFAM::getEvent: FAMNextEvent failed, errno " << (errno) << "\n" );
|
452 |
close();
|
453 |
close();
|
453 |
return false;
|
454 |
return false;
|
454 |
}
|
455 |
}
|
455 |
MONDEB(("RclFAM::getEvent: FAMNextEvent returned\n"));
|
456 |
MONDEB("RclFAM::getEvent: FAMNextEvent returned\n");
|
456 |
|
457 |
|
457 |
map<int,string>::const_iterator it;
|
458 |
map<int,string>::const_iterator it;
|
458 |
if ((!path_isabsolute(fe.filename)) &&
|
459 |
if ((!path_isabsolute(fe.filename)) &&
|
459 |
(it = m_idtopath.find(fe.fr.reqnum)) != m_idtopath.end()) {
|
460 |
(it = m_idtopath.find(fe.fr.reqnum)) != m_idtopath.end()) {
|
460 |
ev.m_path = path_cat(it->second, fe.filename);
|
461 |
ev.m_path = path_cat(it->second, fe.filename);
|
461 |
} else {
|
462 |
} else {
|
462 |
ev.m_path = fe.filename;
|
463 |
ev.m_path = fe.filename;
|
463 |
}
|
464 |
}
|
464 |
|
465 |
|
465 |
MONDEB(("RclFAM::getEvent: %-12s %s\n",
|
466 |
MONDEB("RclFAM::getEvent: " << event_name(fe.code) < " " <<
|
466 |
event_name(fe.code), ev.m_path.c_str()));
|
467 |
ev.m_path << std::endl);
|
467 |
|
468 |
|
468 |
switch (fe.code) {
|
469 |
switch (fe.code) {
|
469 |
case FAMCreated:
|
470 |
case FAMCreated:
|
470 |
if (path_isdir(ev.m_path)) {
|
471 |
if (path_isdir(ev.m_path)) {
|
471 |
ev.m_etyp = RclMonEvent::RCLEVT_DIRCREATE;
|
472 |
ev.m_etyp = RclMonEvent::RCLEVT_DIRCREATE;
|
|
... |
|
... |
582 |
|
583 |
|
583 |
bool RclIntf::addWatch(const string& path, bool)
|
584 |
bool RclIntf::addWatch(const string& path, bool)
|
584 |
{
|
585 |
{
|
585 |
if (!ok())
|
586 |
if (!ok())
|
586 |
return false;
|
587 |
return false;
|
587 |
MONDEB(("RclIntf::addWatch: adding %s\n", path.c_str()));
|
588 |
MONDEB("RclIntf::addWatch: adding " << path << std::endl);
|
588 |
// CLOSE_WRITE is covered through MODIFY. CREATE is needed for mkdirs
|
589 |
// CLOSE_WRITE is covered through MODIFY. CREATE is needed for mkdirs
|
589 |
uint32_t mask = IN_MODIFY | IN_CREATE
|
590 |
uint32_t mask = IN_MODIFY | IN_CREATE
|
590 |
| IN_MOVED_FROM | IN_MOVED_TO | IN_DELETE
|
591 |
| IN_MOVED_FROM | IN_MOVED_TO | IN_DELETE
|
591 |
// IN_ATTRIB used to be not needed to receive extattr
|
592 |
// IN_ATTRIB used to be not needed to receive extattr
|
592 |
// modification events, which was a bit weird because only ctime is
|
593 |
// modification events, which was a bit weird because only ctime is
|
|
... |
|
... |
617 |
bool RclIntf::getEvent(RclMonEvent& ev, int msecs)
|
618 |
bool RclIntf::getEvent(RclMonEvent& ev, int msecs)
|
618 |
{
|
619 |
{
|
619 |
if (!ok())
|
620 |
if (!ok())
|
620 |
return false;
|
621 |
return false;
|
621 |
ev.m_etyp = RclMonEvent::RCLEVT_NONE;
|
622 |
ev.m_etyp = RclMonEvent::RCLEVT_NONE;
|
622 |
MONDEB(("RclIntf::getEvent:\n"));
|
623 |
MONDEB("RclIntf::getEvent:\n");
|
623 |
|
624 |
|
624 |
if (m_evp == 0) {
|
625 |
if (m_evp == 0) {
|
625 |
fd_set readfds;
|
626 |
fd_set readfds;
|
626 |
FD_ZERO(&readfds);
|
627 |
FD_ZERO(&readfds);
|
627 |
FD_SET(m_fd, &readfds);
|
628 |
FD_SET(m_fd, &readfds);
|
|
... |
|
... |
629 |
if (msecs >= 0) {
|
630 |
if (msecs >= 0) {
|
630 |
timeout.tv_sec = msecs / 1000;
|
631 |
timeout.tv_sec = msecs / 1000;
|
631 |
timeout.tv_usec = (msecs % 1000) * 1000;
|
632 |
timeout.tv_usec = (msecs % 1000) * 1000;
|
632 |
}
|
633 |
}
|
633 |
int ret;
|
634 |
int ret;
|
634 |
MONDEB(("RclIntf::getEvent: select\n"));
|
635 |
MONDEB("RclIntf::getEvent: select\n");
|
635 |
if ((ret=select(m_fd + 1, &readfds, 0, 0, msecs >= 0 ? &timeout : 0)) < 0) {
|
636 |
if ((ret=select(m_fd + 1, &readfds, 0, 0, msecs >= 0 ? &timeout : 0)) < 0) {
|
636 |
LOGERR("RclIntf::getEvent: select failed, errno " << (errno) << "\n" );
|
637 |
LOGERR("RclIntf::getEvent: select failed, errno " << (errno) << "\n" );
|
637 |
close();
|
638 |
close();
|
638 |
return false;
|
639 |
return false;
|
639 |
} else if (ret == 0) {
|
640 |
} else if (ret == 0) {
|
640 |
MONDEB(("RclIntf::getEvent: select timeout\n"));
|
641 |
MONDEB("RclIntf::getEvent: select timeout\n");
|
641 |
// timeout
|
642 |
// timeout
|
642 |
return false;
|
643 |
return false;
|
643 |
}
|
644 |
}
|
644 |
MONDEB(("RclIntf::getEvent: select returned\n"));
|
645 |
MONDEB("RclIntf::getEvent: select returned\n");
|
645 |
|
646 |
|
646 |
if (!FD_ISSET(m_fd, &readfds))
|
647 |
if (!FD_ISSET(m_fd, &readfds))
|
647 |
return false;
|
648 |
return false;
|
648 |
int rret;
|
649 |
int rret;
|
649 |
if ((rret=read(m_fd, m_evbuf, sizeof(m_evbuf))) <= 0) {
|
650 |
if ((rret=read(m_fd, m_evbuf, sizeof(m_evbuf))) <= 0) {
|
650 |
LOGERR("RclIntf::getEvent: read failed, " << (sizeof(m_evbuf)) << "->" << (rret) << " errno " << (errno) << "\n" );
|
651 |
LOGERR("RclIntf::getEvent: read failed, " << sizeof(m_evbuf) <<
|
|
|
652 |
"->" << rret << " errno " << errno << "\n");
|
651 |
close();
|
653 |
close();
|
652 |
return false;
|
654 |
return false;
|
653 |
}
|
655 |
}
|
654 |
m_evp = m_evbuf;
|
656 |
m_evp = m_evbuf;
|
655 |
m_ep = m_evbuf + rret;
|
657 |
m_ep = m_evbuf + rret;
|
|
... |
|
... |
671 |
|
673 |
|
672 |
if (evp->len > 0) {
|
674 |
if (evp->len > 0) {
|
673 |
ev.m_path = path_cat(ev.m_path, evp->name);
|
675 |
ev.m_path = path_cat(ev.m_path, evp->name);
|
674 |
}
|
676 |
}
|
675 |
|
677 |
|
676 |
MONDEB(("RclIntf::getEvent: %-12s %s\n",
|
678 |
MONDEB("RclIntf::getEvent: " << event_name(evp->mask) << " " <<
|
677 |
event_name(evp->mask), ev.m_path.c_str()));
|
679 |
ev.m_path << std::endl);
|
678 |
|
680 |
|
679 |
if ((evp->mask & IN_MOVED_FROM) && (evp->mask & IN_ISDIR)) {
|
681 |
if ((evp->mask & IN_MOVED_FROM) && (evp->mask & IN_ISDIR)) {
|
680 |
// We get this when a directory is renamed. Erase the subtree
|
682 |
// We get this when a directory is renamed. Erase the subtree
|
681 |
// entries in the map. The subsequent MOVED_TO will recreate
|
683 |
// entries in the map. The subsequent MOVED_TO will recreate
|
682 |
// them. This is probably not needed because the watches
|
684 |
// them. This is probably not needed because the watches
|