~ubuntu-branches/ubuntu/utopic/dovecot/utopic-proposed

« back to all changes in this revision

Viewing changes to src/plugins/fts-solr/fts-backend-solr.c

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2014-01-08 09:35:49 UTC
  • mfrom: (4.1.35 sid)
  • Revision ID: package-import@ubuntu.com-20140108093549-i72o93pux8p0dlaf
Tags: 1:2.2.9-1ubuntu1
* Merge from Debian unstable, remaining changes:
  + Add mail-stack-delivery package:
    - Update d/rules
    - d/control: convert existing dovecot-postfix package to a dummy
      package and add new mail-stack-delivery package.
    - Update maintainer scripts.
    - Rename d/dovecot-postfix.* to debian/mail-stack-delivery.*
    - d/mail-stack-delivery.preinst: Move previously installed backups and
      config files to a new package namespace.
    - d/mail-stack-delivery.prerm: Added to handle downgrades.
  + Use Snakeoil SSL certificates by default:
    - d/control: Depend on ssl-cert.
    - d/dovecot-core.postinst: Relax grep for SSL_* a bit.
  + Add autopkgtest to debian/tests/*.
  + Add ufw integration:
    - d/dovecot-core.ufw.profile: new ufw profile.
    - d/rules: install profile in dovecot-core.
    - d/control: dovecot-core - suggest ufw.
  + d/dovecot-core.dirs: Added usr/share/doc/dovecot-core
  + Add apport hook:
    - d/rules, d/source_dovecot.py
  + Add upstart job:
    - d/rules, d/dovecot-core.dovecot.upstart, d/control,
      d/dovecot-core.dirs, dovecot-imapd.{postrm, postinst, prerm},
      d/dovecot-pop3d.{postinst, postrm, prerm}.
      d/mail-stack-deliver.postinst: Convert init script to upstart.
  + Use the autotools-dev dh addon to update config.guess/config.sub for
    arm64.
* Dropped changes, included in Debian:
  - Update Dovecot name to reflect distribution in login greeting.
  - Update Drac plugin for >= 2.0.0 support.
* d/control: Drop dovecot-postfix package as its no longer required.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (c) 2006-2012 Dovecot authors, see the included COPYING file */
 
1
/* Copyright (c) 2006-2013 Dovecot authors, see the included COPYING file */
2
2
 
3
3
#include "lib.h"
4
4
#include "array.h"
6
6
#include "hash.h"
7
7
#include "strescape.h"
8
8
#include "unichar.h"
 
9
#include "http-url.h"
9
10
#include "mail-storage-private.h"
10
11
#include "mailbox-list-private.h"
11
12
#include "mail-search.h"
17
18
 
18
19
#define SOLR_CMDBUF_SIZE (1024*64)
19
20
#define SOLR_CMDBUF_FLUSH_SIZE (SOLR_CMDBUF_SIZE-128)
20
 
#define SOLR_BUFFER_WARN_SIZE (1024*1024)
21
21
#define SOLR_MAX_MULTI_ROWS 100000
22
22
 
 
23
/* If header is larger than this, truncate it. */
 
24
#define SOLR_HEADER_MAX_SIZE (1024*1024)
 
25
/* If SOLR_HEADER_MAX_SIZE was already reached, write still to individual
 
26
   header fields as long as they're smaller than this */
 
27
#define SOLR_HEADER_LINE_MAX_TRUNC_SIZE 1024
 
28
 
23
29
struct solr_fts_backend {
24
30
        struct fts_backend backend;
 
31
        struct solr_connection *solr_conn;
25
32
};
26
33
 
27
34
struct solr_fts_field {
38
45
        struct solr_connection_post *post;
39
46
        uint32_t prev_uid;
40
47
        string_t *cmd, *cur_value, *cur_value2;
41
 
        ARRAY_DEFINE(fields, struct solr_fts_field);
 
48
        string_t *cmd_expunge;
 
49
        ARRAY(struct solr_fts_field) fields;
42
50
 
43
51
        uint32_t last_indexed_uid;
44
 
        uint32_t size_warned_uid;
45
52
 
46
53
        unsigned int last_indexed_uid_set:1;
47
54
        unsigned int body_open:1;
48
55
        unsigned int documents_added:1;
49
56
        unsigned int expunges:1;
 
57
        unsigned int truncate_header:1;
50
58
};
51
59
 
52
 
static struct solr_connection *solr_conn = NULL;
53
 
 
54
60
static bool is_valid_xml_char(unichar_t chr)
55
61
{
56
62
        /* Valid characters in XML:
136
142
static void solr_quote_http(string_t *dest, const char *str)
137
143
{
138
144
        str_append(dest, "%22");
139
 
        solr_connection_http_escape(solr_conn, dest, str);
 
145
        http_url_escape_param(dest, str);
140
146
        str_append(dest, "%22");
141
147
}
142
148
 
150
156
}
151
157
 
152
158
static int
153
 
fts_backend_solr_init(struct fts_backend *_backend,
154
 
                      const char **error_r ATTR_UNUSED)
 
159
fts_backend_solr_init(struct fts_backend *_backend, const char **error_r)
155
160
{
 
161
        struct solr_fts_backend *backend = (struct solr_fts_backend *)_backend;
156
162
        struct fts_solr_user *fuser = FTS_SOLR_USER_CONTEXT(_backend->ns->user);
157
 
        const struct fts_solr_settings *set = &fuser->set;
158
163
 
159
 
        if (solr_conn == NULL)
160
 
                solr_conn = solr_connection_init(set->url, set->debug);
161
 
        return 0;
 
164
        if (fuser == NULL) {
 
165
                *error_r = "Invalid fts_solr setting";
 
166
                return -1;
 
167
        }
 
168
        return solr_connection_init(fuser->set.url, fuser->set.debug,
 
169
                                    &backend->solr_conn, error_r);
162
170
}
163
171
 
164
172
static void fts_backend_solr_deinit(struct fts_backend *_backend)
172
180
get_last_uid_fallback(struct fts_backend *_backend, struct mailbox *box,
173
181
                      uint32_t *last_uid_r)
174
182
{
 
183
        struct solr_fts_backend *backend = (struct solr_fts_backend *)_backend;
175
184
        const struct seq_range *uidvals;
176
185
        const char *box_guid;
177
186
        unsigned int count;
193
202
                str_append(str, "%22%22");
194
203
 
195
204
        pool = pool_alloconly_create("solr last uid lookup", 1024);
196
 
        if (solr_connection_select(solr_conn, str_c(str),
 
205
        if (solr_connection_select(backend->solr_conn, str_c(str),
197
206
                                   pool, &results) < 0)
198
207
                ret = -1;
199
208
        else if (results[0] == NULL) {
229
238
        if (get_last_uid_fallback(_backend, box, last_uid_r) < 0)
230
239
                return -1;
231
240
 
232
 
        (void)fts_index_set_last_uid(box, *last_uid_r);
 
241
        fts_index_set_last_uid(box, *last_uid_r);
233
242
        return 0;
234
243
}
235
244
 
240
249
 
241
250
        ctx = i_new(struct solr_fts_backend_update_context, 1);
242
251
        ctx->ctx.backend = _backend;
243
 
        ctx->cmd = str_new(default_pool, SOLR_CMDBUF_SIZE);
244
252
        i_array_init(&ctx->fields, 16);
245
253
        return &ctx->ctx;
246
254
}
305
313
        }
306
314
        array_foreach_modifiable(&ctx->fields, field) {
307
315
                str_printfa(ctx->cmd, "<field name=\"%s\">", field->key);
308
 
                str_append_str(ctx->cmd, field->value);
 
316
                xml_encode_data(ctx->cmd, str_data(field->value), str_len(field->value));
309
317
                str_append(ctx->cmd, "</field>");
310
318
                str_truncate(field->value, 0);
311
319
        }
326
334
        return solr_connection_post_end(ctx->post);
327
335
}
328
336
 
 
337
static void
 
338
fts_backend_solr_expunge_flush(struct solr_fts_backend_update_context *ctx)
 
339
{
 
340
        struct solr_fts_backend *backend =
 
341
                (struct solr_fts_backend *)ctx->ctx.backend;
 
342
 
 
343
        str_append(ctx->cmd_expunge, "</delete>");
 
344
        (void)solr_connection_post(backend->solr_conn, str_c(ctx->cmd_expunge));
 
345
        str_truncate(ctx->cmd_expunge, 0);
 
346
        str_append(ctx->cmd_expunge, "<delete>");
 
347
}
 
348
 
329
349
static int
330
350
fts_backend_solr_update_deinit(struct fts_backend_update_context *_ctx)
331
351
{
332
352
        struct solr_fts_backend_update_context *ctx =
333
353
                (struct solr_fts_backend_update_context *)_ctx;
 
354
        struct solr_fts_backend *backend =
 
355
                (struct solr_fts_backend *)_ctx->backend;
334
356
        struct solr_fts_field *field;
335
357
        const char *str;
336
358
        int ret = _ctx->failed ? -1 : 0;
341
363
        if (ctx->documents_added || ctx->expunges) {
342
364
                /* commit and wait until the documents we just indexed are
343
365
                   visible to the following search */
344
 
                str = t_strdup_printf("<commit waitFlush=\"false\" "
345
 
                                      "waitSearcher=\"%s\"/>",
 
366
                if (ctx->expunges)
 
367
                        fts_backend_solr_expunge_flush(ctx);
 
368
                str = t_strdup_printf("<commit softCommit=\"true\" waitSearcher=\"%s\"/>",
346
369
                                      ctx->documents_added ? "true" : "false");
347
 
                if (solr_connection_post(solr_conn, str) < 0)
 
370
                if (solr_connection_post(backend->solr_conn, str) < 0)
348
371
                        ret = -1;
349
372
        }
350
373
 
351
 
        str_free(&ctx->cmd);
 
374
        if (ctx->cmd != NULL)
 
375
                str_free(&ctx->cmd);
 
376
        if (ctx->cmd_expunge != NULL)
 
377
                str_free(&ctx->cmd_expunge);
352
378
        array_foreach_modifiable(&ctx->fields, field) {
353
379
                str_free(&field->value);
354
380
                i_free(field->key);
367
393
        const char *box_guid;
368
394
 
369
395
        if (ctx->prev_uid != 0) {
370
 
                (void)fts_index_set_last_uid(ctx->cur_box, ctx->prev_uid);
 
396
                fts_index_set_last_uid(ctx->cur_box, ctx->prev_uid);
371
397
                ctx->prev_uid = 0;
372
398
        }
373
399
 
404
430
                   highly unlikely to be indexed at this time. */
405
431
                return;
406
432
        }
407
 
        ctx->expunges = TRUE;
408
 
 
409
 
        T_BEGIN {
410
 
                string_t *cmd;
411
 
 
412
 
                cmd = t_str_new(256);
413
 
                str_append(cmd, "<delete><id>");
414
 
                xml_encode_id(ctx, cmd, uid);
415
 
                str_append(cmd, "</id></delete>");
416
 
 
417
 
                (void)solr_connection_post(solr_conn, str_c(cmd));
418
 
        } T_END;
 
433
        if (!ctx->expunges) {
 
434
                ctx->expunges = TRUE;
 
435
                ctx->cmd_expunge = str_new(default_pool, 1024);
 
436
                str_append(ctx->cmd_expunge, "<delete>");
 
437
        }
 
438
 
 
439
        if (str_len(ctx->cmd_expunge) >= SOLR_CMDBUF_FLUSH_SIZE)
 
440
                fts_backend_solr_expunge_flush(ctx);
 
441
 
 
442
        str_append(ctx->cmd_expunge, "<id>");
 
443
        xml_encode_id(ctx, ctx->cmd_expunge, uid);
 
444
        str_append(ctx->cmd_expunge, "</id>");
419
445
}
420
446
 
421
447
static void
422
448
fts_backend_solr_uid_changed(struct solr_fts_backend_update_context *ctx,
423
449
                             uint32_t uid)
424
450
{
 
451
        struct solr_fts_backend *backend =
 
452
                (struct solr_fts_backend *)ctx->ctx.backend;
 
453
 
425
454
        if (ctx->post == NULL) {
426
455
                i_assert(ctx->prev_uid == 0);
427
456
 
428
 
                ctx->post = solr_connection_post_begin(solr_conn);
 
457
                ctx->cmd = str_new(default_pool, SOLR_CMDBUF_SIZE);
 
458
                ctx->post = solr_connection_post_begin(backend->solr_conn);
429
459
                str_append(ctx->cmd, "<add>");
430
460
        } else {
431
461
                fts_backend_solr_doc_close(ctx);
432
462
        }
433
463
        ctx->prev_uid = uid;
 
464
        ctx->truncate_header = FALSE;
434
465
        fts_backend_solr_doc_open(ctx, uid);
435
466
}
436
467
 
517
548
                }
518
549
                xml_encode_data(ctx->cmd, data, size);
519
550
        } else {
520
 
                xml_encode_data(ctx->cur_value, data, size);
521
 
                if (ctx->cur_value2 != NULL)
 
551
                if (!ctx->truncate_header)
 
552
                        xml_encode_data(ctx->cur_value, data, size);
 
553
                if (ctx->cur_value2 != NULL &&
 
554
                    (!ctx->truncate_header ||
 
555
                     str_len(ctx->cur_value2) < SOLR_HEADER_LINE_MAX_TRUNC_SIZE))
522
556
                        xml_encode_data(ctx->cur_value2, data, size);
523
557
        }
524
558
 
527
561
                                          str_len(ctx->cmd));
528
562
                str_truncate(ctx->cmd, 0);
529
563
        }
530
 
        if (str_len(ctx->cur_value) >= SOLR_BUFFER_WARN_SIZE &&
531
 
            ctx->size_warned_uid != ctx->prev_uid) {
 
564
        if (!ctx->truncate_header &&
 
565
            str_len(ctx->cur_value) >= SOLR_HEADER_MAX_SIZE) {
532
566
                /* a large header */
533
567
                i_assert(ctx->cur_value != ctx->cmd);
534
568
 
535
 
                ctx->size_warned_uid = ctx->prev_uid;
536
 
                i_warning("fts-solr(%s): Mailbox %s UID=%u header size is huge",
 
569
                i_warning("fts-solr(%s): Mailbox %s UID=%u header size is huge, truncating",
537
570
                          ctx->cur_box->storage->user->username,
538
571
                          mailbox_get_vname(ctx->cur_box), ctx->prev_uid);
 
572
                ctx->truncate_header = TRUE;
539
573
        }
540
574
        return 0;
541
575
}
555
589
        /* FIXME: proper rescan needed. for now we'll just reset the
556
590
           last-uids */
557
591
        iter = mailbox_list_iter_init(backend->ns->list, "*",
 
592
                                      MAILBOX_LIST_ITER_SKIP_ALIASES |
558
593
                                      MAILBOX_LIST_ITER_NO_AUTO_BOXES);
559
594
        while ((info = mailbox_list_iter_next(iter)) != NULL) {
560
595
                if ((info->flags &
561
596
                     (MAILBOX_NONEXISTENT | MAILBOX_NOSELECT)) != 0)
562
597
                        continue;
563
598
 
564
 
                box = mailbox_alloc(info->ns->list, info->name, 0);
 
599
                box = mailbox_alloc(info->ns->list, info->vname, 0);
565
600
                if (mailbox_open(box) == 0) {
566
601
                        if (fts_index_set_last_uid(box, 0) < 0)
567
602
                                ret = -1;
723
758
                       const char *box_guid, ARRAY_TYPE(seq_range) *uids_r,
724
759
                       ARRAY_TYPE(fts_score_map) *scores_r)
725
760
{
 
761
        struct solr_fts_backend *backend = (struct solr_fts_backend *)_backend;
726
762
        pool_t pool = pool_alloconly_create("fts solr search", 1024);
727
763
        struct solr_result **results;
728
764
        int ret;
735
771
        else
736
772
                str_append(str, "%22%22");
737
773
 
738
 
        ret = solr_connection_select(solr_conn, str_c(str), pool, &results);
 
774
        ret = solr_connection_select(backend->solr_conn, str_c(str),
 
775
                                     pool, &results);
739
776
        if (ret == 0 && results[0] != NULL) {
740
777
                array_append_array(uids_r, &results[0]->uids);
741
778
                array_append_array(scores_r, &results[0]->scores);
783
820
                  struct mailbox *const boxes[],
784
821
                  struct fts_multi_result *result)
785
822
{
 
823
        struct solr_fts_backend *backend = (struct solr_fts_backend *)_backend;
786
824
        struct solr_result **solr_results;
787
825
        struct fts_result *fts_result;
788
 
        ARRAY_DEFINE(fts_results, struct fts_result);
789
 
        struct hash_table *mailboxes;
 
826
        ARRAY(struct fts_result) fts_results;
 
827
        HASH_TABLE(char *, struct mailbox *) mailboxes;
790
828
        struct mailbox *box;
791
829
        const char *box_guid;
792
830
        unsigned int i, len;
799
837
        else
800
838
                str_append(str, "%22%22");
801
839
 
802
 
        mailboxes = hash_table_create(default_pool, default_pool, 0,
803
 
                                      str_hash, (hash_cmp_callback_t *)strcmp);
 
840
        hash_table_create(&mailboxes, default_pool, 0, str_hash, strcmp);
804
841
        str_append(str, "%2B(");
805
842
        len = str_len(str);
806
843
        for (i = 0; boxes[i] != NULL; i++) {
815
852
        }
816
853
        str_append_c(str, ')');
817
854
 
818
 
        if (solr_connection_select(solr_conn, str_c(str),
 
855
        if (solr_connection_select(backend->solr_conn, str_c(str),
819
856
                                   result->pool, &solr_results) < 0) {
820
857
                hash_table_destroy(&mailboxes);
821
858
                return -1;
835
872
                fts_result->scores = solr_results[i]->scores;
836
873
                fts_result->scores_sorted = TRUE;
837
874
        }
838
 
        (void)array_append_space(&fts_results);
 
875
        array_append_zero(&fts_results);
839
876
        result->box_results = array_idx_modifiable(&fts_results, 0);
840
877
        hash_table_destroy(&mailboxes);
841
878
        return 0;