mirror of
https://github.com/vim/vim.git
synced 2025-07-26 11:04:33 -04:00
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.
This commit is contained in:
parent
8240433f48
commit
b25f9a97e9
117
src/buffer.c
117
src/buffer.c
@ -67,6 +67,9 @@ static char *msg_qflist = N_("[Quickfix List]");
|
||||
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.
|
||||
@ -308,8 +311,30 @@ open_buffer(
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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,6 +376,7 @@ close_buffer(
|
||||
#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,13 +421,15 @@ close_buffer(
|
||||
}
|
||||
|
||||
#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)
|
||||
&& !buf_valid(buf))
|
||||
&& !bufref_valid(&bufref))
|
||||
{
|
||||
/* Autocommands deleted the buffer. */
|
||||
aucmd_abort:
|
||||
@ -420,7 +448,7 @@ aucmd_abort:
|
||||
buf->b_closing = TRUE;
|
||||
if (apply_autocmds(EVENT_BUFHIDDEN, buf->b_fname, buf->b_fname,
|
||||
FALSE, buf)
|
||||
&& !buf_valid(buf))
|
||||
&& !bufref_valid(&bufref))
|
||||
/* Autocommands deleted the buffer. */
|
||||
goto aucmd_abort;
|
||||
buf->b_closing = FALSE;
|
||||
@ -464,7 +492,7 @@ aucmd_abort:
|
||||
|
||||
#ifdef FEAT_AUTOCMD
|
||||
/* Autocommands may have deleted the buffer. */
|
||||
if (!buf_valid(buf))
|
||||
if (!bufref_valid(&bufref))
|
||||
return;
|
||||
# ifdef FEAT_EVAL
|
||||
if (aborting()) /* autocmds may abort script processing */
|
||||
@ -575,27 +603,32 @@ buf_freeall(buf_T *buf, int flags)
|
||||
{
|
||||
#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)
|
||||
&& !buf_valid(buf)) /* autocommands may delete the buffer */
|
||||
&& !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)
|
||||
&& !buf_valid(buf)) /* autocommands may delete the buffer */
|
||||
&& !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)
|
||||
&& !buf_valid(buf)) /* autocommands may delete the buffer */
|
||||
&& !bufref_valid(&bufref))
|
||||
/* autocommands deleted the buffer */
|
||||
return;
|
||||
}
|
||||
buf->b_closing = FALSE;
|
||||
@ -662,6 +695,7 @@ buf_freeall(buf_T *buf, int flags)
|
||||
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,6 +1061,7 @@ empty_curbuf(
|
||||
{
|
||||
int retval;
|
||||
buf_T *buf = curbuf;
|
||||
bufref_T bufref;
|
||||
|
||||
if (action == DOBUF_UNLOAD)
|
||||
{
|
||||
@ -1034,13 +1069,12 @@ empty_curbuf(
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
if (close_others)
|
||||
{
|
||||
/* Close any other windows on this buffer, then make it empty. */
|
||||
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,7 +1085,7 @@ empty_curbuf(
|
||||
* 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)
|
||||
if (buf != curbuf && bufref_valid(&bufref) && buf->b_nwindows == 0)
|
||||
close_buffer(NULL, buf, action, FALSE);
|
||||
if (!close_others)
|
||||
need_fileinfo = FALSE;
|
||||
@ -1177,6 +1211,11 @@ do_buffer(
|
||||
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,7 +1229,7 @@ do_buffer(
|
||||
{
|
||||
dialog_changed(buf, FALSE);
|
||||
# ifdef FEAT_AUTOCMD
|
||||
if (!buf_valid(buf))
|
||||
if (!bufref_valid(&bufref))
|
||||
/* Autocommand deleted buffer, oops! It's not changed
|
||||
* now. */
|
||||
return FAIL;
|
||||
@ -1243,9 +1282,10 @@ do_buffer(
|
||||
{
|
||||
#ifdef FEAT_WINDOWS
|
||||
close_windows(buf, FALSE);
|
||||
if (buf != curbuf && bufref_valid(&bufref))
|
||||
#endif
|
||||
if (buf != curbuf && buf_valid(buf) && buf->b_nwindows <= 0)
|
||||
close_buffer(NULL, buf, action, FALSE);
|
||||
if (buf->b_nwindows <= 0)
|
||||
close_buffer(NULL, buf, action, FALSE);
|
||||
return OK;
|
||||
}
|
||||
|
||||
@ -1390,9 +1430,14 @@ do_buffer(
|
||||
#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 (!buf_valid(buf))
|
||||
if (!bufref_valid(&bufref))
|
||||
/* Autocommand deleted buffer, oops! */
|
||||
return FAIL;
|
||||
# endif
|
||||
@ -1443,6 +1488,9 @@ set_curbuf(buf_T *buf, int action)
|
||||
#ifdef FEAT_SYN_HL
|
||||
long old_tw = curbuf->b_p_tw;
|
||||
#endif
|
||||
#ifdef FEAT_AUTOCMD
|
||||
bufref_T bufref;
|
||||
#endif
|
||||
|
||||
setpcmark();
|
||||
if (!cmdmod.keepalt)
|
||||
@ -1456,11 +1504,12 @@ set_curbuf(buf_T *buf, int action)
|
||||
prevbuf = curbuf;
|
||||
|
||||
#ifdef FEAT_AUTOCMD
|
||||
set_bufref(&bufref, prevbuf);
|
||||
if (!apply_autocmds(EVENT_BUFLEAVE, NULL, NULL, FALSE, curbuf)
|
||||
# ifdef FEAT_EVAL
|
||||
|| (buf_valid(prevbuf) && !aborting()))
|
||||
|| (bufref_valid(&bufref) && !aborting()))
|
||||
# else
|
||||
|| buf_valid(prevbuf))
|
||||
|| bufref_valid(&bufref))
|
||||
# endif
|
||||
#endif
|
||||
{
|
||||
@ -1473,9 +1522,9 @@ set_curbuf(buf_T *buf, int action)
|
||||
close_windows(prevbuf, FALSE);
|
||||
#endif
|
||||
#if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL)
|
||||
if (buf_valid(prevbuf) && !aborting())
|
||||
if (bufref_valid(&bufref) && !aborting())
|
||||
#else
|
||||
if (buf_valid(prevbuf))
|
||||
if (bufref_valid(&bufref))
|
||||
#endif
|
||||
{
|
||||
#ifdef FEAT_WINDOWS
|
||||
@ -1496,7 +1545,7 @@ set_curbuf(buf_T *buf, int action)
|
||||
}
|
||||
#ifdef FEAT_AUTOCMD
|
||||
/* An autocommand may have deleted "buf", already entered it (e.g., when
|
||||
* it did ":bunload") or aborted the script processing!
|
||||
* 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,12 +1755,16 @@ buflist_new(
|
||||
|
||||
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)
|
||||
&& !buf_valid(buf))
|
||||
&& !bufref_valid(&bufref))
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
@ -1887,16 +1940,19 @@ buflist_new(
|
||||
#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)
|
||||
&& !buf_valid(buf))
|
||||
&& !bufref_valid(&bufref))
|
||||
return NULL;
|
||||
if (flags & BLN_LISTED)
|
||||
{
|
||||
if (apply_autocmds(EVENT_BUFADD, NULL, NULL, FALSE, buf)
|
||||
&& !buf_valid(buf))
|
||||
&& !bufref_valid(&bufref))
|
||||
return NULL;
|
||||
}
|
||||
# ifdef FEAT_EVAL
|
||||
@ -4708,10 +4764,15 @@ do_arg_all(
|
||||
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) || !buf_valid(buf))
|
||||
if (!win_valid(wp) || !bufref_valid(&bufref))
|
||||
{
|
||||
wpnext = firstwin; /* start all over... */
|
||||
continue;
|
||||
@ -4993,6 +5054,11 @@ ex_buffer_all(exarg_T *eap)
|
||||
|
||||
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,8 +5074,9 @@ ex_buffer_all(exarg_T *eap)
|
||||
#endif
|
||||
set_curbuf(buf, DOBUF_GOTO);
|
||||
#ifdef FEAT_AUTOCMD
|
||||
if (!buf_valid(buf)) /* autocommands deleted the buffer!!! */
|
||||
if (!bufref_valid(&bufref))
|
||||
{
|
||||
/* autocommands deleted the buffer!!! */
|
||||
#if defined(HAS_SWAP_EXISTS_ACTION)
|
||||
swap_exists_action = SEA_NONE;
|
||||
# endif
|
||||
|
@ -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);
|
||||
|
@ -1487,7 +1487,7 @@ copy_loclist(win_T *from, win_T *to)
|
||||
* 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;
|
||||
static bufref_T qf_last_bufref = {NULL, 0};
|
||||
|
||||
/*
|
||||
* Get buffer number for file "dir.name".
|
||||
@ -1536,9 +1536,9 @@ qf_get_fnum(qf_info_T *qi, char_u *directory, char_u *fname)
|
||||
bufname = fname;
|
||||
|
||||
if (qf_last_bufname != NULL && STRCMP(bufname, qf_last_bufname) == 0
|
||||
&& buf_valid(qf_last_buf))
|
||||
&& bufref_valid(&qf_last_bufref))
|
||||
{
|
||||
buf = qf_last_buf;
|
||||
buf = qf_last_bufref.br_buf;
|
||||
vim_free(ptr);
|
||||
}
|
||||
else
|
||||
@ -1549,7 +1549,7 @@ qf_get_fnum(qf_info_T *qi, char_u *directory, char_u *fname)
|
||||
qf_last_bufname = bufname;
|
||||
else
|
||||
qf_last_bufname = vim_strsave(bufname);
|
||||
qf_last_buf = buf;
|
||||
set_bufref(&qf_last_bufref, buf);
|
||||
}
|
||||
if (buf == NULL)
|
||||
return 0;
|
||||
|
@ -69,6 +69,14 @@ typedef struct frame_S frame_T;
|
||||
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.
|
||||
*/
|
||||
|
@ -758,6 +758,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
2018,
|
||||
/**/
|
||||
2017,
|
||||
/**/
|
||||
|
Loading…
x
Reference in New Issue
Block a user