deal sensibly with permanent errors

don't retry dead Stores for every Channel.

this also introduces a state for transient errors (specifically, connect
failures), but this is currently unused.
This commit is contained in:
Oswald Buddenhagen 2015-01-04 00:39:06 +01:00
parent 5f265ad7da
commit 74c78c70b9
4 changed files with 42 additions and 18 deletions

View File

@ -27,6 +27,10 @@
typedef struct driver driver_t; typedef struct driver driver_t;
#define FAIL_TEMP 0 /* Retry immediately (also: no error) */
#define FAIL_WAIT 1 /* Retry after some time (if at all) */
#define FAIL_FINAL 2 /* Don't retry until store reconfiguration */
typedef struct store_conf { typedef struct store_conf {
struct store_conf *next; struct store_conf *next;
char *name; char *name;
@ -37,6 +41,7 @@ typedef struct store_conf {
const char *trash; const char *trash;
uint max_size; /* off_t is overkill */ uint max_size; /* off_t is overkill */
char trash_remote_new, trash_only_new; char trash_remote_new, trash_only_new;
char failed;
} store_conf_t; } store_conf_t;
/* For message->flags */ /* For message->flags */

View File

@ -1508,7 +1508,13 @@ static void imap_open_store_finalize( imap_store_t * );
#ifdef HAVE_LIBSSL #ifdef HAVE_LIBSSL
static void imap_open_store_ssl_bail( imap_store_t * ); static void imap_open_store_ssl_bail( imap_store_t * );
#endif #endif
static void imap_open_store_bail( imap_store_t * ); static void imap_open_store_bail( imap_store_t *, int );
static void
imap_open_store_bad( void *aux )
{
imap_open_store_bail( (imap_store_t *)aux, FAIL_TEMP );
}
static void static void
imap_open_store( store_conf_t *conf, const char *label, imap_open_store( store_conf_t *conf, const char *label,
@ -1540,7 +1546,7 @@ imap_open_store( store_conf_t *conf, const char *label,
ctx->delimiter = 0; ctx->delimiter = 0;
ctx->callbacks.imap_open = cb; ctx->callbacks.imap_open = cb;
ctx->callback_aux = aux; ctx->callback_aux = aux;
set_bad_callback( &ctx->gen, (void (*)(void *))imap_open_store_bail, ctx ); set_bad_callback( &ctx->gen, imap_open_store_bad, ctx );
imap_open_store_namespace( ctx ); imap_open_store_namespace( ctx );
return; return;
} }
@ -1551,7 +1557,7 @@ imap_open_store( store_conf_t *conf, const char *label,
ctx->ref_count = 1; ctx->ref_count = 1;
ctx->callbacks.imap_open = cb; ctx->callbacks.imap_open = cb;
ctx->callback_aux = aux; ctx->callback_aux = aux;
set_bad_callback( &ctx->gen, (void (*)(void *))imap_open_store_bail, ctx ); set_bad_callback( &ctx->gen, imap_open_store_bad, ctx );
ctx->in_progress_append = &ctx->in_progress; ctx->in_progress_append = &ctx->in_progress;
ctx->pending_append = &ctx->pending; ctx->pending_append = &ctx->pending;
@ -1571,7 +1577,7 @@ imap_open_store_connected( int ok, void *aux )
#endif #endif
if (!ok) if (!ok)
imap_open_store_bail( ctx ); imap_open_store_bail( ctx, FAIL_WAIT );
#ifdef HAVE_LIBSSL #ifdef HAVE_LIBSSL
else if (srvc->ssl_type == SSL_IMAPS) else if (srvc->ssl_type == SSL_IMAPS)
socket_start_tls( &ctx->conn, imap_open_store_tlsstarted1 ); socket_start_tls( &ctx->conn, imap_open_store_tlsstarted1 );
@ -1602,7 +1608,7 @@ static void
imap_open_store_p2( imap_store_t *ctx, struct imap_cmd *cmd ATTR_UNUSED, int response ) imap_open_store_p2( imap_store_t *ctx, struct imap_cmd *cmd ATTR_UNUSED, int response )
{ {
if (response == RESP_NO) if (response == RESP_NO)
imap_open_store_bail( ctx ); imap_open_store_bail( ctx, FAIL_FINAL );
else if (response == RESP_OK) else if (response == RESP_OK)
imap_open_store_authenticate( ctx ); imap_open_store_authenticate( ctx );
} }
@ -1623,7 +1629,7 @@ imap_open_store_authenticate( imap_store_t *ctx )
return; return;
} else { } else {
error( "IMAP error: SSL support not available\n" ); error( "IMAP error: SSL support not available\n" );
imap_open_store_bail( ctx ); imap_open_store_bail( ctx, FAIL_FINAL );
return; return;
} }
} }
@ -1633,7 +1639,7 @@ imap_open_store_authenticate( imap_store_t *ctx )
#ifdef HAVE_LIBSSL #ifdef HAVE_LIBSSL
if (srvc->ssl_type == SSL_STARTTLS) { if (srvc->ssl_type == SSL_STARTTLS) {
error( "IMAP error: SSL support not available\n" ); error( "IMAP error: SSL support not available\n" );
imap_open_store_bail( ctx ); imap_open_store_bail( ctx, FAIL_FINAL );
return; return;
} }
#endif #endif
@ -1646,7 +1652,7 @@ static void
imap_open_store_authenticate_p2( imap_store_t *ctx, struct imap_cmd *cmd ATTR_UNUSED, int response ) imap_open_store_authenticate_p2( imap_store_t *ctx, struct imap_cmd *cmd ATTR_UNUSED, int response )
{ {
if (response == RESP_NO) if (response == RESP_NO)
imap_open_store_bail( ctx ); imap_open_store_bail( ctx, FAIL_FINAL );
else if (response == RESP_OK) else if (response == RESP_OK)
socket_start_tls( &ctx->conn, imap_open_store_tlsstarted2 ); socket_start_tls( &ctx->conn, imap_open_store_tlsstarted2 );
} }
@ -1666,7 +1672,7 @@ static void
imap_open_store_authenticate_p3( imap_store_t *ctx, struct imap_cmd *cmd ATTR_UNUSED, int response ) imap_open_store_authenticate_p3( imap_store_t *ctx, struct imap_cmd *cmd ATTR_UNUSED, int response )
{ {
if (response == RESP_NO) if (response == RESP_NO)
imap_open_store_bail( ctx ); imap_open_store_bail( ctx, FAIL_FINAL );
else if (response == RESP_OK) else if (response == RESP_OK)
imap_open_store_authenticate2( ctx ); imap_open_store_authenticate2( ctx );
} }
@ -1872,7 +1878,7 @@ do_sasl_auth( imap_store_t *ctx, struct imap_cmd *cmdp ATTR_UNUSED, const char *
return socket_write( &ctx->conn, iov, iovcnt ); return socket_write( &ctx->conn, iov, iovcnt );
bail: bail:
imap_open_store_bail( ctx ); imap_open_store_bail( ctx, FAIL_FINAL );
return -1; return -1;
} }
@ -1996,14 +2002,14 @@ imap_open_store_authenticate2( imap_store_t *ctx )
error( "IMAP error: server supports no acceptable authentication mechanism\n" ); error( "IMAP error: server supports no acceptable authentication mechanism\n" );
bail: bail:
imap_open_store_bail( ctx ); imap_open_store_bail( ctx, FAIL_FINAL );
} }
static void static void
imap_open_store_authenticate2_p2( imap_store_t *ctx, struct imap_cmd *cmd ATTR_UNUSED, int response ) imap_open_store_authenticate2_p2( imap_store_t *ctx, struct imap_cmd *cmd ATTR_UNUSED, int response )
{ {
if (response == RESP_NO) if (response == RESP_NO)
imap_open_store_bail( ctx ); imap_open_store_bail( ctx, FAIL_FINAL );
else if (response == RESP_OK) else if (response == RESP_OK)
imap_open_store_namespace( ctx ); imap_open_store_namespace( ctx );
} }
@ -2030,7 +2036,7 @@ static void
imap_open_store_namespace_p2( imap_store_t *ctx, struct imap_cmd *cmd ATTR_UNUSED, int response ) imap_open_store_namespace_p2( imap_store_t *ctx, struct imap_cmd *cmd ATTR_UNUSED, int response )
{ {
if (response == RESP_NO) { if (response == RESP_NO) {
imap_open_store_bail( ctx ); imap_open_store_bail( ctx, FAIL_FINAL );
} else if (response == RESP_OK) { } else if (response == RESP_OK) {
ctx->got_namespace = 1; ctx->got_namespace = 1;
imap_open_store_namespace2( ctx ); imap_open_store_namespace2( ctx );
@ -2061,7 +2067,7 @@ imap_open_store_namespace2( imap_store_t *ctx )
#endif #endif
imap_open_store_finalize( ctx ); imap_open_store_finalize( ctx );
} else { } else {
imap_open_store_bail( ctx ); imap_open_store_bail( ctx, FAIL_FINAL );
} }
} }
@ -2095,15 +2101,16 @@ imap_open_store_ssl_bail( imap_store_t *ctx )
{ {
/* This avoids that we try to send LOGOUT to an unusable socket. */ /* This avoids that we try to send LOGOUT to an unusable socket. */
socket_close( &ctx->conn ); socket_close( &ctx->conn );
imap_open_store_bail( ctx ); imap_open_store_bail( ctx, FAIL_FINAL );
} }
#endif #endif
static void static void
imap_open_store_bail( imap_store_t *ctx ) imap_open_store_bail( imap_store_t *ctx, int failed )
{ {
void (*cb)( store_t *srv, void *aux ) = ctx->callbacks.imap_open; void (*cb)( store_t *srv, void *aux ) = ctx->callbacks.imap_open;
void *aux = ctx->callback_aux; void *aux = ctx->callback_aux;
ctx->gen.conf->failed = failed;
imap_cancel_store( &ctx->gen ); imap_cancel_store( &ctx->gen );
cb( 0, aux ); cb( 0, aux );
} }

View File

@ -126,16 +126,18 @@ maildir_join_path( const char *prefix, const char *box )
} }
static int static int
maildir_validate_path( const store_conf_t *conf ) maildir_validate_path( store_conf_t *conf )
{ {
struct stat st; struct stat st;
if (!conf->path) { if (!conf->path) {
error( "Maildir error: store '%s' has no Path\n", conf->name ); error( "Maildir error: store '%s' has no Path\n", conf->name );
conf->failed = FAIL_FINAL;
return -1; return -1;
} }
if (stat( conf->path, &st ) || !S_ISDIR(st.st_mode)) { if (stat( conf->path, &st ) || !S_ISDIR(st.st_mode)) {
error( "Maildir error: cannot open store '%s'\n", conf->path ); error( "Maildir error: cannot open store '%s'\n", conf->path );
conf->failed = FAIL_FINAL;
return -1; return -1;
} }
return 0; return 0;
@ -414,6 +416,7 @@ maildir_validate( const char *box, int create, maildir_store_t *ctx )
return DRV_BOX_BAD; return DRV_BOX_BAD;
if (make_box_dir( buf, bl )) { if (make_box_dir( buf, bl )) {
sys_error( "Maildir error: cannot create mailbox '%s'", box ); sys_error( "Maildir error: cannot create mailbox '%s'", box );
ctx->gen.conf->failed = FAIL_FINAL;
maildir_invoke_bad_callback( &ctx->gen ); maildir_invoke_bad_callback( &ctx->gen );
return DRV_CANCELED; return DRV_CANCELED;
} }

View File

@ -601,9 +601,17 @@ sync_chans( main_vars_t *mvars, int ent )
merge_actions( mvars->chan, mvars->ops, XOP_HAVE_REMOVE, OP_REMOVE, 0 ); merge_actions( mvars->chan, mvars->ops, XOP_HAVE_REMOVE, OP_REMOVE, 0 );
merge_actions( mvars->chan, mvars->ops, XOP_HAVE_EXPUNGE, OP_EXPUNGE, 0 ); merge_actions( mvars->chan, mvars->ops, XOP_HAVE_EXPUNGE, OP_EXPUNGE, 0 );
mvars->state[M] = mvars->state[S] = ST_FRESH;
info( "Channel %s\n", mvars->chan->name ); info( "Channel %s\n", mvars->chan->name );
mvars->skip = mvars->cben = 0; mvars->skip = mvars->cben = 0;
for (t = 0; t < 2; t++) {
if (mvars->chan->stores[t]->failed != FAIL_TEMP) {
info( "Skipping due to failed %s store %s.\n", str_ms[t], mvars->chan->stores[t]->name );
mvars->skip = 1;
}
}
if (mvars->skip)
goto next2;
mvars->state[M] = mvars->state[S] = ST_FRESH;
if (mvars->chan->stores[M]->driver->flags & mvars->chan->stores[S]->driver->flags & DRV_VERBOSE) if (mvars->chan->stores[M]->driver->flags & mvars->chan->stores[S]->driver->flags & DRV_VERBOSE)
labels[M] = "M: ", labels[S] = "S: "; labels[M] = "M: ", labels[S] = "S: ";
else else
@ -694,6 +702,7 @@ sync_chans( main_vars_t *mvars, int ent )
free_string_list( mvars->cboxes ); free_string_list( mvars->cboxes );
free_string_list( mvars->boxes[M] ); free_string_list( mvars->boxes[M] );
free_string_list( mvars->boxes[S] ); free_string_list( mvars->boxes[S] );
next2:
if (mvars->all) { if (mvars->all) {
if (!(mvars->chan = mvars->chan->next)) if (!(mvars->chan = mvars->chan->next))
break; break;