Skip to content

Commit 7024d47

Browse files
committed
io OPTIMIZE remove redundant buffers
Refactoring also included.
1 parent 1b95224 commit 7024d47

File tree

3 files changed

+148
-152
lines changed

3 files changed

+148
-152
lines changed

src/io.c

Lines changed: 64 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,6 @@ const char *nc_msgtype2str[] = {
5757
"notification message",
5858
};
5959

60-
#define BUFFERSIZE 512
61-
6260
static ssize_t
6361
nc_read(struct nc_session *session, char *buf, uint32_t count, uint32_t inact_timeout, struct timespec *ts_act_timeout)
6462
{
@@ -174,68 +172,55 @@ nc_read(struct nc_session *session, char *buf, uint32_t count, uint32_t inact_ti
174172
return (ssize_t)readd;
175173
}
176174

177-
static ssize_t
178-
nc_read_chunk(struct nc_session *session, size_t len, uint32_t inact_timeout, struct timespec *ts_act_timeout, char **chunk)
179-
{
180-
ssize_t r;
181-
182-
assert(session);
183-
assert(chunk);
184-
185-
if (!len) {
186-
return 0;
187-
}
188-
189-
*chunk = malloc((len + 1) * sizeof **chunk);
190-
NC_CHECK_ERRMEM_RET(!*chunk, -1);
191-
192-
r = nc_read(session, *chunk, len, inact_timeout, ts_act_timeout);
193-
if (r <= 0) {
194-
free(*chunk);
195-
return -1;
196-
}
197-
198-
/* terminating null byte */
199-
(*chunk)[r] = 0;
200-
201-
return r;
202-
}
203-
175+
/**
176+
* @brief Read data until a specific characters sequence is found.
177+
*
178+
* @param[in] session Session to read from.
179+
* @param[in] endtag End tag to match, no characters read after that.
180+
* @param[in] inact_timeout Inactive timeout to use.
181+
* @param[in] ts_act_timeout Active timeout to use.
182+
* @param[in,out] buf Buffer for read data, may be NULL.
183+
* @param[in,out] buf_size Current size of @p buf - 1 (actual size is one byte larger).
184+
* @return Number of characters read;
185+
* @return -1 on error.
186+
*/
204187
static ssize_t
205188
nc_read_until(struct nc_session *session, const char *endtag, uint32_t inact_timeout, struct timespec *ts_act_timeout,
206-
char **result)
189+
char **buf, uint32_t *buf_size)
207190
{
208-
char *chunk = NULL;
209-
size_t size, count = 0, r, len, i, matched = 0;
191+
char *local_buf = NULL;
192+
uint32_t local_size = 0;
193+
size_t r, len, i, matched = 0;
194+
ssize_t count = 0;
210195

211196
assert(session);
212197
assert(endtag);
213198

214-
size = BUFFERSIZE;
215-
chunk = malloc((size + 1) * sizeof *chunk);
216-
NC_CHECK_ERRMEM_RET(!chunk, -1);
199+
if (!buf) {
200+
buf = &local_buf;
201+
buf_size = &local_size;
202+
}
217203

218204
len = strlen(endtag);
219-
while (1) {
205+
do {
220206
/* resize buffer if needed */
221-
if ((count + (len - matched)) >= size) {
222-
/* get more memory */
223-
size = size + BUFFERSIZE;
224-
chunk = nc_realloc(chunk, (size + 1) * sizeof *chunk);
225-
NC_CHECK_ERRMEM_RET(!chunk, -1);
207+
if ((count + (len - matched)) > *buf_size) {
208+
*buf_size += NC_READ_BUF_SIZE_STEP;
209+
*buf = nc_realloc(*buf, (*buf_size + 1) * sizeof **buf);
210+
NC_CHECK_ERRMEM_GOTO(!*buf, count = -1, cleanup);
226211
}
227212

228213
/* get another character */
229-
r = nc_read(session, &(chunk[count]), len - matched, inact_timeout, ts_act_timeout);
214+
r = nc_read(session, *buf + count, len - matched, inact_timeout, ts_act_timeout);
230215
if (r != len - matched) {
231-
free(chunk);
232-
return -1;
216+
count = -1;
217+
goto cleanup;
233218
}
234219

235220
count += len - matched;
236221

237222
for (i = len - matched; i > 0; i--) {
238-
if (!strncmp(&endtag[matched], &(chunk[count - i]), i)) {
223+
if (!strncmp(endtag + matched, *buf + (count - i), i)) {
239224
/*part of endtag found */
240225
matched += i;
241226
break;
@@ -245,35 +230,30 @@ nc_read_until(struct nc_session *session, const char *endtag, uint32_t inact_tim
245230
}
246231

247232
/* whole endtag found */
248-
if (matched == len) {
249-
break;
250-
}
251-
}
233+
} while (matched < len);
252234

253235
/* terminating null byte */
254-
chunk[count] = 0;
236+
(*buf)[count] = 0;
255237

256-
if (result) {
257-
*result = chunk;
258-
} else {
259-
free(chunk);
260-
}
238+
cleanup:
239+
free(local_buf);
261240
return count;
262241
}
263242

264243
int
265244
nc_read_msg_io(struct nc_session *session, int io_timeout, struct ly_in **msg, int passing_io_lock)
266245
{
267246
int ret = 1, r, io_locked = passing_io_lock;
268-
char *data = NULL, *chunk;
269-
uint64_t chunk_len, len = 0;
270-
/* use timeout in milliseconds instead seconds */
271-
uint32_t inact_timeout = NC_READ_INACT_TIMEOUT * 1000;
247+
char *data = NULL, *frame_size_buf = NULL;
248+
uint32_t chunk_len, frame_buf_len, data_len = 0, inact_timeout;
272249
struct timespec ts_act_timeout;
273250

274251
assert(session && msg);
275252
*msg = NULL;
276253

254+
/* use timeout in milliseconds instead seconds */
255+
inact_timeout = NC_READ_INACT_TIMEOUT * 1000;
256+
277257
if ((session->status != NC_STATUS_RUNNING) && (session->status != NC_STATUS_STARTING)) {
278258
ERR(session, "Invalid session to read from.");
279259
ret = -1;
@@ -294,7 +274,7 @@ nc_read_msg_io(struct nc_session *session, int io_timeout, struct ly_in **msg, i
294274
/* read the message */
295275
switch (session->version) {
296276
case NC_VERSION_10:
297-
r = nc_read_until(session, NC_VERSION_10_ENDTAG, inact_timeout, &ts_act_timeout, &data);
277+
r = nc_read_until(session, NC_VERSION_10_ENDTAG, inact_timeout, &ts_act_timeout, &data, &data_len);
298278
if (r == -1) {
299279
ret = r;
300280
goto cleanup;
@@ -304,21 +284,25 @@ nc_read_msg_io(struct nc_session *session, int io_timeout, struct ly_in **msg, i
304284
data[r - NC_VERSION_10_ENDTAG_LEN] = '\0';
305285
break;
306286
case NC_VERSION_11:
287+
/* prepare the buffer large enough for reading the framing chunk size */
288+
frame_buf_len = 11;
289+
frame_size_buf = malloc(frame_buf_len + 1);
290+
NC_CHECK_ERRMEM_GOTO(!frame_size_buf, ret = -1, cleanup);
291+
307292
while (1) {
308-
r = nc_read_until(session, "\n#", inact_timeout, &ts_act_timeout, NULL);
293+
r = nc_read_until(session, "\n#", inact_timeout, &ts_act_timeout, NULL, NULL);
309294
if (r == -1) {
310295
ret = r;
311296
goto cleanup;
312297
}
313-
r = nc_read_until(session, "\n", inact_timeout, &ts_act_timeout, &chunk);
298+
r = nc_read_until(session, "\n", inact_timeout, &ts_act_timeout, &frame_size_buf, &frame_buf_len);
314299
if (r == -1) {
315300
ret = r;
316301
goto cleanup;
317302
}
318303

319-
if (!strcmp(chunk, "#\n")) {
304+
if (!strcmp(frame_size_buf, "#\n")) {
320305
/* end of chunked framing message */
321-
free(chunk);
322306
if (!data) {
323307
ERR(session, "Invalid frame chunk delimiters.");
324308
ret = -2;
@@ -328,28 +312,27 @@ nc_read_msg_io(struct nc_session *session, int io_timeout, struct ly_in **msg, i
328312
}
329313

330314
/* convert string to the size of the following chunk */
331-
chunk_len = strtoul(chunk, (char **)NULL, 10);
332-
free(chunk);
315+
chunk_len = strtoul(frame_size_buf, NULL, 10);
333316
if (!chunk_len) {
334317
ERR(session, "Invalid frame chunk size detected, fatal error.");
335318
ret = -2;
336319
goto cleanup;
337320
}
338321

339-
/* now we have size of next chunk, so read the chunk */
340-
r = nc_read_chunk(session, chunk_len, inact_timeout, &ts_act_timeout, &chunk);
322+
/* now we have size of next chunk, prepare a buffer large enough */
323+
data = nc_realloc(data, data_len + chunk_len + 1);
324+
NC_CHECK_ERRMEM_GOTO(!data, ret = -1, cleanup);
325+
326+
/* read the next chunk */
327+
r = nc_read(session, data + data_len, chunk_len, inact_timeout, &ts_act_timeout);
341328
if (r == -1) {
342329
ret = r;
343330
goto cleanup;
344331
}
345332

346-
/* realloc message buffer, remember to count terminating null byte */
347-
data = nc_realloc(data, len + chunk_len + 1);
348-
NC_CHECK_ERRMEM_GOTO(!data, ret = -1, cleanup);
349-
memcpy(data + len, chunk, chunk_len);
350-
len += chunk_len;
351-
data[len] = '\0';
352-
free(chunk);
333+
/* update data length and terminate the data */
334+
data_len += chunk_len;
335+
data[data_len] = '\0';
353336
}
354337

355338
break;
@@ -374,6 +357,7 @@ nc_read_msg_io(struct nc_session *session, int io_timeout, struct ly_in **msg, i
374357
/* SESSION IO UNLOCK */
375358
nc_session_io_unlock(session, __func__);
376359
}
360+
free(frame_size_buf);
377361
free(data);
378362
return ret;
379363
}
@@ -551,10 +535,9 @@ nc_session_is_connected(const struct nc_session *session)
551535
return 1;
552536
}
553537

554-
#define WRITE_BUFSIZE (2 * BUFFERSIZE)
555538
struct nc_wclb_arg {
556539
struct nc_session *session;
557-
char buf[WRITE_BUFSIZE];
540+
char buf[NC_WRITE_CHUNK_SIZE_MAX];
558541
uint32_t len;
559542
};
560543

@@ -757,7 +740,7 @@ nc_write_clb(void *arg, const void *buf, uint32_t count, int xmlcontent)
757740
return ret;
758741
}
759742

760-
if (warg->len && (warg->len + count > WRITE_BUFSIZE)) {
743+
if (warg->len && (warg->len + count > NC_WRITE_CHUNK_SIZE_MAX)) {
761744
/* dump current buffer */
762745
c = nc_write_clb_flush(warg);
763746
if (c == -1) {
@@ -766,7 +749,7 @@ nc_write_clb(void *arg, const void *buf, uint32_t count, int xmlcontent)
766749
ret += c;
767750
}
768751

769-
if (!xmlcontent && (count > WRITE_BUFSIZE)) {
752+
if (!xmlcontent && (count > NC_WRITE_CHUNK_SIZE_MAX)) {
770753
/* write directly */
771754
c = nc_write_starttag_and_msg(warg->session, buf, count);
772755
if (c == -1) {
@@ -777,7 +760,7 @@ nc_write_clb(void *arg, const void *buf, uint32_t count, int xmlcontent)
777760
/* keep in buffer and write later */
778761
if (xmlcontent) {
779762
for (l = 0; l < count; l++) {
780-
if (warg->len + 5 >= WRITE_BUFSIZE) {
763+
if (warg->len + 5 >= NC_WRITE_CHUNK_SIZE_MAX) {
781764
/* buffer is full */
782765
c = nc_write_clb_flush(warg);
783766
if (c == -1) {
@@ -810,7 +793,7 @@ nc_write_clb(void *arg, const void *buf, uint32_t count, int xmlcontent)
810793
}
811794
} else {
812795
memcpy(&warg->buf[warg->len], buf, count);
813-
warg->len += count; /* is <= WRITE_BUFSIZE */
796+
warg->len += count; /* is <= NC_WRITE_CHUNK_SIZE_MAX */
814797
ret += count;
815798
}
816799
}

0 commit comments

Comments
 (0)