forked from wal-g/wal-g
/
util.go
101 lines (83 loc) · 2.24 KB
/
util.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package oplog
import (
"fmt"
"github.com/mongodb/mongo-tools-common/db"
"go.mongodb.org/mongo-driver/bson"
)
// filterUUIDs recursively removes 'ui' entries from ops, including nested applyOps ops.
func filterUUIDs(op db.Oplog) (db.Oplog, error) {
// Remove UUIDs from oplog entries
op.UI = nil
// Check for and filter nested applyOps ops
if op.Operation == "c" && isApplyOpsCmd(op.Object) {
filtered, err := newFilteredApplyOps(op.Object)
if err != nil {
return db.Oplog{}, err
}
op.Object = filtered
}
return op, nil
}
// newFilteredApplyOps iterates over nested ops in an applyOps document and
// returns a new applyOps document that omits the 'ui' field from nested ops.
func newFilteredApplyOps(cmd bson.D) (bson.D, error) {
ops, err := unwrapNestedApplyOps(cmd)
if err != nil {
return nil, err
}
filtered := make([]db.Oplog, len(ops))
for i := range ops {
filtered[i], err = filterUUIDs(filtered[i])
if err != nil {
return nil, err
}
}
doc, err := wrapNestedApplyOps(filtered)
if err != nil {
return nil, err
}
return doc, nil
}
// isApplyOpsCmd returns true if a document seems to be an applyOps command.
func isApplyOpsCmd(cmd bson.D) bool {
for _, v := range cmd {
if v.Key == "applyOps" {
return true
}
}
return false
}
type nestedApplyOps struct {
ApplyOps []db.Oplog `bson:"applyOps"`
}
// unwrapNestedApplyOps converts a bson.D to a typed data structure.
func unwrapNestedApplyOps(doc bson.D) ([]db.Oplog, error) {
// Doc to bytes
bs, err := bson.Marshal(doc)
if err != nil {
return nil, fmt.Errorf("remarshal nested applyOps: %w", err)
}
// Bytes to typed data
var cmd nestedApplyOps
err = bson.Unmarshal(bs, &cmd)
if err != nil {
return nil, fmt.Errorf("unwrap nested applyOps: %w", err)
}
return cmd.ApplyOps, nil
}
// wrapNestedApplyOps converts a typed data structure to a bson.D.
func wrapNestedApplyOps(ops []db.Oplog) (bson.D, error) {
cmd := &nestedApplyOps{ApplyOps: ops}
// Typed data to bytes
raw, err := bson.Marshal(cmd)
if err != nil {
return nil, fmt.Errorf("rewrap nested applyOps op: %w", err)
}
// Bytes to doc
var doc bson.D
err = bson.Unmarshal(raw, &doc)
if err != nil {
return nil, fmt.Errorf("reunmarshal nested applyOps op: %w", err)
}
return doc, nil
}