Skip to content

Additional replication slots#434

Merged
sgotti merged 1 commit into
masterfrom
unknown repository
Feb 23, 2018
Merged

Additional replication slots#434
sgotti merged 1 commit into
masterfrom
unknown repository

Conversation

@ghost

@ghost ghost commented Feb 8, 2018

Copy link
Copy Markdown

@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

@sgotti sgotti left a comment

Copy link
Copy Markdown
Member

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.

Comment thread pkg/cluster/cluster.go Outdated
if s.InitMode == nil {
return fmt.Errorf("initMode undefined")
}
if len(s.AdditionalReplicationSlotNames) > 0 {

Copy link
Copy Markdown
Member

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.

Comment thread pkg/cluster/cluster.go Outdated
symbolsNameFilter := regexp.MustCompile("[_0-9]")

for _, replSlotName := range s.AdditionalReplicationSlotNames {
if trimmedSlotName := strings.TrimSpace(replSlotName); len(trimmedSlotName) == 0 ||

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread pkg/cluster/cluster.go Outdated
if s.InitMode == nil {
return fmt.Errorf("initMode undefined")
}
if len(s.AdditionalReplicationSlotNames) > 0 {

Copy link
Copy Markdown
Member

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.

Comment thread pkg/cluster/cluster.go Outdated
// addition to the ones internally defined by stolon
AdditionalWalSenders uint16 `json:"additionalWalSenders"`
AdditionalWalSenders uint16 `json:"additionalWalSenders"`
AdditionalReplicationSlotNames []string `json:"additionalReplicationSlotNames"`

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing comment

Comment thread cmd/keeper/keeper.go Outdated
}

// drop unnecessary slots
if len(slotsToDrop) > 0 {

Copy link
Copy Markdown
Member

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.

Comment thread cmd/keeper/keeper.go Outdated
// create required slots
if len(slotsToCreate) > 0 {
for _, createSlotName := range slotsToCreate {
log.Infow("Create slot", "createSlotName", createSlotName)

Copy link
Copy Markdown
Member

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)

Comment thread cmd/keeper/keeper.go Outdated
if !slotShouldSurvive { // slot not detected as additional, so schedule the removal
slotsToDrop = append(slotsToDrop, removeCandidateSlot)
}
}

Copy link
Copy Markdown
Member

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)
	}
}

Comment thread cmd/keeper/keeper.go
if !slotExists {
slotsToCreate = append(slotsToCreate, strings.TrimSpace(addReplicationSlotName))
}
}

Copy link
Copy Markdown
Member

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)
	}
}

Comment thread cmd/sentinel/sentinel.go Outdated
db.Spec.FollowConfig.StandbySettings = clusterSpec.StandbySettings
}
db.Spec.AdditionalWalSenders = *clusterSpec.AdditionalWalSenders
db.Spec.AdditionalReplicationSlotNames = clusterSpec.AdditionalReplicationSlotNames

Copy link
Copy Markdown
Member

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.

Comment thread doc/cluster_spec.md Outdated
| 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 |

Copy link
Copy Markdown
Member

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.

Comment thread cmd/keeper/keeper.go Outdated
return nil
}

func (p *PostgresKeeper) recreateAddonReplicationSlots(existingReplicationSlots []string, addonSlotNames []string) error {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/recreateAddonReplicationSlots/updateAdditionalReplSlots/

Comment thread 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

Copy link
Copy Markdown
Member

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.

Comment thread cmd/keeper/keeper.go Outdated

// create required slots
for _, createSlotName := range slotsToCreate {
log.Infow("Creatint replication slot", "createSlotName", createSlotName)

Copy link
Copy Markdown
Member

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)

Comment thread cmd/keeper/keeper.go Outdated

// drop unnecessary slots
for _, dropSlotName := range slotsToDrop {
log.Infow("Dropping replication slot", "dropSlotName", dropSlotName)

Copy link
Copy Markdown
Member

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.

@sgotti sgotti left a comment

Copy link
Copy Markdown
Member

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.

Comment thread 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))

Copy link
Copy Markdown
Member

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.

Comment thread cmd/keeper/keeper.go Outdated

// drop unnecessary slots
for _, dropSlotName := range slotsToDrop {
log.Infow("Dropping replication slot", "dropSlotName", dropSlotName)

Copy link
Copy Markdown
Member

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)

Comment thread cmd/keeper/keeper.go
if err = p.updateReplSlots(currentReplicationSlots, dbls, followersUIDs); err != nil {
log.Errorw("error updating replication slots", zap.Error(err))
return
}

Copy link
Copy Markdown
Member

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

Comment thread pkg/cluster/cluster.go Outdated
// addition to the ones internally defined by stolon
AdditionalWalSenders *uint16 `json:"additionalWalSenders"`
AdditionalWalSenders *uint16 `json:"additionalWalSenders"`
AdditionalReplicationSlotNames []string `json:"additionalReplicationSlotNames"`

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing comment

Comment thread pkg/cluster/cluster.go Outdated
return nil
}

rp := regexp.MustCompile("[_0-9a-z]+")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread pkg/cluster/cluster.go Outdated

for _, replSlotName := range s.AdditionalReplicationSlotNames {
if trimmedSlotName := strings.TrimSpace(replSlotName); len(trimmedSlotName) == 0 ||
len(rp.ReplaceAllString(trimmedSlotName, "")) > 0 ||

Copy link
Copy Markdown
Member

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.

@sgotti

sgotti commented Feb 14, 2018

Copy link
Copy Markdown
Member

@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:

  • validateReplicationSlot is now a generic function that takes one replslot and only uses util.IsValidReplSlotName and IsStolonName, not trimming or other uneeded things: Additional replication slots #434 (comment)

  • added a test for validateReplicationSlot to check that it works correcly

  • fixed the dbSpec option since it wasn't needed. Now it's a generic DBSpec option where we ask the keeper which additional replslots to use. Please note (written in the TODOs) that now they are managed only on the master instance.

  • fixed missing logging after call to refreshReplicationSlots

  • simplified updateAdditionalReplSlots.

  • On postgres >= 10 there's the concept of temporary replication slot. We should ignore them.

You can see and take the commit here: 00007b2

@sgotti

sgotti commented Feb 15, 2018

Copy link
Copy Markdown
Member

@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.
@sgotti

sgotti commented Feb 23, 2018

Copy link
Copy Markdown
Member

@saranhada Thanks! Merging.

@sgotti sgotti merged commit 15164a3 into sorintlab:master Feb 23, 2018
sgotti added a commit that referenced this pull request Feb 23, 2018
@sgotti sgotti added this to the 0.10.0 milestone Mar 21, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant