]> granicus.if.org Git - vim/commitdiff
patch 7.4.1666 v7.4.1666
authorBram Moolenaar <Bram@vim.org>
Mon, 28 Mar 2016 12:11:42 +0000 (14:11 +0200)
committerBram Moolenaar <Bram@vim.org>
Mon, 28 Mar 2016 12:11:42 +0000 (14:11 +0200)
Problem:    When reading JSON from a channel all readahead is used.
Solution:   Use the fill function to reduce overhead.

src/channel.c
src/json.c
src/structs.h
src/version.c

index ccab2cb447e61c9d6afd6f27ffe41a475da58975..a506598d7d1dd23456f16937b4f9e6a5f45a882d 100644 (file)
@@ -1184,7 +1184,6 @@ write_buf_line(buf_T *buf, linenr_T lnum, channel_T *channel)
     int            len = (int)STRLEN(line);
     char_u  *p;
 
-    /* TODO: check if channel can be written to, do not block on write */
     if ((p = alloc(len + 2)) == NULL)
        return;
     STRCPY(p, line);
@@ -1213,13 +1212,14 @@ channel_write_in(channel_T *channel)
        in_part->ch_buffer = NULL;
        return;
     }
-    if (in_part->ch_fd == INVALID_FD)
-       /* pipe was closed */
-       return;
 
     for (lnum = in_part->ch_buf_top; lnum <= in_part->ch_buf_bot
                                   && lnum <= buf->b_ml.ml_line_count; ++lnum)
     {
+       if (in_part->ch_fd == INVALID_FD)
+           /* pipe was closed */
+           return;
+       /* TODO: check if channel can be written to, do not block on write */
        write_buf_line(buf, lnum, channel);
        ++written;
     }
@@ -1365,10 +1365,12 @@ channel_collapse(channel_T *channel, int part)
 
 /*
  * Store "buf[len]" on "channel"/"part".
+ * When "prepend" is TRUE put in front, otherwise append at the end.
  * Returns OK or FAIL.
  */
     static int
-channel_save(channel_T *channel, int part, char_u *buf, int len, char *lead)
+channel_save(channel_T *channel, int part, char_u *buf, int len,
+                                                     int prepend, char *lead)
 {
     readq_T *node;
     readq_T *head = &channel->ch_part[part].ch_head;
@@ -1400,14 +1402,28 @@ channel_save(channel_T *channel, int part, char_u *buf, int len, char *lead)
        node->rq_buffer[len] = NUL;
     }
 
-    /* append node to the tail of the queue */
-    node->rq_next = NULL;
-    node->rq_prev = head->rq_prev;
-    if (head->rq_prev == NULL)
+    if (prepend)
+    {
+       /* preend node to the head of the queue */
+       node->rq_next = head->rq_next;
+       node->rq_prev = NULL;
+       if (head->rq_next == NULL)
+           head->rq_prev = node;
+       else
+           head->rq_next->rq_prev = node;
        head->rq_next = node;
+    }
     else
-       head->rq_prev->rq_next = node;
-    head->rq_prev = node;
+    {
+       /* append node to the tail of the queue */
+       node->rq_next = NULL;
+       node->rq_prev = head->rq_prev;
+       if (head->rq_prev == NULL)
+           head->rq_next = node;
+       else
+           head->rq_prev->rq_next = node;
+       head->rq_prev = node;
+    }
 
     if (log_fd != NULL && lead != NULL)
     {
@@ -1420,6 +1436,42 @@ channel_save(channel_T *channel, int part, char_u *buf, int len, char *lead)
     return OK;
 }
 
+    static int
+channel_fill(js_read_T *reader)
+{
+    channel_T  *channel = (channel_T *)reader->js_cookie;
+    int                part = reader->js_cookie_arg;
+    char_u     *next = channel_get(channel, part);
+    int                unused;
+    int                len;
+    char_u     *p;
+
+    if (next == NULL)
+       return FALSE;
+
+    unused = reader->js_end - reader->js_buf - reader->js_used;
+    if (unused > 0)
+    {
+       /* Prepend unused text. */
+       len = (int)STRLEN(next);
+       p = alloc(unused + len + 1);
+       if (p == NULL)
+       {
+           vim_free(next);
+           return FALSE;
+       }
+       mch_memmove(p, reader->js_buf + reader->js_used, unused);
+       mch_memmove(p + unused, next, len + 1);
+       vim_free(next);
+       next = p;
+    }
+
+    vim_free(reader->js_buf);
+    reader->js_buf = next;
+    reader->js_used = 0;
+    return TRUE;
+}
+
 /*
  * Use the read buffer of "channel"/"part" and parse a JSON message that is
  * complete.  The messages are added to the queue.
@@ -1439,19 +1491,17 @@ channel_parse_json(channel_T *channel, int part)
     if (channel_peek(channel, part) == NULL)
        return FALSE;
 
-    /* TODO: make reader work properly */
-    /* reader.js_buf = channel_peek(channel, part); */
-    reader.js_buf = channel_get_all(channel, part);
+    reader.js_buf = channel_get(channel, part);
     reader.js_used = 0;
-    reader.js_fill = NULL;
-    /* reader.js_fill = channel_fill; */
+    reader.js_fill = channel_fill;
     reader.js_cookie = channel;
+    reader.js_cookie_arg = part;
 
     /* When a message is incomplete we wait for a short while for more to
      * arrive.  After the delay drop the input, otherwise a truncated string
      * or list will make us hang.  */
     status = json_decode(&reader, &listtv,
-                    chanpart->ch_mode == MODE_JS ? JSON_JS : 0);
+                                 chanpart->ch_mode == MODE_JS ? JSON_JS : 0);
     if (status == OK)
     {
        /* Only accept the response when it is a list with at least two
@@ -1552,10 +1602,10 @@ channel_parse_json(channel_T *channel, int part)
     }
     else if (reader.js_buf[reader.js_used] != NUL)
     {
-       /* Put the unread part back into the channel.
-        * TODO: insert in front */
+       /* Put the unread part back into the channel. */
        channel_save(channel, part, reader.js_buf + reader.js_used,
-               (int)(reader.js_end - reader.js_buf) - reader.js_used, NULL);
+                       (int)(reader.js_end - reader.js_buf) - reader.js_used,
+                                                                 TRUE, NULL);
        ret = status == MAYBE ? FALSE: TRUE;
     }
     else
@@ -2419,7 +2469,7 @@ channel_read(channel_T *channel, int part, char *func)
            break;      /* error or nothing more to read */
 
        /* Store the read message in the queue. */
-       channel_save(channel, part, buf, len, "RECV ");
+       channel_save(channel, part, buf, len, FALSE, "RECV ");
        readlen += len;
        if (len < MAXMSGSIZE)
            break;      /* did read everything that's available */
@@ -2446,7 +2496,7 @@ channel_read(channel_T *channel, int part, char *func)
        if (channel->ch_part[part].ch_mode == MODE_RAW
                                 || channel->ch_part[part].ch_mode == MODE_NL)
            channel_save(channel, part, (char_u *)DETACH_MSG_RAW,
-                                        (int)STRLEN(DETACH_MSG_RAW), "PUT ");
+                                 (int)STRLEN(DETACH_MSG_RAW), FALSE, "PUT ");
 
        /* TODO: When reading from stdout is not possible, should we try to
         * keep stdin and stderr open?  Probably not, assume the other side
index 9738fc5fec59ee37e13dc9c12b7be46732b8da46..b4ebe74146746ed7acf1d0cf74de5263e91a0eb4 100644 (file)
@@ -350,8 +350,10 @@ json_skip_white(js_read_T *reader)
        if (reader->js_fill != NULL && c == NUL)
        {
            if (reader->js_fill(reader))
+           {
                reader->js_end = reader->js_buf + STRLEN(reader->js_buf);
-           continue;
+               continue;
+           }
        }
        if (c == NUL || c > ' ')
            break;
index abfe6cd781c9ee3b551e5ca79cc5ab64c80a1c05..68b791789ef8fabf1f5ad13fcc474dba46ba7d1d 100644 (file)
@@ -2971,6 +2971,7 @@ struct js_reader
                                /* function to fill the buffer or NULL;
                                  * return TRUE when the buffer was filled */
     void       *js_cookie;     /* can be used by js_fill */
+    int                js_cookie_arg;  /* can be used by js_fill */
 };
 typedef struct js_reader js_read_T;
 
index e183717f4db63190da872aa79c66d072529386b4..5a55707fa352ab249a8b79308785483d3d21a2ff 100644 (file)
@@ -748,6 +748,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1666,
 /**/
     1665,
 /**/