pgpool2.git / summary / log / commit / refs

commit    cf4fb96434af5f3b861b563653ae35d13ce230b5
Author:   Toshihiro Kitagawa <kitagawa at sraoss.co.jp>
Date:     Fri Mar 19 11:39:36 2010 +0000

    Fix SimpleForwardToBackend() so that pgpool doesn't keep waiting
    for reply from a backend, when clients using the extended query
    protocol cause a command error such as bind error.
    
    This bug occur in raw mode or connection pool mode.
    This fix is, sending SYNC message to recover error after command error.


pool_process_query.c | 118 +++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 100 insertions(+), 18 deletions(-) diff --git a/pool_process_query.c b/pool_process_query.c index 987c57bed..41c3a2fca 100644 --- a/pool_process_query.c +++ b/pool_process_query.c @@ -68,6 +68,8 @@ static int is_cache_empty(POOL_CONNECTION *frontend, POOL_CONNECTION_POOL *backe static POOL_STATUS ParallelForwardToFrontend(char kind, POOL_CONNECTION *frontend, POOL_CONNECTION *backend, char *database, bool send_to_frontend); static void query_cache_register(char kind, POOL_CONNECTION *frontend, char *database, char *data, int data_len); static int extract_ntuples(char *message); +static bool is_panic_or_fatal_error(const char *message); +static POOL_STATUS send_sync_to_recover(POOL_CONNECTION *frontend, POOL_CONNECTION *backend); static int detect_error(POOL_CONNECTION *master, char *error_code, int major, char class, bool unread); static int detect_postmaster_down_error(POOL_CONNECTION *master, int major); @@ -1330,25 +1332,10 @@ POOL_STATUS SimpleForwardToFrontend(char kind, POOL_CONNECTION *frontend, POOL_C * the message and exit since the backend will close the * channel immediately. */ - for (;;) + if (is_panic_or_fatal_error(p)) { - char e; - - e = *p++; - if (e == '\0') - break; - - if (e == 'S' && (strcasecmp("PANIC", p) == 0 || strcasecmp("FATAL", p) == 0)) - { - pool_flush(frontend); - return POOL_END; - } - else - { - while (*p++) - ; - continue; - } + pool_flush(frontend); + return POOL_END; } if (select_in_transaction) @@ -1738,6 +1725,15 @@ POOL_STATUS SimpleForwardToBackend(char kind, POOL_CONNECTION *frontend, POOL_CO return POOL_END; if (pool_write_and_flush(frontend, p, len)) return POOL_END; + + if (kind1 == 'E') + { + if (is_panic_or_fatal_error(p)) + return POOL_END; + ret = send_sync_to_recover(frontend, MASTER(backend)); + if (ret != POOL_CONTINUE) + return ret; + } } } @@ -1770,6 +1766,15 @@ POOL_STATUS SimpleForwardToBackend(char kind, POOL_CONNECTION *frontend, POOL_CO return POOL_END; if (pool_write_and_flush(frontend, p, len)) return POOL_END; + + if (kind1 == 'E') + { + if (is_panic_or_fatal_error(p)) + return POOL_END; + ret = send_sync_to_recover(frontend, MASTER(backend)); + if (ret != POOL_CONTINUE) + return ret; + } } if (kind1 != 'N') @@ -4242,6 +4247,83 @@ static int extract_ntuples(char *message) return atoi(rows); } +/* + * Returns true if error message contains PANIC or FATAL. + * This function works for V3 only. + */ +static bool is_panic_or_fatal_error(const char *message) +{ + for (;;) + { + char id; + + id = *message++; + if (id == '\0') + break; + + if (id == 'S' && (strcasecmp("PANIC", message) == 0 || strcasecmp("FATAL", message) == 0)) + return true; + else + { + while (*message++) + ; + continue; + } + } + return false; +} + +/* + * Send a "Sync"(S) message to a backend in extended query + * protocol so that it accepts next command. + * This function is called in raw Mode or Connection Pool Mode. + */ +static POOL_STATUS send_sync_to_recover(POOL_CONNECTION *frontend, POOL_CONNECTION *backend) +{ + int res; + int ret; + int len; + int sendlen; + char kind; + char *p; + + pool_write(backend, "S", 1); + res = htonl(4); + if (pool_write_and_flush(backend, &res, sizeof(res)) < 0) + return POOL_END; + + /* + * We don't send "ReadyForQuery"(Z) message to frontend, + * because "Sync"(S) message is sent by pgpool. + */ + while ((ret = pool_read(backend, &kind, 1)) == 0) + { + pool_debug("send_sync_to_recover: kind from backend: %c", kind); + + if (pool_read(backend, &sendlen, sizeof(sendlen))) + return POOL_END; + len = ntohl(sendlen) - 4; + p = pool_read2(backend, len); + if (p == NULL) + return POOL_END; + + if (kind == 'Z') + break; + + if (pool_write(frontend, &kind, 1)) + return POOL_END; + if (pool_write(frontend, &sendlen, sizeof(sendlen))) + return POOL_END; + if (pool_write_and_flush(frontend, p, len)) + return POOL_END; + } + + if (ret != 0) + return POOL_END; + + return POOL_CONTINUE; +} + static int detect_postmaster_down_error(POOL_CONNECTION *backend, int major) { int r = detect_error(backend, ADMIN_SHUTDOWN_ERROR_CODE, major, 'E', false); [parent: c3d730107020]