Skip to content

Commit 746df0d

Browse files
authored
do not remove publications of slot defined in manifest (#2868)
* do not remove publications of slot defined in manifest * improve condition to sync streams * init publication tables map when adding manifest slots * need to update c.Stream when there is no update
1 parent 2a4be1c commit 746df0d

File tree

4 files changed

+38
-20
lines changed

4 files changed

+38
-20
lines changed

pkg/cluster/cluster.go

+1
Original file line numberDiff line numberDiff line change
@@ -1160,6 +1160,7 @@ func (c *Cluster) Update(oldSpec, newSpec *acidv1.Postgresql) error {
11601160

11611161
// streams
11621162
if len(newSpec.Spec.Streams) > 0 || len(oldSpec.Spec.Streams) != len(newSpec.Spec.Streams) {
1163+
c.logger.Debug("syncing streams")
11631164
if err := c.syncStreams(); err != nil {
11641165
c.logger.Errorf("could not sync streams: %v", err)
11651166
updateFailed = true

pkg/cluster/streams.go

+32-18
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,10 @@ func (c *Cluster) syncPublication(dbName string, databaseSlotsList map[string]za
114114
}
115115

116116
for slotName, slotAndPublication := range databaseSlotsList {
117-
tables := slotAndPublication.Publication
118-
tableNames := make([]string, len(tables))
117+
newTables := slotAndPublication.Publication
118+
tableNames := make([]string, len(newTables))
119119
i := 0
120-
for t := range tables {
120+
for t := range newTables {
121121
tableName, schemaName := getTableSchema(t)
122122
tableNames[i] = fmt.Sprintf("%s.%s", schemaName, tableName)
123123
i++
@@ -126,6 +126,12 @@ func (c *Cluster) syncPublication(dbName string, databaseSlotsList map[string]za
126126
tableList := strings.Join(tableNames, ", ")
127127

128128
currentTables, exists := currentPublications[slotName]
129+
// if newTables is empty it means that it's definition was removed from streams section
130+
// but when slot is defined in manifest we should sync publications, too
131+
// by reusing current tables we make sure it is not
132+
if len(newTables) == 0 {
133+
tableList = currentTables
134+
}
129135
if !exists {
130136
createPublications[slotName] = tableList
131137
} else if currentTables != tableList {
@@ -350,16 +356,8 @@ func (c *Cluster) syncStreams() error {
350356
return nil
351357
}
352358

353-
databaseSlots := make(map[string]map[string]zalandov1.Slot)
354-
slotsToSync := make(map[string]map[string]string)
355-
requiredPatroniConfig := c.Spec.Patroni
356-
357-
if len(requiredPatroniConfig.Slots) > 0 {
358-
for slotName, slotConfig := range requiredPatroniConfig.Slots {
359-
slotsToSync[slotName] = slotConfig
360-
}
361-
}
362-
359+
// create map with every database and empty slot defintion
360+
// we need it to detect removal of streams from databases
363361
if err := c.initDbConn(); err != nil {
364362
return fmt.Errorf("could not init database connection")
365363
}
@@ -372,13 +370,28 @@ func (c *Cluster) syncStreams() error {
372370
if err != nil {
373371
return fmt.Errorf("could not get list of databases: %v", err)
374372
}
375-
// get database name with empty list of slot, except template0 and template1
373+
databaseSlots := make(map[string]map[string]zalandov1.Slot)
376374
for dbName := range listDatabases {
377375
if dbName != "template0" && dbName != "template1" {
378376
databaseSlots[dbName] = map[string]zalandov1.Slot{}
379377
}
380378
}
381379

380+
// need to take explicitly defined slots into account whey syncing Patroni config
381+
slotsToSync := make(map[string]map[string]string)
382+
requiredPatroniConfig := c.Spec.Patroni
383+
if len(requiredPatroniConfig.Slots) > 0 {
384+
for slotName, slotConfig := range requiredPatroniConfig.Slots {
385+
slotsToSync[slotName] = slotConfig
386+
if _, exists := databaseSlots[slotConfig["database"]]; exists {
387+
databaseSlots[slotConfig["database"]][slotName] = zalandov1.Slot{
388+
Slot: slotConfig,
389+
Publication: make(map[string]acidv1.StreamTable),
390+
}
391+
}
392+
}
393+
}
394+
382395
// get list of required slots and publications, group by database
383396
for _, stream := range c.Spec.Streams {
384397
if _, exists := databaseSlots[stream.Database]; !exists {
@@ -391,13 +404,13 @@ func (c *Cluster) syncStreams() error {
391404
"type": "logical",
392405
}
393406
slotName := getSlotName(stream.Database, stream.ApplicationId)
394-
if _, exists := databaseSlots[stream.Database][slotName]; !exists {
407+
slotAndPublication, exists := databaseSlots[stream.Database][slotName]
408+
if !exists {
395409
databaseSlots[stream.Database][slotName] = zalandov1.Slot{
396410
Slot: slot,
397411
Publication: stream.Tables,
398412
}
399413
} else {
400-
slotAndPublication := databaseSlots[stream.Database][slotName]
401414
streamTables := slotAndPublication.Publication
402415
for tableName, table := range stream.Tables {
403416
if _, exists := streamTables[tableName]; !exists {
@@ -492,16 +505,17 @@ func (c *Cluster) syncStream(appId string) error {
492505
continue
493506
}
494507
streamExists = true
508+
c.Streams[appId] = &stream
495509
desiredStreams := c.generateFabricEventStream(appId)
496510
if !reflect.DeepEqual(stream.ObjectMeta.OwnerReferences, desiredStreams.ObjectMeta.OwnerReferences) {
497511
c.logger.Infof("owner references of event streams with applicationId %s do not match the current ones", appId)
498512
stream.ObjectMeta.OwnerReferences = desiredStreams.ObjectMeta.OwnerReferences
499513
c.setProcessName("updating event streams with applicationId %s", appId)
500-
stream, err := c.KubeClient.FabricEventStreams(stream.Namespace).Update(context.TODO(), &stream, metav1.UpdateOptions{})
514+
updatedStream, err := c.KubeClient.FabricEventStreams(stream.Namespace).Update(context.TODO(), &stream, metav1.UpdateOptions{})
501515
if err != nil {
502516
return fmt.Errorf("could not update event streams with applicationId %s: %v", appId, err)
503517
}
504-
c.Streams[appId] = stream
518+
c.Streams[appId] = updatedStream
505519
}
506520
if match, reason := c.compareStreams(&stream, desiredStreams); !match {
507521
c.logger.Infof("updating event streams with applicationId %s: %s", appId, reason)

pkg/cluster/sync.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,10 @@ func (c *Cluster) Sync(newSpec *acidv1.Postgresql) error {
153153
return fmt.Errorf("could not sync connection pooler: %v", err)
154154
}
155155

156-
if len(c.Spec.Streams) > 0 {
156+
// sync if manifest stream count is different from stream CR count
157+
// it can be that they are always different due to grouping of manifest streams
158+
// but we would catch missed removals on update
159+
if len(c.Spec.Streams) != len(c.Streams) {
157160
c.logger.Debug("syncing streams")
158161
if err = c.syncStreams(); err != nil {
159162
err = fmt.Errorf("could not sync streams: %v", err)

pkg/cluster/util_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -650,7 +650,7 @@ func Test_trimCronjobName(t *testing.T) {
650650
}
651651
}
652652

653-
func TestisInMaintenanceWindow(t *testing.T) {
653+
func TestIsInMaintenanceWindow(t *testing.T) {
654654
now := time.Now()
655655
futureTimeStart := now.Add(1 * time.Hour)
656656
futureTimeStartFormatted := futureTimeStart.Format("15:04")

0 commit comments

Comments
 (0)