Skip to content

Commit 667b4af

Browse files
committed
cyrusdb: lock conversion section, and add cyrusdb_autconvert config
1 parent 7a6b4a5 commit 667b4af

File tree

5 files changed

+79
-60
lines changed

5 files changed

+79
-60
lines changed

imap/global.c

+2
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,8 @@ EXPORTED int cyrus_init(const char *alt_config, const char *ident, unsigned flag
409409
config_getswitch(IMAPOPT_SKIPLIST_ALWAYS_CHECKPOINT));
410410
libcyrus_config_setswitch(CYRUSOPT_ACL_ADMIN_IMPLIES_WRITE,
411411
config_getswitch(IMAPOPT_ACL_ADMIN_IMPLIES_WRITE));
412+
libcyrus_config_setswitch(CYRUSOPT_CYRUSDB_AUTOCONVERT,
413+
config_getswitch(IMAPOPT_CYRUSDB_AUTOCONVERT));
412414

413415
/* Not until all configuration parameters are set! */
414416
libcyrus_init();

lib/cyrusdb.c

+67-60
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
#include "assert.h"
5858
#include "bsearch.h"
5959
#include "cyrusdb.h"
60+
#include "cyr_lock.h"
6061
#include "util.h"
6162
#include "libcyr_cfg.h"
6263
#include "xmalloc.h"
@@ -108,30 +109,10 @@ static struct cyrusdb_backend *cyrusdb_fromname(const char *name)
108109
fatal(errbuf, EX_CONFIG);
109110
}
110111

111-
static int _myopen(const char *backend, const char *fname,
112-
int flags, struct db **ret, struct txn **tid)
112+
static int _detect_or_convert(struct db *db, const char *backend,
113+
const char *fname, int flags)
113114
{
114-
const char *realname;
115-
struct db *db = xzmalloc(sizeof(struct db));
116-
int r;
117-
118-
if (!backend) backend = DEFAULT_BACKEND; /* not used yet, later */
119-
db->backend = cyrusdb_fromname(backend);
120-
121-
/* Check if shared lock is requested */
122-
if (flags & CYRUSDB_SHARED) {
123-
assert(tid && *tid == NULL);
124-
if (flags & CYRUSDB_CONVERT) {
125-
xsyslog(LOG_ERR,
126-
"DBERROR: CONVERT and SHARED are mutually exclusive,"
127-
" won't open db",
128-
"fname=<%s> backend=<%s>",
129-
fname, backend);
130-
r = CYRUSDB_INTERNAL;
131-
goto done;
132-
}
133-
}
134-
115+
int r = 0;
135116
/* This whole thing is a fricking critical section. We don't have the API
136117
* in place for a safe rename of a locked database, so the choices are
137118
* basically:
@@ -142,29 +123,43 @@ static int _myopen(const char *backend, const char *fname,
142123
* We do that.
143124
*/
144125

145-
/* check if it opens normally. Horray */
146-
r = db->backend->open(fname, flags, &db->engine, tid);
147-
if (r == CYRUSDB_NOTFOUND) goto done; /* no open flags */
148-
if (!r) goto done;
126+
// make sure we have a lock file fd
127+
if (cyrusdb_convertlock_fd < 0) {
128+
struct buf namebuf = BUF_INITIALIZER;
129+
const char *config_dir = libcyrus_config_getstring(CYRUSOPT_CONFIG_DIR);
130+
buf_printf(&namebuf, "%s/lock/cyrusdb_convert.lock", config_dir);
131+
const char *fname = buf_cstring(&namebuf);
132+
cyrusdb_convertlock_fd = open(fname, O_CREAT | O_TRUNC | O_RDWR, 0666);
133+
if (cyrusdb_convertlock_fd < 0) {
134+
if (!cyrus_mkdir(fname, 0755)) {
135+
cyrusdb_convertlock_fd = open(fname, O_CREAT | O_TRUNC | O_RDWR, 0666);
136+
}
137+
}
138+
buf_free(&namebuf);
139+
if (cyrusdb_convertlock_fd < 0)
140+
return CYRUSDB_IOERROR;
141+
}
142+
143+
// lock the lock file
144+
if (lock_setlock(cyrusdb_convertlock_fd, 1, 0, "cyrusdb_convert.lock"))
145+
return CYRUSDB_IOERROR;
149146

150147
/* magic time - we need to work out if the file was created by a different
151148
* backend and convert if possible */
152-
153-
realname = cyrusdb_detect(fname);
149+
const char *realname = cyrusdb_detect(fname);
154150
if (!realname) {
155151
xsyslog(LOG_ERR, "DBERROR: failed to detect DB type",
156-
"fname=<%s> backend=<%s> r=<%d>",
157-
fname, backend, r);
158-
/* r is still set */
159-
goto done;
152+
"fname=<%s> backend=<%s>",
153+
fname, backend);
154+
r = CYRUSDB_IOERROR;
160155
}
161156

162157
/* different type */
163-
if (strcmp(realname, backend)) {
164-
if (flags & CYRUSDB_CONVERT) {
158+
if (!r && strcmp(realname, backend)) {
159+
if (flags & CYRUSDB_CONVERT || libcyrus_config_getswitch(CYRUSOPT_CYRUSDB_AUTOCONVERT)) {
165160
r = cyrusdb_convert(fname, fname, realname, backend);
166161
if (r) {
167-
xsyslog(LOG_ERR, "DBERROR: failed to convert, maybe someone beat us",
162+
xsyslog(LOG_ERR, "DBERROR: failed to convert",
168163
"fname=<%s> from=<%s> to=<%s>",
169164
fname, realname, backend);
170165
}
@@ -180,6 +175,42 @@ static int _myopen(const char *backend, const char *fname,
180175
}
181176
}
182177

178+
lock_unlock(cyrusdb_convertlock_fd, "cyrusdb_convert.lock");
179+
180+
return r;
181+
}
182+
183+
static int _myopen(const char *backend, const char *fname,
184+
int flags, struct db **ret, struct txn **tid)
185+
{
186+
struct db *db = xzmalloc(sizeof(struct db));
187+
int r = 0;
188+
189+
if (!backend) backend = DEFAULT_BACKEND; /* not used yet, later */
190+
db->backend = cyrusdb_fromname(backend);
191+
192+
/* Check if shared lock is requested */
193+
if (flags & CYRUSDB_SHARED) {
194+
assert(tid && *tid == NULL);
195+
if (flags & CYRUSDB_CONVERT) {
196+
xsyslog(LOG_ERR,
197+
"DBERROR: CONVERT and SHARED are mutually exclusive,"
198+
" won't open db",
199+
"fname=<%s> backend=<%s>",
200+
fname, backend);
201+
r = CYRUSDB_INTERNAL;
202+
goto done;
203+
}
204+
}
205+
206+
/* check if it opens normally. Horray */
207+
r = db->backend->open(fname, flags, &db->engine, tid);
208+
if (r == CYRUSDB_NOTFOUND) goto done; /* no open flags */
209+
if (!r) goto done;
210+
211+
r = _detect_or_convert(db, backend, fname, flags);
212+
if (r) goto done;
213+
183214
r = db->backend->open(fname, flags, &db->engine, tid);
184215

185216
#ifdef DEBUGDB
@@ -549,26 +580,6 @@ EXPORTED int cyrusdb_convert(const char *fromfname, const char *tofname,
549580
struct txn *totid = NULL;
550581
int r;
551582

552-
// make sure we have a lock file fd
553-
if (cyrusdb_convertlock_fd < 0) {
554-
struct buf namebuf = BUF_INITIALIZER;
555-
buf_printf(&namebuf, "%s/lock/cyrusdb_convert.lock", config_dir);
556-
const char *fname = buf_cstring(&namebuf);
557-
cyrusdb_convertlock_fd = open(fname, O_CREAT | O_TRUNC | O_RDWR, 0666);
558-
if (cyrusdb_convertlock_fd < 0) {
559-
if (!cyrus_mkdir(fname, 0755))
560-
cyrusdb_convertlock_fd = open(fname, O_CREAT | O_TRUNC | O_RDWR, 0666);
561-
}
562-
}
563-
buf_free(&namebuf);
564-
}
565-
if (cyrusdb_convertlock_fd < 0)
566-
return CYRUSDB_IOERROR;
567-
568-
// lock the lock file
569-
if (lock_setlock(cyrusdb_convertlock_fd, LOCK_EXCLUSIVE, 0, "cyrusdb_convert.lock"))
570-
return CYRUSDB_IOERROR;
571-
572583
/* open source database */
573584
r = cyrusdb_open(frombackend, fromfname, 0, &fromdb);
574585
if (r) goto err;
@@ -610,8 +621,6 @@ EXPORTED int cyrusdb_convert(const char *fromfname, const char *tofname,
610621

611622
free(newfname);
612623

613-
lock_unlock(cyrusdb_convertlock_fd, "cyrusdb_convert.lock");
614-
615624
return 0;
616625

617626
err:
@@ -623,8 +632,6 @@ EXPORTED int cyrusdb_convert(const char *fromfname, const char *tofname,
623632
xunlink(tofname);
624633
free(newfname);
625634

626-
lock_unlock(cyrusdb_convertlock_fd, "cyrusdb_convert.lock");
627-
628635
return r;
629636
}
630637

lib/imapoptions

+4
Original file line numberDiff line numberDiff line change
@@ -762,6 +762,10 @@ Blank lines and lines beginning with ``#'' are ignored.
762762
/* only show the domain for users in other domains than your own (for
763763
backwards compatibility if you're already sharing. */
764764

765+
{ "cyrusdb_autoconvert", 0, SWITCH, "UNRELEASED" }
766+
/* automatically convert any existing db to the configured engine for that
767+
database if possible. */
768+
765769
{ "cyrus_group", NULL, STRING, "3.1.7" }
766770
/* The name of the group Cyrus services will run as. If not configured, the
767771
primary group of cyrus_user will be used. Can be further overridden by

lib/libcyr_cfg.c

+4
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,10 @@ static struct cyrusopt_s cyrus_options[] = {
161161
CFGVAL(long, 0),
162162
CYRUS_OPT_SWITCH },
163163

164+
{ CYRUSOPT_CYRUSDB_AUTOCONVERT,
165+
CFGVAL(long, 0),
166+
CYRUS_OPT_SWITCH },
167+
164168
{ CYRUSOPT_LAST, { NULL }, CYRUS_OPT_NOTOPT }
165169
};
166170

lib/libcyr_cfg.h

+2
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ enum cyrus_opt {
107107
CYRUSOPT_SKIPLIST_ALWAYS_CHECKPOINT,
108108
/* ACL override */
109109
CYRUSOPT_ACL_ADMIN_IMPLIES_WRITE,
110+
/* cyrusdb autoconvert */
111+
CYRUSOPT_CYRUSDB_AUTOCONVERT,
110112

111113
CYRUSOPT_LAST
112114

0 commit comments

Comments
 (0)