diff --git a/src/index/rclmon.h b/src/index/rclmon.h index fea641a5..05474af8 100644 --- a/src/index/rclmon.h +++ b/src/index/rclmon.h @@ -2,7 +2,7 @@ #define _RCLMON_H_INCLUDED_ #include "autoconfig.h" #ifdef RCL_MONITOR -/* @(#$Id: rclmon.h,v 1.3 2006-10-23 15:01:12 dockes Exp $ (C) 2006 J.F.Dockes */ +/* @(#$Id: rclmon.h,v 1.4 2006-10-24 12:48:08 dockes Exp $ (C) 2006 J.F.Dockes */ /** * Definitions for the real-time monitoring recoll. * We're interested in file modifications, deletions and renaming. @@ -24,6 +24,9 @@ using std::string; using std::multimap; #endif +/** + * Monitoring event: something changed in the filesystem + */ class RclMonEvent { public: enum EvType {RCLEVT_NONE, RCLEVT_MODIFY, RCLEVT_DELETE, @@ -34,8 +37,12 @@ class RclMonEvent { RclMonEvent() : m_etyp(RCLEVT_NONE) {} }; +/** + * Monitoring event queue. This is the shared object between the main thread + * (which does the actual indexing work), and the monitoring thread which + * receives events from FAM / inotify / etc. + */ class RclEQData; - class RclMonEventQueue { public: RclMonEventQueue(); @@ -62,7 +69,15 @@ class RclMonEventQueue { RclEQData *m_data; }; -extern RclMonEventQueue rclEQ; +/** Start monitoring on the topdirs described in conf */ extern bool startMonitor(RclConfig *conf, bool nofork); + +/** Main routine for the event receiving thread */ +extern void *rclMonRcvRun(void *); + +/** There can only be one of us. Name of the lock file inside the config + * directory. We write our pid in there */ +#define RCL_MONITOR_PIDFILENAME "rclmonpid" + #endif // RCL_MONITOR #endif /* _RCLMON_H_INCLUDED_ */ diff --git a/src/index/rclmonprc.cpp b/src/index/rclmonprc.cpp index df7cef92..bb53ecd7 100644 --- a/src/index/rclmonprc.cpp +++ b/src/index/rclmonprc.cpp @@ -2,7 +2,7 @@ #ifdef RCL_MONITOR #ifndef lint -static char rcsid[] = "@(#$Id: rclmonprc.cpp,v 1.3 2006-10-22 14:47:13 dockes Exp $ (C) 2006 J.F.Dockes"; +static char rcsid[] = "@(#$Id: rclmonprc.cpp,v 1.4 2006-10-24 12:48:09 dockes Exp $ (C) 2006 J.F.Dockes"; #endif /* * This program is free software; you can redistribute it and/or modify @@ -28,14 +28,22 @@ static char rcsid[] = "@(#$Id: rclmonprc.cpp,v 1.3 2006-10-22 14:47:13 dockes Ex */ #include +#include +#include +#include +#include #include "debuglog.h" #include "rclmon.h" #include "debuglog.h" #include "indexer.h" +#include "pathut.h" typedef map queue_type; +/** Private part of RclEQ: things that we don't wish to exist in the interface + * include file. + */ class RclEQData { public: queue_type m_queue; @@ -51,16 +59,18 @@ public: } }; -RclMonEventQueue rclEQ; +static RclMonEventQueue rclEQ; RclMonEventQueue::RclMonEventQueue() { m_data = new RclEQData; } + RclMonEventQueue::~RclMonEventQueue() { delete m_data; } + bool RclMonEventQueue::empty() { return m_data == 0 ? true : m_data->m_queue.empty(); @@ -138,22 +148,91 @@ bool RclMonEventQueue::pushEvent(const RclMonEvent &ev) { LOGDEB2(("RclMonEventQueue::pushEvent for %s\n", ev.m_path.c_str())); lock(); - // It seems that a newer event always override any older. TBVerified ? + // It seems that a newer event is always correct to override any + // older. TBVerified ? m_data->m_queue[ev.m_path] = ev; pthread_cond_broadcast(&m_data->m_cond); unlock(); return true; } +static string pidfile; +/** There can only be one real time indexing process running */ +static bool processlock(const string &confdir) +{ + pidfile = path_cat(confdir, RCL_MONITOR_PIDFILENAME); + for (int i = 0; i < 2; i++) { + int fd = open(pidfile.c_str(), O_RDWR|O_CREAT|O_EXCL, 0644); + if (fd < 0) { + if (errno != EEXIST) { + LOGERR(("processlock: cant create %s, errno %d\n", + pidfile.c_str(), errno)); + return false; + } + if ((fd = open(pidfile.c_str(), O_RDONLY)) < 0) { + LOGERR(("processlock: cant open existing %s, errno %d\n", + pidfile.c_str(), errno)); + return false; + } + char buf[20]; + memset(buf, 0, sizeof(buf)); + if (read(fd, buf, 19) < 0) { + LOGERR(("processlock: cant read existing %s, errno %d\n", + pidfile.c_str(), errno)); + close(fd); + return false; + } + close(fd); + int pid = atoi(buf); + if (pid <= 0 || (kill(pid, 0) < 0 && errno == ESRCH)) { + // File exists but no process + if (unlink(pidfile.c_str()) < 0) { + LOGERR(("processlock: cant unlink existing %s, errno %d\n", + pidfile.c_str(), errno)); + return false; + } + // Let's retry + continue; + } else { + // Other process running + return false; + } + } + + // File could be created, write my pid in there + char buf[20]; + sprintf(buf, "%d\n", getpid()); + if (write(fd, buf, strlen(buf)+1) != int(strlen(buf)+1)) { + LOGERR(("processlock: cant write to %s, errno %d\n", + pidfile.c_str(), errno)); + close(fd); + return false; + } + close(fd); + // Ok + break; + } + return true; +} + +static void processunlock() +{ + unlink(pidfile.c_str()); +} + pthread_t rcv_thrid; -void *rcv_result; -extern void *rclMonRcvRun(void *); bool startMonitor(RclConfig *conf, bool nofork) { + if (!processlock(conf->getConfDir())) { + LOGERR(("startMonitor: lock error. Other process running ?\n")); + return false; + } + atexit(processunlock); + rclEQ.setConfig(conf); if (pthread_create(&rcv_thrid, 0, &rclMonRcvRun, &rclEQ) != 0) { - LOGERR(("start_monitoring: cant create event-receiving thread\n")); + LOGERR(("startMonitor: cant create event-receiving thread\n")); return false; }