Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 57 additions & 3 deletions src/bin/common/pgsql.c
Original file line number Diff line number Diff line change
Expand Up @@ -3190,8 +3190,62 @@ parseTimeLineHistory(const char *filename, const char *content,

system->timelines.count = 0;

TimeLineHistoryEntry *entry =
&(system->timelines.history[system->timelines.count]);
/*
* Ensure the history buffer exists and has room for at least lineCount + 1
* entries (all parsed lines plus the tip entry written after the loop).
* We reuse the buffer across calls; realloc only when capacity is tight.
*/
int needed = lineCount + 1;

if (system->timelines.history == NULL)
{
int cap = PG_AUTOCTL_TIMELINES_INITIAL_CAPACITY;

while (cap < needed)
{
cap *= 2;
}

system->timelines.history =
(TimeLineHistoryEntry *) calloc(cap, sizeof(TimeLineHistoryEntry));

if (system->timelines.history == NULL)
{
log_error(ALLOCATION_FAILED_ERROR);
free(historyLines);
return false;
}

system->timelines.capacity = cap;
}
else if (system->timelines.capacity < needed)
{
int cap = system->timelines.capacity;

while (cap < needed)
{
cap *= 2;
}

TimeLineHistoryEntry *newHistory =
(TimeLineHistoryEntry *) realloc(system->timelines.history,
cap * sizeof(TimeLineHistoryEntry));

if (newHistory == NULL)
{
log_error(ALLOCATION_FAILED_ERROR);
free(historyLines);
return false;
}

memset(newHistory + system->timelines.capacity,
0,
(cap - system->timelines.capacity) * sizeof(TimeLineHistoryEntry));
system->timelines.history = newHistory;
system->timelines.capacity = cap;
}

TimeLineHistoryEntry *entry = &(system->timelines.history[0]);

for (lineNumber = 0; lineNumber < lineCount; lineNumber++)
{
Expand Down Expand Up @@ -3271,7 +3325,7 @@ parseTimeLineHistory(const char *filename, const char *content,

/*
* Create one more entry for the "tip" of the timeline, which has no entry
* in the history file.
* in the history file. Capacity was pre-checked above to include this slot.
*/
entry->tli = system->timeline;
entry->begin = prevend;
Expand Down
13 changes: 11 additions & 2 deletions src/bin/common/pgsql.h
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ typedef struct NodeAddressArray
#define InvalidXLogRecPtr 0
#define XLogRecPtrIsInvalid(r) ((r) == InvalidXLogRecPtr)

#define PG_AUTOCTL_MAX_TIMELINES 1024
#define PG_AUTOCTL_TIMELINES_INITIAL_CAPACITY 16

typedef struct TimeLineHistoryEntry
{
Expand All @@ -203,10 +203,19 @@ typedef struct TimeLineHistoryEntry
} TimeLineHistoryEntry;


/*
* TimeLineHistory holds a dynamically-allocated array of timeline history
* entries. The history pointer starts as NULL and is allocated on first use
* inside parseTimeLineHistory(); subsequent calls reuse the same buffer,
* growing it with realloc() when needed. No explicit free is required because
* this struct is embedded in long-lived per-process structs (LocalPostgresServer
* → ReplicationSource → IdentifySystem) that live for the process lifetime.
*/
typedef struct TimeLineHistory
{
int count;
TimeLineHistoryEntry history[PG_AUTOCTL_MAX_TIMELINES];
int capacity;
TimeLineHistoryEntry *history;
} TimeLineHistory;


Expand Down