Additional replication slots#434
Conversation
sgotti
left a comment
There was a problem hiding this comment.
@saranhada Thanks for the PR. First review pass.
| if s.InitMode == nil { | ||
| return fmt.Errorf("initMode undefined") | ||
| } | ||
| if len(s.AdditionalReplicationSlotNames) > 0 { |
There was a problem hiding this comment.
no need to check the length > 0. The range will just take care of it.
| 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.
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
| if s.InitMode == nil { | ||
| return fmt.Errorf("initMode undefined") | ||
| } | ||
| if len(s.AdditionalReplicationSlotNames) > 0 { |
There was a problem hiding this comment.
please put this in its own function so we can add unit tests.
| // addition to the ones internally defined by stolon | ||
| AdditionalWalSenders uint16 `json:"additionalWalSenders"` | ||
| AdditionalWalSenders uint16 `json:"additionalWalSenders"` | ||
| AdditionalReplicationSlotNames []string `json:"additionalReplicationSlotNames"` |
| } | ||
|
|
||
| // drop unnecessary slots | ||
| if len(slotsToDrop) > 0 { |
There was a problem hiding this comment.
no need to check the length > 0. The range will just take care of it.
| // create required slots | ||
| if len(slotsToCreate) > 0 { | ||
| for _, createSlotName := range slotsToCreate { | ||
| log.Infow("Create slot", "createSlotName", createSlotName) |
There was a problem hiding this comment.
log.Infow("creating replication slot", "createSlotName", createSlotName)
| if !slotShouldSurvive { // slot not detected as additional, so schedule the removal | ||
| slotsToDrop = append(slotsToDrop, removeCandidateSlot) | ||
| } | ||
| } |
There was a problem hiding this comment.
This could be simplified in (not tested):
for _, rs := range notStolonSlots {
if !util.StringInSlice(addonSlotNames, replSlot) {
slotsToDrop = append(slotsToDrop, rs)
}
}
| if !slotExists { | ||
| slotsToCreate = append(slotsToCreate, strings.TrimSpace(addReplicationSlotName)) | ||
| } | ||
| } |
There was a problem hiding this comment.
This could be simplified in (not tested):
for _, rs := range addonSlotNames {
if !util.StringInSlice(notStolonSlots, replSlot) {
slotsToCreate = append(slotsToCreate, rs)
}
}
| db.Spec.FollowConfig.StandbySettings = clusterSpec.StandbySettings | ||
| } | ||
| db.Spec.AdditionalWalSenders = *clusterSpec.AdditionalWalSenders | ||
| db.Spec.AdditionalReplicationSlotNames = clusterSpec.AdditionalReplicationSlotNames |
There was a problem hiding this comment.
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.
| | 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.
a list of additional replication slots to be created on the master postgres instance. Replication slots not defined here will be dropped.
| return nil | ||
| } | ||
|
|
||
| func (p *PostgresKeeper) recreateAddonReplicationSlots(existingReplicationSlots []string, addonSlotNames []string) error { |
There was a problem hiding this comment.
s/recreateAddonReplicationSlots/updateAdditionalReplSlots/
| 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.
ignore dropping errors like done in updateReplSlot since they can be in use and this will fail.
|
|
||
| // create required slots | ||
| for _, createSlotName := range slotsToCreate { | ||
| log.Infow("Creatint replication slot", "createSlotName", createSlotName) |
There was a problem hiding this comment.
log.Infow("creating replication slot", "slotName", createSlotName)
|
|
||
| // drop unnecessary slots | ||
| for _, dropSlotName := range slotsToDrop { | ||
| log.Infow("Dropping replication slot", "dropSlotName", dropSlotName) |
There was a problem hiding this comment.
Don't use capital letters in logs.
sgotti
left a comment
There was a problem hiding this comment.
There were some unhandled comments from previous review, readded them.
| 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.
Don't use capital letters in logs.
|
|
||
| // drop unnecessary slots | ||
| for _, dropSlotName := range slotsToDrop { | ||
| log.Infow("Dropping replication slot", "dropSlotName", dropSlotName) |
There was a problem hiding this comment.
log.Infow("dropping replication slot", "slotName", dropSlotName)
| 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.
you should call updateAdditionalReplSlots also here
| // addition to the ones internally defined by stolon | ||
| AdditionalWalSenders *uint16 `json:"additionalWalSenders"` | ||
| AdditionalWalSenders *uint16 `json:"additionalWalSenders"` | ||
| AdditionalReplicationSlotNames []string `json:"additionalReplicationSlotNames"` |
| return nil | ||
| } | ||
|
|
||
| rp := regexp.MustCompile("[_0-9a-z]+") |
There was a problem hiding this comment.
put it in a global var like done here: https://github.com/sorintlab/stolon/blob/master/pkg/postgresql/utils.go#L39
|
|
||
| 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.
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