Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit e6725d1

Browse files
committed
Add explicit buffering in backend libpq, to compensate for
buffering lost by not going through stdio anymore for client I/O.
1 parent 13c7c18 commit e6725d1

File tree

5 files changed

+195
-100
lines changed

5 files changed

+195
-100
lines changed

src/backend/commands/copy.c

+2-4
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
*
77
*
88
* IDENTIFICATION
9-
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.67 1999/01/17 06:18:15 momjian Exp $
9+
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.68 1999/01/23 22:27:26 tgl Exp $
1010
*
1111
*-------------------------------------------------------------------------
1212
*/
@@ -303,9 +303,7 @@ DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe,
303303
}
304304
else if (!from && !binary)
305305
{
306-
CopySendData("\\.\n",3,fp);
307-
if (IsUnderPostmaster)
308-
pq_flush();
306+
CopySendData("\\.\n",3,fp);
309307
}
310308
}
311309
}

src/backend/libpq/pqcomm.c

+126-52
Original file line numberDiff line numberDiff line change
@@ -5,39 +5,40 @@
55
*
66
* Copyright (c) 1994, Regents of the University of California
77
*
8-
* $Id: pqcomm.c,v 1.63 1999/01/17 06:18:26 momjian Exp $
8+
* $Id: pqcomm.c,v 1.64 1999/01/23 22:27:28 tgl Exp $
99
*
1010
*-------------------------------------------------------------------------
1111
*/
1212
/*
1313
* INTERFACE ROUTINES
14-
* pq_init - initialize libpq
14+
* pq_init - initialize libpq
1515
* pq_getport - return the PGPORT setting
1616
* pq_close - close input / output connections
1717
* pq_flush - flush pending output
18+
* pq_recvbuf - load some bytes into the input buffer
1819
* pq_getstr - get a null terminated string from connection
19-
* pq_getchar - get 1 character from connection
20-
* pq_peekchar - peek at first character in connection
20+
* pq_getchar - get 1 character from connection
21+
* pq_peekchar - peek at next character from connection
2122
* pq_getnchar - get n characters from connection, and null-terminate
2223
* pq_getint - get an integer from connection
23-
* pq_putchar - send 1 character to connection
24+
* pq_putchar - send 1 character to connection
2425
* pq_putstr - send a null terminated string to connection
2526
* pq_putnchar - send n characters to connection
2627
* pq_putint - send an integer to connection
27-
* pq_putncharlen - send n characters to connection
28+
* pq_putncharlen - send n characters to connection
2829
* (also send an int header indicating
2930
* the length)
3031
* pq_getinaddr - initialize address from host and port number
3132
* pq_getinserv - initialize address from host and service name
3233
*
33-
* StreamDoUnlink - Shutdown UNIX socket connectioin
34-
* StreamServerPort - Open sock stream
35-
* StreamConnection - Create new connection with client
36-
* StreamClose - Close a client/backend connection
34+
* StreamDoUnlink - Shutdown UNIX socket connection
35+
* StreamServerPort - Open socket stream
36+
* StreamConnection - Create new connection with client
37+
* StreamClose - Close a client/backend connection
3738
*
3839
* NOTES
39-
* Frontend is now completey in interfaces/libpq, and no
40-
* functions from this file is used.
40+
* Frontend is now completely in interfaces/libpq, and no
41+
* functions from this file are used there.
4142
*
4243
*/
4344
#include "postgres.h"
@@ -79,13 +80,22 @@
7980

8081
extern FILE * debug_port; /* in util.c */
8182

83+
/*
84+
* Buffers
85+
*/
86+
char PqSendBuffer[PQ_BUFFER_SIZE];
87+
char PqRecvBuffer[PQ_BUFFER_SIZE];
88+
int PqSendPointer,PqRecvPointer,PqRecvLength;
89+
90+
8291
/* --------------------------------
8392
* pq_init - open portal file descriptors
8493
* --------------------------------
8594
*/
8695
void
8796
pq_init(int fd)
8897
{
98+
PqSendPointer = PqRecvPointer = PqRecvLength = 0;
8999
PQnotifies_init();
90100
if (getenv("LIBPQ_DEBUG"))
91101
debug_port = stderr;
@@ -94,40 +104,40 @@ pq_init(int fd)
94104
/* -------------------------
95105
* pq_getchar()
96106
*
97-
* get a character from the input file,
98-
*
107+
* get a character from the input file, or EOF if trouble
108+
* --------------------------------
99109
*/
100110

101111
int
102112
pq_getchar(void)
103113
{
104-
char c;
105-
106-
while (recv(MyProcPort->sock, &c, 1, 0) != 1) {
107-
if (errno != EINTR)
108-
return EOF; /* Not interrupted, so something went wrong */
114+
while (PqRecvPointer >= PqRecvLength)
115+
{
116+
if (pq_recvbuf()) /* If nothing in buffer, then recv some */
117+
return EOF; /* Failed to recv data */
109118
}
110-
111-
return c;
119+
return PqRecvBuffer[PqRecvPointer++];
112120
}
113121

114-
/*
122+
/* -------------------------
123+
* pq_peekchar()
124+
*
125+
* get a character from the connection, but leave it in the buffer
126+
* to be read again
115127
* --------------------------------
116-
* pq_peekchar - get 1 character from connection, but leave it in the stream
117128
*/
118-
int
119-
pq_peekchar(void) {
120-
char c;
121129

122-
while (recv(MyProcPort->sock, &c, 1, MSG_PEEK) != 1) {
123-
if (errno != EINTR)
124-
return EOF; /* Not interrupted, so something went wrong */
130+
int
131+
pq_peekchar(void)
132+
{
133+
while (PqRecvPointer >= PqRecvLength)
134+
{
135+
if (pq_recvbuf()) /* If nothing in buffer, then recv some */
136+
return EOF; /* Failed to recv data */
125137
}
126-
127-
return c;
138+
/* Note we don't bump the pointer... */
139+
return PqRecvBuffer[PqRecvPointer];
128140
}
129-
130-
131141

132142
/* --------------------------------
133143
* pq_getport - return the PGPORT setting
@@ -150,18 +160,91 @@ pq_getport()
150160
void
151161
pq_close()
152162
{
153-
close(MyProcPort->sock);
163+
close(MyProcPort->sock);
154164
PQnotifies_init();
155165
}
156166

157167
/* --------------------------------
158168
* pq_flush - flush pending output
169+
*
170+
* returns 0 if OK, EOF if trouble
159171
* --------------------------------
160172
*/
161-
void
173+
int
162174
pq_flush()
163175
{
164-
/* Not supported/required? */
176+
char *bufptr = PqSendBuffer;
177+
char *bufend = PqSendBuffer + PqSendPointer;
178+
179+
while (bufptr < bufend)
180+
{
181+
int r = send(MyProcPort->sock, bufptr, bufend - bufptr, 0);
182+
if (r <= 0)
183+
{
184+
if (errno == EINTR)
185+
continue; /* Ok if we were interrupted */
186+
/* We would like to use elog() here, but cannot because elog
187+
* tries to write to the client, which would cause a recursive
188+
* flush attempt! So just write it out to the postmaster log.
189+
*/
190+
fprintf(stderr, "pq_flush: send() failed, errno %d\n", errno);
191+
/* We drop the buffered data anyway so that processing
192+
* can continue, even though we'll probably quit soon.
193+
*/
194+
PqSendPointer = 0;
195+
return EOF;
196+
}
197+
bufptr += r;
198+
}
199+
PqSendPointer = 0;
200+
return 0;
201+
}
202+
203+
/* --------------------------------
204+
* pq_recvbuf - load some bytes into the input buffer
205+
*
206+
* returns 0 if OK, EOF if trouble
207+
* --------------------------------
208+
*/
209+
210+
int
211+
pq_recvbuf()
212+
{
213+
if (PqRecvPointer > 0)
214+
{
215+
if (PqRecvLength > PqRecvPointer)
216+
{
217+
/* still some unread data, left-justify it in the buffer */
218+
memmove(PqRecvBuffer, PqRecvBuffer+PqRecvPointer,
219+
PqRecvLength-PqRecvPointer);
220+
PqRecvLength -= PqRecvPointer;
221+
PqRecvPointer = 0;
222+
}
223+
else
224+
PqRecvLength = PqRecvPointer = 0;
225+
}
226+
227+
/* Can fill buffer from PqRecvLength and upwards */
228+
for (;;)
229+
{
230+
int r = recv(MyProcPort->sock, PqRecvBuffer + PqRecvLength,
231+
PQ_BUFFER_SIZE - PqRecvLength, 0);
232+
if (r <= 0)
233+
{
234+
if (errno == EINTR)
235+
continue; /* Ok if interrupted */
236+
/* We would like to use elog() here, but dare not because elog
237+
* tries to write to the client, which will cause problems
238+
* if we have a hard communications failure ...
239+
* So just write the message to the postmaster log.
240+
*/
241+
fprintf(stderr, "pq_recvbuf: recv() failed, errno %d\n", errno);
242+
return EOF;
243+
}
244+
/* r contains number of bytes read, so just incr length */
245+
PqRecvLength += r;
246+
return 0;
247+
}
165248
}
166249

167250
/* --------------------------------
@@ -194,7 +277,7 @@ pq_getstr(char *s, int maxlen)
194277
int
195278
pq_getnchar(char *s, int off, int maxlen)
196279
{
197-
int r = pqGetNBytes(s + off, maxlen);
280+
int r = pqGetNBytes(s + off, maxlen);
198281
s[off+maxlen] = '\0';
199282
return r;
200283
}
@@ -602,7 +685,7 @@ StreamConnection(int server_fd, Port *port)
602685
if (setsockopt(port->sock, pe->p_proto, TCP_NODELAY,
603686
&on, sizeof(on)) < 0)
604687
{
605-
elog(ERROR, "postmaster: setsockopt failed");
688+
elog(ERROR, "postmaster: setsockopt failed: %m");
606689
return STATUS_ERROR;
607690
}
608691
}
@@ -644,18 +727,9 @@ pq_putncharlen(char *s, int n)
644727
*/
645728
int pq_putchar(char c)
646729
{
647-
char isDone = 0;
648-
649-
do {
650-
if (send(MyProcPort->sock, &c, 1, 0) != 1) {
651-
if (errno != EINTR)
652-
return EOF; /* Anything other than interrupt is error! */
653-
}
654-
else
655-
isDone = 1; /* Done if we sent one char */
656-
} while (!isDone);
657-
return c;
730+
if (PqSendPointer >= PQ_BUFFER_SIZE)
731+
if (pq_flush()) /* If buffer is full, then flush it out */
732+
return EOF;
733+
PqSendBuffer[PqSendPointer++] = c; /* Put in buffer */
734+
return c;
658735
}
659-
660-
661-

0 commit comments

Comments
 (0)