Commit 8328c0ef 8328c0efd4eff1f1cbb10af13c042fc1162a3872 by Sergey Poznyakoff

Optimized for speed:

_mh_message_save(): scan the message while saving it. If expunge==0,
do not create temporary, operate directly on the message file instead.
mh_append_message(): Do not rescan appended message.
mh_scan_message(): Do not rescan the message if it's not changed
1 parent 503d34b8
...@@ -71,9 +71,10 @@ struct _mh_message ...@@ -71,9 +71,10 @@ struct _mh_message
71 int attr_flags; /* Attribute flags */ 71 int attr_flags; /* Attribute flags */
72 int deleted; /* Was the message originally deleted */ 72 int deleted; /* Was the message originally deleted */
73 73
74 size_t header_lines; 74 time_t mtime; /* Time of last modification */
75 size_t body_lines; 75 size_t header_lines; /* Number of lines in the header part */
76 76 size_t body_lines; /* Number of lines in the body */
77
77 message_t message; /* Corresponding message_t */ 78 message_t message; /* Corresponding message_t */
78 struct _mh_data *mhd; /* Back pointer. */ 79 struct _mh_data *mhd; /* Back pointer. */
79 }; 80 };
...@@ -479,19 +480,26 @@ static int ...@@ -479,19 +480,26 @@ static int
479 _mh_message_save (struct _mh_data *mhd, struct _mh_message *mhm, int expunge) 480 _mh_message_save (struct _mh_data *mhd, struct _mh_message *mhm, int expunge)
480 { 481 {
481 stream_t stream = NULL; 482 stream_t stream = NULL;
482 char *name, *buf = NULL, *msg_name; 483 char *name = NULL, *buf = NULL, *msg_name;
483 size_t n, off = 0; 484 size_t n, off = 0;
484 size_t bsize; 485 size_t bsize;
486 size_t nlines;
485 FILE *fp; 487 FILE *fp;
486 message_t msg = mhm->message; 488 message_t msg = mhm->message;
487 header_t hdr; 489 header_t hdr;
488 int status; 490 int status;
489 attribute_t attr; 491 attribute_t attr;
490 body_t body; 492 body_t body;
491
492 (void)expunge;
493 493
494 fp = _mh_tempfile (mhm->mhd, &name); 494 if (expunge)
495 fp = _mh_tempfile (mhm->mhd, &name);
496 else
497 {
498 msg_name = _mh_message_name (mhm, mhm->deleted);
499 fp = fopen (msg_name, "w");
500 free (msg_name);
501 }
502
495 if (!fp) 503 if (!fp)
496 { 504 {
497 free (mhm); 505 free (mhm);
...@@ -515,11 +523,14 @@ _mh_message_save (struct _mh_data *mhd, struct _mh_message *mhm, int expunge) ...@@ -515,11 +523,14 @@ _mh_message_save (struct _mh_data *mhd, struct _mh_message *mhm, int expunge)
515 message_get_header (msg, &hdr); 523 message_get_header (msg, &hdr);
516 header_get_stream (hdr, &stream); 524 header_get_stream (hdr, &stream);
517 off = 0; 525 off = 0;
526 nlines = 0;
518 while ((status = stream_readline (stream, buf, bsize, off, &n)) == 0 527 while ((status = stream_readline (stream, buf, bsize, off, &n)) == 0
519 && n != 0) 528 && n != 0)
520 { 529 {
521 if (buf[0] == '\n') 530 if (buf[0] == '\n')
522 break; 531 break;
532
533 nlines++;
523 534
524 if (!(strncasecmp (buf, "status:", 7) == 0 535 if (!(strncasecmp (buf, "status:", 7) == 0
525 || strncasecmp (buf, "x-imapbase:", 11) == 0 536 || strncasecmp (buf, "x-imapbase:", 11) == 0
...@@ -527,6 +538,10 @@ _mh_message_save (struct _mh_data *mhd, struct _mh_message *mhm, int expunge) ...@@ -527,6 +538,10 @@ _mh_message_save (struct _mh_data *mhd, struct _mh_message *mhm, int expunge)
527 fprintf (fp, "%s", buf); 538 fprintf (fp, "%s", buf);
528 off += n; 539 off += n;
529 } 540 }
541
542 mhm->header_lines = nlines;
543 mhm->body_start = off;
544
530 /* Add imapbase */ 545 /* Add imapbase */
531 if (!mhd->msg_head || (mhd->msg_head == mhm)) /*FIXME*/ 546 if (!mhd->msg_head || (mhd->msg_head == mhm)) /*FIXME*/
532 fprintf (fp, "X-IMAPbase: %lu %u\n", mhd->uidvalidity, mhd->uidnext); 547 fprintf (fp, "X-IMAPbase: %lu %u\n", mhd->uidvalidity, mhd->uidnext);
...@@ -545,19 +560,30 @@ _mh_message_save (struct _mh_data *mhd, struct _mh_message *mhm, int expunge) ...@@ -545,19 +560,30 @@ _mh_message_save (struct _mh_data *mhd, struct _mh_message *mhm, int expunge)
545 message_get_body (msg, &body); 560 message_get_body (msg, &body);
546 body_get_stream (body, &stream); 561 body_get_stream (body, &stream);
547 off = 0; 562 off = 0;
563 nlines = 0;
548 while (stream_read (stream, buf, bsize, off, &n) == 0 && n != 0) 564 while (stream_read (stream, buf, bsize, off, &n) == 0 && n != 0)
549 { 565 {
566 char *p;
567 for (p = buf; p < buf + n; p++)
568 if (*p == '\n')
569 nlines++;
550 fwrite (buf, 1, n, fp); 570 fwrite (buf, 1, n, fp);
551 off += n; 571 off += n;
552 } 572 }
553 573
574 mhm->body_lines = nlines;
575 mhm->body_end = off;
576
554 free (buf); 577 free (buf);
555 fclose (fp); 578 fclose (fp);
556 579
557 msg_name = _mh_message_name (mhm, mhm->deleted); 580 if (expunge)
558 rename (name, msg_name); 581 {
559 free (name); 582 msg_name = _mh_message_name (mhm, mhm->deleted);
560 free (msg_name); 583 rename (name, msg_name);
584 free (name);
585 free (msg_name);
586 }
561 587
562 return 0; 588 return 0;
563 } 589 }
...@@ -584,8 +610,6 @@ mh_append_message (mailbox_t mailbox, message_t msg) ...@@ -584,8 +610,6 @@ mh_append_message (mailbox_t mailbox, message_t msg)
584 mhm->message = NULL; 610 mhm->message = NULL;
585 /* Insert and re-scan the message */ 611 /* Insert and re-scan the message */
586 _mh_message_insert (mhd, mhm); 612 _mh_message_insert (mhd, mhm);
587 mh_message_stream_open (mhm);
588 mh_message_stream_close (mhm);
589 return status; 613 return status;
590 } 614 }
591 615
...@@ -851,9 +875,7 @@ _mh_message_delete (struct _mh_data *mhd, struct _mh_message *msg) ...@@ -851,9 +875,7 @@ _mh_message_delete (struct _mh_data *mhd, struct _mh_message *msg)
851 } 875 }
852 876
853 /* Scan given message and fill mh_message_t fields. 877 /* Scan given message and fill mh_message_t fields.
854 NOTE: the function assumes mhm->stream != NULL. 878 NOTE: the function assumes mhm->stream != NULL. */
855 FIXME: Cache all the information and do not rescan the message when
856 re-opening it. */
857 static int 879 static int
858 mh_scan_message (struct _mh_message *mhm) 880 mh_scan_message (struct _mh_message *mhm)
859 { 881 {
...@@ -867,6 +889,21 @@ mh_scan_message (struct _mh_message *mhm) ...@@ -867,6 +889,21 @@ mh_scan_message (struct _mh_message *mhm)
867 size_t blines = 0; 889 size_t blines = 0;
868 size_t body_start = 0; 890 size_t body_start = 0;
869 891
892 /* Check if the message was modified after the last scan */
893 if (mhm->mtime)
894 {
895 struct stat st;
896 char *msg_name = _mh_message_name (mhm, mhm->deleted);
897
898 if (stat (msg_name, &st) == 0 && st.st_mtime == mhm->mtime)
899 {
900 /* Nothing to do */
901 free (msg_name);
902 return 0;
903 }
904 free (msg_name);
905 }
906
870 while ((status = stream_readline (stream, buf, sizeof (buf), off, &n) == 0) 907 while ((status = stream_readline (stream, buf, sizeof (buf), off, &n) == 0)
871 && n != 0) 908 && n != 0)
872 { 909 {
...@@ -1391,8 +1428,7 @@ mh_envelope_date (envelope_t envelope, char *buf, size_t len, ...@@ -1391,8 +1428,7 @@ mh_envelope_date (envelope_t envelope, char *buf, size_t len,
1391 } 1428 }
1392 1429
1393 static int 1430 static int
1394 mh_envelope_sender (envelope_t envelope, char *buf, size_t len, 1431 mh_envelope_sender (envelope_t envelope, char *buf, size_t len, size_t *psize)
1395 size_t *psize)
1396 { 1432 {
1397 message_t msg = envelope_get_owner (envelope); 1433 message_t msg = envelope_get_owner (envelope);
1398 struct _mh_message *mhm = message_get_owner (msg); 1434 struct _mh_message *mhm = message_get_owner (msg);
......