particularly for mailinglist and smarthost cases.
JH/02 Add transaction support for hintsdbs. The sole initial provider is
- sqlite, and is used for the wait-trasnprot DB. Transactions imply
- locking internal to the DB. We no longer need a separate lockfile, can
- keep the DB handle open for extended periods, and still potentially
- benefit from concurrency on non-conlicting record uses.
+ sqlite, and is used for the wait-transport and retry DBs. Transactions
+ imply locking internal to the DB. We no longer need a separate lockfile,
+ can keep the DB handle open for extended periods, yet potentially benefit
+ from concurrency on non-conflicting record uses.
Exim version 4.98
-----------------
*/
open_db *
-dbfn_open_multi(const uschar * name, open_db * dbblock)
+dbfn_open_multi(const uschar * name, int flags, open_db * dbblock)
{
int rc, save_errno;
flock_t lock_data;
snprintf(CS filename, sizeof(filename), "%s/%s", dirname, name);
priv_drop_temp(exim_uid, exim_gid);
-dbblock->dbptr = exim_dbopen_multi(filename, dirname, O_RDWR, EXIMDB_MODE);
-if (!dbblock->dbptr && errno == ENOENT)
+dbblock->dbptr = exim_dbopen_multi(filename, dirname, flags, EXIMDB_MODE);
+if (!dbblock->dbptr && errno == ENOENT && flags == O_RDWR)
{
DEBUG(D_hints_lookup)
debug_printf_indent("%s appears not to exist: trying to create\n", filename);
dbfn_transaction_commit(open_db * dbp)
{
DEBUG(D_hints_lookup) debug_printf_indent("dbfn_transaction_commit\n");
-return exim_dbtransaction_commit(dbp->dbptr);
+exim_dbtransaction_commit(dbp->dbptr);
}
void dbfn_close_multi(open_db *);
int dbfn_delete(open_db *, const uschar *);
open_db *dbfn_open(const uschar *, int, open_db *, BOOL, BOOL);
-open_db *dbfn_open_multi(const uschar *, open_db *);
+open_db *dbfn_open_multi(const uschar *, int, open_db *);
void *dbfn_read_with_length(open_db *, const uschar *, int *);
void *dbfn_read_enforce_length(open_db *, const uschar *, size_t);
uschar *dbfn_scan(open_db *, BOOL, EXIM_CURSOR **);
static void
do_local_deliveries(void)
{
-open_db dbblock;
-open_db *dbm_file = NULL;
+open_db dbblock, * dbm_file = NULL;
time_t now = time(NULL);
/* Loop until we have exhausted the supply of local deliveries */
do_remote_deliveries par_reduce par_wait par_read_pipe
*/
-if ( continue_transport
- && !continue_wait_db
- && !exim_lockfile_needed()
- )
- {
- open_db * dbp = store_get(sizeof(open_db), GET_UNTAINTED);
- continue_wait_db = dbfn_open_multi(
- string_sprintf("wait-%.200s", continue_transport), dbp);
- continue_next_id[0] = '\0';
- }
+if (continue_transport && !exim_lockfile_needed())
+ if (!continue_wait_db)
+ {
+ continue_wait_db = dbfn_open_multi(
+ string_sprintf("wait-%.200s", continue_transport),
+ O_RDWR,
+ (open_db *) store_get(sizeof(open_db), GET_UNTAINTED));
+ continue_next_id[0] = '\0';
+ }
if ((pid = exim_fork(US"transport")) == 0)
{
if (continue_transport)
{
par_reduce(0, fallback);
- if (continue_wait_db && !continue_next_id)
- { dbfn_close_multi(continue_wait_db); continue_wait_db = NULL; }
+ if (!continue_next_id && continue_wait_db)
+ { dbfn_close_multi(continue_wait_db); continue_wait_db = NULL; }
}
/* Otherwise, if we are running in the test harness, wait a bit, to let the
if (f.queue_2stage)
dbm_file = NULL;
- else if (!(dbm_file = dbfn_open(US"retry", O_RDONLY, &dbblock, FALSE, TRUE)))
- DEBUG(D_deliver|D_retry|D_route|D_hints_lookup)
- debug_printf("no retry data available\n");
+ else
+ {
+ /* If we have transaction-capable hintsdbs, open the retry db without
+ locking, and leave open for the transport process and for subsequent
+ deliveries. If the open fails, tag that explicitly for the transport but
+ retry the open next time around, in case it was created in the interim. */
+
+ if (continue_retry_db == (open_db *)-1)
+ continue_retry_db = NULL;
+
+ if (continue_retry_db)
+ dbm_file = continue_retry_db;
+ else if (!exim_lockfile_needed() && continue_transport)
+ {
+ dbm_file = dbfn_open_multi(US"retry", O_RDONLY, &dbblock);
+ continue_retry_db = dbm_file ? dbm_file : (open_db *)-1;
+ }
+ else
+ dbm_file = dbfn_open(US"retry", O_RDONLY, &dbblock, FALSE, TRUE);
+
+ if (!dbm_file)
+ DEBUG(D_deliver|D_retry|D_route|D_hints_lookup)
+ debug_printf("no retry data available\n");
+ }
/* Scan the current batch of new addresses, to handle pipes, files and
autoreplies, and determine which others are ready for routing. */
/* The database is closed while routing is actually happening. Requests to
update it are put on a chain and all processed together at the end. */
- if (dbm_file) dbfn_close(dbm_file);
+ if (dbm_file && !continue_retry_db)
+ { dbfn_close(dbm_file); dbm_file = NULL; }
/* If queue_domains is set, we don't even want to try routing addresses in
those domains. During queue runs, queue_domains is forced to be unset.
}
} /* Continue with routing the next address. */
} /* Loop to process any child addresses that the routers created, and
- any rerouted addresses that got put back on the new chain. */
+ any rerouted addresses that got put back on the new chain. */
+if (dbm_file) /* Can only be continue_retry_db */
+ { dbfn_close_multi(continue_retry_db); continue_retry_db = dbm_file = NULL; }
/* Debugging: show the results of the routing */
uschar *continue_transport = NULL;
#ifndef COMPILE_UTILITY
open_db *continue_wait_db = NULL;
+open_db *continue_retry_db = NULL;
#endif
#ifndef DISABLE_ESMTP_LIMITS
unsigned continue_limit_mail = 0;
extern uschar *continue_transport; /* Transport for continued delivery */
#ifndef COMPILE_UTILITY
extern open_db *continue_wait_db; /* Hintsdb for wait-transport */
+extern open_db *continue_retry_db; /* Hintsdb for retries */
#endif
#ifndef DISABLE_ESMTP_LIMITS
extern unsigned continue_limit_mail; /* Peer advertised limit */
/* Open the retry database, giving up if there isn't one. Otherwise, search for
the retry records, and then close the database again. */
-if (!(dbm_file = dbfn_open(US"retry", O_RDONLY, &dbblock, FALSE, TRUE)))
+if (!continue_retry_db)
+ dbm_file = dbfn_open(US"retry", O_RDONLY, &dbblock, FALSE, TRUE);
+else if ((dbm_file = continue_retry_db) == (open_db *)-1)
+ dbm_file = NULL;
+
+if (!dbm_file)
{
DEBUG(D_deliver|D_retry|D_hints_lookup)
debug_printf("no retry data available\n");
}
host_retry_record = dbfn_read(dbm_file, host_key);
message_retry_record = dbfn_read(dbm_file, message_key);
-dbfn_close(dbm_file);
+if (!continue_retry_db)
+ dbfn_close(dbm_file);
/* Ignore the data if it is too old - too long since it was written */
case (instead, passing back the next-id. But in case it does... */
if (continue_wait_db)
{ dbfn_close_multi(continue_wait_db); continue_wait_db = NULL; }
+if (continue_retry_db)
+ { dbfn_close_multi(continue_retry_db); continue_retry_db = NULL; }
#ifndef DISABLE_ESMTP_LIMITS
continue_limit_mail = peer_limit_mail;