Hack.
authorRobert Haas <[email protected]>
Mon, 3 Feb 2014 18:54:38 +0000 (13:54 -0500)
committerRobert Haas <[email protected]>
Thu, 6 Feb 2014 14:23:01 +0000 (09:23 -0500)
src/backend/utils/mmgr/mspan.c

index 6ad8cfcd4fcbfd82df728d46e9559fc6bcba79f2..c84de1b92c03121bec3938a263dae452f1ccf78d 100644 (file)
@@ -617,18 +617,69 @@ mspan_allocate_span(char *base, mspan_manager *mgr, mspan_context *cxt,
        {
                /* Remove the span from the free list. */
                mspan_unlink_span(base, span);
-               mspan_initialize_span(base, mgr, cxt, span, span_type);
 
-               /* XXX. Update page map entries.  */
+               /* Reinitialize span for new usage. */
+               mspan_initialize_span(base, mgr, cxt, span, span_type);
 
+               /* If needed, shrink or split the span. */
                if (span->npages > pages)
                {
-                       /* XXX. Split the span. */
-                       /*
-                        * XXX. Note that if we split a span than abutts the boundary,
-                        * we should instead destroy it and move back the boundary.
-                        */
+                       if (base != NULL &&
+                               span->first_page + span->npages >= mgr->boundary)
+                       {
+                               Size    newboundary;
+                               Size    nreturned;
+
+                               /*
+                                * The span is adjacent to the boundary, so we can just shrink
+                                * it and move the boundary backwards.  But we need to clear
+                                * any page map entries in the region we're returning, to
+                                * prevent confusion down the road.
+                                */
+                               Assert(span->first_page + span->npages == mgr->boundary);
+                               newboundary = span->first_page + pages;
+                               nreturned = mgr->boundary - newboundary;
+                               mspan_update_page_map(base, mgr, newboundary, nreturned, 0);
+                               mgr->boundary = newboundary;
+                               span->npages = pages;
+                       }
+                       else
+                       {
+                               /* 
+                                * XXX. The span isn't adjacent to the boundary.  If there's
+                                * a free span following this one, we can transfer the excess
+                                * pages from this span to that span.  If not, we need to
+                                * allocate a new span to contain the free pages.
+                                */
+                       }
                }
+
+               /*
+                * Make page map entries for the new span.
+                *
+                * If this is anything other than a large allocation, we could
+                * potentially see requests to free objects located anywhere within
+                * the span, so page map entries are needed for every page of the span.
+                * But for a large object, the first and last page are good enough;
+                * we should never get a request to free something in the middle of
+                * such a span, and the only other lookups we expect are for the pages
+                * end pages to check whether this is a free span that can be
+                * consolidated.
+                */
+               Assert(span->npages == pages);
+               if (span_type != MSPAN_TYPE_LARGE)
+                       mspan_update_page_map(base, mgr, span->first_page,
+                                                                 span->npages, (((char *) span) - base) | 1);
+               else
+               {
+                       mspan_update_page_map(base, mgr, span->first_page, 1,
+                                                                 (((char *) span) - base) | 1);
+                       mspan_update_page_map(base, mgr,
+                                                                 span->first_page + span->npages - 1, 1,
+                                                                 (((char *) span) - base) | 1);
+               }
+
+               return span;
        }
 
        /*
@@ -678,7 +729,8 @@ mspan_allocate_span(char *base, mspan_manager *mgr, mspan_context *cxt,
 
        /*
         * If this is a span-of-spans, allocate a descriptor for the new span
-        * out of the span itself.  Otherwise, we
+        * out of the span itself.  If it's not, span shuold already be non-NULL;
+        * see above.
         */
        if (span_type == MSPAN_TYPE_SPAN_OF_SPANS)
        {