Thread

  1. Re: eliminate xl_heap_visible to reduce WAL (and eventually set VM on-access)

    Peter Eisentraut <peter@eisentraut.org> — 2025-12-16T12:18:25Z

    On 15.12.25 22:05, Melanie Plageman wrote:
    > On Sat, Dec 13, 2025 at 8:59 AM Peter Eisentraut <peter@eisentraut.org> wrote:
    >>
    >> On 20.11.25 18:19, Melanie Plageman wrote:
    >>> +     prstate->deadoffsets = (OffsetNumber *) presult->deadoffsets;
    >>
    >> In your patch
    >> v22-0001-Split-heap_page_prune_and_freeze-into-helpers.patch, the
    >> assignment above casts away the const qualification of the function
    >> argument presult:
    > 
    > Yea, this code (prune_freeze_setup() with a const-qualified
    > PruneFreezeResult parameter) is actually already in master -- not just
    > in this patchset.
    > 
    >> +static void
    >> +prune_freeze_setup(PruneFreezeParams *params,
    >> +                                  TransactionId new_relfrozen_xid,
    >> +                                  MultiXactId new_relmin_mxid,
    >> +                                  const PruneFreezeResult *presult,
    >> +                                  PruneState *prstate)
    >>
    >> (The cast is otherwise unnecessary, since the underlying type is the
    >> same on both sides.)
    >>
    >> Since prstate->deadoffsets is in fact later modified, this makes the
    >> original const qualification invalid.
    > 
    > I didn't realize I was misusing const here. What I meant to indicate
    > by defining the prune_freeze_setup() parameter, as const, is that the
    > PruneFreezeResult wouldn't be modified by prune_freeze_setup(). I did
    > not mean to indicate that no members of PruneFreezeResult would ever
    > be modified.
    
    I'm not sure there is a difference between these two statements.  The 
    struct won't be modified is the same as none of its fields will be modified.
    
    > deadoffsets is not modified in prune_freeze_setup(). So,
    > are you saying that I can't define a parameter as const if even the
    > caller modifies it?
    
    You are not modifying deadoffsets in prune_freeze_setup(), but you are 
    assigning its address to a pointer variable that is not const-qualified, 
    and so it could be used to modify it later on.
    
    A caller to prune_freeze_setup() that sees the signature const 
    PruneFreezeResult *presult could pass a pointer to a PruneFreezeResult 
    object that is notionally in read-only memory.  But through the 
    non-const-qualified pointer you could later modify the pointed-to 
    memory, which would be invalid.  The point of propagating the qualifiers 
    is to prevent that at compile time.
    
    If what you want is something like, "prune_freeze_setup() does not 
    change any of the fields of what presult points to, but it does record a 
    pointer to one of its fields with the intention of modifying it later 
    after prune_freeze_setup() is finished", then I think C cannot represent 
    that with this API.
    
    Here is a simplified example:
    
    #include <stdlib.h>
    
    // corresponds to PruneFreezeResult
    struct foo
    {
    	int offsets[5];
    };
    
    // corresponds to PruneState
    struct bar
    {
    	int *offsets;
    };
    
    static void setup(const struct foo *f)
    {
    	struct bar *b = malloc(sizeof(struct bar));
    
    	b->offsets = f->offsets;  // warning
    }
    
    This produces a warning:
    
    test.c:20:20: warning: assignment discards 'const' qualifier from 
    pointer target type
    
    The reason is that what "f" points to is const, which means that all its 
    fields are const.  The fix is to remove the const from the function 
    argument declaration.
    
    One of the possible sources of confusion here is that one struct uses an 
    array and the other a pointer, and these sometimes behave similarly and 
    sometimes not.