Обсуждение: Call EndCopyFrom() after initial table sync in logical replication

Поиск
Список
Период
Сортировка

Call EndCopyFrom() after initial table sync in logical replication

От
Shinya Kato
Дата:
Hi hackers,

While reading the logical replication initial table sync code, I
noticed that copy_table() calls BeginCopyFrom() and CopyFrom() but
never calls the matching EndCopyFrom().

EndCopyFrom() calls pgstat_progress_end_command(), which resets
st_progress_command to PROGRESS_COMMAND_INVALID. Without that call,
the backend status entry continues to report an active COPY operation
while the tablesync worker proceeds to WAL catchup. As a result,
pg_stat_progress_copy shows a stale entry for the entire WAL catchup
phase.

Attached patch adds EndCopyFrom(cstate) immediately after
CopyFrom(cstate) returns.

--
Best regards,
Shinya Kato
NTT OSS Center

Вложения

Re: Call EndCopyFrom() after initial table sync in logical replication

От
Fujii Masao
Дата:
On Mon, May 4, 2026 at 4:58 PM Shinya Kato <shinya11.kato@gmail.com> wrote:
>
> Hi hackers,
>
> While reading the logical replication initial table sync code, I
> noticed that copy_table() calls BeginCopyFrom() and CopyFrom() but
> never calls the matching EndCopyFrom().
>
> EndCopyFrom() calls pgstat_progress_end_command(), which resets
> st_progress_command to PROGRESS_COMMAND_INVALID. Without that call,
> the backend status entry continues to report an active COPY operation
> while the tablesync worker proceeds to WAL catchup. As a result,
> pg_stat_progress_copy shows a stale entry for the entire WAL catchup
> phase.
>
> Attached patch adds EndCopyFrom(cstate) immediately after
> CopyFrom(cstate) returns.

Thanks for the patch! It looks good to me.
Barring any objections, I will commit the patch.

Regards,

--
Fujii Masao



Re: Call EndCopyFrom() after initial table sync in logical replication

От
"cca5507"
Дата:
Hi,

Maybe we want to add "free_parsestate(pstate);" after the "EndCopyFrom()" as well?

--
Regards,
ChangAo Chen


> On May 8, 2026, at 10:34, cca5507 <cca5507@qq.com> wrote:
>
> Hi,
>
> Maybe we want to add "free_parsestate(pstate);" after the "EndCopyFrom()" as well?
>

I agree. While here, looks like attnamelist can also be freed.

Best regards,
--
Chao Li (Evan)
HighGo Software Co., Ltd.
https://www.highgo.com/







Re: Call EndCopyFrom() after initial table sync in logical replication

От
Fujii Masao
Дата:
On Fri, May 8, 2026 at 11:34 AM cca5507 <cca5507@qq.com> wrote:
>
> Hi,
>
> Maybe we want to add "free_parsestate(pstate);" after the "EndCopyFrom()" as well?

What actual issue could occur if free_parsestate() is not called there?

Since pstate->p_target_relation does not seem to be used afterward,
omitting free_parsestate() appears mostly harmless to me. Bascailly
calling free_parsestate() after make_parsestate() seems intuitive,
but from a quick grep I found several places that call make_parsestate()
without a corresponding free_parsestate().

Regards,

--
Fujii Masao



Re: Call EndCopyFrom() after initial table sync in logical replication

От
"cca5507"
Дата:
> > Maybe we want to add "free_parsestate(pstate);" after the "EndCopyFrom()" as well?
>
> What actual issue could occur if free_parsestate() is not called there?
>
> Since pstate->p_target_relation does not seem to be used afterward,
> omitting free_parsestate() appears mostly harmless to me. Bascailly
> calling free_parsestate() after make_parsestate() seems intuitive,
> but from a quick grep I found several places that call make_parsestate()
> without a corresponding free_parsestate().

Yeah, I agree that it's harmless. I just noticed the comment above make_parsestate():

    Caller should eventually release the ParseState via free_parsestate().

Not sure whether it's worth to fix all of these places.

--
Regards,
ChangAo Chen


> On May 8, 2026, at 12:21, Fujii Masao <masao.fujii@gmail.com> wrote:
>
> On Fri, May 8, 2026 at 11:34 AM cca5507 <cca5507@qq.com> wrote:
>>
>> Hi,
>>
>> Maybe we want to add "free_parsestate(pstate);" after the "EndCopyFrom()" as well?
>
> What actual issue could occur if free_parsestate() is not called there?
>
> Since pstate->p_target_relation does not seem to be used afterward,
> omitting free_parsestate() appears mostly harmless to me. Bascailly
> calling free_parsestate() after make_parsestate() seems intuitive,
> but from a quick grep I found several places that call make_parsestate()
> without a corresponding free_parsestate().
>
> Regards,
>
> --
> Fujii Masao

I don’t think this is a serious leak. In this path, pstate and attnamelist are allocated in CurTransactionContext, and
thetransaction is committed immediately after copy_table() finishes, so that memory is reclaimed at transaction end.
Explicitlyfreeing them would be mostly for code readability, not to fix a memory leak. So, I am okay to not free them. 

While tracing the code, I noticed another issue that is probably more worth addressing. copy_table() currently does:
```
    copybuf = makeStringInfo();
```

But copybuf is only used by copy_read_data(), and there it's really just acting as a small state holder for data, len,
andcursor, rather than as a normal growable StringInfo. That means we do not need to allocate a StringInfo object or
itsbacking buffer at all. 

It would be cleaner to use a plain StringInfoData and simply reinitialize or zero it in copy_table(). See the attached
difffor the proposed change. 

David Rowley has made several cleanup changes in this area to prefer stack-allocated StringInfoData, for example
a63bbc811d41b3567eb37fe2636e660a852dbbf2.This change seems consistent with that direction. 

Best regards,
--
Chao Li (Evan)
HighGo Software Co., Ltd.
https://www.highgo.com/





Вложения