]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
dict: Fix potential hang when iterating
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Wed, 12 Aug 2020 08:58:07 +0000 (11:58 +0300)
committerTimo Sirainen <timo.sirainen@open-xchange.com>
Wed, 12 Aug 2020 09:55:23 +0000 (12:55 +0300)
Broken by 2937287a72cffa8c709c22ede838058d48b61778

src/dict/dict-commands.c
src/dict/dict-connection.h

index ef9912c29d30ee6645010723685d7e0be0666815..e7eaa1c339b860f7725514d0b0343de7910f98b6 100644 (file)
@@ -238,6 +238,7 @@ static bool dict_connection_flush_if_full(struct dict_connection *conn)
                        /* continue later when there's more space
                           in output buffer */
                        o_stream_set_flush_pending(conn->conn.output, TRUE);
+                       conn->iter_flush_pending = TRUE;
                        return FALSE;
                }
                /* flushed everything, continue */
@@ -313,14 +314,21 @@ static void cmd_iterate_callback(void *context)
 
        dict_connection_ref(conn);
        o_stream_cork(conn->conn.output);
-       /* Uncork only if all the output has been finished. Some dict drivers
-          (e.g. dict-client) don't do any kind of buffering internally, so
-          this callback can write out only a single iteration. By leaving the
-          ostream corked it doesn't result in many tiny writes. */
+       /* Don't uncork if we're just waiting for more input from the dict
+          driver. Some dict drivers (e.g. dict-client) don't do any kind of
+          buffering internally, so this callback can write out only a single
+          iteration. By leaving the ostream corked it doesn't result in many
+          tiny writes. However, we could be here also because the connection
+          output buffer is full already, in which case don't want to leave a
+          cork. */
+       conn->iter_flush_pending = FALSE;
        cmd->uncork_pending = FALSE;
        if (dict_connection_cmd_output_more(cmd)) {
                /* NOTE: cmd may be freed now */
                o_stream_uncork(conn->conn.output);
+       } else if (conn->iter_flush_pending) {
+               /* Don't leave the stream uncorked or we might get stuck. */
+               o_stream_uncork(conn->conn.output);
        } else {
                /* It's possible that the command gets finished via some other
                   code path. To make sure this doesn't cause hangs, uncork the
index a07b64b7addc1080f6c496f055a12475133c9ff9..d733e2ff86577b8ddccf5054328cf1a0060e02ed 100644 (file)
@@ -29,6 +29,7 @@ struct dict_connection {
        ARRAY(struct dict_connection_cmd *) cmds;
        unsigned int async_id_counter;
 
+       bool iter_flush_pending;
        bool destroyed;
 };