Commit f96ce94e f96ce94e2ad041c0f6011eafb74e1799e1f90eb0 by Sergey Poznyakoff

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.
1 parent 03aa45f1
...@@ -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;
......