In order to boost performance, when doing the scan we use
the approach of downloading part of the header of the total set of messages. The it was done before is that the headers were ask one by one per message. This was causing performance delay because we were doing a lot of small transaction on the TCP/IP stack. By bundling the entire thing in one request there was much less transcation and the speed was increase by a factor of 10++. The Imap code folder_imap.c and mbx_imap.c is now messy. The rewrite in mailbox2 should clean this up though. * mailbox/folder_imap.c (imap_quoted_string): Allocated the memory instead. (imap_body): If we were doing the scan free the memory and create the cache header. (imap_fetch): Create the message if was not done, important for the scan. * mailbox/mbx_imap.c (imap_scan): Bundle one big request to fetch as much information as possible. (message_operation): Free the buffer when done. * mailbox/include/imap0.h: Add IMAP_SCAN states. * mailbox/file_stream.c (_file_readline): It seems that fgets() can not handle binary data. Try to do our best.
Showing
6 changed files
with
119 additions
and
30 deletions
1 | 2001-10-11 Alain Magloire | 1 | 2001-10-11 Alain Magloire |
2 | 2 | ||
3 | In order to boost performance, when doing the scan we use | ||
4 | the approach of downloading part of the header of the total | ||
5 | set of messages. The it was done before is that the headers | ||
6 | were ask one by one per message. This was causing performance | ||
7 | delay because we were doing a lot of small transaction on | ||
8 | the TCP/IP stack. By bundling the entire thing in one request | ||
9 | there was much less transcation and the speed was increase | ||
10 | by a factor of 10++. | ||
11 | The Imap code folder_imap.c and mbx_imap.c is now messy. | ||
12 | The rewrite in mailbox2 should clean this up though. | ||
13 | |||
14 | * mailbox/folder_imap.c (imap_quoted_string): Allocated the | ||
15 | memory instead. | ||
16 | (imap_body): If we were doing the scan free the memory and create | ||
17 | the cache header. | ||
18 | (imap_fetch): Create the message if was not done, important for | ||
19 | the scan. | ||
20 | * mailbox/mbx_imap.c (imap_scan): Bundle one big request to | ||
21 | fetch as much information as possible. | ||
22 | (message_operation): Free the buffer when done. | ||
23 | * mailbox/include/imap0.h: Add IMAP_SCAN states. | ||
24 | |||
25 | * mailbox/file_stream.c (_file_readline): It seems that fgets() can | ||
26 | not handle binary data. Try to do our best. | ||
27 | |||
28 | 2001-10-11 Alain Magloire | ||
29 | |||
3 | * mailbox/header.c (header_get_fvalue): When it fails set the number | 30 | * mailbox/header.c (header_get_fvalue): When it fails set the number |
4 | of byte written to 0. | 31 | of byte written to 0. |
5 | (header_get_value): Likewised. | 32 | (header_get_value): Likewised. | ... | ... |
... | @@ -110,7 +110,11 @@ _file_readline (stream_t stream, char *optr, size_t osize, | ... | @@ -110,7 +110,11 @@ _file_readline (stream_t stream, char *optr, size_t osize, |
110 | char *tmp = optr; | 110 | char *tmp = optr; |
111 | while (*tmp) tmp++; /* strlen(optr) */ | 111 | while (*tmp) tmp++; /* strlen(optr) */ |
112 | n = tmp - optr; | 112 | n = tmp - optr; |
113 | fs->offset += n; | 113 | /* !!!!! WTF ??? */ |
114 | if (n == 0) | ||
115 | n++; | ||
116 | else | ||
117 | fs->offset += n; | ||
114 | } | 118 | } |
115 | else | 119 | else |
116 | { | 120 | { | ... | ... |
... | @@ -912,6 +912,8 @@ imap_quoted_string (f_imap_t f_imap, char **ptr) | ... | @@ -912,6 +912,8 @@ imap_quoted_string (f_imap_t f_imap, char **ptr) |
912 | (*ptr)++; | 912 | (*ptr)++; |
913 | } | 913 | } |
914 | f_imap->callback.total = *ptr - bquote; | 914 | f_imap->callback.total = *ptr - bquote; |
915 | f_imap->callback.buffer = calloc (f_imap->callback.total + 1, 1); | ||
916 | f_imap->callback.buflen = f_imap->callback.total; | ||
915 | /* Fill the call back buffer. The if is redundant there should always | 917 | /* Fill the call back buffer. The if is redundant there should always |
916 | be enough room since the request is base on the buffer size. */ | 918 | be enough room since the request is base on the buffer size. */ |
917 | if (f_imap->callback.total <= f_imap->callback.buflen | 919 | if (f_imap->callback.total <= f_imap->callback.buflen |
... | @@ -940,6 +942,8 @@ imap_string (f_imap_t f_imap, char **ptr) | ... | @@ -940,6 +942,8 @@ imap_string (f_imap_t f_imap, char **ptr) |
940 | { | 942 | { |
941 | (*ptr)++; | 943 | (*ptr)++; |
942 | /* Reset the buffer to the beginning. */ | 944 | /* Reset the buffer to the beginning. */ |
945 | f_imap->callback.buffer = calloc (f_imap->callback.nleft + 1, 1); | ||
946 | f_imap->callback.buflen = f_imap->callback.nleft; | ||
943 | f_imap->ptr = f_imap->buffer; | 947 | f_imap->ptr = f_imap->buffer; |
944 | status = imap_literal_string (f_imap, ptr); | 948 | status = imap_literal_string (f_imap, ptr); |
945 | } | 949 | } |
... | @@ -1333,26 +1337,22 @@ imap_body (f_imap_t f_imap, char **ptr) | ... | @@ -1333,26 +1337,22 @@ imap_body (f_imap_t f_imap, char **ptr) |
1333 | strncpy (section, *ptr, len); | 1337 | strncpy (section, *ptr, len); |
1334 | section[len] = '\0'; | 1338 | section[len] = '\0'; |
1335 | /* strupper. */ | 1339 | /* strupper. */ |
1336 | for (; *p; p++) | 1340 | for (; *p; p++) if (isupper((unsigned)*p)) *p = toupper ((unsigned)*p); |
1341 | /* Set the callback type to update the correct line count. */ | ||
1342 | //if (!strstr (section, "FIELD")) | ||
1337 | { | 1343 | { |
1338 | if (isalpha((unsigned)*p)) | 1344 | if (strstr (section, "MIME") || (strstr (section, "HEADER"))) |
1339 | *p = toupper ((unsigned)*p); | 1345 | { |
1340 | } | 1346 | f_imap->callback.type = IMAP_HEADER; |
1341 | /* Check to see the callback type to update the line count. */ | 1347 | } |
1342 | if (!strstr (section, "FIELD")) | 1348 | else if (strstr (section, "TEXT") || len > 0) |
1343 | { | 1349 | { |
1344 | if (strstr (section, "MIME") || (strstr (section, "HEADER"))) | 1350 | f_imap->callback.type = IMAP_BODY; |
1345 | { | 1351 | } |
1346 | f_imap->callback.type = IMAP_HEADER; | 1352 | else if (len == 0) /* body[] */ |
1347 | } | 1353 | { |
1348 | else if (strstr (section, "TEXT") || len > 0) | 1354 | f_imap->callback.type = IMAP_MESSAGE; |
1349 | { | 1355 | } |
1350 | f_imap->callback.type = IMAP_BODY; | ||
1351 | } | ||
1352 | else if (len == 0) /* body[] */ | ||
1353 | { | ||
1354 | f_imap->callback.type = IMAP_MESSAGE; | ||
1355 | } | ||
1356 | } | 1356 | } |
1357 | sep++; /* Move pass the ']' */ | 1357 | sep++; /* Move pass the ']' */ |
1358 | *ptr = sep; | 1358 | *ptr = sep; |
... | @@ -1370,7 +1370,17 @@ imap_body (f_imap_t f_imap, char **ptr) | ... | @@ -1370,7 +1370,17 @@ imap_body (f_imap_t f_imap, char **ptr) |
1370 | } | 1370 | } |
1371 | } | 1371 | } |
1372 | status = imap_string (f_imap, ptr); | 1372 | status = imap_string (f_imap, ptr); |
1373 | f_imap->callback.type = IMAP_MESSAGE; | 1373 | if (f_imap->state == IMAP_SCAN_ACK && f_imap->callback.total) |
1374 | { | ||
1375 | status = header_create (&f_imap->callback.msg_imap->fheader, | ||
1376 | f_imap->callback.buffer, f_imap->callback.total, | ||
1377 | NULL); | ||
1378 | free (f_imap->callback.buffer); | ||
1379 | f_imap->callback.buffer = NULL; | ||
1380 | f_imap->callback.buflen = 0; | ||
1381 | f_imap->callback.total = 0; | ||
1382 | f_imap->callback.nleft = 0; | ||
1383 | } | ||
1374 | return status; | 1384 | return status; |
1375 | } | 1385 | } |
1376 | 1386 | ||
... | @@ -1479,6 +1489,8 @@ imap_fetch (f_imap_t f_imap) | ... | @@ -1479,6 +1489,8 @@ imap_fetch (f_imap_t f_imap) |
1479 | { | 1489 | { |
1480 | /* Find the imap mesg struct. */ | 1490 | /* Find the imap mesg struct. */ |
1481 | size_t i; | 1491 | size_t i; |
1492 | message_t msg = NULL; | ||
1493 | mailbox_get_message (m_imap->mailbox, msgno, &msg); | ||
1482 | for (i = 0; i < m_imap->imessages_count; i++) | 1494 | for (i = 0; i < m_imap->imessages_count; i++) |
1483 | { | 1495 | { |
1484 | if (m_imap->imessages[i] && m_imap->imessages[i]->num == msgno) | 1496 | if (m_imap->imessages[i] && m_imap->imessages[i]->num == msgno) |
... | @@ -1487,6 +1499,7 @@ imap_fetch (f_imap_t f_imap) | ... | @@ -1487,6 +1499,7 @@ imap_fetch (f_imap_t f_imap) |
1487 | break; | 1499 | break; |
1488 | } | 1500 | } |
1489 | } | 1501 | } |
1502 | /* message_destroy (&msg); */ | ||
1490 | } | 1503 | } |
1491 | 1504 | ||
1492 | while (*sp && *sp != ')') | 1505 | while (*sp && *sp != ')') |
... | @@ -1781,7 +1794,6 @@ imap_parse (f_imap_t f_imap) | ... | @@ -1781,7 +1794,6 @@ imap_parse (f_imap_t f_imap) |
1781 | /* Is the response untagged ? */ | 1794 | /* Is the response untagged ? */ |
1782 | if (tag && tag[0] == '*') | 1795 | if (tag && tag[0] == '*') |
1783 | { | 1796 | { |
1784 | |||
1785 | /* Is it a Status Response. */ | 1797 | /* Is it a Status Response. */ |
1786 | if (strcasecmp (response, "OK") == 0) | 1798 | if (strcasecmp (response, "OK") == 0) |
1787 | { | 1799 | { |
... | @@ -1923,6 +1935,7 @@ imap_parse (f_imap_t f_imap) | ... | @@ -1923,6 +1935,7 @@ imap_parse (f_imap_t f_imap) |
1923 | } | 1935 | } |
1924 | else if (strcasecmp (response, "PREAUTH") == 0) | 1936 | else if (strcasecmp (response, "PREAUTH") == 0) |
1925 | { | 1937 | { |
1938 | /* Should we be dealing with this? */ | ||
1926 | } | 1939 | } |
1927 | else if (strcasecmp (response, "BYE") == 0) | 1940 | else if (strcasecmp (response, "BYE") == 0) |
1928 | { | 1941 | { | ... | ... |
... | @@ -111,6 +111,7 @@ enum imap_state | ... | @@ -111,6 +111,7 @@ enum imap_state |
111 | IMAP_NOOP, IMAP_NOOP_ACK, | 111 | IMAP_NOOP, IMAP_NOOP_ACK, |
112 | IMAP_OPEN_CONNECTION, | 112 | IMAP_OPEN_CONNECTION, |
113 | IMAP_RENAME, IMAP_RENAME_ACK, | 113 | IMAP_RENAME, IMAP_RENAME_ACK, |
114 | IMAP_SCAN, IMAP_SCAN_ACK, | ||
114 | IMAP_SELECT, IMAP_SELECT_ACK, | 115 | IMAP_SELECT, IMAP_SELECT_ACK, |
115 | IMAP_STORE, IMAP_STORE_ACK, | 116 | IMAP_STORE, IMAP_STORE_ACK, |
116 | IMAP_SUBSCRIBE, IMAP_SUBSCRIBE_ACK, | 117 | IMAP_SUBSCRIBE, IMAP_SUBSCRIBE_ACK, | ... | ... |
... | @@ -34,6 +34,10 @@ | ... | @@ -34,6 +34,10 @@ |
34 | #include <mailbox0.h> | 34 | #include <mailbox0.h> |
35 | #include <registrar0.h> | 35 | #include <registrar0.h> |
36 | #include <imap0.h> | 36 | #include <imap0.h> |
37 | #undef min | ||
38 | #define min(a,b) ((a) < (b) ? (a) : (b)) | ||
39 | |||
40 | #define MU_IMAP_CACHE_HEADERS "Bcc Cc Content-Language Content-Transfer-Encoding Content-Type Date From In-Reply-To Message-ID Reference Reply-To Sender Subject To X-UIDL" | ||
37 | 41 | ||
38 | /* Functions to overload the mailbox_t API. */ | 42 | /* Functions to overload the mailbox_t API. */ |
39 | static void mailbox_imap_destroy __P ((mailbox_t)); | 43 | static void mailbox_imap_destroy __P ((mailbox_t)); |
... | @@ -217,7 +221,7 @@ mailbox_imap_close (mailbox_t mailbox) | ... | @@ -217,7 +221,7 @@ mailbox_imap_close (mailbox_t mailbox) |
217 | f_imap_t f_imap = m_imap->f_imap; | 221 | f_imap_t f_imap = m_imap->f_imap; |
218 | int status = 0; | 222 | int status = 0; |
219 | 223 | ||
220 | /* Select first. */ | 224 | /* Select first. */ |
221 | status = imap_messages_count (mailbox, NULL); | 225 | status = imap_messages_count (mailbox, NULL); |
222 | if (status != 0) | 226 | if (status != 0) |
223 | return status; | 227 | return status; |
... | @@ -279,7 +283,7 @@ imap_get_message (mailbox_t mailbox, size_t msgno, message_t *pmsg) | ... | @@ -279,7 +283,7 @@ imap_get_message (mailbox_t mailbox, size_t msgno, message_t *pmsg) |
279 | int status = 0; | 283 | int status = 0; |
280 | size_t i; | 284 | size_t i; |
281 | 285 | ||
282 | if (pmsg == NULL) | 286 | if (pmsg == NULL || msgno == 0 || msgno > m_imap->messages_count) |
283 | return EINVAL; | 287 | return EINVAL; |
284 | 288 | ||
285 | monitor_rdlock (mailbox->monitor); | 289 | monitor_rdlock (mailbox->monitor); |
... | @@ -535,6 +539,8 @@ imap_scan (mailbox_t mailbox, size_t msgno, size_t *pcount) | ... | @@ -535,6 +539,8 @@ imap_scan (mailbox_t mailbox, size_t msgno, size_t *pcount) |
535 | int status; | 539 | int status; |
536 | size_t i; | 540 | size_t i; |
537 | size_t count = 0; | 541 | size_t count = 0; |
542 | m_imap_t m_imap = mailbox->data; | ||
543 | f_imap_t f_imap = m_imap->f_imap; | ||
538 | 544 | ||
539 | /* Selected. */ | 545 | /* Selected. */ |
540 | status = imap_messages_count (mailbox, &count); | 546 | status = imap_messages_count (mailbox, &count); |
... | @@ -542,8 +548,38 @@ imap_scan (mailbox_t mailbox, size_t msgno, size_t *pcount) | ... | @@ -542,8 +548,38 @@ imap_scan (mailbox_t mailbox, size_t msgno, size_t *pcount) |
542 | *pcount = count; | 548 | *pcount = count; |
543 | if (status != 0) | 549 | if (status != 0) |
544 | return status; | 550 | return status; |
551 | |||
552 | switch (f_imap->state) | ||
553 | { | ||
554 | case IMAP_NO_STATE: | ||
555 | status = imap_writeline (f_imap, | ||
556 | "g%d FETCH 1:* (FLAGS RFC822.SIZE BODY.PEEK[HEADER.FIELDS (%s)])\r\n", | ||
557 | f_imap->seq++, MU_IMAP_CACHE_HEADERS); | ||
558 | CHECK_ERROR (f_imap, status); | ||
559 | MAILBOX_DEBUG0 (mailbox, MU_DEBUG_PROT, f_imap->buffer); | ||
560 | f_imap->state = IMAP_SCAN; | ||
561 | |||
562 | case IMAP_SCAN: | ||
563 | status = imap_send (f_imap); | ||
564 | CHECK_EAGAIN (f_imap, status); | ||
565 | f_imap->state = IMAP_SCAN_ACK; | ||
566 | |||
567 | case IMAP_SCAN_ACK: | ||
568 | status = imap_parse (f_imap); | ||
569 | CHECK_EAGAIN (f_imap, status); | ||
570 | MAILBOX_DEBUG0 (mailbox, MU_DEBUG_PROT, f_imap->buffer); | ||
571 | |||
572 | default: | ||
573 | CHECK_EAGAIN (f_imap, status); | ||
574 | return status; | ||
575 | } | ||
576 | |||
577 | f_imap->state = IMAP_NO_STATE; | ||
578 | |||
579 | /* If no callbacks bail out early. */ | ||
545 | if (mailbox->observable == NULL) | 580 | if (mailbox->observable == NULL) |
546 | return 0; | 581 | return 0; |
582 | |||
547 | for (i = msgno; i <= *pcount; i++) | 583 | for (i = msgno; i <= *pcount; i++) |
548 | { | 584 | { |
549 | if (observable_notify (mailbox->observable, MU_EVT_MESSAGE_ADD) != 0) | 585 | if (observable_notify (mailbox->observable, MU_EVT_MESSAGE_ADD) != 0) |
... | @@ -1591,7 +1627,6 @@ imap_header_get_fvalue (header_t header, const char *field, char * buffer, | ... | @@ -1591,7 +1627,6 @@ imap_header_get_fvalue (header_t header, const char *field, char * buffer, |
1591 | status = imap_messages_count (m_imap->mailbox, NULL); | 1627 | status = imap_messages_count (m_imap->mailbox, NULL); |
1592 | if (status != 0) | 1628 | if (status != 0) |
1593 | return status; | 1629 | return status; |
1594 | #define MU_IMAP_CACHE_HEADERS "Bcc Cc Content-Language Content-Transfer-Encoding Content-Type Date From In-Reply-To Message-ID Reference Reply-To Sender Subject To X-UIDL" | ||
1595 | status = imap_writeline (f_imap, | 1630 | status = imap_writeline (f_imap, |
1596 | "g%d FETCH %d (FLAGS RFC822.SIZE BODY.PEEK[HEADER.FIELDS (%s)])\r\n", | 1631 | "g%d FETCH %d (FLAGS RFC822.SIZE BODY.PEEK[HEADER.FIELDS (%s)])\r\n", |
1597 | f_imap->seq++, msg_imap->num, | 1632 | f_imap->seq++, msg_imap->num, |
... | @@ -1800,9 +1835,12 @@ message_operation (f_imap_t f_imap, msg_imap_t msg_imap, char *buffer, | ... | @@ -1800,9 +1835,12 @@ message_operation (f_imap_t f_imap, msg_imap_t msg_imap, char *buffer, |
1800 | status = imap_send (f_imap); | 1835 | status = imap_send (f_imap); |
1801 | CHECK_EAGAIN (f_imap, status); | 1836 | CHECK_EAGAIN (f_imap, status); |
1802 | /* Set the callback, we want the results. */ | 1837 | /* Set the callback, we want the results. */ |
1803 | f_imap->callback.buffer = buffer; | 1838 | if (f_imap->callback.buffer) |
1804 | f_imap->callback.buflen = buflen; | 1839 | free (f_imap->callback.buffer); |
1840 | f_imap->callback.buffer = NULL; | ||
1841 | f_imap->callback.buflen = 0; | ||
1805 | f_imap->callback.total = 0; | 1842 | f_imap->callback.total = 0; |
1843 | f_imap->callback.nleft = 0; | ||
1806 | f_imap->callback.msg_imap = msg_imap; | 1844 | f_imap->callback.msg_imap = msg_imap; |
1807 | f_imap->state = IMAP_FETCH_ACK; | 1845 | f_imap->state = IMAP_FETCH_ACK; |
1808 | 1846 | ||
... | @@ -1816,15 +1854,22 @@ message_operation (f_imap_t f_imap, msg_imap_t msg_imap, char *buffer, | ... | @@ -1816,15 +1854,22 @@ message_operation (f_imap_t f_imap, msg_imap_t msg_imap, char *buffer, |
1816 | default: | 1854 | default: |
1817 | break; | 1855 | break; |
1818 | } | 1856 | } |
1819 | if (plen) | ||
1820 | *plen = f_imap->callback.total; | ||
1821 | 1857 | ||
1822 | if (status == 0 && f_imap->isopen == 0 && f_imap->callback.total == 0) | 1858 | if (status == 0 && f_imap->isopen == 0 && f_imap->callback.total == 0) |
1823 | status = EBADF; | 1859 | status = EBADF; |
1860 | |||
1824 | /* Clear the callback. */ | 1861 | /* Clear the callback. */ |
1862 | buflen = min (buflen, f_imap->callback.total); | ||
1863 | if (buffer && f_imap->callback.buffer) | ||
1864 | memcpy (buffer, f_imap->callback.buffer, buflen); | ||
1865 | if (plen) | ||
1866 | *plen = buflen; | ||
1867 | if (f_imap->callback.buffer) | ||
1868 | free (f_imap->callback.buffer); | ||
1825 | f_imap->callback.buffer = NULL; | 1869 | f_imap->callback.buffer = NULL; |
1826 | f_imap->callback.buflen = 0; | 1870 | f_imap->callback.buflen = 0; |
1827 | f_imap->callback.total = 0; | 1871 | f_imap->callback.total = 0; |
1872 | f_imap->callback.nleft = 0; | ||
1828 | f_imap->callback.type = 0; | 1873 | f_imap->callback.type = 0; |
1829 | f_imap->callback.msg_imap = NULL; | 1874 | f_imap->callback.msg_imap = NULL; |
1830 | f_imap->state = IMAP_NO_STATE; | 1875 | f_imap->state = IMAP_NO_STATE; | ... | ... |
-
Please register or sign in to post a comment