fe-misc.c

来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 1,131 行 · 第 1/2 页

C
1,131
字号
	 * If the buffer is fairly full, enlarge it. We need to be able to	 * enlarge the buffer in case a single message exceeds the initial	 * buffer size.  We enlarge before filling the buffer entirely so as	 * to avoid asking the kernel for a partial packet. The magic constant	 * here should be large enough for a TCP packet or Unix pipe	 * bufferload.	8K is the usual pipe buffer size, so...	 */	if (conn->inBufSize - conn->inEnd < 8192)	{		if (pqCheckInBufferSpace(conn->inEnd + 8192, conn))		{			/*			 * We don't insist that the enlarge worked, but we need some			 * room			 */			if (conn->inBufSize - conn->inEnd < 100)				return -1;		/* errorMessage already set */		}	}	/* OK, try to read some data */retry3:	nread = pqsecure_read(conn, conn->inBuffer + conn->inEnd,						  conn->inBufSize - conn->inEnd);	if (nread < 0)	{		if (SOCK_ERRNO == EINTR)			goto retry3;		/* Some systems return EAGAIN/EWOULDBLOCK for no data */#ifdef EAGAIN		if (SOCK_ERRNO == EAGAIN)			return someread;#endif#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))		if (SOCK_ERRNO == EWOULDBLOCK)			return someread;#endif		/* We might get ECONNRESET here if using TCP and backend died */#ifdef ECONNRESET		if (SOCK_ERRNO == ECONNRESET)			goto definitelyFailed;#endif		printfPQExpBuffer(&conn->errorMessage,			   libpq_gettext("could not receive data from server: %s\n"),						SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));		return -1;	}	if (nread > 0)	{		conn->inEnd += nread;		/*		 * Hack to deal with the fact that some kernels will only give us		 * back 1 packet per recv() call, even if we asked for more and		 * there is more available.  If it looks like we are reading a		 * long message, loop back to recv() again immediately, until we		 * run out of data or buffer space.  Without this, the		 * block-and-restart behavior of libpq's higher levels leads to		 * O(N^2) performance on long messages.		 *		 * Since we left-justified the data above, conn->inEnd gives the		 * amount of data already read in the current message.	We		 * consider the message "long" once we have acquired 32k ...		 */		if (conn->inEnd > 32768 &&			(conn->inBufSize - conn->inEnd) >= 8192)		{			someread = 1;			goto retry3;		}		return 1;	}	if (someread)		return 1;				/* got a zero read after successful tries */	/*	 * A return value of 0 could mean just that no data is now available,	 * or it could mean EOF --- that is, the server has closed the	 * connection. Since we have the socket in nonblock mode, the only way	 * to tell the difference is to see if select() is saying that the	 * file is ready. Grumble.	Fortunately, we don't expect this path to	 * be taken much, since in normal practice we should not be trying to	 * read data unless the file selected for reading already.	 *	 * In SSL mode it's even worse: SSL_read() could say WANT_READ and then	 * data could arrive before we make the pqReadReady() test.  So we	 * must play dumb and assume there is more data, relying on the SSL	 * layer to detect true EOF.	 */#ifdef USE_SSL	if (conn->ssl)		return 0;#endif	switch (pqReadReady(conn))	{		case 0:			/* definitely no data available */			return 0;		case 1:			/* ready for read */			break;		default:			goto definitelyFailed;	}	/*	 * Still not sure that it's EOF, because some data could have just	 * arrived.	 */retry4:	nread = pqsecure_read(conn, conn->inBuffer + conn->inEnd,						  conn->inBufSize - conn->inEnd);	if (nread < 0)	{		if (SOCK_ERRNO == EINTR)			goto retry4;		/* Some systems return EAGAIN/EWOULDBLOCK for no data */#ifdef EAGAIN		if (SOCK_ERRNO == EAGAIN)			return 0;#endif#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))		if (SOCK_ERRNO == EWOULDBLOCK)			return 0;#endif		/* We might get ECONNRESET here if using TCP and backend died */#ifdef ECONNRESET		if (SOCK_ERRNO == ECONNRESET)			goto definitelyFailed;#endif		printfPQExpBuffer(&conn->errorMessage,			   libpq_gettext("could not receive data from server: %s\n"),						SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));		return -1;	}	if (nread > 0)	{		conn->inEnd += nread;		return 1;	}	/*	 * OK, we are getting a zero read even though select() says ready.	 * This means the connection has been closed.  Cope.	 */definitelyFailed:	printfPQExpBuffer(&conn->errorMessage,					  libpq_gettext(							"server closed the connection unexpectedly\n"			   "\tThis probably means the server terminated abnormally\n"						 "\tbefore or while processing the request.\n"));	conn->status = CONNECTION_BAD;		/* No more connection to backend */	pqsecure_close(conn);	closesocket(conn->sock);	conn->sock = -1;	return -1;}/* * pqSendSome: send data waiting in the output buffer. * * len is how much to try to send (typically equal to outCount, but may * be less). * * Return 0 on success, -1 on failure and 1 when not all data could be sent * because the socket would block and the connection is non-blocking. */static intpqSendSome(PGconn *conn, int len){	char	   *ptr = conn->outBuffer;	int			remaining = conn->outCount;	int			result = 0;	if (conn->sock < 0)	{		printfPQExpBuffer(&conn->errorMessage,						  libpq_gettext("connection not open\n"));		return -1;	}	/* while there's still data to send */	while (len > 0)	{		int			sent;		char		sebuf[256];		sent = pqsecure_write(conn, ptr, len);		if (sent < 0)		{			/*			 * Anything except EAGAIN/EWOULDBLOCK/EINTR is trouble. If			 * it's EPIPE or ECONNRESET, assume we've lost the backend			 * connection permanently.			 */			switch (SOCK_ERRNO)			{#ifdef EAGAIN				case EAGAIN:					break;#endif#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))				case EWOULDBLOCK:					break;#endif				case EINTR:					continue;				case EPIPE:#ifdef ECONNRESET				case ECONNRESET:#endif					printfPQExpBuffer(&conn->errorMessage,									  libpq_gettext(							"server closed the connection unexpectedly\n"													"\tThis probably means the server terminated abnormally\n"						 "\tbefore or while processing the request.\n"));					/*					 * We used to close the socket here, but that's a bad					 * idea since there might be unread data waiting					 * (typically, a NOTICE message from the backend					 * telling us it's committing hara-kiri...).  Leave					 * the socket open until pqReadData finds no more data					 * can be read.  But abandon attempt to send data.					 */					conn->outCount = 0;					return -1;				default:					printfPQExpBuffer(&conn->errorMessage,					libpq_gettext("could not send data to server: %s\n"),						SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));					/* We don't assume it's a fatal error... */					conn->outCount = 0;					return -1;			}		}		else		{			ptr += sent;			len -= sent;			remaining -= sent;		}		if (len > 0)		{			/*			 * We didn't send it all, wait till we can send more.			 *			 * If the connection is in non-blocking mode we don't wait, but			 * return 1 to indicate that data is still pending.			 */			if (pqIsnonblocking(conn))			{				result = 1;				break;			}			/*			 * There are scenarios in which we can't send data because the			 * communications channel is full, but we cannot expect the server			 * to clear the channel eventually because it's blocked trying to			 * send data to us.  (This can happen when we are sending a large			 * amount of COPY data, and the server has generated lots of			 * NOTICE responses.)  To avoid a deadlock situation, we must be			 * prepared to accept and buffer incoming data before we try			 * again.  Furthermore, it is possible that such incoming data			 * might not arrive until after we've gone to sleep.  Therefore,			 * we wait for either read ready or write ready.			 */			if (pqReadData(conn) < 0)			{				result = -1;	/* error message already set up */				break;			}			if (pqWait(TRUE, TRUE, conn))			{				result = -1;				break;			}		}	}	/* shift the remaining contents of the buffer */	if (remaining > 0)		memmove(conn->outBuffer, ptr, remaining);	conn->outCount = remaining;	return result;}/* * pqFlush: send any data waiting in the output buffer * * Return 0 on success, -1 on failure and 1 when not all data could be sent * because the socket would block and the connection is non-blocking. */intpqFlush(PGconn *conn){	if (conn->Pfdebug)		fflush(conn->Pfdebug);	if (conn->outCount > 0)		return pqSendSome(conn, conn->outCount);	return 0;}/* * pqWait: wait until we can read or write the connection socket * * JAB: If SSL enabled and used and forRead, buffered bytes short-circuit the * call to select(). * * We also stop waiting and return if the kernel flags an exception condition * on the socket.  The actual error condition will be detected and reported * when the caller tries to read or write the socket. */intpqWait(int forRead, int forWrite, PGconn *conn){	return pqWaitTimed(forRead, forWrite, conn, (time_t) -1);}/* * pqWaitTimed: wait, but not past finish_time. * * If finish_time is exceeded then we return failure (EOF).  This is like * the response for a kernel exception because we don't want the caller * to try to read/write in that case. * * finish_time = ((time_t) -1) disables the wait limit. */intpqWaitTimed(int forRead, int forWrite, PGconn *conn, time_t finish_time){	int			result;	result = pqSocketCheck(conn, forRead, forWrite, finish_time);	if (result < 0)		return EOF;				/* errorMessage is already set */	if (result == 0)	{		printfPQExpBuffer(&conn->errorMessage,						  libpq_gettext("timeout expired\n"));		return EOF;	}	return 0;}/* * pqReadReady: is select() saying the file is ready to read? * Returns -1 on failure, 0 if not ready, 1 if ready. */intpqReadReady(PGconn *conn){	return pqSocketCheck(conn, 1, 0, (time_t) 0);}/* * pqWriteReady: is select() saying the file is ready to write? * Returns -1 on failure, 0 if not ready, 1 if ready. */intpqWriteReady(PGconn *conn){	return pqSocketCheck(conn, 0, 1, (time_t) 0);}/* * Checks a socket, using poll or select, for data to be read, written, * or both.  Returns >0 if one or more conditions are met, 0 if it timed * out, -1 if an error occurred. * * If SSL is in use, the SSL buffer is checked prior to checking the socket * for read data directly. */static intpqSocketCheck(PGconn *conn, int forRead, int forWrite, time_t end_time){	int			result;	if (!conn)		return -1;	if (conn->sock < 0)	{		printfPQExpBuffer(&conn->errorMessage,						  libpq_gettext("socket not open\n"));		return -1;	}#ifdef USE_SSL	/* Check for SSL library buffering read bytes */	if (forRead && conn->ssl && SSL_pending(conn->ssl) > 0)	{		/* short-circuit the select */		return 1;	}#endif	/* We will retry as long as we get EINTR */	do		result = pqSocketPoll(conn->sock, forRead, forWrite, end_time);	while (result < 0 && SOCK_ERRNO == EINTR);	if (result < 0)	{		char		sebuf[256];		printfPQExpBuffer(&conn->errorMessage,						  libpq_gettext("select() failed: %s\n"),						SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf)));	}	return result;}/* * Check a file descriptor for read and/or write data, possibly waiting. * If neither forRead nor forWrite are set, immediately return a timeout * condition (without waiting).  Return >0 if condition is met, 0 * if a timeout occurred, -1 if an error or interrupt occurred. * * Timeout is infinite if end_time is -1.  Timeout is immediate (no blocking) * if end_time is 0 (or indeed, any time before now). */static intpqSocketPoll(int sock, int forRead, int forWrite, time_t end_time){	/* We use poll(2) if available, otherwise select(2) */#ifdef HAVE_POLL	struct pollfd input_fd;	int			timeout_ms;	if (!forRead && !forWrite)		return 0;	input_fd.fd = sock;	input_fd.events = POLLERR;	input_fd.revents = 0;	if (forRead)		input_fd.events |= POLLIN;	if (forWrite)		input_fd.events |= POLLOUT;	/* Compute appropriate timeout interval */	if (end_time == ((time_t) -1))		timeout_ms = -1;	else	{		time_t		now = time(NULL);		if (end_time > now)			timeout_ms = (end_time - now) * 1000;		else			timeout_ms = 0;	}	return poll(&input_fd, 1, timeout_ms);#else							/* !HAVE_POLL */	fd_set		input_mask;	fd_set		output_mask;	fd_set		except_mask;	struct timeval timeout;	struct timeval *ptr_timeout;	if (!forRead && !forWrite)		return 0;	FD_ZERO(&input_mask);	FD_ZERO(&output_mask);	FD_ZERO(&except_mask);	if (forRead)		FD_SET(sock, &input_mask);	if (forWrite)		FD_SET(sock, &output_mask);	FD_SET(sock, &except_mask);	/* Compute appropriate timeout interval */	if (end_time == ((time_t) -1))		ptr_timeout = NULL;	else	{		time_t		now = time(NULL);		if (end_time > now)			timeout.tv_sec = end_time - now;		else			timeout.tv_sec = 0;		timeout.tv_usec = 0;		ptr_timeout = &timeout;	}	return select(sock + 1, &input_mask, &output_mask,				  &except_mask, ptr_timeout);#endif   /* HAVE_POLL */}/* * A couple of "miscellaneous" multibyte related functions. They used * to be in fe-print.c but that file is doomed. *//* * returns the byte length of the word beginning s, using the * specified encoding. */intPQmblen(const unsigned char *s, int encoding){	return (pg_encoding_mblen(encoding, s));}/* * Get encoding id from environment variable PGCLIENTENCODING. */intPQenv2encoding(void){	char	   *str;	int			encoding = PG_SQL_ASCII;	str = getenv("PGCLIENTENCODING");	if (str && *str != '\0')		encoding = pg_char_to_encoding(str);	return (encoding);}#ifdef ENABLE_NLSchar *libpq_gettext(const char *msgid){	static int	already_bound = 0;	if (!already_bound)	{		already_bound = 1;		bindtextdomain("libpq", LOCALEDIR);	}	return dgettext("libpq", msgid);}#endif   /* ENABLE_NLS */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?