Windows: improve indexing process management. Fix Pidfile locking.
Use a stop file to request stop of indexing when the indexer was not started from the current GUI instance.
This commit is contained in:
parent
0e866f1bce
commit
8853cb505a
@ -1377,6 +1377,10 @@ string RclConfig::getPidfile() const
|
||||
{
|
||||
return path_cat(getCacheDir(), "index.pid");
|
||||
}
|
||||
string RclConfig::getIdxStopFile() const
|
||||
{
|
||||
return path_cat(getCacheDir(), "index.stop");
|
||||
}
|
||||
|
||||
/* Eliminate the common leaf part of file paths p1 and p2. Example:
|
||||
* /mnt1/common/part /mnt2/common/part -> /mnt1 /mnt2. This is used
|
||||
|
||||
@ -203,6 +203,7 @@ class RclConfig {
|
||||
string getPidfile() const;
|
||||
/** Get indexing status file name */
|
||||
string getIdxStatusFile() const;
|
||||
string getIdxStopFile() const;
|
||||
/** Do path translation according to the ptrans table */
|
||||
void urlrewrite(const string& dbdir, string& url) const;
|
||||
ConfSimple *getPTrans() {
|
||||
|
||||
@ -111,6 +111,7 @@ class MyUpdater : public DbIxStatusUpdater {
|
||||
public:
|
||||
MyUpdater(const RclConfig *config)
|
||||
: m_file(config->getIdxStatusFile().c_str()),
|
||||
m_stopfilename(config->getIdxStopFile()),
|
||||
m_prevphase(DbIxStatus::DBIXS_NONE) {
|
||||
// The total number of files included in the index is actually
|
||||
// difficult to compute from the index itself. For display
|
||||
@ -145,7 +146,10 @@ class MyUpdater : public DbIxStatusUpdater {
|
||||
m_file.set("hasmonitor", status.hasmonitor);
|
||||
m_file.holdWrites(false);
|
||||
}
|
||||
|
||||
if (path_exists(m_stopfilename)) {
|
||||
unlink(m_stopfilename.c_str());
|
||||
stopindexing = true;
|
||||
}
|
||||
if (stopindexing) {
|
||||
return false;
|
||||
}
|
||||
@ -166,6 +170,7 @@ class MyUpdater : public DbIxStatusUpdater {
|
||||
|
||||
private:
|
||||
ConfSimple m_file;
|
||||
string m_stopfilename;
|
||||
Chrono m_chron;
|
||||
DbIxStatus::Phase m_prevphase;
|
||||
};
|
||||
|
||||
@ -246,13 +246,6 @@ void RclMain::toggleIndexing()
|
||||
break;
|
||||
case IXST_RUNNINGNOTMINE:
|
||||
{
|
||||
#ifdef _WIN32
|
||||
QMessageBox::warning(0, tr("Warning"),
|
||||
tr("The current indexing process "
|
||||
"was not started from this "
|
||||
"interface, can't kill it"),
|
||||
QMessageBox::Ok, QMessageBox::NoButton);
|
||||
#else
|
||||
int rep =
|
||||
QMessageBox::information(
|
||||
0, tr("Warning"),
|
||||
@ -261,12 +254,16 @@ void RclMain::toggleIndexing()
|
||||
"anyway, or Cancel to leave it alone"),
|
||||
QMessageBox::Ok, QMessageBox::Cancel, QMessageBox::NoButton);
|
||||
if (rep == QMessageBox::Ok) {
|
||||
#ifdef _WIN32
|
||||
// No simple way to signal the process. Use the stop file
|
||||
::close(::creat(theconfig->getIdxStopFile().c_str(), 0666));
|
||||
#else
|
||||
Pidfile pidfile(theconfig->getPidfile());
|
||||
pid_t pid = pidfile.open();
|
||||
if (pid > 0)
|
||||
kill(pid, SIGTERM);
|
||||
#endif // !_WIN32
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case IXST_NOTRUNNING:
|
||||
|
||||
@ -13,6 +13,30 @@
|
||||
* along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* flock emulation:
|
||||
* Emulate flock on platforms that lack it, primarily Windows and MinGW.
|
||||
*
|
||||
* This is derived from sqlite3 sources.
|
||||
* https://www.sqlite.org/src/finfo?name=src/os_win.c
|
||||
* https://www.sqlite.org/copyright.html
|
||||
*
|
||||
* Written by Richard W.M. Jones <rjones.at.redhat.com>
|
||||
*
|
||||
* Copyright (C) 2008-2019 Free Software Foundation, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef BUILDING_RECOLL
|
||||
@ -105,7 +129,144 @@ static bool path_isdriveabs(const string& s)
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Operations for the 'flock' call (same as Linux kernel constants). */
|
||||
# define LOCK_SH 1 /* Shared lock. */
|
||||
# define LOCK_EX 2 /* Exclusive lock. */
|
||||
# define LOCK_UN 8 /* Unlock. */
|
||||
|
||||
/* Can be OR'd in to one of the above. */
|
||||
# define LOCK_NB 4 /* Don't block when locking. */
|
||||
|
||||
#include <io.h>
|
||||
|
||||
/* Determine the current size of a file. Because the other braindead
|
||||
* APIs we'll call need lower/upper 32 bit pairs, keep the file size
|
||||
* like that too.
|
||||
*/
|
||||
static BOOL
|
||||
file_size (HANDLE h, DWORD * lower, DWORD * upper)
|
||||
{
|
||||
*lower = GetFileSize (h, upper);
|
||||
/* It appears that we can't lock an empty file, a lock is always
|
||||
over a data section. But we seem to be able to set a lock
|
||||
beyond the current file size, which is enough to get Pidfile
|
||||
working */
|
||||
if (*lower == 0 && *upper == 0) {
|
||||
*lower = 100;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* LOCKFILE_FAIL_IMMEDIATELY is undefined on some Windows systems. */
|
||||
# ifndef LOCKFILE_FAIL_IMMEDIATELY
|
||||
# define LOCKFILE_FAIL_IMMEDIATELY 1
|
||||
# endif
|
||||
|
||||
/* Acquire a lock. */
|
||||
static BOOL
|
||||
do_lock (HANDLE h, int non_blocking, int exclusive)
|
||||
{
|
||||
BOOL res;
|
||||
DWORD size_lower, size_upper;
|
||||
OVERLAPPED ovlp;
|
||||
int flags = 0;
|
||||
|
||||
/* We're going to lock the whole file, so get the file size. */
|
||||
res = file_size (h, &size_lower, &size_upper);
|
||||
if (!res)
|
||||
return 0;
|
||||
|
||||
/* Start offset is 0, and also zero the remaining members of this struct. */
|
||||
memset (&ovlp, 0, sizeof ovlp);
|
||||
|
||||
if (non_blocking)
|
||||
flags |= LOCKFILE_FAIL_IMMEDIATELY;
|
||||
if (exclusive)
|
||||
flags |= LOCKFILE_EXCLUSIVE_LOCK;
|
||||
|
||||
return LockFileEx (h, flags, 0, size_lower, size_upper, &ovlp);
|
||||
}
|
||||
|
||||
/* Unlock reader or exclusive lock. */
|
||||
static BOOL
|
||||
do_unlock (HANDLE h)
|
||||
{
|
||||
int res;
|
||||
DWORD size_lower, size_upper;
|
||||
|
||||
res = file_size (h, &size_lower, &size_upper);
|
||||
if (!res)
|
||||
return 0;
|
||||
|
||||
return UnlockFile (h, 0, 0, size_lower, size_upper);
|
||||
}
|
||||
|
||||
/* Now our BSD-like flock operation. */
|
||||
int
|
||||
flock (int fd, int operation)
|
||||
{
|
||||
HANDLE h = (HANDLE) _get_osfhandle (fd);
|
||||
DWORD res;
|
||||
int non_blocking;
|
||||
|
||||
if (h == INVALID_HANDLE_VALUE) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
non_blocking = operation & LOCK_NB;
|
||||
operation &= ~LOCK_NB;
|
||||
|
||||
switch (operation) {
|
||||
case LOCK_SH:
|
||||
res = do_lock (h, non_blocking, 0);
|
||||
break;
|
||||
case LOCK_EX:
|
||||
res = do_lock (h, non_blocking, 1);
|
||||
break;
|
||||
case LOCK_UN:
|
||||
res = do_unlock (h);
|
||||
break;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Map Windows errors into Unix errnos. As usual MSDN fails to
|
||||
* document the permissible error codes.
|
||||
*/
|
||||
if (!res) {
|
||||
DWORD err = GetLastError ();
|
||||
switch (err){
|
||||
/* This means someone else is holding a lock. */
|
||||
case ERROR_LOCK_VIOLATION:
|
||||
errno = EAGAIN;
|
||||
break;
|
||||
|
||||
/* Out of memory. */
|
||||
case ERROR_NOT_ENOUGH_MEMORY:
|
||||
errno = ENOMEM;
|
||||
break;
|
||||
|
||||
case ERROR_BAD_COMMAND:
|
||||
errno = EINVAL;
|
||||
break;
|
||||
|
||||
/* Unlikely to be other errors, but at least don't lose the
|
||||
* error code.
|
||||
*/
|
||||
default:
|
||||
errno = err;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // Win32 only section
|
||||
|
||||
bool fsocc(const string& path, int *pc, long long *avmbs)
|
||||
{
|
||||
@ -931,14 +1092,14 @@ pid_t Pidfile::read_pid()
|
||||
{
|
||||
int fd = ::open(m_path.c_str(), O_RDONLY);
|
||||
if (fd == -1) {
|
||||
return (pid_t) - 1;
|
||||
return (pid_t) -1;
|
||||
}
|
||||
|
||||
char buf[16];
|
||||
int i = read(fd, buf, sizeof(buf) - 1);
|
||||
::close(fd);
|
||||
if (i <= 0) {
|
||||
return (pid_t) - 1;
|
||||
return (pid_t) -1;
|
||||
}
|
||||
buf[i] = '\0';
|
||||
char *endptr;
|
||||
@ -967,12 +1128,9 @@ int Pidfile::flopen()
|
||||
int serrno = errno;
|
||||
this->close()
|
||||
errno = serrno;
|
||||
m_reason = "fcntl lock failed";
|
||||
m_reason = "fcntl lock failed";
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
#ifdef _WIN32
|
||||
return 0;
|
||||
#else
|
||||
int operation = LOCK_EX | LOCK_NB;
|
||||
if (flock(m_fd, operation) == -1) {
|
||||
@ -982,7 +1140,6 @@ int Pidfile::flopen()
|
||||
m_reason = "flock failed";
|
||||
return -1;
|
||||
}
|
||||
#endif // ! win32
|
||||
#endif // ! sun
|
||||
|
||||
if (ftruncate(m_fd, 0) != 0) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user