Skip to content

Commit 13c211b

Browse files
authored
Merge pull request globalsign#18 from globalsign/merge-development
Merge development
2 parents 436ce4b + 7af1da3 commit 13c211b

File tree

9 files changed

+487
-46
lines changed

9 files changed

+487
-46
lines changed

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,5 +46,6 @@ script:
4646
- (cd bson && go test -check.v)
4747
- go test -check.v -fast
4848
- (cd txn && go test -check.v)
49+
- make stopdb
4950

5051
# vim:sw=4:ts=4:et

README.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,23 @@ Further PR's (with tests) are welcome, but please maintain backwards compatibili
1515
* Support majority read concerns ([details](https://github.com/globalsign/mgo/pull/2))
1616
* Improved connection handling ([details](https://github.com/globalsign/mgo/pull/5))
1717
* Hides SASL warnings ([details](https://github.com/globalsign/mgo/pull/7))
18-
* Improved multi-document transaction performance ([details](https://github.com/globalsign/mgo/pull/10), [more](https://github.com/globalsign/mgo/pull/11))
19-
* Integration tests run against newest MongoDB 3.2 releases ([details](https://github.com/globalsign/mgo/pull/4))
2018
* Support for partial indexes ([detials](https://github.com/domodwyer/mgo/commit/5efe8eccb028238d93c222828cae4806aeae9f51))
19+
* Fixes timezone handling ([details](https://github.com/go-mgo/mgo/pull/464))
20+
* Integration tests run against newest MongoDB 3.2 releases ([details](https://github.com/globalsign/mgo/pull/4))
21+
* Improved multi-document transaction performance ([details](https://github.com/globalsign/mgo/pull/10), [more](https://github.com/globalsign/mgo/pull/11), [more](https://github.com/globalsign/mgo/pull/16))
22+
* Fixes cursor timeouts ([detials](https://jira.mongodb.org/browse/SERVER-24899))
23+
* Support index hints and timeouts for count queries ([details](https://github.com/globalsign/mgo/pull/17))
2124

2225
---
2326

2427
### Thanks to
28+
* @BenLubar
2529
* @carter2000
2630
* @cezarsa
27-
* @eaglerayp
2831
* @drichelson
32+
* @eaglerayp
33+
* @fmpwizard
2934
* @jameinel
35+
* @Reenjii
3036
* @smoya
3137
* @wgallagher

bson/json.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"encoding/base64"
66
"fmt"
77
"strconv"
8+
"strings"
89
"time"
910

1011
"github.com/globalsign/mgo/internal/json"
@@ -156,7 +157,7 @@ func jencBinaryType(v interface{}) ([]byte, error) {
156157
return fbytes(`{"$binary":"%s","$type":"0x%x"}`, out, in.Kind), nil
157158
}
158159

159-
const jdateFormat = "2006-01-02T15:04:05.999Z"
160+
const jdateFormat = "2006-01-02T15:04:05.999Z07:00"
160161

161162
func jdecDate(data []byte) (interface{}, error) {
162163
var v struct {
@@ -170,13 +171,15 @@ func jdecDate(data []byte) (interface{}, error) {
170171
v.S = v.Func.S
171172
}
172173
if v.S != "" {
174+
var errs []string
173175
for _, format := range []string{jdateFormat, "2006-01-02"} {
174176
t, err := time.Parse(format, v.S)
175177
if err == nil {
176178
return t, nil
177179
}
180+
errs = append(errs, err.Error())
178181
}
179-
return nil, fmt.Errorf("cannot parse date: %q", v.S)
182+
return nil, fmt.Errorf("cannot parse date: %q [%s]", v.S, strings.Join(errs, ", "))
180183
}
181184

182185
var vn struct {

bson/json_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,18 @@ var jsonTests = []jsonTest{
3434
{
3535
a: time.Date(2016, 5, 15, 1, 2, 3, 4000000, time.UTC),
3636
b: `{"$date":"2016-05-15T01:02:03.004Z"}`,
37+
}, {
38+
a: time.Date(2016, 5, 15, 1, 2, 3, 4000000, time.FixedZone("CET", 60*60)),
39+
b: `{"$date":"2016-05-15T01:02:03.004+01:00"}`,
3740
}, {
3841
b: `{"$date": {"$numberLong": "1002"}}`,
3942
c: time.Date(1970, 1, 1, 0, 0, 1, 2e6, time.UTC),
4043
}, {
4144
b: `ISODate("2016-05-15T01:02:03.004Z")`,
4245
c: time.Date(2016, 5, 15, 1, 2, 3, 4000000, time.UTC),
46+
}, {
47+
b: `ISODate("2016-05-15T01:02:03.004-07:00")`,
48+
c: time.Date(2016, 5, 15, 1, 2, 3, 4000000, time.FixedZone("PDT", -7*60*60)),
4349
}, {
4450
b: `new Date(1000)`,
4551
c: time.Date(1970, 1, 1, 0, 0, 1, 0, time.UTC),
@@ -180,6 +186,11 @@ func (s *S) TestJSON(c *C) {
180186
value = zerov.Elem().Interface()
181187
}
182188
c.Logf("Loaded: %#v", value)
189+
if ctime, ok := item.c.(time.Time); ok {
190+
// time.Time must be compared with time.Time.Equal and not reflect.DeepEquals
191+
c.Assert(ctime.Equal(value.(time.Time)), Equals, true)
192+
continue
193+
}
183194
c.Assert(value, DeepEquals, item.c)
184195
}
185196
}

session.go

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3281,20 +3281,23 @@ func prepareFindOp(socket *mongoSocket, op *queryOp, limit int32) bool {
32813281
}
32823282

32833283
find := findCmd{
3284-
Collection: op.collection[nameDot+1:],
3285-
Filter: op.query,
3286-
Projection: op.selector,
3287-
Sort: op.options.OrderBy,
3288-
Skip: op.skip,
3289-
Limit: limit,
3290-
MaxTimeMS: op.options.MaxTimeMS,
3291-
MaxScan: op.options.MaxScan,
3292-
Hint: op.options.Hint,
3293-
Comment: op.options.Comment,
3294-
Snapshot: op.options.Snapshot,
3295-
OplogReplay: op.flags&flagLogReplay != 0,
3296-
Collation: op.options.Collation,
3297-
ReadConcern: readLevel{level: op.readConcern},
3284+
Collection: op.collection[nameDot+1:],
3285+
Filter: op.query,
3286+
Projection: op.selector,
3287+
Sort: op.options.OrderBy,
3288+
Skip: op.skip,
3289+
Limit: limit,
3290+
MaxTimeMS: op.options.MaxTimeMS,
3291+
MaxScan: op.options.MaxScan,
3292+
Hint: op.options.Hint,
3293+
Comment: op.options.Comment,
3294+
Snapshot: op.options.Snapshot,
3295+
Collation: op.options.Collation,
3296+
Tailable: op.flags&flagTailable != 0,
3297+
AwaitData: op.flags&flagAwaitData != 0,
3298+
OplogReplay: op.flags&flagLogReplay != 0,
3299+
NoCursorTimeout: op.flags&flagNoCursorTimeout != 0,
3300+
ReadConcern: readLevel{level: op.readConcern},
32983301
}
32993302

33003303
if op.limit < 0 {
@@ -4083,10 +4086,12 @@ func (iter *Iter) getMoreCmd() *queryOp {
40834086
}
40844087

40854088
type countCmd struct {
4086-
Count string
4087-
Query interface{}
4088-
Limit int32 ",omitempty"
4089-
Skip int32 ",omitempty"
4089+
Count string
4090+
Query interface{}
4091+
Limit int32 ",omitempty"
4092+
Skip int32 ",omitempty"
4093+
Hint bson.D `bson:"hint,omitempty"`
4094+
MaxTimeMS int `bson:"maxTimeMS,omitempty"`
40904095
}
40914096

40924097
// Count returns the total number of documents in the result set.
@@ -4108,8 +4113,12 @@ func (q *Query) Count() (n int, err error) {
41084113
if query == nil {
41094114
query = bson.D{}
41104115
}
4116+
// not checking the error because if type assertion fails, we
4117+
// simply want a Zero bson.D
4118+
hint, _ := q.op.options.Hint.(bson.D)
41114119
result := struct{ N int }{}
4112-
err = session.DB(dbname).Run(countCmd{cname, query, limit, op.skip}, &result)
4120+
err = session.DB(dbname).Run(countCmd{cname, query, limit, op.skip, hint, op.options.MaxTimeMS}, &result)
4121+
41134122
return result.N, err
41144123
}
41154124

session_test.go

Lines changed: 94 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1275,6 +1275,49 @@ func (s *S) TestCountSkipLimit(c *C) {
12751275
c.Assert(n, Equals, 4)
12761276
}
12771277

1278+
func (s *S) TestCountMaxTimeMS(c *C) {
1279+
if !s.versionAtLeast(2, 6) {
1280+
c.Skip("SetMaxTime only supported in 2.6+")
1281+
}
1282+
1283+
session, err := mgo.Dial("localhost:40001")
1284+
c.Assert(err, IsNil)
1285+
defer session.Close()
1286+
1287+
coll := session.DB("mydb").C("mycoll")
1288+
1289+
ns := make([]int, 100000)
1290+
for _, n := range ns {
1291+
err := coll.Insert(M{"n": n})
1292+
c.Assert(err, IsNil)
1293+
}
1294+
_, err = coll.Find(M{"n": M{"$gt": 1}}).SetMaxTime(1 * time.Millisecond).Count()
1295+
e := err.(*mgo.QueryError)
1296+
// We hope this query took longer than 1 ms, which triggers an error code 50
1297+
c.Assert(e.Code, Equals, 50)
1298+
1299+
}
1300+
1301+
func (s *S) TestCountHint(c *C) {
1302+
if !s.versionAtLeast(2, 6) {
1303+
c.Skip("Not implemented until mongo 2.5.5 https://jira.mongodb.org/browse/SERVER-2677")
1304+
}
1305+
1306+
session, err := mgo.Dial("localhost:40001")
1307+
c.Assert(err, IsNil)
1308+
defer session.Close()
1309+
1310+
coll := session.DB("mydb").C("mycoll")
1311+
err = coll.Insert(M{"n": 1})
1312+
c.Assert(err, IsNil)
1313+
1314+
_, err = coll.Find(M{"n": M{"$gt": 1}}).Hint("does_not_exists").Count()
1315+
e := err.(*mgo.QueryError)
1316+
// If Hint wasn't doing anything, then Count would ignore the non existent index hint
1317+
// and return the normal ount. But we instead get an error code 2: bad hint
1318+
c.Assert(e.Code, Equals, 2)
1319+
}
1320+
12781321
func (s *S) TestQueryExplain(c *C) {
12791322
session, err := mgo.Dial("localhost:40001")
12801323
c.Assert(err, IsNil)
@@ -1673,7 +1716,7 @@ func (s *S) TestResumeIter(c *C) {
16731716
c.Assert(len(batch), Equals, 0)
16741717
}
16751718

1676-
var cursorTimeout = flag.Bool("cursor-timeout", false, "Enable cursor timeout test")
1719+
var cursorTimeout = flag.Bool("cursor-timeout", false, "Enable cursor timeout tests")
16771720

16781721
func (s *S) TestFindIterCursorTimeout(c *C) {
16791722
if !*cursorTimeout {
@@ -1717,6 +1760,56 @@ func (s *S) TestFindIterCursorTimeout(c *C) {
17171760
c.Assert(iter.Err(), Equals, mgo.ErrCursor)
17181761
}
17191762

1763+
func (s *S) TestFindIterCursorNoTimeout(c *C) {
1764+
if !*cursorTimeout {
1765+
c.Skip("-cursor-timeout")
1766+
}
1767+
session, err := mgo.Dial("localhost:40001")
1768+
c.Assert(err, IsNil)
1769+
defer session.Close()
1770+
1771+
session.SetCursorTimeout(0)
1772+
1773+
type Doc struct {
1774+
Id int "_id"
1775+
}
1776+
1777+
coll := session.DB("test").C("test")
1778+
coll.Remove(nil)
1779+
for i := 0; i < 100; i++ {
1780+
err = coll.Insert(Doc{i})
1781+
c.Assert(err, IsNil)
1782+
}
1783+
1784+
session.SetBatch(1)
1785+
iter := coll.Find(nil).Iter()
1786+
var doc Doc
1787+
if !iter.Next(&doc) {
1788+
c.Fatalf("iterator failed to return any documents")
1789+
}
1790+
1791+
for i := 10; i > 0; i-- {
1792+
c.Logf("Sleeping... %d minutes to go...", i)
1793+
time.Sleep(1*time.Minute + 2*time.Second)
1794+
}
1795+
1796+
// Drain any existing documents that were fetched.
1797+
if !iter.Next(&doc) {
1798+
c.Fatalf("iterator failed to return previously cached document")
1799+
}
1800+
for i := 1; i < 100; i++ {
1801+
if !iter.Next(&doc) {
1802+
c.Errorf("iterator failed on iteration %d", i)
1803+
break
1804+
}
1805+
}
1806+
if iter.Next(&doc) {
1807+
c.Error("iterator returned more than 100 documents")
1808+
}
1809+
1810+
c.Assert(iter.Err(), IsNil)
1811+
}
1812+
17201813
func (s *S) TestTooManyItemsLimitBug(c *C) {
17211814
if *fast {
17221815
c.Skip("-fast")

0 commit comments

Comments
 (0)