Sketch out sb_free.
authorRobert Haas <[email protected]>
Tue, 15 Apr 2014 21:15:37 +0000 (17:15 -0400)
committerRobert Haas <[email protected]>
Tue, 15 Apr 2014 21:15:37 +0000 (17:15 -0400)
src/backend/utils/mmgr/sb_alloc.c

index 38b92762d4880cec30b38db74ef30b2ed3bc9384..acd1c05486535ca0ce24f77d9c76ca1bc261ff45 100644 (file)
@@ -47,11 +47,14 @@ struct sb_span
        Size            npages;                 /* Length of span in pages. */
        uint16          size_class;             /* Size class. */
        uint16          ninitialized;   /* Maximum number of objects ever allocated. */
-       uint16          nallocatable;   /* Number of objects currently allocated. */
+       uint16          nallocatable;   /* Number of objects currently allocatable. */
        uint16          firstfree;              /* First object on free list. */
+       uint16          nmax;                   /* Maximum number of objects ever possible. */
+       uint16          fclass;                 /* Current fullness class. */
 };
 
 #define SB_SPAN_NOTHING_FREE           ((uint16) -1)
+#define SB_SUPERBLOCK_SIZE                     (SB_PAGES_PER_SUPERBLOCK * FPM_PAGE_SIZE)
 
 /*
  * Small allocations are handled by dividing a relatively large chunk of
@@ -267,6 +270,94 @@ sb_alloc(sb_allocator *a, Size size, int flags)
        return result;          
 }
 
+/*
+ * Free memory allocated via sb_alloc.
+ */
+void
+sb_free(void *ptr)
+{
+       sb_region *region;
+       char   *fpm_base;
+       char   *base = NULL;
+       sb_span *span;
+       LWLock *lock = NULL;
+       char   *superblock;
+       Size    pageno;
+       Size    obsize;
+
+       /* Locate the containing superblock. */
+       region = sb_lookup_region(ptr);
+       fpm_base = fpm_segment_base(region->fpm);
+       pageno = fpm_pointer_to_page(fpm_base, ptr);
+       span = sb_map_get(region->pagemap, pageno);
+
+       /*
+        * If this is a shared-memory region, we might need locking.  If so,
+        * lock the heap.
+        */
+       if (region->seg != NULL)
+       {
+               sb_heap *heap = relptr_access(fpm_base, span->parent);
+               base = fpm_base;
+               lock = relptr_access(fpm_base, heap->lock);
+               if (lock != NULL)
+                       LWLockAcquire(lock, LW_EXCLUSIVE);
+       }
+
+       /* Put the object on the superblock's freelist. */
+       superblock = relptr_access(base, span->start);
+       obsize = sb_size_classes[span->size_class];
+       Assert(((char *) ptr) >= superblock);
+       Assert(((char *) ptr) < superblock + SB_SUPERBLOCK_SIZE);
+       Assert((((char *) ptr) - superblock) % obsize == 0);
+       * (Size *) ptr = span->firstfree;
+       span->firstfree = (((char *) ptr) - superblock) / obsize;
+       span->nallocatable++;
+
+       /*
+        * If the superblock was previously completely full, we need to move it
+        * out of the highest-numbered fullness class so that it can potentially
+        * be used for new allocations.
+        */
+       if (span->nallocatable == 1 && span->fclass == SB_FULLNESS_CLASSES - 1)
+       {
+               sb_heap *heap = relptr_access(fpm_base, span->parent);
+               sb_span *nextspan = relptr_access(base, span->nextspan);
+               sb_span *prevspan = relptr_access(base, span->prevspan);
+               sb_span *new_nextspan;
+
+               /* Remove from current list. */
+               relptr_store(base, span->prevspan, (sb_span *) NULL);
+               if (nextspan != NULL)
+                       relptr_copy(nextspan->prevspan, span->prevspan);
+               if (prevspan != NULL)
+                       relptr_copy(prevspan->nextspan, span->nextspan);
+               else
+                       relptr_copy(heap->spans[span->fclass], span->nextspan);
+
+               /* Add to correct list. */
+               span->fclass = SB_FULLNESS_CLASSES - 2;
+               relptr_copy(span->nextspan, heap->spans[SB_FULLNESS_CLASSES - 2]);
+               relptr_store(base, span->prevspan, (sb_span *) NULL);
+               new_nextspan = relptr_access(base,
+                                                                        heap->spans[SB_FULLNESS_CLASSES - 2]);
+               relptr_store(base, new_nextspan->prevspan, span);
+               relptr_copy(heap->spans[SB_FULLNESS_CLASSES - 2],
+                                       new_nextspan->prevspan);
+       }
+       else if (span->nallocatable == span->nmax)
+       {
+               /*
+                * XXX. Deallocate the span; and if that causes the span of spans
+                * to need deallocation, do that, too.
+                */
+       }
+
+       /* If we locked the heap, release the lock. */
+       if (lock != NULL)
+               LWLockRelease(lock);
+}
+
 /*
  * Free all memory used by an allocator.
  *
@@ -431,7 +522,7 @@ sb_ensure_active_superblock(char *base, sb_region *region, sb_allocator *a,
        if (size_class == SB_SCLASS_SPAN_OF_SPANS)
                nmax = FPM_PAGE_SIZE / obsize;
        else
-               nmax = (FPM_PAGE_SIZE * SB_PAGES_PER_SUPERBLOCK) / obsize;
+               nmax = SB_SUPERBLOCK_SIZE / obsize;
 
        /*
         * If fullness class 1 is empty, try to find something to put in it by
@@ -472,6 +563,7 @@ sb_ensure_active_superblock(char *base, sb_region *region, sb_allocator *a,
                                        relptr_copy(prevspan->nextspan, span->nextspan);
                                else
                                        relptr_copy(heap->spans[fclass], span->nextspan);
+                               span->fclass = tfclass;
                        }
 
                        /* Advance to next span on list. */
@@ -576,8 +668,10 @@ sb_init_span(char *base, sb_span *span, sb_heap *heap, char *ptr,
        if (size_class == SB_SCLASS_SPAN_OF_SPANS)
                span->nallocatable = FPM_PAGE_SIZE / obsize;
        else if (size_class != SB_SCLASS_SPAN_LARGE)
-               span->nallocatable = (FPM_PAGE_SIZE * SB_PAGES_PER_SUPERBLOCK) / obsize;
+               span->nallocatable = SB_SUPERBLOCK_SIZE / obsize;
        span->firstfree = SB_SPAN_NOTHING_FREE;
+       span->nmax = span->nallocatable;
+       span->fclass = 1;
 }
 
 /*
@@ -623,6 +717,7 @@ sb_transfer_first_span(char *base, sb_heap *heap, int fromclass, int toclass)
        nextspan = relptr_access(base, span->nextspan);
        if (nextspan != NULL)
                relptr_store(base, nextspan->prevspan, span);
+       span->fclass = toclass;
 
        return true;
 }