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);