]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
mbox: Don't cache mbox state after it has been unlocked.
authorTimo Sirainen <tss@iki.fi>
Sat, 13 Dec 2008 09:21:21 +0000 (11:21 +0200)
committerTimo Sirainen <tss@iki.fi>
Sat, 13 Dec 2008 09:21:21 +0000 (11:21 +0200)
--HG--
branch : HEAD

src/lib-storage/index/mbox/istream-raw-mbox.c
src/lib-storage/index/mbox/istream-raw-mbox.h
src/lib-storage/index/mbox/mbox-file.c
src/lib-storage/index/mbox/mbox-lock.c
src/lib-storage/index/mbox/mbox-mail.c

index 52670fc414323a75057fe24da548daa777a76d03..241a5e39e1398c7d51acf05d0ec956e7d0e19223 100644 (file)
@@ -15,8 +15,11 @@ struct raw_mbox_istream {
        uoff_t from_offset, hdr_offset, body_offset, mail_size;
        uoff_t input_peak_offset;
 
+       unsigned int locked:1;
+       unsigned int seeked:1;
        unsigned int crlf_ending:1;
        unsigned int corrupted:1;
+       unsigned int mail_size_forced:1;
        unsigned int eof:1;
        unsigned int header_missing_eoh:1;
 };
@@ -144,6 +147,7 @@ static ssize_t i_stream_raw_mbox_read(struct istream_private *stream)
        int eoh_char, tz;
        bool crlf_ending = FALSE;
 
+       i_assert(rstream->seeked);
        i_assert(stream->istream.v_offset >= rstream->from_offset);
 
        if (stream->istream.eof)
@@ -315,8 +319,9 @@ static ssize_t i_stream_raw_mbox_read(struct istream_private *stream)
                /* istream_raw_mbox_set_next_offset() used invalid
                   cached next_offset? */
                i_error("Next message unexpectedly lost from mbox file "
-                       "%s at %"PRIuUOFF_T, rstream->path,
-                       rstream->hdr_offset + rstream->mail_size);
+                       "%s at %"PRIuUOFF_T" (%s)", rstream->path,
+                       rstream->hdr_offset + rstream->mail_size,
+                       rstream->mail_size_forced ? "cached" : "noncached");
                rstream->eof = TRUE;
                rstream->corrupted = TRUE;
                rstream->istream.istream.stream_errno = EINVAL;
@@ -455,6 +460,8 @@ uoff_t istream_raw_mbox_get_start_offset(struct istream *stream)
        struct raw_mbox_istream *rstream =
                (struct raw_mbox_istream *)stream->real_stream;
 
+       i_assert(rstream->seeked);
+
        return rstream->from_offset;
 }
 
@@ -463,6 +470,8 @@ uoff_t istream_raw_mbox_get_header_offset(struct istream *stream)
        struct raw_mbox_istream *rstream =
                (struct raw_mbox_istream *)stream->real_stream;
 
+       i_assert(rstream->seeked);
+
        if (rstream->hdr_offset == rstream->from_offset)
                (void)i_stream_raw_mbox_read(&rstream->istream);
 
@@ -482,6 +491,8 @@ uoff_t istream_raw_mbox_get_body_offset(struct istream *stream)
        uoff_t offset;
        size_t pos;
 
+       i_assert(rstream->seeked);
+
        if (rstream->body_offset != (uoff_t)-1)
                return rstream->body_offset;
 
@@ -516,6 +527,7 @@ uoff_t istream_raw_mbox_get_body_size(struct istream *stream,
        size_t size;
        uoff_t old_offset, body_size, next_body_offset;
 
+       i_assert(rstream->seeked);
        i_assert(rstream->hdr_offset != (uoff_t)-1);
        i_assert(rstream->body_offset != (uoff_t)-1);
 
@@ -569,6 +581,8 @@ time_t istream_raw_mbox_get_received_time(struct istream *stream)
        struct raw_mbox_istream *rstream =
                (struct raw_mbox_istream *)stream->real_stream;
 
+       i_assert(rstream->seeked);
+
        if (rstream->received_time == (time_t)-1)
                (void)i_stream_raw_mbox_read(&rstream->istream);
        return rstream->received_time;
@@ -579,6 +593,8 @@ const char *istream_raw_mbox_get_sender(struct istream *stream)
        struct raw_mbox_istream *rstream =
                (struct raw_mbox_istream *)stream->real_stream;
 
+       i_assert(rstream->seeked);
+
        if (rstream->sender == NULL)
                (void)i_stream_raw_mbox_read(&rstream->istream);
        return rstream->sender == NULL ? "" : rstream->sender;
@@ -589,6 +605,8 @@ bool istream_raw_mbox_has_crlf_ending(struct istream *stream)
        struct raw_mbox_istream *rstream =
                (struct raw_mbox_istream *)stream->real_stream;
 
+       i_assert(rstream->seeked);
+
        return rstream->crlf_ending;
 }
 
@@ -627,17 +645,21 @@ int istream_raw_mbox_seek(struct istream *stream, uoff_t offset)
                (struct raw_mbox_istream *)stream->real_stream;
        bool check;
 
+       i_assert(rstream->locked);
+
        rstream->corrupted = FALSE;
        rstream->eof = FALSE;
        rstream->istream.istream.eof = FALSE;
 
-       if (rstream->mail_size != (uoff_t)-1 &&
+       /* if seeked is FALSE, we unlocked in the middle. don't try to use
+          any cached state then. */
+       if (rstream->mail_size != (uoff_t)-1 && rstream->seeked &&
            rstream->hdr_offset + rstream->mail_size == offset) {
                istream_raw_mbox_next(stream, (uoff_t)-1);
                return 0;
        }
 
-       if (offset == rstream->from_offset) {
+       if (offset == rstream->from_offset && rstream->seeked) {
                /* back to beginning of current message */
                offset = rstream->hdr_offset;
                check = offset == 0;
@@ -657,6 +679,7 @@ int istream_raw_mbox_seek(struct istream *stream, uoff_t offset)
                rstream->hdr_offset = offset;
                check = TRUE;
        }
+       rstream->seeked = TRUE;
 
        i_stream_seek_mark(stream, offset);
        i_stream_seek_mark(rstream->istream.parent, offset);
@@ -673,6 +696,7 @@ void istream_raw_mbox_set_next_offset(struct istream *stream, uoff_t offset)
 
        i_assert(rstream->hdr_offset != (uoff_t)-1);
 
+       rstream->mail_size_forced = TRUE;
        rstream->mail_size = offset - rstream->hdr_offset;
 }
 
@@ -691,3 +715,20 @@ bool istream_raw_mbox_is_corrupted(struct istream *stream)
 
        return rstream->corrupted;
 }
+
+void istream_raw_mbox_set_locked(struct istream *stream)
+{
+       struct raw_mbox_istream *rstream =
+               (struct raw_mbox_istream *)stream->real_stream;
+
+       rstream->locked = TRUE;
+}
+
+void istream_raw_mbox_set_unlocked(struct istream *stream)
+{
+       struct raw_mbox_istream *rstream =
+               (struct raw_mbox_istream *)stream->real_stream;
+
+       rstream->locked = FALSE;
+       rstream->seeked = FALSE;
+}
index 8bc4c8fa2c24b5500dc0347f4f03afcee609d7a8..4f2705d1d6d6bf193f5dc5161c8e6b1123716ed2 100644 (file)
@@ -46,5 +46,9 @@ void istream_raw_mbox_set_next_offset(struct istream *stream, uoff_t offset);
 bool istream_raw_mbox_is_eof(struct istream *stream);
 /* Returns TRUE if we've noticed corruption in used offsets/sizes. */
 bool istream_raw_mbox_is_corrupted(struct istream *stream);
+/* Change stream's locking state. We'll assert-crash if stream is tried to be
+   read while it's unlocked. */
+void istream_raw_mbox_set_locked(struct istream *stream);
+void istream_raw_mbox_set_unlocked(struct istream *stream);
 
 #endif
index 72c962320f98572cad8e5ddbb66e45652a342322..4f12f05f6fb807b432e658ebc94ec906e1c8f136 100644 (file)
@@ -66,28 +66,26 @@ int mbox_file_open_stream(struct mbox_mailbox *mbox)
        if (mbox->mbox_file_stream != NULL) {
                /* read-only mbox stream */
                i_assert(mbox->mbox_fd == -1 && mbox->mbox_readonly);
+       } else {
+               if (mbox->mbox_fd == -1) {
+                       if (mbox_file_open(mbox) < 0)
+                               return -1;
+               }
 
-               mbox->mbox_stream =
-                       i_stream_create_raw_mbox(mbox->mbox_file_stream,
-                                                mbox->path);
-               return 0;
-       }
-
-       if (mbox->mbox_fd == -1) {
-               if (mbox_file_open(mbox) < 0)
-                       return -1;
-       }
-
-       if (mbox->mbox_writeonly)
-               mbox->mbox_file_stream = i_stream_create_from_data(NULL, 0);
-       else {
-               mbox->mbox_file_stream =
-                       i_stream_create_fd(mbox->mbox_fd,
-                                          MAIL_READ_BLOCK_SIZE, FALSE);
+               if (mbox->mbox_writeonly) {
+                       mbox->mbox_file_stream =
+                               i_stream_create_from_data(NULL, 0);
+               } else {
+                       mbox->mbox_file_stream =
+                               i_stream_create_fd(mbox->mbox_fd,
+                                                  MAIL_READ_BLOCK_SIZE, FALSE);
+               }
        }
 
        mbox->mbox_stream = i_stream_create_raw_mbox(mbox->mbox_file_stream,
                                                     mbox->path);
+       if (mbox->mbox_lock_type != F_UNLCK)
+               istream_raw_mbox_set_locked(mbox->mbox_stream);
        return 0;
 }
 
index ad7ad1c8dfa624b3f6567928682f5a43a1d9f725..905b504b4a3ae0cf2421f8086d9d532a7135c7a4 100644 (file)
@@ -5,6 +5,7 @@
 #include "nfs-workarounds.h"
 #include "mail-index-private.h"
 #include "mbox-storage.h"
+#include "istream-raw-mbox.h"
 #include "mbox-file.h"
 #include "mbox-lock.h"
 
@@ -714,6 +715,8 @@ int mbox_lock(struct mbox_mailbox *mbox, int lock_type,
                mbox->mbox_excl_locks++;
                *lock_id_r = mbox->mbox_lock_id + 1;
        }
+       if (mbox->mbox_stream != NULL)
+               istream_raw_mbox_set_locked(mbox->mbox_stream);
        return 1;
 }
 
@@ -759,6 +762,10 @@ int mbox_unlock(struct mbox_mailbox *mbox, unsigned int lock_id)
        }
        /* all locks gone */
 
+       /* make sure we don't read the stream while unlocked */
+       if (mbox->mbox_stream != NULL)
+               istream_raw_mbox_set_unlocked(mbox->mbox_stream);
+
        memset(&ctx, 0, sizeof(ctx));
        ctx.mbox = mbox;
 
index 6ff5811529d0314ce8f934650a0210fd881fc415..9336390a089b54f797c37ef9961db26387e1fccd 100644 (file)
@@ -194,9 +194,10 @@ mbox_mail_get_next_offset(struct index_mail *mail, uoff_t *next_offset_r)
        }
 
        /* We can't really trust trans_view. The next message may already be
-          expunged from it. Also there hdr.messages_count may be incorrect.
+          expunged from it. Also hdr.messages_count may be incorrect there.
           So refresh the index to get the latest changes and get the next
           message's offset using a new view. */
+       i_assert(mbox->mbox_lock_type != F_UNLCK);
        if (mbox_sync_header_refresh(mbox) < 0)
                return -1;