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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy