-
Notifications
You must be signed in to change notification settings - Fork 446
Additional replication slots #434
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@saranhada Thanks for the PR. First review pass.
pkg/cluster/cluster.go
Outdated
@@ -397,6 +399,23 @@ func (os *ClusterSpec) Validate() error { | |||
if s.InitMode == nil { | |||
return fmt.Errorf("initMode undefined") | |||
} | |||
if len(s.AdditionalReplicationSlotNames) > 0 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no need to check the length > 0. The range will just take care of it.
pkg/cluster/cluster.go
Outdated
symbolsNameFilter := regexp.MustCompile("[_0-9]") | ||
|
||
for _, replSlotName := range s.AdditionalReplicationSlotNames { | ||
if trimmedSlotName := strings.TrimSpace(replSlotName); len(trimmedSlotName) == 0 || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can simplify it:
- Check using using
IsValidReplSlotName
: https://github.com/sorintlab/stolon/blob/master/pkg/postgresql/utils.go#L328 ? - Check that the replslotname isn't a reserved stolon name using
IsStolonName
: https://github.com/sorintlab/stolon/blob/master/common/common.go#L65
pkg/cluster/cluster.go
Outdated
@@ -397,6 +399,23 @@ func (os *ClusterSpec) Validate() error { | |||
if s.InitMode == nil { | |||
return fmt.Errorf("initMode undefined") | |||
} | |||
if len(s.AdditionalReplicationSlotNames) > 0 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please put this in its own function so we can add unit tests.
pkg/cluster/cluster.go
Outdated
@@ -529,7 +548,8 @@ type DBSpec struct { | |||
UsePgrewind bool `json:"usePgrewind,omitempty"` | |||
// AdditionalWalSenders defines the number of additional wal_senders in | |||
// addition to the ones internally defined by stolon | |||
AdditionalWalSenders uint16 `json:"additionalWalSenders"` | |||
AdditionalWalSenders uint16 `json:"additionalWalSenders"` | |||
AdditionalReplicationSlotNames []string `json:"additionalReplicationSlotNames"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing comment
cmd/keeper/keeper.go
Outdated
} | ||
|
||
// drop unnecessary slots | ||
if len(slotsToDrop) > 0 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no need to check the length > 0. The range will just take care of it.
cmd/keeper/keeper.go
Outdated
// create required slots | ||
if len(slotsToCreate) > 0 { | ||
for _, createSlotName := range slotsToCreate { | ||
log.Infow("Create slot", "createSlotName", createSlotName) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
log.Infow("creating replication slot", "createSlotName", createSlotName)
cmd/keeper/keeper.go
Outdated
if !slotShouldSurvive { // slot not detected as additional, so schedule the removal | ||
slotsToDrop = append(slotsToDrop, removeCandidateSlot) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could be simplified in (not tested):
for _, rs := range notStolonSlots {
if !util.StringInSlice(addonSlotNames, replSlot) {
slotsToDrop = append(slotsToDrop, rs)
}
}
cmd/keeper/keeper.go
Outdated
if !slotExists { | ||
slotsToCreate = append(slotsToCreate, strings.TrimSpace(addReplicationSlotName)) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could be simplified in (not tested):
for _, rs := range addonSlotNames {
if !util.StringInSlice(notStolonSlots, replSlot) {
slotsToCreate = append(slotsToCreate, rs)
}
}
cmd/sentinel/sentinel.go
Outdated
@@ -400,6 +400,7 @@ func (s *Sentinel) setDBSpecFromClusterSpec(cd *cluster.ClusterData) { | |||
db.Spec.FollowConfig.StandbySettings = clusterSpec.StandbySettings | |||
} | |||
db.Spec.AdditionalWalSenders = *clusterSpec.AdditionalWalSenders | |||
db.Spec.AdditionalReplicationSlotNames = clusterSpec.AdditionalReplicationSlotNames |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't needed and misleading since it's adding this to all the clusterdata dbs.
Since the replication slots are created only on the master instance (primary postgres instance or master postgres standby instance in a Standby stolon cluster) the keeper could just read the clusterspec.
doc/cluster_spec.md
Outdated
@@ -25,6 +25,7 @@ Some options in a running cluster specification can be changed to update the des | |||
| minSynchronousStandbys | minimum number of required synchronous standbys when synchronous replication is enabled (only set this to a value > 1 when using PostgreSQL >= 9.6) | no | uint16 | 1 | | |||
| maxSynchronousStandbys | maximum number of required synchronous standbys when synchronous replication is enabled (only set this to a value > 1 when using PostgreSQL >= 9.6) | no | uint16 | 1 | | |||
| additionalWalSenders | number of additional wal_senders in addition to the ones internally defined by stolon, useful to provide enough wal senders for external standbys (changing this value requires an instance restart) | no | uint16 | 5 | | |||
| additionalReplicationSlotNames | a list of additional replication slots which are always created by the master postgres instance | no | []string | null | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a list of additional replication slots to be created on the master postgres instance. Replication slots not defined here will be dropped.
cmd/keeper/keeper.go
Outdated
@@ -842,6 +835,53 @@ func (p *PostgresKeeper) updateReplSlots(dbLocalState *DBLocalState, followersUI | |||
return nil | |||
} | |||
|
|||
func (p *PostgresKeeper) recreateAddonReplicationSlots(existingReplicationSlots []string, addonSlotNames []string) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/recreateAddonReplicationSlots/updateAdditionalReplSlots/
cmd/keeper/keeper.go
Outdated
log.Infow("Dropping replication slot", "dropSlotName", dropSlotName) | ||
if err := p.pgm.DropReplicationSlot(dropSlotName); err != nil { | ||
log.Errorw("Failed to drop replication slot", "slotName", dropSlotName, zap.Error(err)) | ||
return err |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ignore dropping errors like done in updateReplSlot since they can be in use and this will fail.
cmd/keeper/keeper.go
Outdated
|
||
// create required slots | ||
for _, createSlotName := range slotsToCreate { | ||
log.Infow("Creatint replication slot", "createSlotName", createSlotName) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
log.Infow("creating replication slot", "slotName", createSlotName)
cmd/keeper/keeper.go
Outdated
|
||
// drop unnecessary slots | ||
for _, dropSlotName := range slotsToDrop { | ||
log.Infow("Dropping replication slot", "dropSlotName", dropSlotName) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't use capital letters in logs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There were some unhandled comments from previous review, readded them.
cmd/keeper/keeper.go
Outdated
for _, createSlotName := range slotsToCreate { | ||
log.Infow("Creatint replication slot", "createSlotName", createSlotName) | ||
if err := p.pgm.CreateReplicationSlot(createSlotName); err != nil { | ||
log.Errorw("Failed to create replication slot", "slotName", createSlotName, zap.Error(err)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't use capital letters in logs.
cmd/keeper/keeper.go
Outdated
|
||
// drop unnecessary slots | ||
for _, dropSlotName := range slotsToDrop { | ||
log.Infow("Dropping replication slot", "dropSlotName", dropSlotName) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
log.Infow("dropping replication slot", "slotName", dropSlotName)
cmd/keeper/keeper.go
Outdated
return | ||
} | ||
|
||
if err = p.updateReplSlots(currentReplicationSlots, dbls, followersUIDs); err != nil { | ||
log.Errorw("error updating replication slots", zap.Error(err)) | ||
return | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you should call updateAdditionalReplSlots
also here
pkg/cluster/cluster.go
Outdated
@@ -224,7 +225,8 @@ type ClusterSpec struct { | |||
MaxSynchronousStandbys *uint16 `json:"maxSynchronousStandbys,omitempty"` | |||
// AdditionalWalSenders defines the number of additional wal_senders in | |||
// addition to the ones internally defined by stolon | |||
AdditionalWalSenders *uint16 `json:"additionalWalSenders"` | |||
AdditionalWalSenders *uint16 `json:"additionalWalSenders"` | |||
AdditionalReplicationSlotNames []string `json:"additionalReplicationSlotNames"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing comment
pkg/cluster/cluster.go
Outdated
return nil | ||
} | ||
|
||
rp := regexp.MustCompile("[_0-9a-z]+") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
put it in a global var like done here: https://github.com/sorintlab/stolon/blob/master/pkg/postgresql/utils.go#L39
pkg/cluster/cluster.go
Outdated
|
||
for _, replSlotName := range s.AdditionalReplicationSlotNames { | ||
if trimmedSlotName := strings.TrimSpace(replSlotName); len(trimmedSlotName) == 0 || | ||
len(rp.ReplaceAllString(trimmedSlotName, "")) > 0 || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isn't utils.IsValidReplSlotName(replSlotName)
enough? I don't see the need to trim space, \n etc... it should already be catched by it. If it's not enough then utils.IsValidReplSlotName should be fixed since the required check belong there.
I don't see the check for IsStolonName to error on repl slots starting with _stolon
see my previous review comment: this function should just call two functions: #434 (comment)
An unit test is needed to prove that all works correctly.
@saranhada to be speed up things, since I noticed some of my comments weren't addresses as I expected I changed your commit to fix it:
You can see and take the commit here: 00007b2 |
@saranhada I also added integration test to verify that all is working as expected. Please take a look and take the commit here: sgotti@c3ab6ea |
* Add a cluster spec option `additionalMasterReplicationSlots` to let the user define additional custom replication slots on the stolon master instance. All the replication slots not defined here (i.e manually created) will be removed. So user should rely on this option when they need to create new replication slots. * Ignore temporary replication slots (PostgreSQL >= 10). * Add unit tests and integration tests.
@saranhada Thanks! Merging. |
@sgotti please review the pull request. If it is ok then let me create auto tests. This PR is the continuance of PR #410 started from the scratch