# HG changeset patch # User Christian Brabandt # Date 1459167305 -7200 # Node ID 7038ec89d1fd7892f8d9e6a93437cc03a6cd618f # Parent 8d0e97cf13441e933b1bd0aa743e07ed5c706c6c commit https://github.com/vim/vim/commit/46c00a6565b8f1f4b7b1041d03eaceaf6ffc4aee Author: Bram Moolenaar Date: Mon Mar 28 14:11:42 2016 +0200 patch 7.4.1666 Problem: When reading JSON from a channel all readahead is used. Solution: Use the fill function to reduce overhead. diff --git a/src/channel.c b/src/channel.c --- a/src/channel.c +++ b/src/channel.c @@ -1184,7 +1184,6 @@ write_buf_line(buf_T *buf, linenr_T lnum 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 /* * 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 par 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 par 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, i 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, i } 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 par 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 par 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 --- 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 --- 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 --- 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,