Patch 7.4.2018
Problem: buf_valid() can be slow when there are many buffers.
Solution: Add bufref_valid(), only go through the buffer list when a buffer
was freed.
Files: src/structs.h, src/buffer.c, src/quickfix.c, src/proto/buffer.pro
*** ../vim-7.4.2017/src/structs.h 2016-07-03 17:47:21.858812593 +0200
--- src/structs.h 2016-07-10 17:03:56.106490100 +0200
***************
*** 69,74 ****
--- 69,82 ----
typedef int scid_T; /* script ID */
typedef struct file_buffer buf_T; /* forward declaration */
+ /* Reference to a buffer that stores the value of buf_free_count.
+ * bufref_valid() only needs to check "buf" when the count differs.
+ */
+ typedef struct {
+ buf_T *br_buf;
+ int br_buf_free_count;
+ } bufref_T;
+
/*
* This is here because regexp.h needs pos_T and below regprog_T is used.
*/
*** ../vim-7.4.2017/src/buffer.c 2016-07-10 17:00:33.313537282 +0200
--- src/buffer.c 2016-07-10 18:18:04.572170378 +0200
***************
*** 67,72 ****
--- 67,75 ----
static char *e_auabort = N_("E855: Autocommands caused command to abort");
#endif
+ /* Number of times free_buffer() was called. */
+ static int buf_free_count = 0;
+
/*
* Open current buffer, that is: open the memfile and read the file into
* memory.
***************
*** 309,315 ****
--- 312,340 ----
}
/*
+ * Store "buf" in "bufref" and set the free count.
+ */
+ void
+ set_bufref(bufref_T *bufref, buf_T *buf)
+ {
+ bufref->br_buf = buf;
+ bufref->br_buf_free_count = buf_free_count;
+ }
+
+ /*
+ * Return TRUE if "bufref->br_buf" points to a valid buffer.
+ * Only goes through the buffer list if buf_free_count changed.
+ */
+ int
+ bufref_valid(bufref_T *bufref)
+ {
+ return bufref->br_buf_free_count == buf_free_count
+ ? TRUE : buf_valid(bufref->br_buf);
+ }
+
+ /*
* Return TRUE if "buf" points to a valid buffer (in the buffer list).
+ * This can be slow if there are many buffers, prefer using bufref_valid().
*/
int
buf_valid(buf_T *buf)
***************
*** 351,356 ****
--- 376,382 ----
#ifdef FEAT_AUTOCMD
int is_curbuf;
int nwindows;
+ bufref_T bufref;
#endif
int unload_buf = (action != 0);
int del_buf = (action == DOBUF_DEL || action == DOBUF_WIPE);
***************
*** 395,407 ****
}
#ifdef FEAT_AUTOCMD
/* When the buffer is no longer in a window, trigger BufWinLeave */
if (buf->b_nwindows == 1)
{
buf->b_closing = TRUE;
if (apply_autocmds(EVENT_BUFWINLEAVE, buf->b_fname, buf->b_fname,
FALSE, buf)
! && !buf_valid(buf))
{
/* Autocommands deleted the buffer. */
aucmd_abort:
--- 421,435 ----
}
#ifdef FEAT_AUTOCMD
+ set_bufref(&bufref, buf);
+
/* When the buffer is no longer in a window, trigger BufWinLeave */
if (buf->b_nwindows == 1)
{
buf->b_closing = TRUE;
if (apply_autocmds(EVENT_BUFWINLEAVE, buf->b_fname, buf->b_fname,
FALSE, buf)
! && !bufref_valid(&bufref))
{
/* Autocommands deleted the buffer. */
aucmd_abort:
***************
*** 420,426 ****
buf->b_closing = TRUE;
if (apply_autocmds(EVENT_BUFHIDDEN, buf->b_fname, buf->b_fname,
FALSE, buf)
! && !buf_valid(buf))
/* Autocommands deleted the buffer. */
goto aucmd_abort;
buf->b_closing = FALSE;
--- 448,454 ----
buf->b_closing = TRUE;
if (apply_autocmds(EVENT_BUFHIDDEN, buf->b_fname, buf->b_fname,
FALSE, buf)
! && !bufref_valid(&bufref))
/* Autocommands deleted the buffer. */
goto aucmd_abort;
buf->b_closing = FALSE;
***************
*** 464,470 ****
#ifdef FEAT_AUTOCMD
/* Autocommands may have deleted the buffer. */
! if (!buf_valid(buf))
return;
# ifdef FEAT_EVAL
if (aborting()) /* autocmds may abort script processing */
--- 492,498 ----
#ifdef FEAT_AUTOCMD
/* Autocommands may have deleted the buffer. */
! if (!bufref_valid(&bufref))
return;
# ifdef FEAT_EVAL
if (aborting()) /* autocmds may abort script processing */
***************
*** 575,601 ****
{
#ifdef FEAT_AUTOCMD
int is_curbuf = (buf == curbuf);
buf->b_closing = TRUE;
if (buf->b_ml.ml_mfp != NULL)
{
if (apply_autocmds(EVENT_BUFUNLOAD, buf->b_fname, buf->b_fname,
FALSE, buf)
! && !buf_valid(buf)) /* autocommands may delete the buffer */
return;
}
if ((flags & BFA_DEL) && buf->b_p_bl)
{
if (apply_autocmds(EVENT_BUFDELETE, buf->b_fname, buf->b_fname,
FALSE, buf)
! && !buf_valid(buf)) /* autocommands may delete the buffer */
return;
}
if (flags & BFA_WIPE)
{
if (apply_autocmds(EVENT_BUFWIPEOUT, buf->b_fname, buf->b_fname,
FALSE, buf)
! && !buf_valid(buf)) /* autocommands may delete the buffer */
return;
}
buf->b_closing = FALSE;
--- 603,634 ----
{
#ifdef FEAT_AUTOCMD
int is_curbuf = (buf == curbuf);
+ bufref_T bufref;
buf->b_closing = TRUE;
+ set_bufref(&bufref, buf);
if (buf->b_ml.ml_mfp != NULL)
{
if (apply_autocmds(EVENT_BUFUNLOAD, buf->b_fname, buf->b_fname,
FALSE, buf)
! && !bufref_valid(&bufref))
! /* autocommands deleted the buffer */
return;
}
if ((flags & BFA_DEL) && buf->b_p_bl)
{
if (apply_autocmds(EVENT_BUFDELETE, buf->b_fname, buf->b_fname,
FALSE, buf)
! && !bufref_valid(&bufref))
! /* autocommands deleted the buffer */
return;
}
if (flags & BFA_WIPE)
{
if (apply_autocmds(EVENT_BUFWIPEOUT, buf->b_fname, buf->b_fname,
FALSE, buf)
! && !bufref_valid(&bufref))
! /* autocommands deleted the buffer */
return;
}
buf->b_closing = FALSE;
***************
*** 662,667 ****
--- 695,701 ----
static void
free_buffer(buf_T *buf)
{
+ ++buf_free_count;
free_buffer_stuff(buf, TRUE);
#ifdef FEAT_EVAL
unref_var_dict(buf->b_vars);
***************
*** 1027,1032 ****
--- 1061,1067 ----
{
int retval;
buf_T *buf = curbuf;
+ bufref_T bufref;
if (action == DOBUF_UNLOAD)
{
***************
*** 1034,1046 ****
return FAIL;
}
if (close_others)
- {
/* Close any other windows on this buffer, then make it empty. */
- #ifdef FEAT_WINDOWS
close_windows(buf, TRUE);
#endif
- }
setpcmark();
retval = do_ecmd(0, NULL, NULL, NULL, ECMD_ONE,
--- 1069,1080 ----
return FAIL;
}
+ set_bufref(&bufref, buf);
+ #ifdef FEAT_WINDOWS
if (close_others)
/* Close any other windows on this buffer, then make it empty. */
close_windows(buf, TRUE);
#endif
setpcmark();
retval = do_ecmd(0, NULL, NULL, NULL, ECMD_ONE,
***************
*** 1051,1057 ****
* the old one. But do_ecmd() may have done that already, check
* if the buffer still exists.
*/
! if (buf != curbuf && buf_valid(buf) && buf->b_nwindows == 0)
close_buffer(NULL, buf, action, FALSE);
if (!close_others)
need_fileinfo = FALSE;
--- 1085,1091 ----
* the old one. But do_ecmd() may have done that already, check
* if the buffer still exists.
*/
! if (buf != curbuf && bufref_valid(&bufref) && buf->b_nwindows == 0)
close_buffer(NULL, buf, action, FALSE);
if (!close_others)
need_fileinfo = FALSE;
***************
*** 1177,1182 ****
--- 1211,1221 ----
if (unload)
{
int forward;
+ # if defined(FEAT_AUTOCMD) || defined(FEAT_WINDOWS)
+ bufref_T bufref;
+
+ set_bufref(&bufref, buf);
+ # endif
/* When unloading or deleting a buffer that's already unloaded and
* unlisted: fail silently. */
***************
*** 1190,1196 ****
{
dialog_changed(buf, FALSE);
# ifdef FEAT_AUTOCMD
! if (!buf_valid(buf))
/* Autocommand deleted buffer, oops! It's not changed
* now. */
return FAIL;
--- 1229,1235 ----
{
dialog_changed(buf, FALSE);
# ifdef FEAT_AUTOCMD
! if (!bufref_valid(&bufref))
/* Autocommand deleted buffer, oops! It's not changed
* now. */
return FAIL;
***************
*** 1243,1251 ****
{
#ifdef FEAT_WINDOWS
close_windows(buf, FALSE);
#endif
! if (buf != curbuf && buf_valid(buf) && buf->b_nwindows <= 0)
! close_buffer(NULL, buf, action, FALSE);
return OK;
}
--- 1282,1291 ----
{
#ifdef FEAT_WINDOWS
close_windows(buf, FALSE);
+ if (buf != curbuf && bufref_valid(&bufref))
#endif
! if (buf->b_nwindows <= 0)
! close_buffer(NULL, buf, action, FALSE);
return OK;
}
***************
*** 1390,1398 ****
#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
if ((p_confirm || cmdmod.confirm) && p_write)
{
dialog_changed(curbuf, FALSE);
# ifdef FEAT_AUTOCMD
! if (!buf_valid(buf))
/* Autocommand deleted buffer, oops! */
return FAIL;
# endif
--- 1430,1443 ----
#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
if ((p_confirm || cmdmod.confirm) && p_write)
{
+ # ifdef FEAT_AUTOCMD
+ bufref_T bufref;
+
+ set_bufref(&bufref, buf);
+ # endif
dialog_changed(curbuf, FALSE);
# ifdef FEAT_AUTOCMD
! if (!bufref_valid(&bufref))
/* Autocommand deleted buffer, oops! */
return FAIL;
# endif
***************
*** 1443,1448 ****
--- 1488,1496 ----
#ifdef FEAT_SYN_HL
long old_tw = curbuf->b_p_tw;
#endif
+ #ifdef FEAT_AUTOCMD
+ bufref_T bufref;
+ #endif
setpcmark();
if (!cmdmod.keepalt)
***************
*** 1456,1466 ****
prevbuf = curbuf;
#ifdef FEAT_AUTOCMD
if (!apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf)
# ifdef FEAT_EVAL
! || (buf_valid(prevbuf) && !aborting()))
# else
! || buf_valid(prevbuf))
# endif
#endif
{
--- 1504,1515 ----
prevbuf = curbuf;
#ifdef FEAT_AUTOCMD
+ set_bufref(&bufref, prevbuf);
if (!apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf)
# ifdef FEAT_EVAL
! || (bufref_valid(&bufref) && !aborting()))
# else
! || bufref_valid(&bufref))
# endif
#endif
{
***************
*** 1473,1481 ****
close_windows(prevbuf, FALSE);
#endif
#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
! if (buf_valid(prevbuf) && !aborting())
#else
! if (buf_valid(prevbuf))
#endif
{
#ifdef FEAT_WINDOWS
--- 1522,1530 ----
close_windows(prevbuf, FALSE);
#endif
#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
! if (bufref_valid(&bufref) && !aborting())
#else
! if (bufref_valid(&bufref))
#endif
{
#ifdef FEAT_WINDOWS
***************
*** 1496,1502 ****
}
#ifdef FEAT_AUTOCMD
/* An autocommand may have deleted "buf", already entered it (e.g., when
! * it did ":bunload") or aborted the script processing!
* If curwin->w_buffer is null, enter_buffer() will make it valid again */
if ((buf_valid(buf) && buf != curbuf
# ifdef FEAT_EVAL
--- 1545,1551 ----
}
#ifdef FEAT_AUTOCMD
/* An autocommand may have deleted "buf", already entered it (e.g., when
! * it did ":bunload") or aborted the script processing.
* If curwin->w_buffer is null, enter_buffer() will make it valid again */
if ((buf_valid(buf) && buf != curbuf
# ifdef FEAT_EVAL
***************
*** 1706,1717 ****
if ((flags & BLN_LISTED) && !buf->b_p_bl)
{
buf->b_p_bl = TRUE;
#ifdef FEAT_AUTOCMD
if (!(flags & BLN_DUMMY))
{
if (apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, buf)
! && !buf_valid(buf))
return NULL;
}
#endif
--- 1755,1770 ----
if ((flags & BLN_LISTED) && !buf->b_p_bl)
{
+ #ifdef FEAT_AUTOCMD
+ bufref_T bufref;
+ #endif
buf->b_p_bl = TRUE;
#ifdef FEAT_AUTOCMD
+ set_bufref(&bufref, buf);
if (!(flags & BLN_DUMMY))
{
if (apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, buf)
! && !bufref_valid(&bufref))
return NULL;
}
#endif
***************
*** 1887,1902 ****
#ifdef FEAT_AUTOCMD
if (!(flags & BLN_DUMMY))
{
/* Tricky: these autocommands may change the buffer list. They could
* also split the window with re-using the one empty buffer. This may
* result in unexpectedly losing the empty buffer. */
if (apply_autocmds(EVENT_BUFNEW, NULL, NULL, FALSE, buf)
! && !buf_valid(buf))
return NULL;
if (flags & BLN_LISTED)
{
if (apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, buf)
! && !buf_valid(buf))
return NULL;
}
# ifdef FEAT_EVAL
--- 1940,1958 ----
#ifdef FEAT_AUTOCMD
if (!(flags & BLN_DUMMY))
{
+ bufref_T bufref;
+
/* Tricky: these autocommands may change the buffer list. They could
* also split the window with re-using the one empty buffer. This may
* result in unexpectedly losing the empty buffer. */
+ set_bufref(&bufref, buf);
if (apply_autocmds(EVENT_BUFNEW, NULL, NULL, FALSE, buf)
! && !bufref_valid(&bufref))
return NULL;
if (flags & BLN_LISTED)
{
if (apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, buf)
! && !bufref_valid(&bufref))
return NULL;
}
# ifdef FEAT_EVAL
***************
*** 4708,4717 ****
if (!P_HID(buf) && buf->b_nwindows <= 1
&& bufIsChanged(buf))
{
(void)autowrite(buf, FALSE);
#ifdef FEAT_AUTOCMD
/* check if autocommands removed the window */
! if (!win_valid(wp) || !buf_valid(buf))
{
wpnext = firstwin; /* start all over... */
continue;
--- 4764,4778 ----
if (!P_HID(buf) && buf->b_nwindows <= 1
&& bufIsChanged(buf))
{
+ #ifdef FEAT_AUTOCMD
+ bufref_T bufref;
+
+ set_bufref(&bufref, buf);
+ #endif
(void)autowrite(buf, FALSE);
#ifdef FEAT_AUTOCMD
/* check if autocommands removed the window */
! if (!win_valid(wp) || !bufref_valid(&bufref))
{
wpnext = firstwin; /* start all over... */
continue;
***************
*** 4993,4998 ****
--- 5054,5064 ----
if (wp == NULL && split_ret == OK)
{
+ #ifdef FEAT_AUTOCMD
+ bufref_T bufref;
+
+ set_bufref(&bufref, buf);
+ #endif
/* Split the window and put the buffer in it */
p_ea_save = p_ea;
p_ea = TRUE; /* use space from all windows */
***************
*** 5008,5015 ****
#endif
set_curbuf(buf, DOBUF_GOTO);
#ifdef FEAT_AUTOCMD
! if (!buf_valid(buf)) /* autocommands deleted the buffer!!! */
{
#if defined(HAS_SWAP_EXISTS_ACTION)
swap_exists_action = SEA_NONE;
# endif
--- 5074,5082 ----
#endif
set_curbuf(buf, DOBUF_GOTO);
#ifdef FEAT_AUTOCMD
! if (!bufref_valid(&bufref))
{
+ /* autocommands deleted the buffer!!! */
#if defined(HAS_SWAP_EXISTS_ACTION)
swap_exists_action = SEA_NONE;
# endif
*** ../vim-7.4.2017/src/quickfix.c 2016-07-10 17:00:33.317537221 +0200
--- src/quickfix.c 2016-07-10 17:16:38.511074061 +0200
***************
*** 1487,1493 ****
* to make this a lot faster if there are multiple matches in the same file.
*/
static char_u *qf_last_bufname = NULL;
! static buf_T *qf_last_buf = NULL;
/*
* Get buffer number for file "dir.name".
--- 1487,1493 ----
* to make this a lot faster if there are multiple matches in the same file.
*/
static char_u *qf_last_bufname = NULL;
! static bufref_T qf_last_bufref = {NULL, 0};
/*
* Get buffer number for file "dir.name".
***************
*** 1536,1544 ****
bufname = fname;
if (qf_last_bufname != NULL && STRCMP(bufname, qf_last_bufname) == 0
! && buf_valid(qf_last_buf))
{
! buf = qf_last_buf;
vim_free(ptr);
}
else
--- 1536,1544 ----
bufname = fname;
if (qf_last_bufname != NULL && STRCMP(bufname, qf_last_bufname) == 0
! && bufref_valid(&qf_last_bufref))
{
! buf = qf_last_bufref.br_buf;
vim_free(ptr);
}
else
***************
*** 1549,1555 ****
qf_last_bufname = bufname;
else
qf_last_bufname = vim_strsave(bufname);
! qf_last_buf = buf;
}
if (buf == NULL)
return 0;
--- 1549,1555 ----
qf_last_bufname = bufname;
else
qf_last_bufname = vim_strsave(bufname);
! set_bufref(&qf_last_bufref, buf);
}
if (buf == NULL)
return 0;
*** ../vim-7.4.2017/src/proto/buffer.pro 2016-01-19 13:21:55.833334420
+0100
--- src/proto/buffer.pro 2016-07-10 17:11:50.255384426 +0200
***************
*** 1,5 ****
--- 1,7 ----
/* buffer.c */
int open_buffer(int read_stdin, exarg_T *eap, int flags);
+ void set_bufref(bufref_T *bufref, buf_T *buf);
+ int bufref_valid(bufref_T *bufref);
int buf_valid(buf_T *buf);
void close_buffer(win_T *win, buf_T *buf, int action, int abort_if_last);
void buf_clear_file(buf_T *buf);
*** ../vim-7.4.2017/src/version.c 2016-07-10 17:00:33.321537162 +0200
--- src/version.c 2016-07-10 17:04:51.681655986 +0200
***************
*** 760,761 ****
--- 760,763 ----
{ /* Add new patch number below this line */
+ /**/
+ 2018,
/**/
--
hundred-and-one symptoms of being an internet addict:
264. You turn to the teletext page "surfing report" and are surprised that it
is about sizes of waves and a weather forecast for seaside resorts.
/// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language -- http://www.Zimbu.org ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.