Mercurial > dovecot > original-hg > dovecot-1.2
comparison src/plugins/fts-solr/fts-backend-solr.c @ 8950:ec1ae90af21a HEAD
fts: Fixes to how virtual mailboxes are searched.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Wed, 15 Apr 2009 19:48:55 -0400 |
parents | 7e639229c2c8 |
children | d21bd1a1710a |
comparison
equal
deleted
inserted
replaced
8949:508bbbd4e6f6 | 8950:ec1ae90af21a |
---|---|
16 #define FTS_SOLR_MAX_BOX_INC_PATTERNS 5 | 16 #define FTS_SOLR_MAX_BOX_INC_PATTERNS 5 |
17 #define FTS_SOLR_MAX_BOX_EXC_PATTERNS 5 | 17 #define FTS_SOLR_MAX_BOX_EXC_PATTERNS 5 |
18 | 18 |
19 struct solr_fts_backend { | 19 struct solr_fts_backend { |
20 struct fts_backend backend; | 20 struct fts_backend backend; |
21 char *id_username, *id_namespace; | 21 char *id_username, *id_namespace, *id_box_name; |
22 struct mail_namespace *default_ns; | 22 struct mail_namespace *default_ns; |
23 }; | 23 }; |
24 | 24 |
25 struct solr_fts_backend_build_context { | 25 struct solr_fts_backend_build_context { |
26 struct fts_backend_build_context ctx; | 26 struct fts_backend_build_context ctx; |
45 struct mailbox *box; | 45 struct mailbox *box; |
46 string_t *vname; | 46 string_t *vname; |
47 }; | 47 }; |
48 | 48 |
49 static struct solr_connection *solr_conn = NULL; | 49 static struct solr_connection *solr_conn = NULL; |
50 | |
51 static void fts_box_name_get_root(struct mail_namespace **ns, const char **name) | |
52 { | |
53 struct mail_namespace *orig_ns = *ns; | |
54 | |
55 while ((*ns)->alias_for != NULL) | |
56 *ns = (*ns)->alias_for; | |
57 | |
58 if (**name == '\0' && *ns != orig_ns && | |
59 ((*ns)->flags & NAMESPACE_FLAG_INBOX) != 0) { | |
60 /* ugly workaround to allow selecting INBOX from a Maildir/ | |
61 when it's not in the inbox=yes namespace. */ | |
62 *name = "INBOX"; | |
63 } | |
64 } | |
65 | |
66 static const char * | |
67 fts_box_get_root(struct mailbox *box, struct mail_namespace **ns_r) | |
68 { | |
69 struct mail_namespace *ns = box->storage->ns; | |
70 const char *name = box->name; | |
71 | |
72 fts_box_name_get_root(&ns, &name); | |
73 *ns_r = ns; | |
74 return name; | |
75 } | |
50 | 76 |
51 static void | 77 static void |
52 xml_encode_data(string_t *dest, const unsigned char *data, unsigned int len) | 78 xml_encode_data(string_t *dest, const unsigned char *data, unsigned int len) |
53 { | 79 { |
54 unsigned int i; | 80 unsigned int i; |
134 static struct fts_backend * | 160 static struct fts_backend * |
135 fts_backend_solr_init(struct mailbox *box) | 161 fts_backend_solr_init(struct mailbox *box) |
136 { | 162 { |
137 const struct fts_solr_settings *set = &fts_solr_settings; | 163 const struct fts_solr_settings *set = &fts_solr_settings; |
138 struct solr_fts_backend *backend; | 164 struct solr_fts_backend *backend; |
139 struct mail_namespace *ns = box->storage->ns; | 165 struct mail_namespace *ns; |
140 const char *str; | 166 const char *str, *box_name; |
141 | 167 |
142 while (ns->alias_for != NULL) | 168 |
143 ns = ns->alias_for; | 169 box_name = fts_box_get_root(box, &ns); |
170 i_assert(*box_name != '\0'); | |
144 | 171 |
145 if (solr_conn == NULL) | 172 if (solr_conn == NULL) |
146 solr_conn = solr_connection_init(set->url, set->debug); | 173 solr_conn = solr_connection_init(set->url, set->debug); |
147 | 174 |
148 backend = i_new(struct solr_fts_backend, 1); | 175 backend = i_new(struct solr_fts_backend, 1); |
165 backend->id_username = i_strdup(str); | 192 backend->id_username = i_strdup(str); |
166 if (ns != backend->default_ns) { | 193 if (ns != backend->default_ns) { |
167 str = solr_escape_id_str(ns->prefix); | 194 str = solr_escape_id_str(ns->prefix); |
168 backend->id_namespace = i_strdup(str); | 195 backend->id_namespace = i_strdup(str); |
169 } | 196 } |
197 backend->id_box_name = i_strdup(box_name); | |
170 backend->backend = fts_backend_solr; | 198 backend->backend = fts_backend_solr; |
171 | 199 |
172 if (set->substring_search) | 200 if (set->substring_search) |
173 backend->backend.flags |= FTS_BACKEND_FLAG_SUBSTRING_LOOKUPS; | 201 backend->backend.flags |= FTS_BACKEND_FLAG_SUBSTRING_LOOKUPS; |
174 return &backend->backend; | 202 return &backend->backend; |
176 | 204 |
177 static void fts_backend_solr_deinit(struct fts_backend *_backend) | 205 static void fts_backend_solr_deinit(struct fts_backend *_backend) |
178 { | 206 { |
179 struct solr_fts_backend *backend = (struct solr_fts_backend *)_backend; | 207 struct solr_fts_backend *backend = (struct solr_fts_backend *)_backend; |
180 | 208 |
209 i_free(backend->id_box_name); | |
181 i_free(backend->id_namespace); | 210 i_free(backend->id_namespace); |
182 i_free(backend->id_username); | 211 i_free(backend->id_username); |
183 i_free(backend); | 212 i_free(backend); |
184 } | 213 } |
185 | 214 |
219 | 248 |
220 static int fts_backend_solr_get_last_uid_fallback(struct fts_backend *backend, | 249 static int fts_backend_solr_get_last_uid_fallback(struct fts_backend *backend, |
221 uint32_t *last_uid_r) | 250 uint32_t *last_uid_r) |
222 { | 251 { |
223 struct mailbox *box = backend->box; | 252 struct mailbox *box = backend->box; |
253 struct mail_namespace *ns; | |
224 struct mailbox_status status; | 254 struct mailbox_status status; |
225 ARRAY_TYPE(seq_range) uids; | 255 ARRAY_TYPE(seq_range) uids; |
226 const struct seq_range *uidvals; | 256 const struct seq_range *uidvals; |
257 const char *box_name; | |
227 unsigned int count; | 258 unsigned int count; |
228 string_t *str; | 259 string_t *str; |
229 | 260 |
230 str = t_str_new(256); | 261 str = t_str_new(256); |
231 str_append(str, "fl=uid&rows=1&sort=uid+desc&q="); | 262 str_append(str, "fl=uid&rows=1&sort=uid+desc&q="); |
232 | 263 |
264 box_name = fts_box_get_root(box, &ns); | |
265 | |
233 mailbox_get_status(box, STATUS_UIDVALIDITY, &status); | 266 mailbox_get_status(box, STATUS_UIDVALIDITY, &status); |
234 str_printfa(str, "uidv:%u+box:", status.uidvalidity); | 267 str_printfa(str, "uidv:%u+box:", status.uidvalidity); |
235 solr_quote_http(str, box->name); | 268 solr_quote_http(str, box_name); |
236 solr_add_ns_query_http(str, backend, box->storage->ns); | 269 solr_add_ns_query_http(str, backend, ns); |
237 str_append(str, "+user:"); | 270 str_append(str, "+user:"); |
238 solr_quote_http(str, box->storage->ns->user->username); | 271 solr_quote_http(str, ns->user->username); |
239 | 272 |
240 t_array_init(&uids, 1); | 273 t_array_init(&uids, 1); |
241 if (solr_connection_select(solr_conn, str_c(str), | 274 if (solr_connection_select(solr_conn, str_c(str), |
242 NULL, NULL, &uids, NULL) < 0) | 275 NULL, NULL, &uids, NULL) < 0) |
243 return -1; | 276 return -1; |
257 | 290 |
258 static int fts_backend_solr_get_last_uid(struct fts_backend *backend, | 291 static int fts_backend_solr_get_last_uid(struct fts_backend *backend, |
259 uint32_t *last_uid_r) | 292 uint32_t *last_uid_r) |
260 { | 293 { |
261 struct mailbox *box = backend->box; | 294 struct mailbox *box = backend->box; |
295 struct mail_namespace *ns; | |
262 struct mailbox_status status; | 296 struct mailbox_status status; |
263 ARRAY_TYPE(seq_range) uids; | 297 ARRAY_TYPE(seq_range) uids; |
264 const struct seq_range *uidvals; | 298 const struct seq_range *uidvals; |
299 const char *box_name; | |
265 unsigned int count; | 300 unsigned int count; |
266 string_t *str; | 301 string_t *str; |
267 | 302 |
268 str = t_str_new(256); | 303 str = t_str_new(256); |
269 str_append(str, "fl=uid&rows=1&q=last_uid:TRUE+"); | 304 str_append(str, "fl=uid&rows=1&q=last_uid:TRUE+"); |
270 | 305 |
306 box_name = fts_box_get_root(box, &ns); | |
307 | |
271 mailbox_get_status(box, STATUS_UIDVALIDITY, &status); | 308 mailbox_get_status(box, STATUS_UIDVALIDITY, &status); |
272 str_printfa(str, "uidv:%u+box:", status.uidvalidity); | 309 str_printfa(str, "uidv:%u+box:", status.uidvalidity); |
273 solr_quote_http(str, box->name); | 310 solr_quote_http(str, box_name); |
274 solr_add_ns_query_http(str, backend, box->storage->ns); | 311 solr_add_ns_query_http(str, backend, ns); |
275 str_append(str, "+user:"); | 312 str_append(str, "+user:"); |
276 solr_quote_http(str, box->storage->ns->user->username); | 313 solr_quote_http(str, ns->user->username); |
277 | 314 |
278 t_array_init(&uids, 1); | 315 t_array_init(&uids, 1); |
279 if (solr_connection_select(solr_conn, str_c(str), | 316 if (solr_connection_select(solr_conn, str_c(str), |
280 NULL, NULL, &uids, NULL) < 0) | 317 NULL, NULL, &uids, NULL) < 0) |
281 return -1; | 318 return -1; |
329 } | 366 } |
330 | 367 |
331 static void | 368 static void |
332 solr_add_pattern(string_t *str, const struct mailbox_virtual_pattern *pattern) | 369 solr_add_pattern(string_t *str, const struct mailbox_virtual_pattern *pattern) |
333 { | 370 { |
371 struct mail_namespace *ns = pattern->ns; | |
334 const char *name, *p; | 372 const char *name, *p; |
335 | 373 |
336 name = pattern->pattern; | 374 name = pattern->pattern; |
337 if (!mail_namespace_update_name(pattern->ns, &name)) | 375 if (!mail_namespace_update_name(pattern->ns, &name)) |
338 name = mail_namespace_fix_sep(pattern->ns, name); | 376 name = mail_namespace_fix_sep(pattern->ns, name); |
377 | |
378 fts_box_name_get_root(&ns, &name); | |
339 | 379 |
340 if (strcmp(name, "*") == 0) { | 380 if (strcmp(name, "*") == 0) { |
341 str_append(str, "[* TO *]"); | 381 str_append(str, "[* TO *]"); |
342 return; | 382 return; |
343 } | 383 } |
476 uint32_t uid) | 516 uint32_t uid) |
477 { | 517 { |
478 struct solr_fts_backend *backend = | 518 struct solr_fts_backend *backend = |
479 (struct solr_fts_backend *)ctx->ctx.backend; | 519 (struct solr_fts_backend *)ctx->ctx.backend; |
480 struct mailbox *box = ctx->ctx.backend->box; | 520 struct mailbox *box = ctx->ctx.backend->box; |
481 struct mail_namespace *ns = box->storage->ns; | 521 struct mail_namespace *ns; |
522 const char *box_name; | |
482 | 523 |
483 str_printfa(ctx->cmd, "<doc>" | 524 str_printfa(ctx->cmd, "<doc>" |
484 "<field name=\"uid\">%u</field>" | 525 "<field name=\"uid\">%u</field>" |
485 "<field name=\"uidv\">%u</field>", | 526 "<field name=\"uidv\">%u</field>", |
486 uid, ctx->uid_validity); | 527 uid, ctx->uid_validity); |
487 | 528 |
488 while (ns->alias_for != NULL) | 529 box_name = fts_box_get_root(box, &ns); |
489 ns = ns->alias_for; | |
490 | 530 |
491 if (ns != backend->default_ns) { | 531 if (ns != backend->default_ns) { |
492 str_append(ctx->cmd, "<field name=\"ns\">"); | 532 str_append(ctx->cmd, "<field name=\"ns\">"); |
493 xml_encode(ctx->cmd, ns->prefix); | 533 xml_encode(ctx->cmd, ns->prefix); |
494 str_append(ctx->cmd, "</field>"); | 534 str_append(ctx->cmd, "</field>"); |
495 } | 535 } |
496 str_append(ctx->cmd, "<field name=\"box\">"); | 536 str_append(ctx->cmd, "<field name=\"box\">"); |
497 xml_encode(ctx->cmd, box->name); | 537 xml_encode(ctx->cmd, box_name); |
498 str_append(ctx->cmd, "</field><field name=\"user\">"); | 538 str_append(ctx->cmd, "</field><field name=\"user\">"); |
499 xml_encode(ctx->cmd, ns->user->username); | 539 xml_encode(ctx->cmd, ns->user->username); |
500 str_append(ctx->cmd, "</field>"); | 540 str_append(ctx->cmd, "</field>"); |
501 } | 541 } |
502 | 542 |
503 static void xml_encode_id(string_t *str, struct fts_backend *_backend, | 543 static void xml_encode_id(string_t *str, struct fts_backend *_backend, |
504 uint32_t uid, uint32_t uid_validity, | 544 uint32_t uid, uint32_t uid_validity) |
505 const char *mailbox) | |
506 { | 545 { |
507 struct solr_fts_backend *backend = (struct solr_fts_backend *)_backend; | 546 struct solr_fts_backend *backend = (struct solr_fts_backend *)_backend; |
508 | 547 |
509 if (uid != 0) | 548 if (uid != 0) |
510 str_printfa(str, "%u/", uid); | 549 str_printfa(str, "%u/", uid); |
515 str_append_c(str, '/'); | 554 str_append_c(str, '/'); |
516 } | 555 } |
517 str_printfa(str, "%u/", uid_validity); | 556 str_printfa(str, "%u/", uid_validity); |
518 xml_encode(str, backend->id_username); | 557 xml_encode(str, backend->id_username); |
519 str_append_c(str, '/'); | 558 str_append_c(str, '/'); |
520 xml_encode(str, mailbox); | 559 xml_encode(str, backend->id_box_name); |
521 } | 560 } |
522 | 561 |
523 static int | 562 static int |
524 fts_backend_solr_build_more(struct fts_backend_build_context *_ctx, | 563 fts_backend_solr_build_more(struct fts_backend_build_context *_ctx, |
525 uint32_t uid, const unsigned char *data, | 564 uint32_t uid, const unsigned char *data, |
526 size_t size, bool headers) | 565 size_t size, bool headers) |
527 { | 566 { |
528 struct solr_fts_backend_build_context *ctx = | 567 struct solr_fts_backend_build_context *ctx = |
529 (struct solr_fts_backend_build_context *)_ctx; | 568 (struct solr_fts_backend_build_context *)_ctx; |
530 struct mailbox *box = _ctx->backend->box; | |
531 string_t *cmd = ctx->cmd; | 569 string_t *cmd = ctx->cmd; |
532 | 570 |
533 /* body comes first, then headers */ | 571 /* body comes first, then headers */ |
534 if (ctx->prev_uid != uid) { | 572 if (ctx->prev_uid != uid) { |
535 /* uid changed */ | 573 /* uid changed */ |
541 } | 579 } |
542 ctx->prev_uid = uid; | 580 ctx->prev_uid = uid; |
543 | 581 |
544 fts_backend_solr_add_doc_prefix(ctx, uid); | 582 fts_backend_solr_add_doc_prefix(ctx, uid); |
545 str_printfa(cmd, "<field name=\"id\">"); | 583 str_printfa(cmd, "<field name=\"id\">"); |
546 xml_encode_id(cmd, _ctx->backend, uid, ctx->uid_validity, | 584 xml_encode_id(cmd, _ctx->backend, uid, ctx->uid_validity); |
547 box->name); | |
548 str_append(cmd, "</field>"); | 585 str_append(cmd, "</field>"); |
549 | 586 |
550 ctx->headers = headers; | 587 ctx->headers = headers; |
551 if (headers) { | 588 if (headers) { |
552 str_append(cmd, "<field name=\"hdr\">"); | 589 str_append(cmd, "<field name=\"hdr\">"); |
569 } | 606 } |
570 | 607 |
571 static int | 608 static int |
572 fts_backed_solr_build_commit(struct solr_fts_backend_build_context *ctx) | 609 fts_backed_solr_build_commit(struct solr_fts_backend_build_context *ctx) |
573 { | 610 { |
574 struct mailbox *box = ctx->ctx.backend->box; | |
575 int ret; | 611 int ret; |
576 | 612 |
577 if (ctx->post == NULL) | 613 if (ctx->post == NULL) |
578 return 0; | 614 return 0; |
579 | 615 |
585 may shrink. This doesn't really matter, we'll simply do more work | 621 may shrink. This doesn't really matter, we'll simply do more work |
586 in future by reindexing some messages. */ | 622 in future by reindexing some messages. */ |
587 fts_backend_solr_add_doc_prefix(ctx, ctx->prev_uid); | 623 fts_backend_solr_add_doc_prefix(ctx, ctx->prev_uid); |
588 str_printfa(ctx->cmd, "<field name=\"last_uid\">TRUE</field>" | 624 str_printfa(ctx->cmd, "<field name=\"last_uid\">TRUE</field>" |
589 "<field name=\"id\">"); | 625 "<field name=\"id\">"); |
590 xml_encode_id(ctx->cmd, ctx->ctx.backend, 0, ctx->uid_validity, | 626 xml_encode_id(ctx->cmd, ctx->ctx.backend, 0, ctx->uid_validity); |
591 box->name); | |
592 str_append(ctx->cmd, "</field></doc></add>"); | 627 str_append(ctx->cmd, "</field></doc></add>"); |
593 | 628 |
594 solr_connection_post_more(ctx->post, str_data(ctx->cmd), | 629 solr_connection_post_more(ctx->post, str_data(ctx->cmd), |
595 str_len(ctx->cmd)); | 630 str_len(ctx->cmd)); |
596 ret = solr_connection_post_end(ctx->post); | 631 ret = solr_connection_post_end(ctx->post); |
625 T_BEGIN { | 660 T_BEGIN { |
626 string_t *cmd; | 661 string_t *cmd; |
627 | 662 |
628 cmd = t_str_new(256); | 663 cmd = t_str_new(256); |
629 str_append(cmd, "<delete><id>"); | 664 str_append(cmd, "<delete><id>"); |
630 xml_encode_id(cmd, backend, mail->uid, status.uidvalidity, | 665 xml_encode_id(cmd, backend, mail->uid, status.uidvalidity); |
631 mail->box->name); | |
632 str_append(cmd, "</id></delete>"); | 666 str_append(cmd, "</id></delete>"); |
633 | 667 |
634 (void)solr_connection_post(solr_conn, str_c(cmd)); | 668 (void)solr_connection_post(solr_conn, str_c(cmd)); |
635 } T_END; | 669 } T_END; |
636 } | 670 } |
658 void *context) | 692 void *context) |
659 { | 693 { |
660 struct solr_virtual_uid_map_context *ctx = context; | 694 struct solr_virtual_uid_map_context *ctx = context; |
661 struct mail_namespace *ns; | 695 struct mail_namespace *ns; |
662 const char *vname; | 696 const char *vname; |
697 bool convert_inbox; | |
663 | 698 |
664 ns = solr_get_namespaces(ctx->backend, ctx->box, ns_prefix); | 699 ns = solr_get_namespaces(ctx->backend, ctx->box, ns_prefix); |
700 convert_inbox = (ns->flags & NAMESPACE_FLAG_INBOX) != 0 && | |
701 strcmp(mailbox, "INBOX") == 0; | |
665 for (; ns != NULL; ns = ns->alias_chain_next) { | 702 for (; ns != NULL; ns = ns->alias_chain_next) { |
666 vname = mail_namespace_get_vname(ns, ctx->vname, mailbox); | 703 vname = convert_inbox ? ns->prefix : |
704 mail_namespace_get_vname(ns, ctx->vname, mailbox); | |
667 if (mailbox_get_virtual_uid(ctx->box, vname, uidvalidity, | 705 if (mailbox_get_virtual_uid(ctx->box, vname, uidvalidity, |
668 *uid, uid)) | 706 *uid, uid)) |
669 return TRUE; | 707 return TRUE; |
670 } | 708 } |
671 return FALSE; | 709 return FALSE; |
675 ARRAY_TYPE(seq_range) *definite_uids, | 713 ARRAY_TYPE(seq_range) *definite_uids, |
676 ARRAY_TYPE(seq_range) *maybe_uids, | 714 ARRAY_TYPE(seq_range) *maybe_uids, |
677 ARRAY_TYPE(fts_score_map) *scores) | 715 ARRAY_TYPE(fts_score_map) *scores) |
678 { | 716 { |
679 struct mailbox *box = ctx->backend->box; | 717 struct mailbox *box = ctx->backend->box; |
718 struct mail_namespace *ns; | |
680 struct solr_virtual_uid_map_context uid_map_ctx; | 719 struct solr_virtual_uid_map_context uid_map_ctx; |
681 const struct fts_backend_lookup_field *fields; | 720 const struct fts_backend_lookup_field *fields; |
721 const char *box_name; | |
682 unsigned int i, count; | 722 unsigned int i, count; |
683 struct mailbox_status status; | 723 struct mailbox_status status; |
684 string_t *str; | 724 string_t *str; |
685 bool virtual; | 725 bool virtual; |
686 | 726 |
725 str_append(str, "&fq=%2Buser:"); | 765 str_append(str, "&fq=%2Buser:"); |
726 solr_quote_http(str, box->storage->ns->user->username); | 766 solr_quote_http(str, box->storage->ns->user->username); |
727 if (virtual) | 767 if (virtual) |
728 fts_backend_solr_filter_mailboxes(ctx->backend, str, box); | 768 fts_backend_solr_filter_mailboxes(ctx->backend, str, box); |
729 else { | 769 else { |
770 box_name = fts_box_get_root(box, &ns); | |
730 str_printfa(str, "+%%2Buidv:%u+%%2Bbox:", status.uidvalidity); | 771 str_printfa(str, "+%%2Buidv:%u+%%2Bbox:", status.uidvalidity); |
731 solr_quote_http(str, box->name); | 772 solr_quote_http(str, box_name); |
732 solr_add_ns_query_http(str, ctx->backend, box->storage->ns); | 773 solr_add_ns_query_http(str, ctx->backend, ns); |
733 } | 774 } |
734 | 775 |
735 array_clear(maybe_uids); | 776 array_clear(maybe_uids); |
736 if (!virtual) { | 777 if (!virtual) { |
737 return solr_connection_select(solr_conn, str_c(str), NULL, NULL, | 778 return solr_connection_select(solr_conn, str_c(str), NULL, NULL, |