mh,maildir: speed up scanning.
* include/mailutils/sys/amd.h (_amd_message_append, amd_sort): New protos. * libmailutils/base/amd.c (amd_array_expand): Call memmove only if there is actually something to move. (_amd_message_append, amd_sort): New functions. * libproto/maildir/mbox.c (maildir_scan_dir): Append new messages to the end of the array, and sort it afterwards. This avoids unnecessary memory moves, which improves performance considerably, especially on large mailboxes. * libproto/mh/mbox.c (mh_scan0): Likewise.
Showing
4 changed files
with
85 additions
and
45 deletions
... | @@ -110,6 +110,8 @@ int _amd_message_lookup_or_insert (struct _amd_data *amd, | ... | @@ -110,6 +110,8 @@ int _amd_message_lookup_or_insert (struct _amd_data *amd, |
110 | struct _amd_message *key, | 110 | struct _amd_message *key, |
111 | size_t *pindex); | 111 | size_t *pindex); |
112 | int _amd_message_insert (struct _amd_data *mhd, struct _amd_message *msg); | 112 | int _amd_message_insert (struct _amd_data *mhd, struct _amd_message *msg); |
113 | int _amd_message_append (struct _amd_data *amd, struct _amd_message *msg); | ||
114 | void amd_sort (struct _amd_data *amd); | ||
113 | int amd_message_stream_open (struct _amd_message *mhm); | 115 | int amd_message_stream_open (struct _amd_message *mhm); |
114 | void amd_message_stream_close (struct _amd_message *mhm); | 116 | void amd_message_stream_close (struct _amd_message *mhm); |
115 | void amd_cleanup (void *arg); | 117 | void amd_cleanup (void *arg); | ... | ... |
... | @@ -241,8 +241,9 @@ amd_array_expand (struct _amd_data *amd, size_t index) | ... | @@ -241,8 +241,9 @@ amd_array_expand (struct _amd_data *amd, size_t index) |
241 | } | 241 | } |
242 | amd->msg_array = p; | 242 | amd->msg_array = p; |
243 | } | 243 | } |
244 | memmove (&amd->msg_array[index+1], &amd->msg_array[index], | 244 | if (amd->msg_count > index) |
245 | (amd->msg_count-index) * amd->msg_size); | 245 | memmove (&amd->msg_array[index+1], &amd->msg_array[index], |
246 | (amd->msg_count-index) * amd->msg_size); | ||
246 | amd->msg_count++; | 247 | amd->msg_count++; |
247 | return 0; | 248 | return 0; |
248 | } | 249 | } |
... | @@ -1381,6 +1382,35 @@ _amd_message_insert (struct _amd_data *amd, struct _amd_message *msg) | ... | @@ -1381,6 +1382,35 @@ _amd_message_insert (struct _amd_data *amd, struct _amd_message *msg) |
1381 | return 0; | 1382 | return 0; |
1382 | } | 1383 | } |
1383 | 1384 | ||
1385 | /* Append message to the end of the array, expanding it if necessary */ | ||
1386 | int | ||
1387 | _amd_message_append (struct _amd_data *amd, struct _amd_message *msg) | ||
1388 | { | ||
1389 | size_t index = amd->msg_count; | ||
1390 | int rc = amd_array_expand (amd, index); | ||
1391 | if (rc) | ||
1392 | return rc; | ||
1393 | amd->msg_array[index] = msg; | ||
1394 | msg->amd = amd; | ||
1395 | return 0; | ||
1396 | } | ||
1397 | |||
1398 | static int | ||
1399 | msg_array_comp (const void *a, const void *b) | ||
1400 | { | ||
1401 | struct _amd_message **ma = (struct _amd_message **) a; | ||
1402 | struct _amd_message **mb = (struct _amd_message **) b; | ||
1403 | struct _amd_data *amd = (*ma)->amd; | ||
1404 | return amd->msg_cmp (*ma, *mb); | ||
1405 | } | ||
1406 | |||
1407 | void | ||
1408 | amd_sort (struct _amd_data *amd) | ||
1409 | { | ||
1410 | qsort (amd->msg_array, amd->msg_count, sizeof (amd->msg_array[0]), | ||
1411 | msg_array_comp); | ||
1412 | } | ||
1413 | |||
1384 | static void | 1414 | static void |
1385 | _amd_message_delete (struct _amd_data *amd, struct _amd_message *msg) | 1415 | _amd_message_delete (struct _amd_data *amd, struct _amd_message *msg) |
1386 | { | 1416 | { | ... | ... |
... | @@ -584,7 +584,8 @@ maildir_scan_dir (struct _amd_data *amd, DIR *dir, char *dirname) | ... | @@ -584,7 +584,8 @@ maildir_scan_dir (struct _amd_data *amd, DIR *dir, char *dirname) |
584 | char *p; | 584 | char *p; |
585 | size_t index; | 585 | size_t index; |
586 | int rc = 0; | 586 | int rc = 0; |
587 | 587 | int need_sort = 0; | |
588 | |||
588 | while ((entry = readdir (dir))) | 589 | while ((entry = readdir (dir))) |
589 | { | 590 | { |
590 | switch (entry->d_name[0]) | 591 | switch (entry->d_name[0]) |
... | @@ -593,31 +594,23 @@ maildir_scan_dir (struct _amd_data *amd, DIR *dir, char *dirname) | ... | @@ -593,31 +594,23 @@ maildir_scan_dir (struct _amd_data *amd, DIR *dir, char *dirname) |
593 | break; | 594 | break; |
594 | 595 | ||
595 | default: | 596 | default: |
596 | key.file_name = entry->d_name; | ||
597 | rc = _amd_message_lookup_or_insert (amd, | ||
598 | (struct _amd_message *)&key, | ||
599 | &index); | ||
600 | if (rc == MU_ERR_NOENT) | ||
601 | { | ||
602 | /* Message not found. Index pointd to the array cell where it | 597 | /* Message not found. Index pointd to the array cell where it |
603 | would be placed */ | 598 | would be placed */ |
604 | msg = calloc (1, sizeof (*msg)); | 599 | msg = calloc (1, sizeof (*msg)); |
605 | if (!msg) | 600 | if (!msg) |
606 | { | 601 | { |
607 | rc = ENOMEM; | 602 | rc = ENOMEM; |
608 | break; | 603 | break; |
609 | } | ||
610 | amd->msg_array[index] = (struct _amd_message *)msg; | ||
611 | msg->amd_message.amd = amd; | ||
612 | rc = 0; | ||
613 | } | 604 | } |
614 | else if (rc == 0) | 605 | key.file_name = entry->d_name; |
606 | if (!amd_msg_lookup (amd, (struct _amd_message *) &key, &index)) | ||
607 | continue; | ||
608 | rc = _amd_message_append (amd, (struct _amd_message *) msg); | ||
609 | if (rc) | ||
615 | { | 610 | { |
616 | msg = (struct _maildir_message *)amd->msg_array[index]; | 611 | free (msg); |
617 | free (msg->file_name); | 612 | break; |
618 | } | 613 | } |
619 | else | ||
620 | break; | ||
621 | 614 | ||
622 | msg->dir = dirname; | 615 | msg->dir = dirname; |
623 | msg->file_name = strdup (entry->d_name); | 616 | msg->file_name = strdup (entry->d_name); |
... | @@ -628,9 +621,12 @@ maildir_scan_dir (struct _amd_data *amd, DIR *dir, char *dirname) | ... | @@ -628,9 +621,12 @@ maildir_scan_dir (struct _amd_data *amd, DIR *dir, char *dirname) |
628 | else | 621 | else |
629 | msg->amd_message.attr_flags = 0; | 622 | msg->amd_message.attr_flags = 0; |
630 | msg->amd_message.orig_flags = msg->amd_message.attr_flags; | 623 | msg->amd_message.orig_flags = msg->amd_message.attr_flags; |
624 | need_sort = 1; | ||
631 | } | 625 | } |
632 | } | 626 | } |
633 | 627 | ||
628 | if (rc == 0 && need_sort) | ||
629 | amd_sort (amd); | ||
634 | return rc; | 630 | return rc; |
635 | } | 631 | } |
636 | 632 | ... | ... |
... | @@ -181,6 +181,7 @@ mh_scan0 (mu_mailbox_t mailbox, size_t msgno MU_ARG_UNUSED, size_t *pcount, | ... | @@ -181,6 +181,7 @@ mh_scan0 (mu_mailbox_t mailbox, size_t msgno MU_ARG_UNUSED, size_t *pcount, |
181 | struct dirent *entry; | 181 | struct dirent *entry; |
182 | int status = 0; | 182 | int status = 0; |
183 | struct stat st; | 183 | struct stat st; |
184 | int need_sort = 0; | ||
184 | 185 | ||
185 | if (amd == NULL) | 186 | if (amd == NULL) |
186 | return EINVAL; | 187 | return EINVAL; |
... | @@ -235,12 +236,18 @@ mh_scan0 (mu_mailbox_t mailbox, size_t msgno MU_ARG_UNUSED, size_t *pcount, | ... | @@ -235,12 +236,18 @@ mh_scan0 (mu_mailbox_t mailbox, size_t msgno MU_ARG_UNUSED, size_t *pcount, |
235 | if (!msg) | 236 | if (!msg) |
236 | { | 237 | { |
237 | msg = calloc (1, sizeof(*msg)); | 238 | msg = calloc (1, sizeof(*msg)); |
239 | status = _amd_message_append (amd, (struct _amd_message *) msg); | ||
240 | if (status) | ||
241 | { | ||
242 | free (msg); | ||
243 | break; | ||
244 | } | ||
238 | 245 | ||
239 | msg->seq_number = num; | 246 | msg->seq_number = num; |
240 | msg->amd_message.attr_flags = attr_flags; | 247 | msg->amd_message.attr_flags = attr_flags; |
241 | msg->amd_message.orig_flags = msg->amd_message.attr_flags; | 248 | msg->amd_message.orig_flags = msg->amd_message.attr_flags; |
242 | 249 | ||
243 | _amd_message_insert (amd, (struct _amd_message*) msg); | 250 | need_sort = 1; |
244 | } | 251 | } |
245 | else | 252 | else |
246 | { | 253 | { |
... | @@ -251,38 +258,43 @@ mh_scan0 (mu_mailbox_t mailbox, size_t msgno MU_ARG_UNUSED, size_t *pcount, | ... | @@ -251,38 +258,43 @@ mh_scan0 (mu_mailbox_t mailbox, size_t msgno MU_ARG_UNUSED, size_t *pcount, |
251 | 258 | ||
252 | closedir (dir); | 259 | closedir (dir); |
253 | 260 | ||
254 | if (do_notify) | 261 | if (need_sort) |
255 | { | 262 | amd_sort (amd); |
256 | size_t i; | ||
257 | 263 | ||
258 | for (i = 0; i < amd->msg_count; i++) | 264 | if (status == 0) |
265 | { | ||
266 | if (do_notify) | ||
259 | { | 267 | { |
260 | DISPATCH_ADD_MSG (mailbox, amd, i); | 268 | size_t i; |
269 | |||
270 | for (i = 0; i < amd->msg_count; i++) | ||
271 | { | ||
272 | DISPATCH_ADD_MSG (mailbox, amd, i); | ||
273 | } | ||
261 | } | 274 | } |
262 | } | ||
263 | 275 | ||
264 | if (stat (amd->name, &st) == 0) | 276 | if (stat (amd->name, &st) == 0) |
265 | amd->mtime = st.st_mtime; | 277 | amd->mtime = st.st_mtime; |
266 | 278 | ||
267 | if (pcount) | 279 | if (pcount) |
268 | *pcount = amd->msg_count; | 280 | *pcount = amd->msg_count; |
269 | 281 | ||
270 | /* Reset the uidvalidity. */ | 282 | /* Reset the uidvalidity. */ |
271 | if (amd->msg_count > 0) | 283 | if (amd->msg_count > 0) |
272 | { | ||
273 | if (amd->uidvalidity == 0) | ||
274 | { | 284 | { |
275 | amd->uidvalidity = (unsigned long)time (NULL); | 285 | if (amd->uidvalidity == 0) |
276 | /* Tell that we have been modified for expunging. */ | ||
277 | if (amd->msg_count) | ||
278 | { | 286 | { |
279 | amd_message_stream_open (amd->msg_array[0]); | 287 | amd->uidvalidity = (unsigned long)time (NULL); |
280 | amd_message_stream_close (amd->msg_array[0]); | 288 | /* Tell that we have been modified for expunging. */ |
281 | amd->msg_array[0]->attr_flags |= MU_ATTRIBUTE_MODIFIED; | 289 | if (amd->msg_count) |
290 | { | ||
291 | amd_message_stream_open (amd->msg_array[0]); | ||
292 | amd_message_stream_close (amd->msg_array[0]); | ||
293 | amd->msg_array[0]->attr_flags |= MU_ATTRIBUTE_MODIFIED; | ||
294 | } | ||
282 | } | 295 | } |
283 | } | 296 | } |
284 | } | 297 | } |
285 | |||
286 | /* Clean up the things */ | 298 | /* Clean up the things */ |
287 | 299 | ||
288 | amd_cleanup (mailbox); | 300 | amd_cleanup (mailbox); | ... | ... |
-
Please register or sign in to post a comment