Add indirection counting to speed up Fkill_buffer.
authorDmitry Antipov <dmantipov@yandex.ru>
Fri, 20 Jul 2012 16:05:47 +0000 (20:05 +0400)
committerDmitry Antipov <dmantipov@yandex.ru>
Fri, 20 Jul 2012 16:05:47 +0000 (20:05 +0400)
* buffer.h (struct buffer): New member.
* buffer.c (Fget_buffer_create): Set indirection counter to 0.
(Fmake_indirect_buffer): Set indirection counter to -1, increment
base buffer indirection counter.
(compact_buffer): If ENABLE_CHECKING, verify indirection counters.
(Fkill_buffer): Adjust indirection counters as needed, don't walk
through buffer list if indirection counter is 0.

src/ChangeLog
src/buffer.c
src/buffer.h

index d7d02a2..e90e48e 100644 (file)
@@ -1,3 +1,14 @@
+2012-07-20  Dmitry Antipov  <dmantipov@yandex.ru>
+
+       Add indirection counting to speed up Fkill_buffer.
+       * buffer.h (struct buffer): New member.
+       * buffer.c (Fget_buffer_create): Set indirection counter to 0.
+       (Fmake_indirect_buffer): Set indirection counter to -1, increment
+       base buffer indirection counter.
+       (compact_buffer): If ENABLE_CHECKING, verify indirection counters.
+       (Fkill_buffer): Adjust indirection counters as needed, don't walk
+       through buffer list if indirection counter is 0.
+
 2012-07-20  Dmitry Antipov  <dmantipov@yandex.ru>
 
        Extend the value returned by Fgarbage_collect with heap statistics.
index b722ff1..5f9f6a7 100644 (file)
@@ -329,7 +329,9 @@ even if it is dead.  The return value is never nil.  */)
 
   /* An ordinary buffer uses its own struct buffer_text.  */
   b->text = &b->own_text;
-  b->base_buffer = 0;
+  b->base_buffer = NULL;
+  /* No one shares the text with us now.  */
+  b->indirections = 0;
 
   BUF_GAP_SIZE (b) = 20;
   BLOCK_INPUT;
@@ -568,12 +570,18 @@ CLONE nil means the indirect buffer's state is reset to default values.  */)
 
   b = allocate_buffer ();
 
+  /* No double indirection - if base buffer is indirect,
+     new buffer becomes an indirect to base's base.  */
   b->base_buffer = (XBUFFER (base_buffer)->base_buffer
                    ? XBUFFER (base_buffer)->base_buffer
                    : XBUFFER (base_buffer));
 
   /* Use the base buffer's text object.  */
   b->text = b->base_buffer->text;
+  /* We have no own text.  */
+  b->indirections = -1;
+  /* Notify base buffer that we share the text now.  */
+  b->base_buffer->indirections++;
 
   b->pt = b->base_buffer->pt;
   b->begv = b->base_buffer->begv;
@@ -1439,6 +1447,15 @@ No argument or nil as argument means do this for the current buffer.  */)
 int
 compact_buffer (struct buffer *buffer)
 {
+  /* Verify indirection counters.  */
+  if (buffer->base_buffer)
+    {
+      eassert (buffer->indirections == -1);
+      eassert (buffer->base_buffer->indirections > 0);
+    }
+  else
+    eassert (buffer->indirections >= 0);
+
   /* Skip dead buffers, indirect buffers and buffers
      which aren't changed since last compaction.  */
   if (!NILP (buffer->BUFFER_INTERNAL_FIELD (name))
@@ -1555,10 +1572,19 @@ cleaning up all windows currently displaying the buffer to be killed. */)
   if (EQ (buffer, XWINDOW (minibuf_window)->buffer))
     return Qnil;
 
-  /* When we kill a base buffer, kill all its indirect buffers.
+  /* Notify our base buffer that we don't share the text anymore.  */
+  if (b->base_buffer)
+    {
+      eassert (b->indirections == -1);
+      b->base_buffer->indirections--;
+      eassert (b->base_buffer->indirections >= 0);
+    }
+
+  /* When we kill an ordinary buffer which shares it's buffer text
+     with indirect buffer(s), we must kill indirect buffer(s) too.
      We do it at this stage so nothing terrible happens if they
      ask questions or their hooks get errors.  */
-  if (! b->base_buffer)
+  if (!b->base_buffer && b->indirections > 0)
     {
       struct buffer *other;
 
index a97cc13..69be4dc 100644 (file)
@@ -775,6 +775,11 @@ struct buffer
      In an ordinary buffer, it is 0.  */
   struct buffer *base_buffer;
 
+  /* In an indirect buffer, this is -1. In an ordinary buffer,
+     it's the number of indirect buffers which shares our text;
+     zero means that we're the only owner of this text.  */
+  int indirections;
+
   /* A non-zero value in slot IDX means that per-buffer variable
      with index IDX has a local value in this buffer.  The index IDX
      for a buffer-local variable is stored in that variable's slot