|
@@ -205,6 +205,8 @@ static int check_cancel( sync_vars_t *svars );
|
|
|
#define ST_SELECTED (1<<10)
|
|
|
#define ST_DID_EXPUNGE (1<<11)
|
|
|
#define ST_CLOSING (1<<12)
|
|
|
+#define ST_CONFIRMED (1<<13)
|
|
|
+#define ST_PRESENT (1<<14)
|
|
|
|
|
|
|
|
|
static void
|
|
@@ -923,7 +925,20 @@ load_state( sync_vars_t *svars )
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
+static void
|
|
|
+delete_state( sync_vars_t *svars )
|
|
|
+{
|
|
|
+ unlink( svars->nname );
|
|
|
+ unlink( svars->jname );
|
|
|
+ if (unlink( svars->dname ) || unlink( svars->lname )) {
|
|
|
+ sys_error( "Error: channel %s: sync state cannot be deleted", svars->chan->name );
|
|
|
+ svars->ret = SYNC_FAIL;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static void box_confirmed( int sts, void *aux );
|
|
|
+static void box_confirmed2( sync_vars_t *svars, int t );
|
|
|
+static void box_deleted( int sts, void *aux );
|
|
|
static void box_created( int sts, void *aux );
|
|
|
static void box_opened( int sts, void *aux );
|
|
|
static void box_opened2( sync_vars_t *svars, int t );
|
|
@@ -988,7 +1003,7 @@ sync_boxes( store_t *ctx[], const char *names[], int present[], channel_conf_t *
|
|
|
for (t = 0; ; t++) {
|
|
|
info( "Opening %s box %s...\n", str_ms[t], svars->orig_name[t] );
|
|
|
if (present[t] == BOX_ABSENT)
|
|
|
- box_confirmed( DRV_BOX_BAD, AUX );
|
|
|
+ box_confirmed2( svars, t );
|
|
|
else
|
|
|
svars->drv[t]->open_box( ctx[t], box_confirmed, AUX );
|
|
|
if (t || check_cancel( svars ))
|
|
@@ -1008,16 +1023,80 @@ box_confirmed( int sts, void *aux )
|
|
|
if (check_cancel( svars ))
|
|
|
return;
|
|
|
|
|
|
- if (sts == DRV_BOX_BAD) {
|
|
|
- if (!(svars->chan->ops[t] & OP_CREATE)) {
|
|
|
- box_opened( sts, aux );
|
|
|
+ if (sts == DRV_OK)
|
|
|
+ svars->state[t] |= ST_PRESENT;
|
|
|
+ box_confirmed2( svars, t );
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+box_confirmed2( sync_vars_t *svars, int t )
|
|
|
+{
|
|
|
+ svars->state[t] |= ST_CONFIRMED;
|
|
|
+ if (!(svars->state[1-t] & ST_CONFIRMED))
|
|
|
+ return;
|
|
|
+
|
|
|
+ sync_ref( svars );
|
|
|
+ for (t = 0; ; t++) {
|
|
|
+ if (!(svars->state[t] & ST_PRESENT)) {
|
|
|
+ if (!(svars->state[1-t] & ST_PRESENT)) {
|
|
|
+ if (!svars->existing) {
|
|
|
+ error( "Error: channel %s: both master %s and slave %s cannot be opened.\n",
|
|
|
+ svars->chan->name, svars->orig_name[M], svars->orig_name[S] );
|
|
|
+ bail:
|
|
|
+ svars->ret = SYNC_FAIL;
|
|
|
+ } else {
|
|
|
+ /* This can legitimately happen if a deletion propagation was interrupted.
|
|
|
+ * We have no place to record this transaction, so we just assume it.
|
|
|
+ * Of course this bears the danger of clearing the state if both mailboxes
|
|
|
+ * temorarily cannot be opened for some weird reason (while the stores can). */
|
|
|
+ delete_state( svars );
|
|
|
+ }
|
|
|
+ done:
|
|
|
+ sync_bail( svars );
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if (svars->existing) {
|
|
|
+ if (!(svars->chan->ops[1-t] & OP_REMOVE)) {
|
|
|
+ error( "Error: channel %s: %s %s cannot be opened.\n",
|
|
|
+ svars->chan->name, str_ms[t], svars->orig_name[t] );
|
|
|
+ goto bail;
|
|
|
+ }
|
|
|
+ if (svars->drv[1-t]->confirm_box_empty( svars->ctx[1-t] ) != DRV_OK) {
|
|
|
+ warn( "Warning: channel %s: %s %s cannot be opened and %s %s not empty.\n",
|
|
|
+ svars->chan->name, str_ms[t], svars->orig_name[t], str_ms[1-t], svars->orig_name[1-t] );
|
|
|
+ goto done;
|
|
|
+ }
|
|
|
+ info( "Deleting %s %s...\n", str_ms[1-t], svars->orig_name[1-t] );
|
|
|
+ svars->drv[1-t]->delete_box( svars->ctx[1-t], box_deleted, INV_AUX );
|
|
|
+ } else {
|
|
|
+ if (!(svars->chan->ops[t] & OP_CREATE)) {
|
|
|
+ box_opened( DRV_BOX_BAD, AUX );
|
|
|
+ } else {
|
|
|
+ info( "Creating %s %s...\n", str_ms[t], svars->orig_name[t] );
|
|
|
+ svars->drv[t]->create_box( svars->ctx[t], box_created, AUX );
|
|
|
+ }
|
|
|
+ }
|
|
|
} else {
|
|
|
- info( "Creating %s %s...\n", str_ms[t], svars->orig_name[t] );
|
|
|
- svars->drv[t]->create_box( svars->ctx[t], box_created, AUX );
|
|
|
+ box_opened2( svars, t );
|
|
|
}
|
|
|
- } else {
|
|
|
- box_opened2( svars, t );
|
|
|
+ if (t || check_cancel( svars ))
|
|
|
+ break;
|
|
|
}
|
|
|
+ sync_deref( svars );
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+box_deleted( int sts, void *aux )
|
|
|
+{
|
|
|
+ DECL_SVARS;
|
|
|
+
|
|
|
+ if (check_ret( sts, aux ))
|
|
|
+ return;
|
|
|
+ INIT_SVARS(aux);
|
|
|
+
|
|
|
+ delete_state( svars );
|
|
|
+ svars->drv[t]->finish_delete_box( svars->ctx[t] );
|
|
|
+ sync_bail( svars );
|
|
|
}
|
|
|
|
|
|
static void
|