Skip to content

Commit ebe5c1e

Browse files
rtokarevbigbes
authored andcommitted
Add tnt_reply_{hdr0,body0}', tnt_reply0' methods to parse reply from buffer
without copying
1 parent e0e1bdc commit ebe5c1e

File tree

2 files changed

+212
-59
lines changed

2 files changed

+212
-59
lines changed

include/tarantool/tnt_reply.h

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@
3535
* \brief Basic reply structure (parsing responses, e.t.c)
3636
*/
3737

38+
/**
39+
* \brief Size of iproto header
40+
*/
41+
#define TNT_REPLY_IPROTO_HDR_SIZE 5
42+
3843
/**
3944
* \brief Callback for recv reply from buffer
4045
*
@@ -128,4 +133,68 @@ tnt_reply(struct tnt_reply *r, char *buf, size_t size, size_t *off);
128133
int
129134
tnt_reply_from(struct tnt_reply *r, tnt_reply_t rcv, void *ptr);
130135

136+
/*!
137+
* \brief Process buffer as reply header without copying processed bytes
138+
*
139+
* \param[in] r reply object pointer
140+
* \param[in] buf buffer data pointer
141+
* \param[in] size buffer data size
142+
* \param[out] off returned offset, may be NULL
143+
*
144+
* if buffer contains valid reply header, then zero is returned and offset set to the
145+
* end of reply header in buffer.
146+
*
147+
* if there were error while parsing buffer, -1 is returned.
148+
*
149+
* \returns status of processing reply
150+
* \retval 0 process reply header
151+
* \retval -1 error while parsing buffer
152+
*/
153+
int
154+
tnt_reply_hdr0(struct tnt_reply *r, const char *buf, size_t size, size_t *off);
155+
156+
/*!
157+
* \brief Process buffer as reply body without copying processed bytes
158+
*
159+
* \param[in] r reply object pointer
160+
* \param[in] buf buffer data pointer
161+
* \param[in] size buffer data size
162+
* \param[out] off returned offset, may be NULL
163+
*
164+
* if buffer contains valid reply body, then zero is returned and offset set to the
165+
* end of reply body in buffer.
166+
*
167+
* if there were error while parsing buffer, -1 is returned.
168+
*
169+
* \returns status of processing reply
170+
* \retval 0 process reply body
171+
* \retval -1 error while parsing buffer
172+
*/
173+
int
174+
tnt_reply_body0(struct tnt_reply *r, const char *buf, size_t size, size_t *off);
175+
176+
/*!
177+
* \brief Process buffer as reply without copying processed bytes
178+
*
179+
* \param[in] r reply object pointer
180+
* \param[in] buf buffer data pointer
181+
* \param[in] size buffer data size
182+
* \param[out] off returned offset, may be NULL
183+
*
184+
* if buffer contains full and valid reply, then zero is returned and offset set to the
185+
* end of reply in buffer.
186+
*
187+
* if buffer doesn't contain full reply, then 1 is returned and offset set to the
188+
* size needed to read.
189+
*
190+
* if there were error while parsing buffer, -1 is returned.
191+
*
192+
* \returns status of processing reply
193+
* \retval 0 process reply
194+
* \retval 1 need 'offset' bytes more
195+
* \retval -1 error while parsing buffer
196+
*/
197+
int
198+
tnt_reply0(struct tnt_reply *r, const char *buf, size_t size, size_t *off);
199+
131200
#endif /* TNT_REPLY_H_INCLUDED */

tnt/tnt_reply.c

Lines changed: 143 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,8 @@ int tnt_reply_from(struct tnt_reply *r, tnt_reply_t rcv, void *ptr) {
6464
memset(r, 0 , sizeof(struct tnt_reply));
6565
r->alloc = alloc;
6666
/* reading iproto header */
67-
char length[9]; const char *data = (const char *)length;
68-
if (rcv(ptr, length, 5) == -1)
67+
char length[TNT_REPLY_IPROTO_HDR_SIZE]; const char *data = (const char *)length;
68+
if (rcv(ptr, length, sizeof(length)) == -1)
6969
goto rollback;
7070
if (mp_typeof(*length) != MP_UINT)
7171
goto rollback;
@@ -76,109 +76,158 @@ int tnt_reply_from(struct tnt_reply *r, tnt_reply_t rcv, void *ptr) {
7676
goto rollback;
7777
if(rcv(ptr, (char *)r->buf, size) == -1)
7878
goto rollback;
79-
/* header */
80-
const char *p = r->buf;
81-
const char *test = p;
82-
if (mp_check(&test, r->buf + size))
79+
size_t hdr_length;
80+
if (tnt_reply_hdr0(r, r->buf, r->buf_size, &hdr_length) != 0)
8381
goto rollback;
84-
if (mp_typeof(*p) != MP_MAP)
82+
if (size == (size_t)hdr_length)
83+
return 0; /* no body */
84+
if (tnt_reply_body0(r, r->buf + hdr_length, r->buf_size - hdr_length, NULL) != 0)
8585
goto rollback;
86+
87+
return 0;
88+
rollback:
89+
if (r->buf) tnt_mem_free((void *)r->buf);
90+
alloc = r->alloc;
91+
memset(r, 0, sizeof(struct tnt_reply));
92+
r->alloc = alloc;
93+
return -1;
94+
}
95+
96+
static ssize_t tnt_reply_cb(void *ptr[2], char *buf, ssize_t size) {
97+
char *src = ptr[0];
98+
ssize_t *off = ptr[1];
99+
memcpy(buf, src + *off, size);
100+
*off += size;
101+
return size;
102+
}
103+
104+
static int
105+
tnt_reply_len(const char *buf, size_t size, size_t *len)
106+
{
107+
if (size < TNT_REPLY_IPROTO_HDR_SIZE) {
108+
*len = TNT_REPLY_IPROTO_HDR_SIZE - size;
109+
return 1;
110+
}
111+
const char *p = buf;
112+
if (mp_typeof(*p) != MP_UINT)
113+
return -1;
114+
size_t length = mp_decode_uint(&p);
115+
if (size < length + TNT_REPLY_IPROTO_HDR_SIZE) {
116+
*len = (length + TNT_REPLY_IPROTO_HDR_SIZE) - size;
117+
return 1;
118+
}
119+
*len = length + TNT_REPLY_IPROTO_HDR_SIZE;
120+
return 0;
121+
}
122+
123+
int
124+
tnt_reply_hdr0(struct tnt_reply *r, const char *buf, size_t size, size_t *off) {
125+
const char *test = buf;
126+
const char *p = buf;
127+
if (mp_check(&test, p + size))
128+
return -1;
129+
if (mp_typeof(*p) != MP_MAP)
130+
return -1;
131+
86132
uint32_t n = mp_decode_map(&p);
133+
uint64_t sync = 0, code = 0, schema_id = 0, bitmap = 0;
87134
while (n-- > 0) {
88135
if (mp_typeof(*p) != MP_UINT)
89-
goto rollback;
136+
return -1;
90137
uint32_t key = mp_decode_uint(&p);
91138
if (mp_typeof(*p) != MP_UINT)
92-
goto rollback;
139+
return -1;
93140
switch (key) {
94141
case TNT_SYNC:
95-
if (mp_typeof(*p) != MP_UINT)
96-
goto rollback;
97-
r->sync = mp_decode_uint(&p);
142+
sync = mp_decode_uint(&p);
98143
break;
99144
case TNT_CODE:
100-
if (mp_typeof(*p) != MP_UINT)
101-
goto rollback;
102-
r->code = mp_decode_uint(&p);
145+
code = mp_decode_uint(&p);
103146
break;
104147
case TNT_SCHEMA_ID:
105-
if (mp_typeof(*p) != MP_UINT)
106-
goto rollback;
107-
r->schema_id = mp_decode_uint(&p);
148+
schema_id = mp_decode_uint(&p);
108149
break;
109150
default:
110-
goto rollback;
151+
return -1;
111152
}
112-
r->bitmap |= (1ULL << key);
153+
bitmap |= (1ULL << key);
113154
}
155+
if (r) {
156+
r->sync = sync;
157+
r->code = code & ((1 << 15) - 1);
158+
r->schema_id = schema_id;
159+
r->bitmap = bitmap;
160+
}
161+
if (off)
162+
*off = p - buf;
163+
return 0;
164+
}
114165

115-
/* body */
116-
if (p == r->buf + size + 5)
117-
return size + 5; /* no body */
118-
test = p;
119-
if (mp_check(&test, r->buf + size))
120-
goto rollback;
166+
int
167+
tnt_reply_body0(struct tnt_reply *r, const char *buf, size_t size, size_t *off) {
168+
const char *test = buf;
169+
const char *p = buf;
170+
if (mp_check(&test, p + size))
171+
return -1;
121172
if (mp_typeof(*p) != MP_MAP)
122-
goto rollback;
123-
n = mp_decode_map(&p);
173+
return -1;
174+
const char *error = NULL, *error_end = NULL, *data = NULL, *data_end = NULL;
175+
uint64_t bitmap = 0;
176+
uint32_t n = mp_decode_map(&p);
124177
while (n-- > 0) {
125178
uint32_t key = mp_decode_uint(&p);
126179
switch (key) {
127180
case TNT_ERROR: {
128181
if (mp_typeof(*p) != MP_STR)
129-
goto rollback;
182+
return -1;
130183
uint32_t elen = 0;
131-
r->error = mp_decode_str(&p, &elen);
132-
r->error_end = r->error + elen;
133-
r->code = r->code & ((1 << 15) - 1);
184+
error = mp_decode_str(&p, &elen);
185+
error_end = error + elen;
134186
break;
135187
}
136188
case TNT_DATA: {
137189
if (mp_typeof(*p) != MP_ARRAY)
138-
goto rollback;
139-
r->data = p;
190+
return -1;
191+
data = p;
140192
mp_next(&p);
141-
r->data_end = p;
193+
data_end = p;
142194
break;
143195
}
144196
}
145-
r->bitmap |= (1ULL << key);
197+
bitmap |= (1ULL << key);
198+
}
199+
if (r) {
200+
r->error = error;
201+
r->error_end = error_end;
202+
r->data = data;
203+
r->data_end = data_end;
204+
r->bitmap |= bitmap;
146205
}
206+
if (off)
207+
*off = p - buf;
147208
return 0;
148-
rollback:
149-
if (r->buf) tnt_mem_free((void *)r->buf);
150-
alloc = r->alloc;
151-
memset(r, 0, sizeof(struct tnt_reply));
152-
r->alloc = alloc;
153-
return -1;
154-
}
155-
156-
static ssize_t tnt_reply_cb(void *ptr[2], char *buf, ssize_t size) {
157-
char *src = ptr[0];
158-
ssize_t *off = ptr[1];
159-
memcpy(buf, src + *off, size);
160-
*off += size;
161-
return size;
162209
}
163210

164211
int
165212
tnt_reply(struct tnt_reply *r, char *buf, size_t size, size_t *off) {
166213
/* supplied buffer must contain full reply,
167214
* if it doesn't then returning count of bytes
168215
* needed to process */
169-
if (size < 5) {
216+
size_t length;
217+
switch (tnt_reply_len(buf, size, &length)) {
218+
case 0:
219+
break;
220+
case 1:
170221
if (off)
171-
*off = 5 - size;
222+
*off = length;
172223
return 1;
173-
}
174-
const char *p = buf;
175-
if (mp_typeof(*p) != MP_UINT)
224+
default:
176225
return -1;
177-
size_t length = mp_decode_uint(&p);
178-
if (size < length + 5) {
226+
}
227+
if (r == NULL) {
179228
if (off)
180-
*off = (length + 5) - size;
181-
return 1;
229+
*off = length;
230+
return 0;
182231
}
183232
size_t offv = 0;
184233
void *ptr[2] = { buf, &offv };
@@ -187,3 +236,38 @@ tnt_reply(struct tnt_reply *r, char *buf, size_t size, size_t *off) {
187236
*off = offv;
188237
return rc;
189238
}
239+
240+
int
241+
tnt_reply0(struct tnt_reply *r, const char *buf, size_t size, size_t *off) {
242+
/* supplied buffer must contain full reply,
243+
* if it doesn't then returning count of bytes
244+
* needed to process */
245+
size_t length;
246+
switch (tnt_reply_len(buf, size, &length)) {
247+
case 0:
248+
break;
249+
case 1:
250+
if (off)
251+
*off = length;
252+
return 1;
253+
default:
254+
return -1;
255+
}
256+
if (r == NULL) {
257+
if (off)
258+
*off = length;
259+
return 0;
260+
}
261+
const char *data = buf + TNT_REPLY_IPROTO_HDR_SIZE;
262+
size_t data_length = length - TNT_REPLY_IPROTO_HDR_SIZE;
263+
size_t hdr_length;
264+
if (tnt_reply_hdr0(r, data, data_length, &hdr_length) != 0)
265+
return -1;
266+
if (data_length != hdr_length) {
267+
if (tnt_reply_body0(r, data + hdr_length, data_length - hdr_length, NULL) != 0)
268+
return -1;
269+
}
270+
if (off)
271+
*off = length;
272+
return 0;
273+
}

0 commit comments

Comments
 (0)