Skip to content

Commit abe06ac

Browse files
Mei-Zhaodomodwyer
authored andcommitted
Contributing:findAndModify support writeConcern (#185)
* socket: only send client metadata once per socket (#105) Periodic cluster synchronisation calls isMaster() which currently resends the "client" metadata every call - the spec specifies: isMaster commands issued after the initial connection handshake MUST NOT contain handshake arguments https://github.com/mongodb/specifications/blob/master/source/mongodb-handshake/handshake.rst#connection-handshake This hotfix prevents subsequent isMaster calls from sending the client metadata again - fixes #101 and fixes #103. Thanks to @changwoo-nam @qhenkart @canthefason @jyoon17 for spotting the initial issue, opening tickets, and having the problem debugged with a PoC fix before I even woke up. * Merge Development (#111) * Brings in a patch on having flusher not suppress errors. (#81) go-mgo#360 * Fallback to JSON tags when BSON tag isn't present (#91) * Fallback to JSON tags when BSON tag isn't present Cleanup. * Add test to demonstrate tagging fallback. - Test coverage for tagging test. * socket: only send client metadata once per socket Periodic cluster synchronisation calls isMaster() which currently resends the "client" metadata every call - the spec specifies: isMaster commands issued after the initial connection handshake MUST NOT contain handshake arguments https://github.com/mongodb/specifications/blob/master/source/mongodb-handshake/handshake.rst#connection-handshake This hotfix prevents subsequent isMaster calls from sending the client metadata again - fixes #101 and fixes #103. Thanks to @changwoo-nam @qhenkart @canthefason @jyoon17 for spotting the initial issue, opening tickets, and having the problem debugged with a PoC fix before I even woke up. * Cluster abended test 254 (#100) * Add a test that mongo Server gets their abended reset as necessary. See https://github.com/go-mgo/mgo/issues/254 and https://github.com/go-mgo/mgo/pull/255/files * Include the patch from Issue 255. This brings in a test which fails without the patch, and passes with the patch. Still to be tested, manual tcpkill of a socket. * changeStream support (#97) Add $changeStream support * readme: credit @peterdeka and @steve-gray (#110) * Hotfix #120 (#136) * cluster: fix deadlock in cluster synchronisation (#120) For a impressively thorough breakdown of the problem, see: #120 (comment) Huge thanks to @dvic and @KJTsanaktsidis for the report and fix. * readme: credit @dvic and @KJTsanaktsidis * findAndModify support writeConcern * fix
1 parent c3b81bb commit abe06ac

File tree

2 files changed

+66
-10
lines changed

2 files changed

+66
-10
lines changed

session.go

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2893,6 +2893,7 @@ func (p *Pipe) SetMaxTime(d time.Duration) *Pipe {
28932893
return p
28942894
}
28952895

2896+
28962897
// Collation allows to specify language-specific rules for string comparison,
28972898
// such as rules for lettercase and accent marks.
28982899
// When specifying collation, the locale field is mandatory; all other collation
@@ -4894,18 +4895,22 @@ type findModifyCmd struct {
48944895
Collection string `bson:"findAndModify"`
48954896
Query, Update, Sort, Fields interface{} `bson:",omitempty"`
48964897
Upsert, Remove, New bool `bson:",omitempty"`
4898+
WriteConcern interface{} `bson:"writeConcern"`
48974899
}
48984900

48994901
type valueResult struct {
4900-
Value bson.Raw
4901-
LastError LastError `bson:"lastErrorObject"`
4902+
Value bson.Raw
4903+
LastError LastError `bson:"lastErrorObject"`
4904+
ConcernError writeConcernError `bson:"writeConcernError"`
49024905
}
49034906

49044907
// Apply runs the findAndModify MongoDB command, which allows updating, upserting
49054908
// or removing a document matching a query and atomically returning either the old
49064909
// version (the default) or the new version of the document (when ReturnNew is true).
49074910
// If no objects are found Apply returns ErrNotFound.
49084911
//
4912+
// If the session is in safe mode, the LastError result will be returned as err.
4913+
//
49094914
// The Sort and Select query methods affect the result of Apply. In case
49104915
// multiple documents match the query, Sort enables selecting which document to
49114916
// act upon by ordering it first. Select enables retrieving only a selection
@@ -4942,15 +4947,27 @@ func (q *Query) Apply(change Change, result interface{}) (info *ChangeInfo, err
49424947
dbname := op.collection[:c]
49434948
cname := op.collection[c+1:]
49444949

4950+
// https://docs.mongodb.com/manual/reference/command/findAndModify/#dbcmd.findAndModify
4951+
session.m.RLock()
4952+
safeOp := session.safeOp
4953+
session.m.RUnlock()
4954+
var writeConcern interface{}
4955+
if safeOp == nil {
4956+
writeConcern = bson.D{{Name: "w", Value: 0}}
4957+
} else {
4958+
writeConcern = safeOp.query.(*getLastError)
4959+
}
4960+
49454961
cmd := findModifyCmd{
4946-
Collection: cname,
4947-
Update: change.Update,
4948-
Upsert: change.Upsert,
4949-
Remove: change.Remove,
4950-
New: change.ReturnNew,
4951-
Query: op.query,
4952-
Sort: op.options.OrderBy,
4953-
Fields: op.selector,
4962+
Collection: cname,
4963+
Update: change.Update,
4964+
Upsert: change.Upsert,
4965+
Remove: change.Remove,
4966+
New: change.ReturnNew,
4967+
Query: op.query,
4968+
Sort: op.options.OrderBy,
4969+
Fields: op.selector,
4970+
WriteConcern: writeConcern,
49544971
}
49554972

49564973
session = session.Clone()
@@ -4993,6 +5010,14 @@ func (q *Query) Apply(change Change, result interface{}) (info *ChangeInfo, err
49935010
} else if change.Upsert {
49945011
info.UpsertedId = lerr.UpsertedId
49955012
}
5013+
if doc.ConcernError.Code != 0 {
5014+
var lerr LastError
5015+
e := doc.ConcernError
5016+
lerr.Code = e.Code
5017+
lerr.Err = e.ErrMsg
5018+
err = &lerr
5019+
return info, err
5020+
}
49965021
return info, nil
49975022
}
49985023

session_test.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1370,6 +1370,37 @@ func (s *S) TestFindAndModify(c *C) {
13701370
c.Assert(info, IsNil)
13711371
}
13721372

1373+
func (s *S) TestFindAndModifyWriteConcern(c *C) {
1374+
session, err := mgo.Dial("localhost:40011")
1375+
c.Assert(err, IsNil)
1376+
defer session.Close()
1377+
1378+
coll := session.DB("mydb").C("mycoll")
1379+
err = coll.Insert(M{"id": 42})
1380+
c.Assert(err, IsNil)
1381+
1382+
// Tweak the safety parameters to something unachievable.
1383+
session.SetSafe(&mgo.Safe{W: 4, WTimeout: 100})
1384+
1385+
var ret struct {
1386+
Id uint64 `bson:"id"`
1387+
}
1388+
1389+
change := mgo.Change{
1390+
Update: M{"$inc": M{"id": 8}},
1391+
ReturnNew: false,
1392+
}
1393+
info, err := coll.Find(M{"id": M{"$exists": true}}).Apply(change, &ret)
1394+
c.Assert(info.Updated, Equals, 1)
1395+
c.Assert(info.Matched, Equals, 1)
1396+
c.Assert(ret.Id, Equals, uint64(42))
1397+
1398+
if s.versionAtLeast(3, 2) {
1399+
// findAndModify support writeConcern after version 3.2.
1400+
c.Assert(err, ErrorMatches, "timeout|timed out waiting for slaves|Not enough data-bearing nodes|waiting for replication timed out")
1401+
}
1402+
}
1403+
13731404
func (s *S) TestFindAndModifyBug997828(c *C) {
13741405
session, err := mgo.Dial("localhost:40001")
13751406
c.Assert(err, IsNil)

0 commit comments

Comments
 (0)