Skip to content

Commit 744857d

Browse files
authored
PBM-1311: PBM fails to do PITR slicing when RS doesn't have a majority (#940)
* Expand RS status with WriteMajorityCount field * Add topo.IsWriteMajorityRequested to determine if majority is requested in current setup * Fix PITR slicing intervals for the case when cluster doesn't have majority
1 parent 5d8cdc4 commit 744857d

File tree

5 files changed

+41
-2
lines changed

5 files changed

+41
-2
lines changed

pbm/backup/logical.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ func (b *Backup) doLogical(
8989

9090
stopOplogSlicer := startOplogSlicer(ctx,
9191
b.nodeConn,
92+
b.leadConn.MongoOptions().WriteConcern,
9293
b.SlicerInterval(),
9394
rsMeta.FirstWriteTS,
9495
func(ctx context.Context, w io.WriterTo, from, till primitive.Timestamp) (int64, error) {

pbm/backup/slicer.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99

1010
"go.mongodb.org/mongo-driver/bson/primitive"
1111
"go.mongodb.org/mongo-driver/mongo"
12+
"go.mongodb.org/mongo-driver/mongo/writeconcern"
1213

1314
"github.com/percona/percona-backup-mongodb/pbm/log"
1415
"github.com/percona/percona-backup-mongodb/pbm/oplog"
@@ -22,6 +23,7 @@ type stopSlicerFunc func() (primitive.Timestamp, int64, error)
2223
func startOplogSlicer(
2324
ctx context.Context,
2425
m *mongo.Client,
26+
writeConcern *writeconcern.WriteConcern,
2527
interval time.Duration,
2628
startOpTime primitive.Timestamp,
2729
upload uploadChunkFunc,
@@ -53,7 +55,11 @@ func startOplogSlicer(
5355
return
5456
}
5557

56-
currOpTime, err := topo.GetLastWrite(ctx, m, true)
58+
majority, err := topo.IsWriteMajorityRequested(ctx, m, writeConcern)
59+
if err != nil {
60+
l.Error("failed to inspect requested majority: %v", err)
61+
}
62+
currOpTime, err := topo.GetLastWrite(ctx, m, majority)
5763
if err != nil {
5864
if errors.Is(err, context.Canceled) {
5965
return

pbm/slicer/slicer.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,11 @@ func (s *Slicer) Stream(
392392
return OpMovedError{ld.Node}
393393
}
394394
if sliceTo.IsZero() {
395-
sliceTo, err = topo.GetLastWrite(ctx, s.node, true)
395+
majority, err := topo.IsWriteMajorityRequested(ctx, s.node, s.leadClient.MongoOptions().WriteConcern)
396+
if err != nil {
397+
return errors.Wrap(err, "define requested majority")
398+
}
399+
sliceTo, err = topo.GetLastWrite(ctx, s.node, majority)
396400
if err != nil {
397401
return errors.Wrap(err, "define last write timestamp")
398402
}

pbm/topo/cluster.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"go.mongodb.org/mongo-driver/bson"
88
"go.mongodb.org/mongo-driver/bson/primitive"
99
"go.mongodb.org/mongo-driver/mongo"
10+
"go.mongodb.org/mongo-driver/mongo/writeconcern"
1011

1112
"github.com/percona/percona-backup-mongodb/pbm/connect"
1213
"github.com/percona/percona-backup-mongodb/pbm/errors"
@@ -66,6 +67,32 @@ func OpTimeFromNodeInfo(inf *NodeInfo, majority bool) (primitive.Timestamp, erro
6667
return lw, nil
6768
}
6869

70+
// IsWriteMajorityRequested compares cluster wide majority (replSetGetStatus.writeMajorityCount)
71+
// with WriteConcern requested in connection string and determinates if majority is requested or not
72+
func IsWriteMajorityRequested(
73+
ctx context.Context,
74+
m *mongo.Client,
75+
writeConcern *writeconcern.WriteConcern,
76+
) (bool, error) {
77+
if writeConcern == nil ||
78+
!writeConcern.IsValid() ||
79+
writeConcern == writeconcern.Majority() {
80+
return true, nil
81+
}
82+
83+
w, ok := writeConcern.W.(int)
84+
if !ok {
85+
return true, nil
86+
}
87+
88+
s, err := GetReplsetStatus(ctx, m)
89+
if err != nil {
90+
return true, errors.Wrap(err, "get replset status")
91+
}
92+
93+
return w >= s.WriteMajorityCount, nil
94+
}
95+
6996
// ClusterMembers returns list of replicasets current cluster consists of
7097
// (shards + configserver). The list would consist of on rs if cluster is
7198
// a non-sharded rs.

pbm/topo/status.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ type ReplsetStatus struct {
5454
ClusterTime *ClusterTime `bson:"$clusterTime,omitempty" json:"$clusterTime,omitempty"`
5555
ConfigServerState *ConfigServerState `bson:"$configServerState,omitempty" json:"$configServerState,omitempty"`
5656
OperationTime *primitive.Timestamp `bson:"operationTime,omitempty" json:"operationTime,omitempty"`
57+
WriteMajorityCount int `bson:"writeMajorityCount,omitempty" json:"writeMajorityCount,omitempty"`
5758
}
5859

5960
func CurrentUser(ctx context.Context, m *mongo.Client) (*AuthInfo, error) {

0 commit comments

Comments
 (0)