comparison src/lib-storage/index/index-sort.c @ 21604:fb8ef6e2c2fe

lib-storage: Add mail_sort_max_read_count setting. This controls how many slow mail accesses sorting can perform before it fails: a NO [LIMIT] Requested sort would have taken too long The SORT reply is still returned, but it's likely not correct.
author Timo Sirainen <timo.sirainen@dovecot.fi>
date Fri, 17 Feb 2017 19:07:53 +0200
parents a90f51ba2e9c
children bcd286fcdbad
comparison
equal deleted inserted replaced
21603:6d50f63cfa67 21604:fb8ef6e2c2fe
38 38
39 static void 39 static void
40 index_sort_program_set_mail_failed(struct mail_search_sort_program *program, 40 index_sort_program_set_mail_failed(struct mail_search_sort_program *program,
41 struct mail *mail) 41 struct mail *mail)
42 { 42 {
43 if (mailbox_get_last_mail_error(mail->box) != MAIL_ERROR_EXPUNGED) 43 switch (mailbox_get_last_mail_error(mail->box)) {
44 case MAIL_ERROR_EXPUNGED:
45 break;
46 case MAIL_ERROR_NOTPOSSIBLE:
47 /* just change the error message */
48 mail_storage_set_error(program->t->box->storage, MAIL_ERROR_LIMIT,
49 "Requested sort would have taken too long.");
50 /* fall through */
51 default:
44 program->failed = TRUE; 52 program->failed = TRUE;
53 break;
54 }
55 }
56
57 static time_t
58 index_sort_program_set_date_failed(struct mail_search_sort_program *program,
59 struct mail *mail)
60 {
61 index_sort_program_set_mail_failed(program, mail);
62
63 if (mailbox_get_last_mail_error(mail->box) == MAIL_ERROR_LIMIT) {
64 /* limit reached - sort the rest of the mails at the end of
65 the list by their UIDs */
66 return LONG_MAX;
67 } else {
68 /* expunged / some other error - sort in the beginning */
69 return 0;
70 }
45 } 71 }
46 72
47 static void 73 static void
48 index_sort_list_add_arrival(struct mail_search_sort_program *program, 74 index_sort_list_add_arrival(struct mail_search_sort_program *program,
49 struct mail *mail) 75 struct mail *mail)
51 ARRAY_TYPE(mail_sort_node_date) *nodes = program->context; 77 ARRAY_TYPE(mail_sort_node_date) *nodes = program->context;
52 struct mail_sort_node_date *node; 78 struct mail_sort_node_date *node;
53 79
54 node = array_append_space(nodes); 80 node = array_append_space(nodes);
55 node->seq = mail->seq; 81 node->seq = mail->seq;
56 if (mail_get_received_date(mail, &node->date) < 0) { 82 if (mail_get_received_date(mail, &node->date) < 0)
57 index_sort_program_set_mail_failed(program, mail); 83 node->date = index_sort_program_set_date_failed(program, mail);
58 node->date = 0;
59 }
60 } 84 }
61 85
62 static void 86 static void
63 index_sort_list_add_date(struct mail_search_sort_program *program, 87 index_sort_list_add_date(struct mail_search_sort_program *program,
64 struct mail *mail) 88 struct mail *mail)
67 struct mail_sort_node_date *node; 91 struct mail_sort_node_date *node;
68 int tz; 92 int tz;
69 93
70 node = array_append_space(nodes); 94 node = array_append_space(nodes);
71 node->seq = mail->seq; 95 node->seq = mail->seq;
72 if (mail_get_date(mail, &node->date, &tz) < 0) { 96 if (mail_get_date(mail, &node->date, &tz) < 0)
73 index_sort_program_set_mail_failed(program, mail); 97 node->date = index_sort_program_set_date_failed(program, mail);
74 node->date = 0; 98 else if (node->date == 0) {
75 } else if (node->date == 0) { 99 if (mail_get_received_date(mail, &node->date) < 0)
76 if (mail_get_received_date(mail, &node->date) < 0) { 100 node->date = index_sort_program_set_date_failed(program, mail);
77 index_sort_program_set_mail_failed(program, mail);
78 node->date = 0;
79 }
80 } 101 }
81 } 102 }
82 103
83 static void 104 static void
84 index_sort_list_add_size(struct mail_search_sort_program *program, 105 index_sort_list_add_size(struct mail_search_sort_program *program,
146 } 167 }
147 168
148 void index_sort_list_add(struct mail_search_sort_program *program, 169 void index_sort_list_add(struct mail_search_sort_program *program,
149 struct mail *mail) 170 struct mail *mail)
150 { 171 {
172 enum mail_lookup_abort orig_abort = mail->lookup_abort;
173 bool prev_slow = mail->mail_stream_opened ||
174 mail->mail_metadata_accessed;
175
151 i_assert(mail->transaction == program->t); 176 i_assert(mail->transaction == program->t);
152 177
178 if (program->slow_mails_left == 0)
179 mail->lookup_abort = MAIL_LOOKUP_ABORT_NOT_IN_CACHE;
153 T_BEGIN { 180 T_BEGIN {
154 program->sort_list_add(program, mail); 181 program->sort_list_add(program, mail);
155 } T_END; 182 } T_END;
183 if (!prev_slow && (mail->mail_stream_opened ||
184 mail->mail_metadata_accessed)) {
185 i_assert(program->slow_mails_left > 0);
186 program->slow_mails_left--;
187 }
188 mail->lookup_abort = orig_abort;
156 } 189 }
157 190
158 static int sort_node_date_cmp(const struct mail_sort_node_date *n1, 191 static int sort_node_date_cmp(const struct mail_sort_node_date *n1,
159 const struct mail_sort_node_date *n2) 192 const struct mail_sort_node_date *n2)
160 { 193 {
273 306
274 /* we support internal sorting by the primary condition */ 307 /* we support internal sorting by the primary condition */
275 program = i_new(struct mail_search_sort_program, 1); 308 program = i_new(struct mail_search_sort_program, 1);
276 program->t = t; 309 program->t = t;
277 program->temp_mail = mail_alloc(t, 0, NULL); 310 program->temp_mail = mail_alloc(t, 0, NULL);
311
312 program->slow_mails_left =
313 program->t->box->storage->set->mail_sort_max_read_count;
314 if (program->slow_mails_left == 0)
315 program->slow_mails_left = UINT_MAX;
278 316
279 for (i = 0; i < MAX_SORT_PROGRAM_SIZE; i++) { 317 for (i = 0; i < MAX_SORT_PROGRAM_SIZE; i++) {
280 program->sort_program[i] = sort_program[i]; 318 program->sort_program[i] = sort_program[i];
281 if (sort_program[i] == MAIL_SORT_END) 319 if (sort_program[i] == MAIL_SORT_END)
282 break; 320 break;
423 else if (addr->mailbox != NULL) 461 else if (addr->mailbox != NULL)
424 *name_r = addr->mailbox; 462 *name_r = addr->mailbox;
425 return 0; 463 return 0;
426 } 464 }
427 465
428 int index_sort_header_get(struct mail *mail, uint32_t seq, 466 static void
467 index_sort_set_seq(struct mail_search_sort_program *program,
468 struct mail *mail, uint32_t seq)
469 {
470 if ((mail->mail_stream_opened || mail->mail_metadata_accessed) &&
471 program->slow_mails_left > 0)
472 program->slow_mails_left--;
473 mail_set_seq(mail, seq);
474 if (program->slow_mails_left == 0) {
475 /* too many slow lookups - just return the rest of the results
476 in whatever order. */
477 mail->lookup_abort = MAIL_LOOKUP_ABORT_NOT_IN_CACHE;
478 }
479 }
480
481 int index_sort_header_get(struct mail_search_sort_program *program, uint32_t seq,
429 enum mail_sort_type sort_type, string_t *dest) 482 enum mail_sort_type sort_type, string_t *dest)
430 { 483 {
484 struct mail *mail = program->temp_mail;
431 const char *str; 485 const char *str;
432 int ret; 486 int ret;
433 bool reply_or_fw; 487 bool reply_or_fw;
434 488
435 mail_set_seq(mail, seq); 489 index_sort_set_seq(program, mail, seq);
436 str_truncate(dest, 0); 490 str_truncate(dest, 0);
437 491
438 switch (sort_type & MAIL_SORT_MASK) { 492 switch (sort_type & MAIL_SORT_MASK) {
439 case MAIL_SORT_SUBJECT: 493 case MAIL_SORT_SUBJECT:
440 ret = mail_get_first_header(mail, "Subject", &str); 494 ret = mail_get_first_header(mail, "Subject", &str);
498 T_BEGIN { 552 T_BEGIN {
499 string_t *str1, *str2; 553 string_t *str1, *str2;
500 554
501 str1 = t_str_new(256); 555 str1 = t_str_new(256);
502 str2 = t_str_new(256); 556 str2 = t_str_new(256);
503 if (index_sort_header_get(mail, seq1, sort_type, str1) < 0) 557 if (index_sort_header_get(program, seq1, sort_type, str1) < 0)
504 index_sort_program_set_mail_failed(program, mail); 558 index_sort_program_set_mail_failed(program, mail);
505 if (index_sort_header_get(mail, seq2, sort_type, str2) < 0) 559 if (index_sort_header_get(program, seq2, sort_type, str2) < 0)
506 index_sort_program_set_mail_failed(program, mail); 560 index_sort_program_set_mail_failed(program, mail);
507 561
508 ret = strcmp(str_c(str1), str_c(str2)); 562 ret = strcmp(str_c(str1), str_c(str2));
509 } T_END; 563 } T_END;
510 break; 564 break;
511 case MAIL_SORT_ARRIVAL: 565 case MAIL_SORT_ARRIVAL:
512 mail_set_seq(mail, seq1); 566 index_sort_set_seq(program, mail, seq1);
513 if (mail_get_received_date(mail, &time1) < 0) { 567 if (mail_get_received_date(mail, &time1) < 0)
514 index_sort_program_set_mail_failed(program, mail); 568 time1 = index_sort_program_set_date_failed(program, mail);
515 time1 = 0; 569
516 } 570 index_sort_set_seq(program, mail, seq2);
517 571 if (mail_get_received_date(mail, &time2) < 0)
518 mail_set_seq(mail, seq2); 572 time2 = index_sort_program_set_date_failed(program, mail);
519 if (mail_get_received_date(mail, &time2) < 0) {
520 index_sort_program_set_mail_failed(program, mail);
521 time2 = 0;
522 }
523 573
524 ret = time1 < time2 ? -1 : 574 ret = time1 < time2 ? -1 :
525 (time1 > time2 ? 1 : 0); 575 (time1 > time2 ? 1 : 0);
526 break; 576 break;
527 case MAIL_SORT_DATE: 577 case MAIL_SORT_DATE:
528 mail_set_seq(mail, seq1); 578 index_sort_set_seq(program, mail, seq1);
529 if (mail_get_date(mail, &time1, &tz) < 0) { 579 if (mail_get_date(mail, &time1, &tz) < 0)
530 index_sort_program_set_mail_failed(program, mail); 580 time1 = index_sort_program_set_date_failed(program, mail);
531 time1 = 0; 581 else if (time1 == 0) {
532 } else if (time1 == 0) { 582 if (mail_get_received_date(mail, &time1) < 0)
533 if (mail_get_received_date(mail, &time1) < 0) { 583 time1 = index_sort_program_set_date_failed(program, mail);
534 index_sort_program_set_mail_failed(program, mail);
535 time1 = 0;
536 }
537 } 584 }
538 585
539 mail_set_seq(mail, seq2); 586 index_sort_set_seq(program, mail, seq2);
540 if (mail_get_date(mail, &time2, &tz) < 0) { 587 if (mail_get_date(mail, &time2, &tz) < 0)
541 index_sort_program_set_mail_failed(program, mail); 588 time2 = index_sort_program_set_date_failed(program, mail);
542 time2 = 0; 589 else if (time2 == 0) {
543 } else if (time2 == 0) { 590 if (mail_get_received_date(mail, &time2) < 0)
544 if (mail_get_received_date(mail, &time2) < 0) { 591 time2 = index_sort_program_set_date_failed(program, mail);
545 index_sort_program_set_mail_failed(program, mail);
546 time2 = 0;
547 }
548 } 592 }
549 593
550 ret = time1 < time2 ? -1 : 594 ret = time1 < time2 ? -1 :
551 (time1 > time2 ? 1 : 0); 595 (time1 > time2 ? 1 : 0);
552 break; 596 break;
553 case MAIL_SORT_SIZE: 597 case MAIL_SORT_SIZE:
554 mail_set_seq(mail, seq1); 598 index_sort_set_seq(program, mail, seq1);
555 if (mail_get_virtual_size(mail, &size1) < 0) { 599 if (mail_get_virtual_size(mail, &size1) < 0) {
556 index_sort_program_set_mail_failed(program, mail); 600 index_sort_program_set_mail_failed(program, mail);
557 size1 = 0; 601 size1 = 0;
558 } 602 }
559 603
560 mail_set_seq(mail, seq2); 604 index_sort_set_seq(program, mail, seq2);
561 if (mail_get_virtual_size(mail, &size2) < 0) { 605 if (mail_get_virtual_size(mail, &size2) < 0) {
562 index_sort_program_set_mail_failed(program, mail); 606 index_sort_program_set_mail_failed(program, mail);
563 size2 = 0; 607 size2 = 0;
564 } 608 }
565 609
566 ret = size1 < size2 ? -1 : 610 ret = size1 < size2 ? -1 :
567 (size1 > size2 ? 1 : 0); 611 (size1 > size2 ? 1 : 0);
568 break; 612 break;
569 case MAIL_SORT_RELEVANCY: 613 case MAIL_SORT_RELEVANCY:
570 mail_set_seq(mail, seq1); 614 index_sort_set_seq(program, mail, seq1);
571 if (index_sort_get_relevancy(mail, &float1) < 0) 615 if (index_sort_get_relevancy(mail, &float1) < 0)
572 index_sort_program_set_mail_failed(program, mail); 616 index_sort_program_set_mail_failed(program, mail);
573 mail_set_seq(mail, seq2); 617 index_sort_set_seq(program, mail, seq2);
574 if (index_sort_get_relevancy(mail, &float2) < 0) 618 if (index_sort_get_relevancy(mail, &float2) < 0)
575 index_sort_program_set_mail_failed(program, mail); 619 index_sort_program_set_mail_failed(program, mail);
576 620
577 /* NOTE: higher relevancy is returned first, unlike with all 621 /* NOTE: higher relevancy is returned first, unlike with all
578 other number based sort keys */ 622 other number based sort keys */
580 (float1 > float2 ? -1 : 0); 624 (float1 > float2 ? -1 : 0);
581 break; 625 break;
582 case MAIL_SORT_POP3_ORDER: 626 case MAIL_SORT_POP3_ORDER:
583 /* 32bit numbers would be enough, but since there is already 627 /* 32bit numbers would be enough, but since there is already
584 existing code for uoff_t in sizes, just use them. */ 628 existing code for uoff_t in sizes, just use them. */
585 mail_set_seq(mail, seq1); 629 index_sort_set_seq(program, mail, seq1);
586 if (index_sort_get_pop3_order(mail, &size1) < 0) 630 if (index_sort_get_pop3_order(mail, &size1) < 0)
587 index_sort_program_set_mail_failed(program, mail); 631 index_sort_program_set_mail_failed(program, mail);
588 mail_set_seq(mail, seq2); 632 index_sort_set_seq(program, mail, seq2);
589 if (index_sort_get_pop3_order(mail, &size2) < 0) 633 if (index_sort_get_pop3_order(mail, &size2) < 0)
590 index_sort_program_set_mail_failed(program, mail); 634 index_sort_program_set_mail_failed(program, mail);
591 635
592 ret = size1 < size2 ? -1 : 636 ret = size1 < size2 ? -1 :
593 (size1 > size2 ? 1 : 0); 637 (size1 > size2 ? 1 : 0);