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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
package db
import (
"fmt"
"github.com/mongodb/mongo-tools/common/json"
"github.com/mongodb/mongo-tools/common/log"
"github.com/mongodb/mongo-tools/common/util"
"gopkg.in/mgo.v2"
"strconv"
)
// write concern fields
const (
j = "j"
w = "w"
fSync = "fsync"
wTimeout = "wtimeout"
)
// constructWCObject takes in a write concern and attempts to construct an
// mgo.Safe object from it. It returns an error if it is unable to parse the
// string or if a parsed write concern field value is invalid.
func constructWCObject(writeConcern string) (sessionSafety *mgo.Safe, err error) {
sessionSafety = &mgo.Safe{}
defer func() {
// If the user passes a w value of 0, we set the session to use the
// unacknowledged write concern but only if journal commit acknowledgment,
// is not required. If commit acknowledgment is required, it prevails,
// and the server will require that mongod acknowledge the write operation
if sessionSafety.WMode == "" && sessionSafety.W == 0 && !sessionSafety.J {
sessionSafety = nil
}
}()
jsonWriteConcern := map[string]interface{}{}
if err = json.Unmarshal([]byte(writeConcern), &jsonWriteConcern); err != nil {
// if the writeConcern string can not be unmarshaled into JSON, this
// allows a default to the old behavior wherein the entire argument
// passed in is assigned to the 'w' field - thus allowing users pass
// a write concern that looks like: "majority", 0, "4", etc.
wValue, err := strconv.Atoi(writeConcern)
if err != nil {
sessionSafety.WMode = writeConcern
} else {
sessionSafety.W = wValue
if wValue < 0 {
return sessionSafety, fmt.Errorf("invalid '%v' argument: %v", w, wValue)
}
}
return sessionSafety, nil
}
if jVal, ok := jsonWriteConcern[j]; ok && util.IsTruthy(jVal) {
sessionSafety.J = true
}
if fsyncVal, ok := jsonWriteConcern[fSync]; ok && util.IsTruthy(fsyncVal) {
sessionSafety.FSync = true
}
if wtimeout, ok := jsonWriteConcern[wTimeout]; ok {
wtimeoutValue, err := util.ToInt(wtimeout)
if err != nil {
return sessionSafety, fmt.Errorf("invalid '%v' argument: %v", wTimeout, wtimeout)
}
sessionSafety.WTimeout = wtimeoutValue
}
if wInterface, ok := jsonWriteConcern[w]; ok {
wValue, err := util.ToInt(wInterface)
if err != nil {
// if the argument is neither a string nor int, error out
wStrVal, ok := wInterface.(string)
if !ok {
return sessionSafety, fmt.Errorf("invalid '%v' argument: %v", w, wInterface)
}
sessionSafety.WMode = wStrVal
} else {
sessionSafety.W = wValue
if wValue < 0 {
return sessionSafety, fmt.Errorf("invalid '%v' argument: %v", w, wValue)
}
}
}
return sessionSafety, nil
}
// BuildWriteConcern takes a string and a NodeType indicating the type of node the write concern
// is intended to be used against, and converts the write concern string argument into an
// mgo.Safe object that's usable on sessions for that node type.
func BuildWriteConcern(writeConcern string, nodeType NodeType) (*mgo.Safe, error) {
sessionSafety, err := constructWCObject(writeConcern)
if err != nil {
return nil, err
}
if sessionSafety == nil {
log.Logvf(log.DebugLow, "using unacknowledged write concern")
return nil, nil
}
// for standalone mongods, set the default write concern to 1
if nodeType == Standalone {
log.Logvf(log.DebugLow, "standalone server: setting write concern %v to 1", w)
sessionSafety.W = 1
sessionSafety.WMode = ""
}
var writeConcernStr interface{}
if sessionSafety.WMode != "" {
writeConcernStr = sessionSafety.WMode
} else {
writeConcernStr = sessionSafety.W
}
log.Logvf(log.Info, "using write concern: %v='%v', %v=%v, %v=%v, %v=%v",
w, writeConcernStr,
j, sessionSafety.J,
fSync, sessionSafety.FSync,
wTimeout, sessionSafety.WTimeout,
)
return sessionSafety, nil
}
|