]> granicus.if.org Git - postgresql/commitdiff
Improve realloc() per idea from Karel Zak --- if chunk to be enlarged is
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 23 Jan 2001 01:01:36 +0000 (01:01 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 23 Jan 2001 01:01:36 +0000 (01:01 +0000)
at end of its block, maybe we can enlarge it in-place.

src/backend/utils/mmgr/aset.c

index 5c0cf3074531a92da0e0afa912e8a14179ef87ce..c78008824b5271f672b1559238aae6ecfbd7612d 100644 (file)
@@ -11,7 +11,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/mmgr/aset.c,v 1.37 2001/01/12 21:54:01 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/mmgr/aset.c,v 1.38 2001/01/23 01:01:36 tgl Exp $
  *
  * NOTE:
  *     This is a new (Feb. 05, 1999) implementation of the allocation set
@@ -879,10 +879,60 @@ AllocSetRealloc(MemoryContext context, void *pointer, Size size)
        }
        else
        {
+               /*
+                * Small-chunk case.  If the chunk is the last one in its block,
+                * there might be enough free space after it that we can just
+                * enlarge the chunk in-place.  It's relatively painful to find
+                * the containing block in the general case, but we can detect
+                * last-ness quite cheaply for the typical case where the chunk
+                * is in the active (topmost) allocation block.  (At least with
+                * the regression tests and code as of 1/2001, realloc'ing the last
+                * chunk of a non-topmost block hardly ever happens, so it's not
+                * worth scanning the block list to catch that case.)
+                *
+                * NOTE: must be careful not to create a chunk of a size that
+                * AllocSetAlloc would not create, else we'll get confused later.
+                */
+               AllocPointer newPointer;
+
+               if (size <= ALLOC_CHUNK_LIMIT)
+               {
+                       AllocBlock      block = set->blocks;
+                       char       *chunk_end;
+
+                       chunk_end = (char *) chunk + (oldsize + ALLOC_CHUNKHDRSZ);
+                       if (chunk_end == block->freeptr)
+                       { 
+                               /* OK, it's last in block ... is there room? */
+                               Size    freespace = block->endptr - block->freeptr;
+                               int             fidx;
+                               Size    newsize;
+                               Size    delta;
+
+                               fidx = AllocSetFreeIndex(size);
+                               newsize = 1 << (fidx + ALLOC_MINBITS);
+                               Assert(newsize >= oldsize);
+                               delta = newsize - oldsize;
+                               if (freespace >= delta)
+                               {
+                                       /* Yes, so just enlarge the chunk. */
+                                       block->freeptr += delta;
+                                       chunk->size += delta;
+#ifdef MEMORY_CONTEXT_CHECKING         
+                                       chunk->requested_size = size;
+                                       /* set mark to catch clobber of "unused" space */
+                                       if (size < chunk->size)
+                                               ((char *) pointer)[size] = 0x7E;
+#endif
+                                       return pointer;
+                               }
+                       }
+               }
+
                /* Normal small-chunk case: just do it by brute force. */
 
                /* allocate new chunk */
-               AllocPointer newPointer = AllocSetAlloc((MemoryContext) set, size);
+               newPointer = AllocSetAlloc((MemoryContext) set, size);
 
                /* transfer existing data (certain to fit) */
                memcpy(newPointer, pointer, oldsize);