Commit 6f9d6633 6f9d663375903caf0a569bbbba7d5f5ad739c0e1 by Alain Magloire

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.
1 parent 3eda93f5
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.
......
1 SUBDIR = mailutils
2 pkginclude_HEADERS = \ 1 pkginclude_HEADERS = \
3 address.h \ 2 address.h \
4 attribute.h \ 3 attribute.h \
......
...@@ -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;
......