static int internal_transaction_started; /* to issue table lock command a transaction
has been started internally */
static int select_in_transaction = 0; /* non 0 if select query is in transaction */
+static int extended_select = 0; /* non 0 if extended mode */
static int in_progress = 0;
static void (*pending_function)(PreparedStatementList *p, PreparedStatement *statement) = NULL;
REPLICATION = 0;
in_load_balance = 1;
select_in_transaction = 1;
+ extended_select = 0;
}
/*
REPLICATION = 0;
in_load_balance = 1;
select_in_transaction = 1;
+ extended_select = 1;
}
}
pending_function(&prepared_list, pending_prepared_stmt);
}
else if (kind == 'C' && select_in_transaction)
+ {
select_in_transaction = 0;
-
+ extended_select = 0;
+ }
/*
* Remove a pending function if a received message is not
* NoticeResponse.
{
int i, k;
int res1, res2;
+ int sync_secondary = 1;
char *p1;
/*
do_error_command(SECONDARY(backend), PROTO_MAJOR_V3);
}
select_in_transaction = 0;
+ if (extended_select)
+ {
+ sync_secondary = 0;
+ extended_select = 0;
+ }
}
for (i = 0;i < backend->num;i++)
* it by itself. Moreover we do not need it in non-extend mode.
* At this point we regard it is not harmfull since error resonse
* will not be sent too frequently.
+
+ * We observed a process stall at the synchronous
+ * point (Line 370 of this code) in this situation:
+ * 1. replicate_select = false
+ * 2. do extended select for MASTER, and get some error
+ * 3. do_error_command for SECONDARY,
+ * 4. send Sync to both MASTER and SECONDARY
+ * 5. SECONDARY returns something but MASTER doesn't.
+ * 6. then pgpool stalls at pool_read on #370 to wait
+ * for a response from MASTER.
+ *
+ * To avoid this situation, we introduced a variable
+ * 'extended_select' so that pgpool sends Sync only to
+ * MASTER when the query is in extended mode.
*/
pool_write(cp, "S", 1);
res1 = htonl(4);
return POOL_END;
}
- if (!DUAL_MODE)
+ if (!DUAL_MODE || sync_secondary == 0)
break;
}