Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtp (Exim 4.84_2) (envelope-from ) id 1av3lI-0004Sj-MC for pgsql-interfaces@arkaria.postgresql.org; Tue, 26 Apr 2016 14:14:48 +0000 Received: from localhost ([127.0.0.1] helo=postgresql.org) by malur.postgresql.org with smtp (Exim 4.84_2) (envelope-from ) id 1av3lI-0003Su-8y for pgsql-interfaces@arkaria.postgresql.org; Tue, 26 Apr 2016 14:14:48 +0000 Received: from makus.postgresql.org ([2001:4800:1501:1::229]) by malur.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA384:256) (Exim 4.84_2) (envelope-from ) id 1av3kx-0002pL-Sx for pgsql-interfaces@postgresql.org; Tue, 26 Apr 2016 14:14:28 +0000 Received: from smtprelay0015.b.hostedemail.com ([64.98.42.15] helo=smtprelay.b.hostedemail.com) by makus.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA384:256) (Exim 4.84_2) (envelope-from ) id 1av3ku-0005eM-HS for pgsql-interfaces@postgresql.org; Tue, 26 Apr 2016 14:14:26 +0000 Received: from filter.hostedemail.com (10.5.19.248.rfc1918.com [10.5.19.248]) by smtprelay03.b.hostedemail.com (Postfix) with ESMTP id 14E0B1A7410; Tue, 26 Apr 2016 14:14:18 +0000 (UTC) X-Session-Marker: 7762636C6179406D6F7272697362622E6E6574 X-Spam-Summary: 42,3.5,0,,d41d8cd98f00b204,william.b.clay@acm.org,:::,RULES_HIT:1:2:41:355:379:599:854:857:960:973:982:988:989:1256:1260:1261:1277:1311:1313:1314:1345:1359:1381:1437:1515:1516:1518:1593:1594:1605:1683:1718:1730:1747:1777:1792:1801:2198:2199:2393:2553:2559:2562:2689:2731:2741:2900:2902:2914:3138:3139:3140:3141:3142:3865:3866:3867:3868:3870:3871:3872:3873:3874:4043:4052:4250:4605:5007:6117:6119:6261:6299:7652:7903:7904:8957:9121:9201:10004:10848:11026:11232:11473:11658:11914:12043:12295:12296:12438:12517:12519:12740:13161:13181:13209:13229:13868:14096:14097:14685:21080:21324:21433:30012:30037:30051:30054:30069:30070:30090:30091,0,RBL:none,CacheIP:none,Bayesian:0.5,0.5,0.5,Netcheck:none,DomainCache:0,MSF:not bulk,SPF:fp,MSBL:0,DNSBL:none,Custom_rules:0:0:0,LFtime:3,LUA_SUMMARY:none X-HE-Tag: bead60_7fb9fc0b8a44 X-Filterd-Recvd-Size: 10350 Received: from tomcat.italianaccent.com (host84-20-dynamic.27-79-r.retail.telecomitalia.it [79.27.20.84]) (Authenticated sender: wbclay@morrisbb.net) by omf12.b.hostedemail.com (Postfix) with ESMTPA; Tue, 26 Apr 2016 14:14:14 +0000 (UTC) Received: from [10.0.0.23] (host84-20-dynamic.27-79-r.retail.telecomitalia.it [79.27.20.84]) (using TLSv1 with cipher DHE-RSA-AES128-SHA (128/128 bits)) (Client did not present a certificate) (Authenticated sender: bill) by tomcat.italianaccent.com (Postfix) with ESMTPSA id 467BB613; Tue, 26 Apr 2016 16:14:13 +0200 (CEST) Subject: Re: Error: no connection to the server To: Marco Bambini , pgsql-interfaces@postgresql.org References: <30F13B2D-78EE-453F-AD3A-57BDA23AA19F@sqlabs.com> From: "William B. Clay" Message-ID: <76efa9df-ca28-59a6-35c6-2ff58210333c@acm.org> Date: Tue, 26 Apr 2016 16:13:56 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Thunderbird/45.0 MIME-Version: 1.0 In-Reply-To: <30F13B2D-78EE-453F-AD3A-57BDA23AA19F@sqlabs.com> Content-Type: text/plain; charset=windows-1252; format=flowed Content-Transfer-Encoding: 7bit X-Pg-Spam-Score: -1.2 (-) List-Archive: List-Help: List-ID: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: X-Mailing-List: pgsql-interfaces Precedence: bulk Sender: pgsql-interfaces-owner@postgresql.org On 04/25/2016 09:58 AM, Marco Bambini wrote: > I have a multithreaded C client and sometimes I receive the "no connection to the server" error message. > I haven't found any documentation about it and about how to fix this issue. Marco, what interface to PGSQL are you using? I haven't seen this exact message coming from from libpq, so I wonder if it's coming from an intermediate SQL library that is calling PostgreSQL. Presuming your client established a session with the server, then this probably means you've lost network connectivity (link down; server/service down; TCP session abandoned due to an inactivity timer somewhere). If your client is intended to be long-running and reliable, it needs to recognize and recover from such outages. Below is an example of insert-only code that has reliably recovered from the inevitable temporary outages in transatlantic Internet connectivity (not to mention scheduled and unscheduled server bounces) while running 7x24 for several years. Good luck, Bill Clay Modena, Italy ==== code snippets ==== The "lost connection" detection snippet: rc = pselect(maxfds, &rfds, &rfds, &rfds, NULL, &nousr2_smask); /* what woke us up? */ if (rc < -1 || rc > 2 || (rc == -1 && errno != EINTR && errno != EBADF)) { /* unexpected result from pselect(): die immediately */ motion_log(LOG_ERR, 1, "Unexpected pgwrite.c pselect() result=%d; PGSQL writer terminating", rc); pgwcnt.quit = PGSQL_TERM_FORCE; return; /* things are totally broken, give up */ } else if (errno == EBADF) { /* invalid FD means DBMS session died; attempt recovery */ if ( pgwrite_init() < 0 ) { /* unrecoverable error while awaiting session recovery; abort */ pgwcnt.quit = PGSQL_TERM_FORCE; return; } else { /* all transactions in flight failed; don't wait for them to complete */ qelem_last = NULL; } } else if (rc>0) { /* PGSQL operation completion: invite PGSQL client library to */ /* process any pending work back from server */ if (!PQconsumeInput(pgwcnt.conn)) { /* did we lose the DBMS connection? */ if (PQstatus(pgwcnt.conn) != PGSQL_CONNECTION_OK) { /* attempt to open new DBMS session */ if ( pgwrite_init() < 0 ) { /* unrecoverable error while awaiting session recovery; abort */ pgwcnt.quit = PGSQL_TERM_FORCE; return; } else { /* we lost all transactions in flight; don't expect them to clear */ qelem_last = NULL; } } else { /* not sure what went wrong, keep trying */ motion_log(LOG_ERR, 0, "PQconsumeInput failed, pgwrite.c: %s.", PQerrorMessage(pgwcnt.conn)); } } else { /* check result of just-completed operation */ The (re-)connection snippet: /** * * pgwrite_init: connect to PGSQL DBMS and PREPARE configured SQL statements * used for initial connection and recovery of broken sessions * * on entry: * SIGUSR2 should be masked; we restore it on exit * * pgwcnt.mutex NOT held, except startup, when queue always empty * * returns: -1 on unrecoverable error * 0 on successful first open attempt * +1 on successful open after failed sessions or open attempts * */ int pgwrite_init() { int ret = 0; // return value int retries = 0; // connection attempt count int qeaband = 0; // local count abandoned queue elements int i, j; int so_val; // getsockopt() parms socklen_t so_len = sizeof(so_val); struct context *cnt0 = cnt[0]; // for easy reference if (pgwcnt.conn) { /* clean up failed connection attempt or broken session */ motion_log(LOG_ERR, 0, "PGSQL database '%s' connection failed: %s", cnt0->conf.pgsql_db, PQerrorMessage(pgwcnt.conn)); pgwcnt.sessloss++; // increment lost session count retries++; PQfinish(pgwcnt.conn); pgwcnt.conn = NULL; } /* PGSQL writer timestamps are UTC, not local time */ setenv("PGTZ", "UTC", 1); pthread_sigmask(SIG_UNBLOCK, &usr2_smask, NULL); /* repeat DBMS session open attempt until success or termination order */ /* NB: PGSQL enum value CONNECTION_OK is redefined as PGSQL_CONNECTION_OK in motion.h */ while (PQstatus(pgwcnt.conn)!=PGSQL_CONNECTION_OK && pgwcnt.quitconf.pgsql_port); if ( !(pgwcnt.conn = PQconnectdbParams( (const char *[]) {"dbname", "host", "user", "password", "port", "sslmode", "application_name", "connect_timeout", "keepalives", "keepalives_idle", "keepalives_interval", "keepalives_count", NULL}, (const char *[]) {cnt0->conf.pgsql_db, cnt0->conf.pgsql_host, cnt0->conf.pgsql_user, cnt0->conf.pgsql_password, pstring, "disable", "motion", PGSQL_KEEPALIVE_QSECS, "1", PGSQL_KEEPALIVE_QSECS, PGSQL_KEEPALIVE_QSECS, "1", NULL}, 0)) ) { motion_log(LOG_CRIT, 0, "LOGIC ERROR: PQconnectdbParams returned NULL"); ret = -1; } /* * PQconnectdbParams() promptly detects lack of connectivity, but the * obvious recovery API, PQreset(), does not block after a failed * connection attempt (at least on my system), causing an infinite * loop. Thus, this less elegant recovery for a failed connection. */ if (PQstatus(pgwcnt.conn)!=PGSQL_CONNECTION_OK) { /* connection attempt failed; first time? */ if (!retries) { /* allow video threads to proceed , even if no DB connection */ if (pthread_mutex_unlock(&pgwcnt.mutex)) { motion_log(LOG_ERR, 1, "PGSQL mutex unlock 2 failed, pgwrite.c; aborting"); ret = -1; break; } motion_log(LOG_ERR, 0, "PGSQL attempting recovery of failed connect attempt: host '%s' database '%s' user '%s': %s", cnt0->conf.pgsql_host, cnt0->conf.pgsql_db, cnt0->conf.pgsql_user, PQerrorMessage(pgwcnt.conn)); pgwcnt.sessloss++; // increment lost session count } PQfinish(pgwcnt.conn); // gotta do this even for failed connections pgwcnt.conn = NULL; retries ++; /* if too many INSERTs queued while we retried, reduce queue */ qeaband += pgwrite_qflush(PGSQL_MAX_DISCONN_Q); /* is PGSQL transport via Unix socket? */ if (!getsockopt(PQsocket(pgwcnt.conn), SOL_SOCKET, SO_DOMAIN, &so_val, &so_len) && so_val == PF_LOCAL ) { /* yes, wait a while to retry */ sleep(PGSQL_KEEPALIVE_SECS); } else { /* no; we probably waited for connect_timeout, but just in case ... */ sleep(5); } } } /* we are here when a new DBMS session has opened or termination has been forced */ if (pgwcnt.conn && qeaband) { /* report work abandoned prior to session recovery */ motion_log(LOG_ERR, 0, "PGSQL writer abandoned %d inserts pending link recovery", qeaband); qeaband = 0; } /* unless forced termination, PREPARE all configured SQL statements */ if (pgwcnt.conn && pgwcnt.quit