Mercurial > dovecot > original-hg > dovecot-1.2
annotate src/plugins/fts/fts-search.c @ 7376:1307a1702e5e HEAD
Small optimization.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Sat, 08 Mar 2008 04:03:45 +0200 |
parents | c3d829cdbfa5 |
children | 077bb84e9e77 |
rev | line source |
---|---|
7086
7ed926ed7aa4
Updated copyright notices to include year 2008.
Timo Sirainen <tss@iki.fi>
parents:
6940
diff
changeset
|
1 /* Copyright (c) 2006-2008 Dovecot authors, see the included COPYING file */ |
6903 | 2 |
3 #include "lib.h" | |
4 #include "array.h" | |
6911 | 5 #include "str.h" |
6903 | 6 #include "seq-range-array.h" |
6911 | 7 #include "charset-utf8.h" |
6903 | 8 #include "mail-search.h" |
9 #include "mail-storage-private.h" | |
10 #include "fts-api-private.h" | |
11 #include "fts-storage.h" | |
12 | |
13 static void | |
14 uid_range_to_seqs(struct mailbox *box, const ARRAY_TYPE(seq_range) *uid_range, | |
15 ARRAY_TYPE(seq_range) *seq_range) | |
16 { | |
17 const struct seq_range *range; | |
18 unsigned int i, count; | |
7376 | 19 uint32_t seq1, seq2; |
6903 | 20 |
21 range = array_get(uid_range, &count); | |
22 i_array_init(seq_range, count); | |
23 for (i = 0; i < count; i++) { | |
24 mailbox_get_uids(box, range[i].seq1, range[i].seq2, | |
7376 | 25 &seq1, &seq2); |
26 if (seq1 != 0) | |
27 seq_range_array_add_range(seq_range, seq1, seq2); | |
6903 | 28 } |
29 } | |
30 | |
31 static void fts_uid_results_to_seq(struct fts_search_context *fctx) | |
32 { | |
33 ARRAY_TYPE(seq_range) uid_range; | |
34 | |
35 uid_range = fctx->definite_seqs; | |
36 uid_range_to_seqs(fctx->t->box, &uid_range, &fctx->definite_seqs); | |
37 array_free(&uid_range); | |
38 | |
39 uid_range = fctx->maybe_seqs; | |
40 uid_range_to_seqs(fctx->t->box, &uid_range, &fctx->maybe_seqs); | |
41 array_free(&uid_range); | |
42 } | |
43 | |
44 static int fts_search_lookup_arg(struct fts_search_context *fctx, | |
45 struct mail_search_arg *arg, bool filter) | |
46 { | |
47 struct fts_backend *backend; | |
48 enum fts_lookup_flags flags = 0; | |
49 const char *key; | |
6911 | 50 string_t *key_utf8; |
51 enum charset_result result; | |
52 int ret; | |
6903 | 53 |
54 switch (arg->type) { | |
55 case SEARCH_HEADER: | |
56 /* we can filter out messages that don't have the header, | |
57 but we can't trust definite results list. */ | |
58 flags = FTS_LOOKUP_FLAG_HEADER; | |
59 backend = fctx->fbox->backend_substr; | |
60 key = arg->value.str; | |
61 if (*key == '\0') { | |
62 /* we're only checking the existence | |
63 of the header. */ | |
64 key = arg->hdr_field_name; | |
65 } | |
66 break; | |
67 case SEARCH_TEXT: | |
68 case SEARCH_TEXT_FAST: | |
69 flags = FTS_LOOKUP_FLAG_HEADER; | |
70 case SEARCH_BODY: | |
71 case SEARCH_BODY_FAST: | |
72 flags |= FTS_LOOKUP_FLAG_BODY; | |
73 key = arg->value.str; | |
74 backend = fctx->fbox->backend_fast != NULL && | |
75 (arg->type == SEARCH_TEXT_FAST || | |
76 arg->type == SEARCH_BODY_FAST) ? | |
77 fctx->fbox->backend_fast : fctx->fbox->backend_substr; | |
78 break; | |
79 default: | |
80 /* can't filter this */ | |
81 i_assert(filter); | |
82 return 0; | |
83 } | |
84 if (arg->not) | |
85 flags |= FTS_LOOKUP_FLAG_INVERT; | |
86 | |
6911 | 87 /* convert key to titlecase */ |
88 key_utf8 = t_str_new(128); | |
89 if (charset_to_utf8_str(fctx->charset, CHARSET_FLAG_DECOMP_TITLECASE, | |
90 key, key_utf8, &result) < 0) { | |
91 /* unknown charset, can't handle this */ | |
92 ret = 0; | |
93 } else if (result != CHARSET_RET_OK) { | |
94 /* let the core code handle this error */ | |
95 ret = 0; | |
96 } else if (!backend->locked && fts_backend_lock(backend) <= 0) | |
97 ret = -1; | |
98 else if (!filter) { | |
99 ret = fts_backend_lookup(backend, str_c(key_utf8), flags, | |
100 &fctx->definite_seqs, | |
101 &fctx->maybe_seqs); | |
102 } else { | |
103 ret = fts_backend_filter(backend, str_c(key_utf8), flags, | |
104 &fctx->definite_seqs, | |
105 &fctx->maybe_seqs); | |
6903 | 106 } |
6911 | 107 return ret; |
6903 | 108 } |
109 | |
110 void fts_search_lookup(struct fts_search_context *fctx) | |
111 { | |
112 struct mail_search_arg *arg; | |
113 int ret; | |
114 | |
115 if (fctx->best_arg == NULL) | |
116 return; | |
117 | |
118 i_array_init(&fctx->definite_seqs, 64); | |
119 i_array_init(&fctx->maybe_seqs, 64); | |
120 | |
121 /* start filtering with the best arg */ | |
7226
e6693a0ec8e1
Renamed T_FRAME_BEGIN/END to T_BEGIN/END. Removed T_FRAME() macro and
Timo Sirainen <tss@iki.fi>
parents:
7086
diff
changeset
|
122 T_BEGIN { |
6940
414c9d631a81
Replaced t_push/t_pop calls with T_FRAME*() macros.
Timo Sirainen <tss@iki.fi>
parents:
6911
diff
changeset
|
123 ret = fts_search_lookup_arg(fctx, fctx->best_arg, FALSE); |
7226
e6693a0ec8e1
Renamed T_FRAME_BEGIN/END to T_BEGIN/END. Removed T_FRAME() macro and
Timo Sirainen <tss@iki.fi>
parents:
7086
diff
changeset
|
124 } T_END; |
6903 | 125 /* filter the rest */ |
126 for (arg = fctx->args; arg != NULL && ret == 0; arg = arg->next) { | |
6940
414c9d631a81
Replaced t_push/t_pop calls with T_FRAME*() macros.
Timo Sirainen <tss@iki.fi>
parents:
6911
diff
changeset
|
127 if (arg != fctx->best_arg) { |
7226
e6693a0ec8e1
Renamed T_FRAME_BEGIN/END to T_BEGIN/END. Removed T_FRAME() macro and
Timo Sirainen <tss@iki.fi>
parents:
7086
diff
changeset
|
128 T_BEGIN { |
6940
414c9d631a81
Replaced t_push/t_pop calls with T_FRAME*() macros.
Timo Sirainen <tss@iki.fi>
parents:
6911
diff
changeset
|
129 ret = fts_search_lookup_arg(fctx, arg, TRUE); |
7226
e6693a0ec8e1
Renamed T_FRAME_BEGIN/END to T_BEGIN/END. Removed T_FRAME() macro and
Timo Sirainen <tss@iki.fi>
parents:
7086
diff
changeset
|
130 } T_END; |
6940
414c9d631a81
Replaced t_push/t_pop calls with T_FRAME*() macros.
Timo Sirainen <tss@iki.fi>
parents:
6911
diff
changeset
|
131 } |
6903 | 132 } |
133 | |
134 if (fctx->fbox->backend_fast != NULL && | |
135 fctx->fbox->backend_fast->locked) | |
136 fts_backend_unlock(fctx->fbox->backend_fast); | |
137 if (fctx->fbox->backend_substr != NULL && | |
138 fctx->fbox->backend_substr->locked) | |
139 fts_backend_unlock(fctx->fbox->backend_substr); | |
140 | |
141 if (ret == 0) { | |
142 fctx->seqs_set = TRUE; | |
143 fts_uid_results_to_seq(fctx); | |
144 } | |
145 } | |
146 | |
147 static bool arg_is_better(const struct mail_search_arg *new_arg, | |
148 const struct mail_search_arg *old_arg) | |
149 { | |
150 if (old_arg == NULL) | |
151 return TRUE; | |
152 if (new_arg == NULL) | |
153 return FALSE; | |
154 | |
155 /* avoid NOTs */ | |
156 if (old_arg->not && !new_arg->not) | |
157 return TRUE; | |
158 if (!old_arg->not && new_arg->not) | |
159 return FALSE; | |
160 | |
161 /* prefer not to use headers. they have a larger possibility of | |
162 having lots of identical strings */ | |
163 if (old_arg->type == SEARCH_HEADER) | |
164 return TRUE; | |
165 else if (new_arg->type == SEARCH_HEADER) | |
166 return FALSE; | |
167 | |
168 return strlen(new_arg->value.str) > strlen(old_arg->value.str); | |
169 } | |
170 | |
171 static void | |
172 fts_search_args_find_best(struct mail_search_arg *args, | |
173 struct mail_search_arg **best_fast_arg, | |
174 struct mail_search_arg **best_substr_arg) | |
175 { | |
176 for (; args != NULL; args = args->next) { | |
177 switch (args->type) { | |
178 case SEARCH_BODY_FAST: | |
179 case SEARCH_TEXT_FAST: | |
180 if (arg_is_better(args, *best_fast_arg)) | |
181 *best_fast_arg = args; | |
182 break; | |
183 case SEARCH_BODY: | |
184 case SEARCH_TEXT: | |
185 case SEARCH_HEADER: | |
186 if (arg_is_better(args, *best_substr_arg)) | |
187 *best_substr_arg = args; | |
188 break; | |
189 default: | |
190 break; | |
191 } | |
192 } | |
193 } | |
194 | |
195 void fts_search_analyze(struct fts_search_context *fctx) | |
196 { | |
197 struct mail_search_arg *best_fast_arg = NULL, *best_substr_arg = NULL; | |
198 | |
199 fts_search_args_find_best(fctx->args, &best_fast_arg, &best_substr_arg); | |
200 | |
201 if (best_fast_arg != NULL && fctx->fbox->backend_fast != NULL) { | |
202 /* use fast backend whenever possible */ | |
203 fctx->best_arg = best_fast_arg; | |
204 fctx->build_backend = fctx->fbox->backend_fast; | |
205 } else if (best_fast_arg != NULL || best_substr_arg != NULL) { | |
206 fctx->build_backend = fctx->fbox->backend_substr; | |
207 fctx->best_arg = arg_is_better(best_substr_arg, best_fast_arg) ? | |
208 best_substr_arg : best_fast_arg; | |
209 } | |
210 } |