Mercurial > dovecot > original-hg > dovecot-1.2
comparison src/imap/imap-fetch-body-section.c @ 991:21788a1e9e39 HEAD
Partial fetches are working fast again - faster than ever actually.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Tue, 21 Jan 2003 07:37:35 +0200 |
parents | 8028c4dcf38f |
children | 5a4461a388d9 |
comparison
equal
deleted
inserted
replaced
990:9c8df18fb2a9 | 991:21788a1e9e39 |
---|---|
29 uoff_t skip, max_size; | 29 uoff_t skip, max_size; |
30 const char *const *fields; | 30 const char *const *fields; |
31 int (*match_func) (const char *const *, const unsigned char *, size_t); | 31 int (*match_func) (const char *const *, const unsigned char *, size_t); |
32 }; | 32 }; |
33 | 33 |
34 struct partial_cache { | |
35 unsigned int select_counter; | |
36 unsigned int uid; | |
37 | |
38 uoff_t physical_start; | |
39 struct message_size pos; | |
40 }; | |
41 | |
42 static struct partial_cache partial = { 0, 0, 0, { 0, 0, 0 } }; | |
43 | |
44 static int seek_partial(unsigned int select_counter, unsigned int uid, | |
45 struct partial_cache *partial, struct istream *stream, | |
46 uoff_t physical_start, uoff_t virtual_skip) | |
47 { | |
48 int cr_skipped; | |
49 | |
50 if (select_counter == partial->select_counter && uid == partial->uid && | |
51 physical_start == partial->physical_start && | |
52 virtual_skip >= partial->pos.virtual_size) { | |
53 /* we can use the cache */ | |
54 virtual_skip -= partial->pos.virtual_size; | |
55 } else { | |
56 partial->select_counter = select_counter; | |
57 partial->uid = uid; | |
58 partial->physical_start = physical_start; | |
59 memset(&partial->pos, 0, sizeof(partial->pos)); | |
60 } | |
61 | |
62 i_warning("skipping %lld", virtual_skip); | |
63 | |
64 i_stream_seek(stream, partial->physical_start + | |
65 partial->pos.physical_size); | |
66 message_skip_virtual(stream, virtual_skip, &partial->pos, &cr_skipped); | |
67 | |
68 if (cr_skipped) | |
69 partial->pos.virtual_size--; | |
70 | |
71 return cr_skipped; | |
72 } | |
73 | |
34 /* fetch BODY[] or BODY[TEXT] */ | 74 /* fetch BODY[] or BODY[TEXT] */ |
35 static int fetch_body(struct imap_fetch_context *ctx, | 75 static int fetch_body(struct imap_fetch_context *ctx, |
36 const struct imap_fetch_body_data *body, | 76 const struct imap_fetch_body_data *body, |
37 struct mail *mail, int fetch_header) | 77 struct mail *mail, int fetch_header) |
38 { | 78 { |
39 struct message_size hdr_size, body_size; | 79 struct message_size hdr_size, body_size; |
40 struct istream *stream; | 80 struct istream *stream; |
41 const char *str; | 81 const char *str; |
82 int skip_cr; | |
83 off_t ret; | |
42 | 84 |
43 stream = mail->get_stream(mail, &hdr_size, &body_size); | 85 stream = mail->get_stream(mail, &hdr_size, &body_size); |
44 if (stream == NULL) | 86 if (stream == NULL) |
45 return FALSE; | 87 return FALSE; |
46 | 88 |
52 str = t_strdup_printf("%s {%"PRIuUOFF_T"}\r\n", | 94 str = t_strdup_printf("%s {%"PRIuUOFF_T"}\r\n", |
53 ctx->prefix, body_size.virtual_size); | 95 ctx->prefix, body_size.virtual_size); |
54 if (o_stream_send_str(ctx->output, str) < 0) | 96 if (o_stream_send_str(ctx->output, str) < 0) |
55 return FALSE; | 97 return FALSE; |
56 | 98 |
57 /* FIXME: SLOW! we need some cache for this. */ | 99 skip_cr = seek_partial(ctx->select_counter, mail->uid, |
58 return message_send(ctx->output, stream, &body_size, | 100 &partial, stream, 0, body->skip); |
59 body->skip, body->max_size); | 101 ret = message_send(ctx->output, stream, &body_size, |
102 skip_cr, body->max_size); | |
103 if (ret > 0) { | |
104 partial.pos.physical_size = | |
105 stream->v_offset - partial.physical_start; | |
106 partial.pos.virtual_size += ret; | |
107 } | |
108 return ret >= 0; | |
60 } | 109 } |
61 | 110 |
62 static const char **get_fields_array(const char *fields) | 111 static const char **get_fields_array(const char *fields) |
63 { | 112 { |
64 const char **field_list, **field; | 113 const char **field_list, **field; |
256 str = t_strdup_printf("%s {%"PRIuUOFF_T"}\r\n", | 305 str = t_strdup_printf("%s {%"PRIuUOFF_T"}\r\n", |
257 ctx->prefix, size->virtual_size); | 306 ctx->prefix, size->virtual_size); |
258 if (o_stream_send_str(ctx->output, str) < 0) | 307 if (o_stream_send_str(ctx->output, str) < 0) |
259 return FALSE; | 308 return FALSE; |
260 return message_send(ctx->output, input, size, | 309 return message_send(ctx->output, input, size, |
261 body->skip, body->max_size); | 310 body->skip, body->max_size) >= 0; |
262 } | 311 } |
263 | 312 |
264 /* partial headers - copy the wanted fields into memory, inserting | 313 /* partial headers - copy the wanted fields into memory, inserting |
265 missing CRs on the way. If the header is too large, calculate | 314 missing CRs on the way. If the header is too large, calculate |
266 the size first and then send the data directly to output stream. */ | 315 the size first and then send the data directly to output stream. */ |
384 | 433 |
385 /* fetch BODY[1.2] or BODY[1.2.TEXT] */ | 434 /* fetch BODY[1.2] or BODY[1.2.TEXT] */ |
386 static int fetch_part_body(struct imap_fetch_context *ctx, | 435 static int fetch_part_body(struct imap_fetch_context *ctx, |
387 struct istream *stream, | 436 struct istream *stream, |
388 const struct imap_fetch_body_data *body, | 437 const struct imap_fetch_body_data *body, |
389 const struct message_part *part) | 438 struct mail *mail, const struct message_part *part) |
390 { | 439 { |
391 const char *str; | 440 const char *str; |
392 | 441 int skip_cr; |
393 /* jump to beginning of part body */ | 442 off_t ret; |
394 i_stream_seek(stream, part->physical_pos + | |
395 part->header_size.physical_size); | |
396 | 443 |
397 str = t_strdup_printf("%s {%"PRIuUOFF_T"}\r\n", | 444 str = t_strdup_printf("%s {%"PRIuUOFF_T"}\r\n", |
398 ctx->prefix, part->body_size.virtual_size); | 445 ctx->prefix, part->body_size.virtual_size); |
399 if (o_stream_send_str(ctx->output, str) < 0) | 446 if (o_stream_send_str(ctx->output, str) < 0) |
400 return FALSE; | 447 return FALSE; |
401 | 448 |
402 /* FIXME: potential performance problem with big messages: | 449 skip_cr = seek_partial(ctx->select_counter, mail->uid, |
403 FETCH BODY[1]<100000..1024>, hopefully no clients do this */ | 450 &partial, stream, part->physical_pos + |
404 return message_send(ctx->output, stream, &part->body_size, | 451 part->header_size.physical_size, body->skip); |
405 body->skip, body->max_size); | 452 ret = message_send(ctx->output, stream, &part->body_size, |
453 skip_cr, body->max_size); | |
454 if (ret > 0) { | |
455 partial.pos.physical_size = | |
456 stream->v_offset - partial.physical_start; | |
457 partial.pos.virtual_size += ret; | |
458 } | |
459 return ret >= 0; | |
406 } | 460 } |
407 | 461 |
408 static int fetch_part(struct imap_fetch_context *ctx, struct mail *mail, | 462 static int fetch_part(struct imap_fetch_context *ctx, struct mail *mail, |
409 const struct imap_fetch_body_data *body) | 463 const struct imap_fetch_body_data *body) |
410 { | 464 { |
419 stream = mail->get_stream(mail, NULL, NULL); | 473 stream = mail->get_stream(mail, NULL, NULL); |
420 if (stream == NULL) | 474 if (stream == NULL) |
421 return FALSE; | 475 return FALSE; |
422 | 476 |
423 if (*section == '\0' || strcmp(section, "TEXT") == 0) | 477 if (*section == '\0' || strcmp(section, "TEXT") == 0) |
424 return fetch_part_body(ctx, stream, body, part); | 478 return fetch_part_body(ctx, stream, body, mail, part); |
425 | 479 |
426 if (strncmp(section, "HEADER", 6) == 0 || | 480 if (strncmp(section, "HEADER", 6) == 0 || |
427 strcmp(section, "MIME") == 0) { | 481 strcmp(section, "MIME") == 0) { |
428 i_stream_seek(stream, part->physical_pos); | 482 i_stream_seek(stream, part->physical_pos); |
429 return fetch_header_from(ctx, stream, &part->header_size, body); | 483 return fetch_header_from(ctx, stream, &part->header_size, body); |