From 166399fd6286c293fbeb8bb4d0674db123df6538 Mon Sep 17 00:00:00 2001 From: Jean-Francois Dockes Date: Sat, 8 Jan 2011 19:24:26 +0100 Subject: [PATCH] indexing: create lock / pid file --- src/common/rclconfig.cpp | 4 ++ src/common/rclconfig.h | 2 + src/index/recollindex.cpp | 20 ++++++- src/qtgui/idxthread.cpp | 30 +++++++---- src/utils/pathut.cpp | 111 +++++++++++++++++++++++++++++++++++++- src/utils/pathut.h | 26 +++++++++ 6 files changed, 182 insertions(+), 11 deletions(-) diff --git a/src/common/rclconfig.cpp b/src/common/rclconfig.cpp index 616ebb22..5025b66d 100644 --- a/src/common/rclconfig.cpp +++ b/src/common/rclconfig.cpp @@ -850,6 +850,10 @@ string RclConfig::getStopfile() { return path_cat(getConfDir(), "stoplist.txt"); } +string RclConfig::getPidfile() +{ + return path_cat(getConfDir(), "index.pid"); +} list& RclConfig::getSkippedNames() { diff --git a/src/common/rclconfig.h b/src/common/rclconfig.h index 7dc0f589..52054164 100644 --- a/src/common/rclconfig.h +++ b/src/common/rclconfig.h @@ -135,6 +135,8 @@ class RclConfig { string getDbDir(); /** Get stoplist file name */ string getStopfile(); + /** Get indexing pid file */ + string getPidfile(); /** Get list of skipped file names for current keydir */ list& getSkippedNames(); diff --git a/src/index/recollindex.cpp b/src/index/recollindex.cpp index f9dc0bd3..e802a93c 100644 --- a/src/index/recollindex.cpp +++ b/src/index/recollindex.cpp @@ -206,6 +206,16 @@ RclConfig *RclConfig::getMainConfig() return config; } +void lockorexit(Pidfile *pidfile) +{ + pid_t pid; + if ((pid = pidfile->open()) != 0) { + cerr << "Can't become exclusive indexer: " << pidfile->getreason() << + ". Return (other pid?): " << pid << endl; + exit(1); + } +} + int main(int argc, const char **argv) { string a_config; @@ -268,12 +278,16 @@ int main(int argc, const char **argv) exit(1); } bool rezero(op_flags & OPT_z); + Pidfile pidfile(config->getPidfile()); if (setpriority(PRIO_PGRP, 0, 20) != 0) { LOGINFO(("recollindex: can't setpriority(), errno %d\n", errno)); } - + if (op_flags & (OPT_i|OPT_e)) { + lockorexit(&pidfile); + pidfile.write_pid(); + list filenames; if (argc == 0) { @@ -316,6 +330,7 @@ int main(int argc, const char **argv) } else if (op_flags & OPT_m) { if (argc != 0) Usage(); + lockorexit(&pidfile); if (!(op_flags&OPT_D)) { LOGDEB(("recollindex: daemonizing\n")); daemon(0,0); @@ -325,6 +340,7 @@ int main(int argc, const char **argv) if (setpriority(PRIO_PGRP, 0, 20) != 0) { LOGINFO(("recollindex: can't setpriority(), errno %d\n", errno)); } + pidfile.write_pid(); if (sleepsecs > 0) { LOGDEB(("recollindex: sleeping %d\n", sleepsecs)); sleep(sleepsecs); @@ -356,6 +372,8 @@ int main(int argc, const char **argv) cerr << "Not yet" << endl; return 1; } else { + lockorexit(&pidfile); + pidfile.write_pid(); confindexer = new ConfIndexer(config, &updater); bool status = confindexer->index(rezero, ConfIndexer::IxTAll); if (!status) diff --git a/src/qtgui/idxthread.cpp b/src/qtgui/idxthread.cpp index b803b77a..497ebdee 100644 --- a/src/qtgui/idxthread.cpp +++ b/src/qtgui/idxthread.cpp @@ -1,5 +1,3 @@ -#include -#include /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,6 +15,9 @@ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include +#include +#include #include #include @@ -27,6 +28,7 @@ #include "idxthread.h" #include "smallut.h" #include "rclinit.h" +#include "pathut.h" static int stopindexing; static int startindexing; @@ -79,16 +81,26 @@ void IdxThread::run() myconf->setKeyDir(""); myconf->getConfParam("loglevel", &loglevel); DebugLog::getdbl()->setloglevel(loglevel); - ConfIndexer *indexer = new ConfIndexer(myconf, this); - if (indexer->index(rezero, ConfIndexer::IxTAll)) { - indexingstatus = IDXTS_OK; - indexingReason = ""; - } else { + + Pidfile pidfile(myconf->getPidfile()); + if (pidfile.open() != 0) { indexingstatus = IDXTS_ERROR; - indexingReason = "Indexing failed: " + indexer->getReason(); + indexingReason = "Indexing failed: other process active? " + + pidfile.getreason(); + } else { + pidfile.write_pid(); + ConfIndexer *indexer = new ConfIndexer(myconf, this); + if (indexer->index(rezero, ConfIndexer::IxTAll)) { + indexingstatus = IDXTS_OK; + indexingReason = ""; + } else { + indexingstatus = IDXTS_ERROR; + indexingReason = "Indexing failed: " + indexer->getReason(); + } + pidfile.close(); + delete indexer; } rezero = false; - delete indexer; action_mutex.lock(); } diff --git a/src/utils/pathut.cpp b/src/utils/pathut.cpp index 0571032b..736fabb8 100644 --- a/src/utils/pathut.cpp +++ b/src/utils/pathut.cpp @@ -26,7 +26,11 @@ static char rcsid[] = "@(#$Id: pathut.cpp,v 1.23 2008-11-24 15:47:40 dockes Exp #include #include #include +#include #include +#include +#include + // Let's include all files where statfs can be defined and hope for no // conflict... #ifdef HAVE_SYS_MOUNT_H @@ -452,6 +456,96 @@ bool printableUrl(const string &fcharset, const string &in, string &out) return true; } + +Pidfile::~Pidfile() +{ + if (m_fd >= 0) + ::close(m_fd); + m_fd = -1; +} + +pid_t Pidfile::read_pid() +{ + int fd = ::open(m_path.c_str(), O_RDONLY); + if (fd == -1) + return (pid_t)-1; + + char buf[16]; + int error; + int i = read(fd, buf, sizeof(buf) - 1); + error = errno; + ::close(fd); + if (i <= 0) + return (pid_t)-1; + buf[i] = '\0'; + char *endptr; + pid_t pid = strtol(buf, &endptr, 10); + if (endptr != &buf[i]) + return (pid_t)-1; + return pid; +} + +int Pidfile::flopen() +{ + const char *path = m_path.c_str(); + int operation = LOCK_EX | LOCK_NB; + if ((m_fd = ::open(path, O_RDWR|O_CREAT, 0644)) == -1) { + m_reason = "Open failed"; + return -1; + } + if (flock(m_fd, operation) == -1) { + int serrno = errno; + (void)::close(m_fd); + errno = serrno; + m_reason = "flock failed"; + return -1; + } + if (ftruncate(m_fd, 0) != 0) { + /* can't happen [tm] */ + int serrno = errno; + (void)::close(m_fd); + errno = serrno; + m_reason = "ftruncate failed"; + return -1; + } + return 0; +} + +pid_t Pidfile::open() +{ + if (flopen() < 0) { + return read_pid(); + } + return (pid_t)0; +} + +int Pidfile::write_pid() +{ + /* truncate to allow multiple calls */ + if (ftruncate(m_fd, 0) == -1) { + m_reason = "ftruncate failed"; + return -1; + } + char pidstr[20]; + sprintf(pidstr, "%u", int(getpid())); + lseek(m_fd, 0, 0); + if (::write(m_fd, pidstr, strlen(pidstr)) != (ssize_t)strlen(pidstr)) { + m_reason = "write failed"; + return -1; + } + return 0; +} + +int Pidfile::close() +{ + return ::close(m_fd); +} + +int Pidfile::remove() +{ + return unlink(m_path.c_str()); +} + #else // TEST_PATHUT #include @@ -522,7 +616,7 @@ int main(int argc, const char **argv) } #endif -#if 1 +#if 0 if (argc != 1) { fprintf(stderr, "Usage: fsocc: trpathut \n"); exit(1); @@ -537,6 +631,21 @@ int main(int argc, const char **argv) } printf("pc %d, megabytes %ld\n", pc, blocks); #endif + +#if 1 + Pidfile pidfile("/tmp/pathutpidfile"); + pid_t pid; + if ((pid = pidfile.open()) != 0) { + cerr << "open failed. reason: " << pidfile.getreason() << + " return " << pid << endl; + exit(1); + } + pidfile.write_pid(); + sleep(10); + pidfile.close(); + pidfile.remove(); +#endif + return 0; } diff --git a/src/utils/pathut.h b/src/utils/pathut.h index c03eb12f..b05b5d7a 100644 --- a/src/utils/pathut.h +++ b/src/utils/pathut.h @@ -101,4 +101,30 @@ private: string m_reason; }; +/// Lock/pid file class. This is quite close to the pidfile_xxx +/// utilities in FreeBSD with a bit more encapsulation. I'd have used +/// the freebsd code if it was available elsewhere +class Pidfile { +public: + Pidfile(const string& path) : m_path(path), m_fd(-1) {} + ~Pidfile(); + /// Open/create the pid file. + /// @return 0 if ok, > 0 for pid of existing process, -1 for other error. + pid_t open(); + /// Write pid into the pid file + /// @return 0 ok, -1 error + int write_pid(); + /// Close the pid file (unlocks) + int close(); + /// Delete the pid file + int remove(); + const string& getreason() {return m_reason;} +private: + string m_path; + int m_fd; + string m_reason; + pid_t read_pid(); + int flopen(); +}; + #endif /* _PATHUT_H_INCLUDED_ */