diff options
author | Bram Moolenaar <Bram@vim.org> | 2016-03-28 14:11:42 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2016-03-28 14:11:42 +0200 |
commit | 46c00a6565b8f1f4b7b1041d03eaceaf6ffc4aee (patch) | |
tree | 097071177477e304c3f7e1438c090ba8ff72bfbf /src/channel.c | |
parent | 8038568722a0aad72d001edf4972c29abab57f8f (diff) | |
download | vim-46c00a6565b8f1f4b7b1041d03eaceaf6ffc4aee.zip |
patch 7.4.1666
Problem: When reading JSON from a channel all readahead is used.
Solution: Use the fill function to reduce overhead.
Diffstat (limited to 'src/channel.c')
-rw-r--r-- | src/channel.c | 94 |
1 files changed, 72 insertions, 22 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 |