Skip to content

Commit d7a8276

Browse files
committed
Remove race condition
Add rwMutex.
1 parent af9ed41 commit d7a8276

2 files changed

Lines changed: 30 additions & 14 deletions

File tree

listener/listener.go

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"fmt"
77
"os"
88
"os/signal"
9+
"sync"
910
"syscall"
1011
"time"
1112

@@ -19,7 +20,7 @@ const errorBufferSize = 100
1920

2021
// Logical decoding plugin.
2122
const (
22-
pgoutputPlugin = "pgoutput"
23+
pgOutputPlugin = "pgoutput"
2324
)
2425

2526
// Service info message.
@@ -55,13 +56,14 @@ type repository interface {
5556

5657
// Listener main service struct.
5758
type Listener struct {
59+
mu sync.RWMutex
5860
config config.Config
5961
slotName string
6062
publisher publisher
6163
replicator replication
6264
repository repository
6365
parser parser
64-
LSN uint64
66+
lsn uint64
6567
errChannel chan error
6668
}
6769

@@ -84,6 +86,18 @@ func NewWalListener(
8486
}
8587
}
8688

89+
func (l *Listener) readLSN() uint64 {
90+
l.mu.RLock()
91+
defer l.mu.RUnlock()
92+
return l.lsn
93+
}
94+
95+
func (l *Listener) setLSN(lsn uint64) {
96+
l.mu.Lock()
97+
l.lsn = lsn
98+
defer l.mu.Unlock()
99+
}
100+
87101
// Process is main service entry point.
88102
func (l *Listener) Process() error {
89103
var serviceErr *serviceErr
@@ -99,16 +113,17 @@ func (l *Listener) Process() error {
99113
}
100114

101115
if !slotIsExists {
102-
consistentPoint, _, err := l.replicator.CreateReplicationSlotEx(l.slotName, pgoutputPlugin)
116+
consistentPoint, _, err := l.replicator.CreateReplicationSlotEx(l.slotName, pgOutputPlugin)
103117
if err != nil {
104118
logger.WithError(err).Infoln("CreateReplicationSlotEx() error")
105119
return err
106120
}
107-
l.LSN, err = pgx.ParseLSN(consistentPoint)
121+
lsn, err := pgx.ParseLSN(consistentPoint)
108122
if err != nil {
109123
logger.WithError(err).Errorln("slotIsExists() error")
110124
return err
111125
}
126+
l.setLSN(lsn)
112127
logger.Infoln("create new slot")
113128
} else {
114129
logger.Infoln("slot already exists, LSN updated")
@@ -164,10 +179,11 @@ func (l *Listener) slotIsExists() (bool, error) {
164179
if len(restartLSNStr) == 0 {
165180
return false, nil
166181
}
167-
l.LSN, err = pgx.ParseLSN(restartLSNStr)
182+
lsn, err := pgx.ParseLSN(restartLSNStr)
168183
if err != nil {
169184
return false, err
170185
}
186+
l.setLSN(lsn)
171187
return true, nil
172188
}
173189

@@ -180,7 +196,7 @@ const protoVersion = "proto_version '1'"
180196
// Stream receive event from PostgreSQL.
181197
// Accept message, apply filter and publish it in NATS server.
182198
func (l *Listener) Stream(ctx context.Context) {
183-
err := l.replicator.StartReplication(l.slotName, l.LSN, -1, protoVersion, publicationNames("sport"))
199+
err := l.replicator.StartReplication(l.slotName, l.readLSN(), -1, protoVersion, publicationNames("sport"))
184200
if err != nil {
185201
l.errChannel <- newListenerError("StartReplication()", err)
186202
return
@@ -220,20 +236,20 @@ func (l *Listener) Stream(ctx context.Context) {
220236
logrus.
221237
WithField("subject", subjectName).
222238
WithField("action", event.Action).
223-
WithField("lsn", l.LSN).
239+
WithField("lsn", l.readLSN()).
224240
Infoln("event was send")
225241
}
226242
}
227243
tx.Clear()
228244
}
229245

230-
if msg.WalMessage.WalStart > l.LSN {
246+
if msg.WalMessage.WalStart > l.readLSN() {
231247
err = l.AckWalMessage(msg.WalMessage.WalStart)
232248
if err != nil {
233249
l.errChannel <- fmt.Errorf("%v: %w", ErrAckWalMessage, err)
234250
continue
235251
} else {
236-
logrus.WithField("lsn", l.LSN).Debugln("ack wal msg")
252+
logrus.WithField("lsn", l.readLSN()).Debugln("ack wal msg")
237253
}
238254
}
239255
}
@@ -298,7 +314,7 @@ func (l *Listener) SendPeriodicHeartbeats(ctx context.Context) {
298314

299315
// SendStandbyStatus sends a `StandbyStatus` object with the current RestartLSN value to the server.
300316
func (l *Listener) SendStandbyStatus() error {
301-
standbyStatus, err := pgx.NewStandbyStatus(l.LSN)
317+
standbyStatus, err := pgx.NewStandbyStatus(l.readLSN())
302318
if err != nil {
303319
return fmt.Errorf("unable to create StandbyStatus object: %w", err)
304320
}
@@ -312,7 +328,7 @@ func (l *Listener) SendStandbyStatus() error {
312328

313329
// AckWalMessage acknowledge received wal message.
314330
func (l *Listener) AckWalMessage(lsn uint64) error {
315-
l.LSN = lsn
331+
l.setLSN(lsn)
316332
err := l.SendStandbyStatus()
317333
if err != nil {
318334
return err

listener/listener_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ func TestListener_SendStandbyStatus(t *testing.T) {
259259
tt.setup()
260260
w := &Listener{
261261
replicator: repl,
262-
LSN: tt.fields.restartLSN,
262+
lsn: tt.fields.restartLSN,
263263
}
264264
if err := w.SendStandbyStatus(); (err != nil) != tt.wantErr {
265265
t.Errorf("SendStandbyStatus() error = %v, wantErr %v", err, tt.wantErr)
@@ -347,7 +347,7 @@ func TestListener_AckWalMessage(t *testing.T) {
347347
tt.setup()
348348
w := &Listener{
349349
replicator: repl,
350-
LSN: tt.fields.restartLSN,
350+
lsn: tt.fields.restartLSN,
351351
}
352352
if err := w.AckWalMessage(tt.args.LSN); (err != nil) != tt.wantErr {
353353
t.Errorf("AckWalMessage() error = %v, wantErr %v", err, tt.wantErr)
@@ -800,7 +800,7 @@ func TestListener_Stream(t *testing.T) {
800800
replicator: repl,
801801
repository: repo,
802802
parser: prs,
803-
LSN: tt.fields.restartLSN,
803+
lsn: tt.fields.restartLSN,
804804
errChannel: make(chan error, errorBufferSize),
805805
}
806806
go func() {

0 commit comments

Comments
 (0)