summaryrefslogtreecommitdiff
path: root/src/mongo/gotools/common/db/write_concern.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/gotools/common/db/write_concern.go')
-rw-r--r--src/mongo/gotools/common/db/write_concern.go123
1 files changed, 123 insertions, 0 deletions
diff --git a/src/mongo/gotools/common/db/write_concern.go b/src/mongo/gotools/common/db/write_concern.go
new file mode 100644
index 00000000000..0a9a16214c8
--- /dev/null
+++ b/src/mongo/gotools/common/db/write_concern.go
@@ -0,0 +1,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
+}