Commit 83219396 authored by Richard Curnow's avatar Richard Curnow

Add dotlocking of the database and --unlock.

Original rev  : rc@rc0.org.uk--2004-mairix/mairix--dev--0.16--patch-26
parent d23aefd8
......@@ -45,7 +45,7 @@ docdir=$(DESTDIR)@docdir@
OBJ = mairix.o db.o rfc822.o tok.o hash.o dirscan.o writer.o \
reader.o search.o stats.o dates.o datescan.o mbox.o md5.o \
fromcheck.o glob.o dumper.o expandstr.o
fromcheck.o glob.o dumper.o expandstr.o dotlock.o
all : mairix
......
......@@ -20,6 +20,8 @@ NEW IN VERSION 0.16
(affects both mfolder option and argument of -o command line switch.) This
prevents disasterous loss of messages in the event of trying to overwrite an
wanted folder with the matches.
* Implement dot-locking on the database file to prevent corruption due to
concurrent updates. Add --unlock file to forcibly remove a stray lockfile.
NEW IN VERSION 0.15
===================
......
/*
mairix - message index builder and finder for maildir folders.
**********************************************************************
* Copyright (C) Richard P. Curnow 2005
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program 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
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*
**********************************************************************
*/
#include "mairix.h"
#include <sys/utsname.h>
#include <sys/types.h>
#include <pwd.h>
#include <unistd.h>
static char *lock_file_name = NULL;
/* This locking code was originally written for tdl */
void lock_database(char *path, int forced_unlock)/*{{{*/
{
struct utsname uu;
struct passwd *pw;
int pid;
int len;
char *tname;
struct stat sb;
FILE *out;
if (uname(&uu) < 0) {
perror("uname");
exit(1);
}
pw = getpwuid(getuid());
if (!pw) {
perror("getpwuid");
exit(1);
}
pid = getpid();
len = 1 + strlen(path) + 5;
lock_file_name = new_array(char, len);
sprintf(lock_file_name, "%s.lock", path);
if (forced_unlock) {
unlock_database();
forced_unlock = 0;
}
len += strlen(uu.nodename);
/* add on max width of pid field (allow up to 32 bit pid_t) + 2 '.' chars */
len += (10 + 2);
tname = new_array(char, len);
sprintf(tname, "%s.%d.%s", lock_file_name, pid, uu.nodename);
out = fopen(tname, "w");
if (!out) {
fprintf(stderr, "Cannot open lock file %s for writing\n", tname);
exit(1);
}
fprintf(out, "%d,%s,%s\n", pid, uu.nodename, pw->pw_name);
fclose(out);
if (link(tname, lock_file_name) < 0) {
/* check if link count==2 */
if (stat(tname, &sb) < 0) {
fprintf(stderr, "Could not stat the lock file\n");
unlink(tname);
exit(1);
} else {
if (sb.st_nlink != 2) {
FILE *in;
in = fopen(lock_file_name, "r");
if (in) {
char line[2048];
fgets(line, sizeof(line), in);
line[strlen(line)-1] = 0; /* strip trailing newline */
fprintf(stderr, "Database %s appears to be locked by (pid,node,user)=(%s)\n", path, line);
unlink(tname);
exit(1);
}
} else {
/* lock succeeded apparently */
}
}
} else {
/* lock succeeded apparently */
}
unlink(tname);
free(tname);
return;
}
/*}}}*/
void unlock_database(void)/*{{{*/
{
if (lock_file_name) unlink(lock_file_name);
return;
}
......@@ -437,9 +437,12 @@ int main (int argc, char **argv)/*{{{*/
int do_raw_output = 0;
int do_dump = 0;
int do_integrity_checks = 1;
int do_forced_unlock = 0;
struct globber_array *omit_globs;
int result;
setlocale(LC_CTYPE, "");
while (++argv, --argc) {
......@@ -465,6 +468,8 @@ int main (int argc, char **argv)/*{{{*/
do_raw_output = 1;
} else if (!strcmp(*argv, "-Q") || !strcmp(*argv, "--no-integrity-checks")) {
do_integrity_checks = 0;
} else if (!strcmp(*argv, "--unlock")) {
do_forced_unlock = 1;
} else if (!strcmp(*argv, "-v") || !strcmp(*argv, "--verbose")) {
verbose = 1;
} else if (!strcmp(*argv, "-h") ||
......@@ -548,10 +553,17 @@ int main (int argc, char **argv)/*{{{*/
} else {
omit_globs = NULL;
}
/* Lock database.
* Prevent concurrent updates due to parallel indexing (e.g. due to stuck
* cron jobs).
* Prevent concurrent searching and indexing. */
lock_database(database_path, do_forced_unlock);
if (do_dump) {
dump_database(database_path);
return 0;
result = 0;
} else if (do_search) {
int len;
......@@ -589,7 +601,7 @@ int main (int argc, char **argv)/*{{{*/
exit(3);
}
return search_top(do_threads, do_augment, database_path, complete_mfolder, argv, output_folder_type, verbose);
result = search_top(do_threads, do_augment, database_path, complete_mfolder, argv, output_folder_type, verbose);
} else {
......@@ -641,8 +653,11 @@ int main (int argc, char **argv)/*{{{*/
free_database(db);
free_msgpath_array(msgs);
return 0;
result = 0;
}
unlock_database();
return result;
}
/*}}}*/
......@@ -333,4 +333,8 @@ void dump_database(char *filename);
/* In strexpand.c */
char *expand_string(const char *p);
/* In dotlock.c */
void lock_database(char *path, int forced_unlock);
void unlock_database(void);
#endif /* MAIRIX_H */
......@@ -577,6 +577,12 @@ to detect mairix bugs much earlier, but it has a performance penalty. This
flag skips the checks, at the cost of some loss in robustness. See also the
@samp{nochecks} directive in @ref{mairixrc}.
The @samp{--unlock} flag is used in any mode. mairix dot-locks the database
file to prevent corruption due to concurrent accesses. If the process holding
the lock exits prematurely for any reason, the lockfile will be left behind.
By using the @samp{--unlock} option, an unwanted lockfile can be conveniently
removed.
The @samp{-t} or @samp{--threads} option applies to search mode. Normally,
only the messages matching all the specified expressions are included in the
@emph{match folder} that is built. With the @samp{-t} flag, any message in
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment