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

Commit 1de09ad

Browse files
committed
Add more efficient functions to pqformat API.
There's three prongs to achieve greater efficiency here: 1) Allow reusing a stringbuffer across pq_beginmessage/endmessage, with the new pq_beginmessage_reuse/endmessage_reuse. This can be beneficial both because it avoids allocating the initial buffer, and because it's more likely to already have an correctly sized buffer. 2) Replacing pq_sendint() with pq_sendint$width() inline functions. Previously unnecessary and unpredictable branches in pq_sendint() were needed. Additionally the replacement functions are implemented more efficiently. pq_sendint is now deprecated, a separate commit will convert all in-tree callers. 3) Add pq_writeint$width(), pq_writestring(). These rely on sufficient space in the StringInfo's buffer, avoiding individual space checks & potential individual resizing. To allow this to be used for strings, expose mbutil.c's MAX_CONVERSION_GROWTH. Followup commits will make use of these facilities. Author: Andres Freund Discussion: https://postgr.es/m/20170914063418.sckdzgjfrsbekae4@alap3.anarazel.de
1 parent 70c2d1b commit 1de09ad

File tree

4 files changed

+208
-70
lines changed

4 files changed

+208
-70
lines changed

src/backend/libpq/pqformat.c

Lines changed: 33 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -97,13 +97,24 @@ pq_beginmessage(StringInfo buf, char msgtype)
9797
}
9898

9999
/* --------------------------------
100-
* pq_sendbyte - append a raw byte to a StringInfo buffer
100+
101+
* pq_beginmessage_reuse - initialize for sending a message, reuse buffer
102+
*
103+
* This requires the buffer to be allocated in an sufficiently long-lived
104+
* memory context.
101105
* --------------------------------
102106
*/
103107
void
104-
pq_sendbyte(StringInfo buf, int byt)
108+
pq_beginmessage_reuse(StringInfo buf, char msgtype)
105109
{
106-
appendStringInfoCharMacro(buf, byt);
110+
resetStringInfo(buf);
111+
112+
/*
113+
* We stash the message type into the buffer's cursor field, expecting
114+
* that the pq_sendXXX routines won't touch it. We could alternatively
115+
* make it the first byte of the buffer contents, but this seems easier.
116+
*/
117+
buf->cursor = msgtype;
107118
}
108119

109120
/* --------------------------------
@@ -113,6 +124,7 @@ pq_sendbyte(StringInfo buf, int byt)
113124
void
114125
pq_sendbytes(StringInfo buf, const char *data, int datalen)
115126
{
127+
/* use variant that maintains a trailing null-byte, out of caution */
116128
appendBinaryStringInfo(buf, data, datalen);
117129
}
118130

@@ -137,13 +149,13 @@ pq_sendcountedtext(StringInfo buf, const char *str, int slen,
137149
if (p != str) /* actual conversion has been done? */
138150
{
139151
slen = strlen(p);
140-
pq_sendint(buf, slen + extra, 4);
152+
pq_sendint32(buf, slen + extra);
141153
appendBinaryStringInfoNT(buf, p, slen);
142154
pfree(p);
143155
}
144156
else
145157
{
146-
pq_sendint(buf, slen + extra, 4);
158+
pq_sendint32(buf, slen + extra);
147159
appendBinaryStringInfoNT(buf, str, slen);
148160
}
149161
}
@@ -227,53 +239,6 @@ pq_send_ascii_string(StringInfo buf, const char *str)
227239
appendStringInfoChar(buf, '\0');
228240
}
229241

230-
/* --------------------------------
231-
* pq_sendint - append a binary integer to a StringInfo buffer
232-
* --------------------------------
233-
*/
234-
void
235-
pq_sendint(StringInfo buf, int i, int b)
236-
{
237-
unsigned char n8;
238-
uint16 n16;
239-
uint32 n32;
240-
241-
switch (b)
242-
{
243-
case 1:
244-
n8 = (unsigned char) i;
245-
appendBinaryStringInfoNT(buf, (char *) &n8, 1);
246-
break;
247-
case 2:
248-
n16 = pg_hton16((uint16) i);
249-
appendBinaryStringInfoNT(buf, (char *) &n16, 2);
250-
break;
251-
case 4:
252-
n32 = pg_hton32((uint32) i);
253-
appendBinaryStringInfoNT(buf, (char *) &n32, 4);
254-
break;
255-
default:
256-
elog(ERROR, "unsupported integer size %d", b);
257-
break;
258-
}
259-
}
260-
261-
/* --------------------------------
262-
* pq_sendint64 - append a binary 8-byte int to a StringInfo buffer
263-
*
264-
* It is tempting to merge this with pq_sendint, but we'd have to make the
265-
* argument int64 for all data widths --- that could be a big performance
266-
* hit on machines where int64 isn't efficient.
267-
* --------------------------------
268-
*/
269-
void
270-
pq_sendint64(StringInfo buf, int64 i)
271-
{
272-
uint64 n64 = pg_hton64(i);
273-
274-
appendBinaryStringInfoNT(buf, (char *) &n64, sizeof(n64));
275-
}
276-
277242
/* --------------------------------
278243
* pq_sendfloat4 - append a float4 to a StringInfo buffer
279244
*
@@ -295,9 +260,7 @@ pq_sendfloat4(StringInfo buf, float4 f)
295260
} swap;
296261

297262
swap.f = f;
298-
swap.i = pg_hton32(swap.i);
299-
300-
appendBinaryStringInfoNT(buf, (char *) &swap.i, 4);
263+
pq_sendint32(buf, swap.i);
301264
}
302265

303266
/* --------------------------------
@@ -341,6 +304,21 @@ pq_endmessage(StringInfo buf)
341304
buf->data = NULL;
342305
}
343306

307+
/* --------------------------------
308+
* pq_endmessage_reuse - send the completed message to the frontend
309+
*
310+
* The data buffer is *not* freed, allowing to reuse the buffer with
311+
* pg_beginmessage_reuse.
312+
--------------------------------
313+
*/
314+
315+
void
316+
pq_endmessage_reuse(StringInfo buf)
317+
{
318+
/* msgtype was saved in cursor field */
319+
(void) pq_putmessage(buf->cursor, buf->data, buf->len);
320+
}
321+
344322

345323
/* --------------------------------
346324
* pq_begintypsend - initialize for constructing a bytea result

src/backend/utils/mb/mbutils.c

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -41,17 +41,6 @@
4141
#include "utils/memutils.h"
4242
#include "utils/syscache.h"
4343

44-
/*
45-
* When converting strings between different encodings, we assume that space
46-
* for converted result is 4-to-1 growth in the worst case. The rate for
47-
* currently supported encoding pairs are within 3 (SJIS JIS X0201 half width
48-
* kanna -> UTF8 is the worst case). So "4" should be enough for the moment.
49-
*
50-
* Note that this is not the same as the maximum character width in any
51-
* particular encoding.
52-
*/
53-
#define MAX_CONVERSION_GROWTH 4
54-
5544
/*
5645
* We maintain a simple linked list caching the fmgr lookup info for the
5746
* currently selected conversion functions, as well as any that have been

src/include/libpq/pqformat.h

Lines changed: 164 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,180 @@
1414
#define PQFORMAT_H
1515

1616
#include "lib/stringinfo.h"
17+
#include "mb/pg_wchar.h"
18+
#include "port/pg_bswap.h"
1719

1820
extern void pq_beginmessage(StringInfo buf, char msgtype);
19-
extern void pq_sendbyte(StringInfo buf, int byt);
21+
extern void pq_beginmessage_reuse(StringInfo buf, char msgtype);
22+
extern void pq_endmessage(StringInfo buf);
23+
extern void pq_endmessage_reuse(StringInfo buf);
24+
2025
extern void pq_sendbytes(StringInfo buf, const char *data, int datalen);
2126
extern void pq_sendcountedtext(StringInfo buf, const char *str, int slen,
2227
bool countincludesself);
2328
extern void pq_sendtext(StringInfo buf, const char *str, int slen);
2429
extern void pq_sendstring(StringInfo buf, const char *str);
2530
extern void pq_send_ascii_string(StringInfo buf, const char *str);
26-
extern void pq_sendint(StringInfo buf, int i, int b);
27-
extern void pq_sendint64(StringInfo buf, int64 i);
2831
extern void pq_sendfloat4(StringInfo buf, float4 f);
2932
extern void pq_sendfloat8(StringInfo buf, float8 f);
30-
extern void pq_endmessage(StringInfo buf);
33+
34+
extern void pq_sendfloat4(StringInfo buf, float4 f);
35+
extern void pq_sendfloat8(StringInfo buf, float8 f);
36+
37+
/*
38+
* Append a int8 to a StringInfo buffer, which already has enough space
39+
* preallocated.
40+
*
41+
* The use of restrict allows the compiler to optimize the code based on the
42+
* assumption that buf, buf->len, buf->data and *buf->data don't
43+
* overlap. Without the annotation buf->len etc cannot be kept in a register
44+
* over subsequent pq_writeint* calls.
45+
*/
46+
static inline void
47+
pq_writeint8(StringInfo restrict buf, int8 i)
48+
{
49+
int8 ni = i;
50+
51+
Assert(buf->len + sizeof(i) <= buf->maxlen);
52+
memcpy((char *restrict) (buf->data + buf->len), &ni, sizeof(ni));
53+
buf->len += sizeof(i);
54+
}
55+
56+
/*
57+
* Append a int16 to a StringInfo buffer, which already has enough space
58+
* preallocated.
59+
*/
60+
static inline void
61+
pq_writeint16(StringInfo restrict buf, int16 i)
62+
{
63+
int16 ni = pg_hton16(i);
64+
65+
Assert(buf->len + sizeof(ni) <= buf->maxlen);
66+
memcpy((char *restrict) (buf->data + buf->len), &ni, sizeof(i));
67+
buf->len += sizeof(i);
68+
}
69+
70+
/*
71+
* Append a int32 to a StringInfo buffer, which already has enough space
72+
* preallocated.
73+
*/
74+
static inline void
75+
pq_writeint32(StringInfo restrict buf, int32 i)
76+
{
77+
int32 ni = pg_hton32(i);
78+
79+
Assert(buf->len + sizeof(i) <= buf->maxlen);
80+
memcpy((char *restrict) (buf->data + buf->len), &ni, sizeof(i));
81+
buf->len += sizeof(i);
82+
}
83+
84+
/*
85+
* Append a int64 to a StringInfo buffer, which already has enough space
86+
* preallocated.
87+
*/
88+
static inline void
89+
pq_writeint64(StringInfo restrict buf, int64 i)
90+
{
91+
int64 ni = pg_hton64(i);
92+
93+
Assert(buf->len + sizeof(i) <= buf->maxlen);
94+
memcpy((char *restrict) (buf->data + buf->len), &ni, sizeof(i));
95+
buf->len += sizeof(i);
96+
}
97+
98+
/*
99+
* Append a null-terminated text string (with conversion) to a buffer with
100+
* preallocated space.
101+
*
102+
* NB: The pre-allocated space needs to be sufficient for the string after
103+
* converting to client encoding.
104+
*
105+
* NB: passed text string must be null-terminated, and so is the data
106+
* sent to the frontend.
107+
*/
108+
static inline void
109+
pq_writestring(StringInfo restrict buf, const char *restrict str)
110+
{
111+
int slen = strlen(str);
112+
char *p;
113+
114+
p = pg_server_to_client(str, slen);
115+
if (p != str) /* actual conversion has been done? */
116+
slen = strlen(p);
117+
118+
Assert(buf->len + slen + 1 <= buf->maxlen);
119+
120+
memcpy(((char *restrict) buf->data + buf->len), p, slen + 1);
121+
buf->len += slen + 1;
122+
123+
if (p != str)
124+
pfree(p);
125+
}
126+
127+
/* append a binary int8 to a StringInfo buffer */
128+
static inline void
129+
pq_sendint8(StringInfo buf, int8 i)
130+
{
131+
enlargeStringInfo(buf, sizeof(i));
132+
pq_writeint8(buf, i);
133+
}
134+
135+
/* append a binary int16 to a StringInfo buffer */
136+
static inline void
137+
pq_sendint16(StringInfo buf, int16 i)
138+
{
139+
enlargeStringInfo(buf, sizeof(i));
140+
pq_writeint16(buf, i);
141+
}
142+
143+
/* append a binary int32 to a StringInfo buffer */
144+
static inline void
145+
pq_sendint32(StringInfo buf, int32 i)
146+
{
147+
enlargeStringInfo(buf, sizeof(i));
148+
pq_writeint32(buf, i);
149+
}
150+
151+
/* append a binary int64 to a StringInfo buffer */
152+
static inline void
153+
pq_sendint64(StringInfo buf, int64 i)
154+
{
155+
enlargeStringInfo(buf, sizeof(i));
156+
pq_writeint64(buf, i);
157+
}
158+
159+
/* append a binary byte to a StringInfo buffer */
160+
static inline void
161+
pq_sendbyte(StringInfo buf, int8 byt)
162+
{
163+
pq_sendint8(buf, byt);
164+
}
165+
166+
/*
167+
* Append a binary integer to a StringInfo buffer
168+
*
169+
* This function is deprecated.
170+
*/
171+
static inline void
172+
pq_sendint(StringInfo buf, int i, int b)
173+
{
174+
switch (b)
175+
{
176+
case 1:
177+
pq_sendint8(buf, (int8) i);
178+
break;
179+
case 2:
180+
pq_sendint16(buf, (int16) i);
181+
break;
182+
case 4:
183+
pq_sendint32(buf, (int32) i);
184+
break;
185+
default:
186+
elog(ERROR, "unsupported integer size %d", b);
187+
break;
188+
}
189+
}
190+
31191

32192
extern void pq_begintypsend(StringInfo buf);
33193
extern bytea *pq_endtypsend(StringInfo buf);

src/include/mb/pg_wchar.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,17 @@ typedef enum pg_enc
304304
/* On FE are possible all encodings */
305305
#define PG_VALID_FE_ENCODING(_enc) PG_VALID_ENCODING(_enc)
306306

307+
/*
308+
* When converting strings between different encodings, we assume that space
309+
* for converted result is 4-to-1 growth in the worst case. The rate for
310+
* currently supported encoding pairs are within 3 (SJIS JIS X0201 half width
311+
* kanna -> UTF8 is the worst case). So "4" should be enough for the moment.
312+
*
313+
* Note that this is not the same as the maximum character width in any
314+
* particular encoding.
315+
*/
316+
#define MAX_CONVERSION_GROWTH 4
317+
307318
/*
308319
* Table for mapping an encoding number to official encoding name and
309320
* possibly other subsidiary data. Be careful to check encoding number

0 commit comments

Comments
 (0)