Optimize readline/readdelim/getdelim calls.
This speeds up common reading operations by factor of 4-6. * include/mailutils/stream.h (mu_stream_readdelim): New proto. * include/mailutils/sys/stream.h (_mu_stream) <readdelim>: New method. * mailbox/stream.c (_stream_scandelim, _stream_readdelim): New functions. (mu_stream_readdelim): New function. (mu_stream_readline): Rewrite using mu_stream_readdelim. (mu_stream_getdelim): Optimize. * mailbox/amd.c (amd_body_stream_readdelim): New function. (_amd_attach_message): Set the readdelim method. * mailbox/header.c: Add a placeholder for readdelim method. * mailbox/message.c (_message_stream_readdelim): New function. (_message_stream_create): Set the readdelim method. * mailbox/streamref.c (_streamref_readdelim): New function. (mu_streamref_create_abridged): Set the readdelim method.
Showing
7 changed files
with
235 additions
and
14 deletions
... | @@ -74,6 +74,8 @@ int mu_stream_seek (mu_stream_t stream, mu_off_t offset, int whence, | ... | @@ -74,6 +74,8 @@ int mu_stream_seek (mu_stream_t stream, mu_off_t offset, int whence, |
74 | int mu_stream_set_buffer (mu_stream_t stream, enum mu_buffer_type type, | 74 | int mu_stream_set_buffer (mu_stream_t stream, enum mu_buffer_type type, |
75 | size_t size); | 75 | size_t size); |
76 | int mu_stream_read (mu_stream_t stream, void *buf, size_t size, size_t *pread); | 76 | int mu_stream_read (mu_stream_t stream, void *buf, size_t size, size_t *pread); |
77 | int mu_stream_readdelim (mu_stream_t stream, char *buf, size_t size, | ||
78 | int delim, size_t *pread); | ||
77 | int mu_stream_readline (mu_stream_t stream, char *buf, size_t size, size_t *pread); | 79 | int mu_stream_readline (mu_stream_t stream, char *buf, size_t size, size_t *pread); |
78 | int mu_stream_getdelim (mu_stream_t stream, char **pbuf, size_t *psize, | 80 | int mu_stream_getdelim (mu_stream_t stream, char **pbuf, size_t *psize, |
79 | int delim, size_t *pread); | 81 | int delim, size_t *pread); | ... | ... |
... | @@ -41,6 +41,7 @@ struct _mu_stream | ... | @@ -41,6 +41,7 @@ struct _mu_stream |
41 | int last_err; | 41 | int last_err; |
42 | 42 | ||
43 | int (*read) (struct _mu_stream *, char *, size_t, size_t *); | 43 | int (*read) (struct _mu_stream *, char *, size_t, size_t *); |
44 | int (*readdelim) (struct _mu_stream *, char *, size_t, int, size_t *); | ||
44 | int (*write) (struct _mu_stream *, const char *, size_t, size_t *); | 45 | int (*write) (struct _mu_stream *, const char *, size_t, size_t *); |
45 | int (*flush) (struct _mu_stream *); | 46 | int (*flush) (struct _mu_stream *); |
46 | int (*open) (struct _mu_stream *); | 47 | int (*open) (struct _mu_stream *); | ... | ... |
... | @@ -117,6 +117,10 @@ static int amd_envelope_sender (mu_envelope_t envelope, char *buf, size_t len, | ... | @@ -117,6 +117,10 @@ static int amd_envelope_sender (mu_envelope_t envelope, char *buf, size_t len, |
117 | static int amd_body_stream_read (mu_stream_t str, char *buffer, | 117 | static int amd_body_stream_read (mu_stream_t str, char *buffer, |
118 | size_t buflen, | 118 | size_t buflen, |
119 | size_t *pnread); | 119 | size_t *pnread); |
120 | static int amd_body_stream_readdelim (mu_stream_t is, | ||
121 | char *buffer, size_t buflen, | ||
122 | int delim, | ||
123 | size_t *pnread); | ||
120 | static int amd_body_stream_size (mu_stream_t str, mu_off_t *psize); | 124 | static int amd_body_stream_size (mu_stream_t str, mu_off_t *psize); |
121 | static int amd_body_stream_seek (mu_stream_t str, mu_off_t off, int whence, | 125 | static int amd_body_stream_seek (mu_stream_t str, mu_off_t off, int whence, |
122 | mu_off_t *presult); | 126 | mu_off_t *presult); |
... | @@ -487,6 +491,7 @@ _amd_attach_message (mu_mailbox_t mailbox, struct _amd_message *mhm, | ... | @@ -487,6 +491,7 @@ _amd_attach_message (mu_mailbox_t mailbox, struct _amd_message *mhm, |
487 | return ENOMEM; | 491 | return ENOMEM; |
488 | } | 492 | } |
489 | str->stream.read = amd_body_stream_read; | 493 | str->stream.read = amd_body_stream_read; |
494 | str->stream.readdelim = amd_body_stream_readdelim; | ||
490 | str->stream.size = amd_body_stream_size; | 495 | str->stream.size = amd_body_stream_size; |
491 | str->stream.seek = amd_body_stream_seek; | 496 | str->stream.seek = amd_body_stream_seek; |
492 | mu_body_set_stream (body, (mu_stream_t) str, msg); | 497 | mu_body_set_stream (body, (mu_stream_t) str, msg); |
... | @@ -1635,13 +1640,75 @@ amd_body_stream_read (mu_stream_t is, char *buffer, size_t buflen, | ... | @@ -1635,13 +1640,75 @@ amd_body_stream_read (mu_stream_t is, char *buffer, size_t buflen, |
1635 | } | 1640 | } |
1636 | 1641 | ||
1637 | static int | 1642 | static int |
1643 | amd_body_stream_readdelim (mu_stream_t is, char *buffer, size_t buflen, | ||
1644 | int delim, | ||
1645 | size_t *pnread) | ||
1646 | { | ||
1647 | struct _amd_body_stream *amdstr = (struct _amd_body_stream *)is; | ||
1648 | mu_body_t body = amdstr->body; | ||
1649 | mu_message_t msg = mu_body_get_owner (body); | ||
1650 | struct _amd_message *mhm = mu_message_get_owner (msg); | ||
1651 | size_t nread = 0; | ||
1652 | int status = 0; | ||
1653 | |||
1654 | amd_pool_open (mhm); | ||
1655 | |||
1656 | if (buffer == NULL || buflen == 0) | ||
1657 | { | ||
1658 | if (pnread) | ||
1659 | *pnread = nread; | ||
1660 | return 0; | ||
1661 | } | ||
1662 | |||
1663 | mu_monitor_rdlock (mhm->amd->mailbox->monitor); | ||
1664 | #ifdef WITH_PTHREAD | ||
1665 | /* read() is cancellation point since we're doing a potentially | ||
1666 | long operation. Lets make sure we clean the state. */ | ||
1667 | pthread_cleanup_push (amd_cleanup, (void *)mhm->amd->mailbox); | ||
1668 | #endif | ||
1669 | |||
1670 | status = mu_stream_seek (mhm->stream, mhm->body_start + amdstr->off, | ||
1671 | MU_SEEK_SET, NULL); | ||
1672 | if (status) | ||
1673 | { | ||
1674 | buflen--; | ||
1675 | while (buflen) | ||
1676 | { | ||
1677 | size_t ln, rdsize; | ||
1678 | |||
1679 | ln = mhm->body_end - (mhm->body_start + amdstr->off); | ||
1680 | if (ln > 0) | ||
1681 | { | ||
1682 | rdsize = ((size_t)ln < buflen) ? (size_t)ln : buflen; | ||
1683 | status = mu_stream_readdelim (mhm->stream, buffer, rdsize, | ||
1684 | delim, &rdsize); | ||
1685 | amdstr->off += nread; | ||
1686 | nread += rdsize; | ||
1687 | if (status) | ||
1688 | break; | ||
1689 | buflen -= rdsize; | ||
1690 | buffer += rdsize; | ||
1691 | } | ||
1692 | } | ||
1693 | } | ||
1694 | |||
1695 | mu_monitor_unlock (mhm->amd->mailbox->monitor); | ||
1696 | #ifdef WITH_PTHREAD | ||
1697 | pthread_cleanup_pop (0); | ||
1698 | #endif | ||
1699 | |||
1700 | if (pnread) | ||
1701 | *pnread = nread; | ||
1702 | return status; | ||
1703 | } | ||
1704 | |||
1705 | static int | ||
1638 | amd_body_stream_seek (mu_stream_t str, mu_off_t off, int whence, | 1706 | amd_body_stream_seek (mu_stream_t str, mu_off_t off, int whence, |
1639 | mu_off_t *presult) | 1707 | mu_off_t *presult) |
1640 | { | 1708 | { |
1641 | size_t size; | 1709 | size_t size; |
1642 | struct _amd_body_stream *amdstr = (struct _amd_body_stream *)str; | 1710 | struct _amd_body_stream *amdstr = (struct _amd_body_stream *)str; |
1643 | mu_message_t msg = mu_body_get_owner (amdstr->body); | 1711 | mu_message_t msg = mu_body_get_owner (amdstr->body); |
1644 | struct _amd_message *mhm = mu_message_get_owner (msg); | ||
1645 | 1712 | ||
1646 | amd_body_size (amdstr->body, &size); | 1713 | amd_body_size (amdstr->body, &size); |
1647 | switch (whence) | 1714 | switch (whence) | ... | ... |
... | @@ -999,6 +999,59 @@ header_read (mu_stream_t is, char *buffer, size_t buflen, size_t *pnread) | ... | @@ -999,6 +999,59 @@ header_read (mu_stream_t is, char *buffer, size_t buflen, size_t *pnread) |
999 | return 0; | 999 | return 0; |
1000 | } | 1000 | } |
1001 | 1001 | ||
1002 | #if 0 | ||
1003 | /* FIXME: Implement header_readdelim based on this: */ | ||
1004 | static int | ||
1005 | _header_readline (mu_stream_t is, char *buffer, size_t buflen, size_t *pnread) | ||
1006 | { | ||
1007 | struct _mu_header_stream *hstr = (struct _mu_header_stream *) is; | ||
1008 | mu_header_t header = hstr->hdr; | ||
1009 | struct mu_hdrent *ent; | ||
1010 | size_t ent_off; | ||
1011 | int status; | ||
1012 | size_t strsize; | ||
1013 | char *start, *end; | ||
1014 | |||
1015 | if (buflen == 0) | ||
1016 | return EINVAL; | ||
1017 | |||
1018 | header = mu_stream_get_owner (is); | ||
1019 | status = mu_header_fill (header); | ||
1020 | if (status) | ||
1021 | return status; | ||
1022 | if (mu_hdrent_find_stream_pos (header, hstr->off, &ent, &ent_off)) | ||
1023 | { | ||
1024 | if (pnread) | ||
1025 | *pnread = 0; | ||
1026 | return 0; | ||
1027 | } | ||
1028 | |||
1029 | buflen--; /* Account for the terminating nul */ | ||
1030 | |||
1031 | mu_hdrent_fixup (header, ent); | ||
1032 | strsize = MU_STR_SIZE (ent->nlen, ent->vlen) - ent_off; | ||
1033 | start = MU_HDRENT_NAME (header, ent) + ent_off; | ||
1034 | end = strchr (start, '\n'); | ||
1035 | if (end) | ||
1036 | { | ||
1037 | size_t len = end - start + 1; | ||
1038 | if (len < strsize) | ||
1039 | strsize = len; | ||
1040 | } | ||
1041 | |||
1042 | if (strsize < buflen) | ||
1043 | buflen = strsize; | ||
1044 | |||
1045 | memcpy (buffer, start, buflen); | ||
1046 | buffer[buflen] = 0; | ||
1047 | hstr->off += buflen; | ||
1048 | mu_hdrent_unroll_fixup (header, ent); | ||
1049 | if (pnread) | ||
1050 | *pnread = buflen; | ||
1051 | return 0; | ||
1052 | } | ||
1053 | #endif | ||
1054 | |||
1002 | static int | 1055 | static int |
1003 | header_write (mu_stream_t os, const char *buf, size_t buflen, size_t *pnwrite) | 1056 | header_write (mu_stream_t os, const char *buf, size_t buflen, size_t *pnwrite) |
1004 | { | 1057 | { | ... | ... |
... | @@ -243,6 +243,31 @@ _message_stream_read (struct _mu_stream *str, char *buf, size_t bufsize, | ... | @@ -243,6 +243,31 @@ _message_stream_read (struct _mu_stream *str, char *buf, size_t bufsize, |
243 | return rc; | 243 | return rc; |
244 | } | 244 | } |
245 | 245 | ||
246 | static int | ||
247 | _message_stream_readdelim (struct _mu_stream *str, char *buf, size_t bufsize, | ||
248 | int delim, size_t *pnread) | ||
249 | { | ||
250 | struct _mu_message_stream *sp = (struct _mu_message_stream *)str; | ||
251 | size_t nread = 0; | ||
252 | int rc; | ||
253 | |||
254 | while (bufsize) | ||
255 | { | ||
256 | size_t n; | ||
257 | rc = _check_stream_state (sp); | ||
258 | if (rc) | ||
259 | break; | ||
260 | if (sp->state == _mss_eof) | ||
261 | break; | ||
262 | rc = mu_stream_readdelim (sp->transport, buf, bufsize, delim, &n); | ||
263 | nread += n; | ||
264 | buf += n; | ||
265 | bufsize -= n; | ||
266 | } | ||
267 | *pnread = nread; | ||
268 | return rc; | ||
269 | } | ||
270 | |||
246 | #if 0 | 271 | #if 0 |
247 | static int | 272 | static int |
248 | _message_stream_write (struct _mu_stream *str, | 273 | _message_stream_write (struct _mu_stream *str, |
... | @@ -266,6 +291,7 @@ _message_stream_create (mu_stream_t *pmsg, mu_message_t msg, int flags) | ... | @@ -266,6 +291,7 @@ _message_stream_create (mu_stream_t *pmsg, mu_message_t msg, int flags) |
266 | return ENOMEM; | 291 | return ENOMEM; |
267 | 292 | ||
268 | sp->stream.read = _message_stream_read; | 293 | sp->stream.read = _message_stream_read; |
294 | sp->stream.readdelim = _message_stream_readdelim; | ||
269 | /* FIXME: Write is not defined */ | 295 | /* FIXME: Write is not defined */ |
270 | /* sp->stream.write = _message_stream_write;*/ | 296 | /* sp->stream.write = _message_stream_write;*/ |
271 | sp->stream.done = _message_stream_done; | 297 | sp->stream.done = _message_stream_done; | ... | ... |
... | @@ -536,22 +536,54 @@ mu_stream_read (mu_stream_t stream, void *buf, size_t size, size_t *pread) | ... | @@ -536,22 +536,54 @@ mu_stream_read (mu_stream_t stream, void *buf, size_t size, size_t *pread) |
536 | } | 536 | } |
537 | 537 | ||
538 | int | 538 | int |
539 | mu_stream_readline (mu_stream_t stream, char *buf, size_t size, size_t *pread) | 539 | _stream_scandelim (mu_stream_t stream, char *buf, size_t size, int delim, |
540 | size_t *pnread) | ||
541 | { | ||
542 | int rc = 0; | ||
543 | size_t nread = 0; | ||
544 | |||
545 | size--; | ||
546 | while (size) | ||
547 | { | ||
548 | char *p; | ||
549 | size_t len; | ||
550 | |||
551 | if (stream->level == 0) | ||
552 | { | ||
553 | if ((rc = _stream_fill_buffer (stream)) || stream->level == 0) | ||
554 | break; | ||
555 | } | ||
556 | |||
557 | p = memchr (stream->cur, delim, stream->level); | ||
558 | len = p ? p - stream->cur + 1 : stream->level; | ||
559 | if (len > size) | ||
560 | len = size; | ||
561 | memcpy (buf, stream->cur, len); | ||
562 | _stream_advance_buffer (stream, len); | ||
563 | buf += len; | ||
564 | size -= len; | ||
565 | nread += len; | ||
566 | } | ||
567 | *buf = 0; | ||
568 | *pnread = nread; | ||
569 | return rc; | ||
570 | } | ||
571 | |||
572 | static int | ||
573 | _stream_readdelim (mu_stream_t stream, char *buf, size_t size, | ||
574 | int delim, size_t *pread) | ||
540 | { | 575 | { |
541 | int rc; | 576 | int rc; |
542 | char c; | 577 | char c; |
543 | size_t n = 0, rdn; | 578 | size_t n = 0, rdn; |
544 | 579 | ||
545 | if (size == 0) | ||
546 | return EINVAL; | ||
547 | |||
548 | size--; | 580 | size--; |
549 | for (n = 0; | 581 | for (n = 0; |
550 | n < size && (rc = mu_stream_read (stream, &c, 1, &rdn)) == 0 && rdn;) | 582 | n < size && (rc = mu_stream_read (stream, &c, 1, &rdn)) == 0 && rdn;) |
551 | { | 583 | { |
552 | *buf++ = c; | 584 | *buf++ = c; |
553 | n++; | 585 | n++; |
554 | if (c == '\n') | 586 | if (c == delim) |
555 | break; | 587 | break; |
556 | } | 588 | } |
557 | *buf = 0; | 589 | *buf = 0; |
... | @@ -561,6 +593,30 @@ mu_stream_readline (mu_stream_t stream, char *buf, size_t size, size_t *pread) | ... | @@ -561,6 +593,30 @@ mu_stream_readline (mu_stream_t stream, char *buf, size_t size, size_t *pread) |
561 | } | 593 | } |
562 | 594 | ||
563 | int | 595 | int |
596 | mu_stream_readdelim (mu_stream_t stream, char *buf, size_t size, | ||
597 | int delim, size_t *pread) | ||
598 | { | ||
599 | int rc; | ||
600 | |||
601 | if (size == 0) | ||
602 | return EINVAL; | ||
603 | |||
604 | if (stream->readdelim) | ||
605 | rc = stream->readdelim (stream, buf, size, delim, pread); | ||
606 | else if (stream->buftype != mu_buffer_none) | ||
607 | rc = _stream_scandelim (stream, buf, size, delim, pread); | ||
608 | else | ||
609 | rc = _stream_readdelim (stream, buf, size, delim, pread); | ||
610 | return rc; | ||
611 | } | ||
612 | |||
613 | int | ||
614 | mu_stream_readline (mu_stream_t stream, char *buf, size_t size, size_t *pread) | ||
615 | { | ||
616 | return mu_stream_readdelim (stream, buf, size, '\n', pread); | ||
617 | } | ||
618 | |||
619 | int | ||
564 | mu_stream_getdelim (mu_stream_t stream, char **pbuf, size_t *psize, | 620 | mu_stream_getdelim (mu_stream_t stream, char **pbuf, size_t *psize, |
565 | int delim, size_t *pread) | 621 | int delim, size_t *pread) |
566 | { | 622 | { |
... | @@ -581,13 +637,8 @@ mu_stream_getdelim (mu_stream_t stream, char **pbuf, size_t *psize, | ... | @@ -581,13 +637,8 @@ mu_stream_getdelim (mu_stream_t stream, char **pbuf, size_t *psize, |
581 | 637 | ||
582 | for (;;) | 638 | for (;;) |
583 | { | 639 | { |
584 | char c; | ||
585 | size_t rdn; | 640 | size_t rdn; |
586 | 641 | ||
587 | rc = mu_stream_read (stream, &c, 1, &rdn); | ||
588 | if (rc || rdn == 0) | ||
589 | break; | ||
590 | |||
591 | /* Make enough space for len+1 (for final NUL) bytes. */ | 642 | /* Make enough space for len+1 (for final NUL) bytes. */ |
592 | if (cur_len + 1 >= n) | 643 | if (cur_len + 1 >= n) |
593 | { | 644 | { |
... | @@ -615,10 +666,20 @@ mu_stream_getdelim (mu_stream_t stream, char **pbuf, size_t *psize, | ... | @@ -615,10 +666,20 @@ mu_stream_getdelim (mu_stream_t stream, char **pbuf, size_t *psize, |
615 | n = needed; | 666 | n = needed; |
616 | } | 667 | } |
617 | 668 | ||
618 | lineptr[cur_len] = c; | 669 | if (stream->readdelim) |
619 | cur_len++; | 670 | rc = stream->readdelim (stream, lineptr + cur_len, n - cur_len, delim, |
671 | &rdn); | ||
672 | else if (stream->buftype != mu_buffer_none) | ||
673 | rc = _stream_scandelim (stream, lineptr + cur_len, n - cur_len, delim, | ||
674 | &rdn); | ||
675 | else | ||
676 | rc = mu_stream_read (stream, lineptr + cur_len, 1, &rdn); | ||
620 | 677 | ||
621 | if (c == delim) | 678 | if (rc || rdn == 0) |
679 | break; | ||
680 | cur_len += rdn; | ||
681 | |||
682 | if (lineptr[cur_len - 1] == delim) | ||
622 | break; | 683 | break; |
623 | } | 684 | } |
624 | lineptr[cur_len] = '\0'; | 685 | lineptr[cur_len] = '\0'; | ... | ... |
... | @@ -69,6 +69,16 @@ _streamref_read (struct _mu_stream *str, char *buf, size_t bufsize, | ... | @@ -69,6 +69,16 @@ _streamref_read (struct _mu_stream *str, char *buf, size_t bufsize, |
69 | } | 69 | } |
70 | 70 | ||
71 | static int | 71 | static int |
72 | _streamref_readdelim (struct _mu_stream *str, char *buf, size_t bufsize, | ||
73 | int delim, size_t *pnread) | ||
74 | { | ||
75 | struct _mu_streamref *sp = (struct _mu_streamref *)str; | ||
76 | return streamref_return (sp, mu_stream_readdelim (sp->transport, | ||
77 | buf, bufsize, | ||
78 | delim, pnread)); | ||
79 | } | ||
80 | |||
81 | static int | ||
72 | _streamref_write (struct _mu_stream *str, const char *buf, size_t bufsize, | 82 | _streamref_write (struct _mu_stream *str, const char *buf, size_t bufsize, |
73 | size_t *pnwrite) | 83 | size_t *pnwrite) |
74 | { | 84 | { |
... | @@ -264,6 +274,7 @@ mu_streamref_create_abridged (mu_stream_t *pref, mu_stream_t str, | ... | @@ -264,6 +274,7 @@ mu_streamref_create_abridged (mu_stream_t *pref, mu_stream_t str, |
264 | mu_stream_ref (str); | 274 | mu_stream_ref (str); |
265 | 275 | ||
266 | sp->stream.read = _streamref_read; | 276 | sp->stream.read = _streamref_read; |
277 | sp->stream.readdelim = _streamref_readdelim; | ||
267 | sp->stream.write = _streamref_write; | 278 | sp->stream.write = _streamref_write; |
268 | sp->stream.flush = _streamref_flush; | 279 | sp->stream.flush = _streamref_flush; |
269 | sp->stream.open = _streamref_open; | 280 | sp->stream.open = _streamref_open; | ... | ... |
-
Please register or sign in to post a comment