summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2016-03-28 14:11:42 +0200
committerBram Moolenaar <Bram@vim.org>2016-03-28 14:11:42 +0200
commit46c00a6565b8f1f4b7b1041d03eaceaf6ffc4aee (patch)
tree097071177477e304c3f7e1438c090ba8ff72bfbf
parent8038568722a0aad72d001edf4972c29abab57f8f (diff)
downloadvim-git-7.4.1666.tar.gz
patch 7.4.1666v7.4.1666
Problem: When reading JSON from a channel all readahead is used. Solution: Use the fill function to reduce overhead.
-rw-r--r--src/channel.c94
-rw-r--r--src/json.c4
-rw-r--r--src/structs.h1
-rw-r--r--src/version.c2
4 files changed, 78 insertions, 23 deletions
diff --git a/src/channel.c b/src/channel.c
index ccab2cb44..a506598d7 100644
--- a/src/channel.c
+++ b/src/channel.c
@@ -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
diff --git a/src/json.c b/src/json.c
index 9738fc5fe..b4ebe7414 100644
--- a/src/json.c
+++ b/src/json.c
@@ -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;
diff --git a/src/structs.h b/src/structs.h
index abfe6cd78..68b791789 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -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;
diff --git a/src/version.c b/src/version.c
index e183717f4..5a55707fa 100644
--- a/src/version.c
+++ b/src/version.c
@@ -749,6 +749,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1666,
+/**/
1665,
/**/
1664,