Skip to content

Commit 7189b37

Browse files
authored
Merge pull request #154 from hpidcock/fix-perf
#154 collstats appears to be quite a slow way to determine if the collection is capped.
2 parents 75df612 + 90981c4 commit 7189b37

File tree

3 files changed

+46
-16
lines changed

3 files changed

+46
-16
lines changed

go.mod

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ go 1.14
44

55
require (
66
github.com/juju/clock v0.0.0-20190205081909-9c5c9712527c
7+
github.com/juju/collections v0.0.0-20200605021417-0d0ec82b7271
78
github.com/juju/errors v0.0.0-20200330140219-3fe23663418f
89
github.com/juju/loggo v0.0.0-20200526014432-9ce3a2e09b5e
910
github.com/juju/retry v0.0.0-20180821225755-9058e192b216

go.sum

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ github.com/juju/ansiterm v0.0.0-20160907234532-b99631de12cf/go.mod h1:UJSiEoRfvx
33
github.com/juju/clock v0.0.0-20190205081909-9c5c9712527c h1:3UvYABOQRhJAApj9MdCN+Ydv841ETSoy6xLzdmmr/9A=
44
github.com/juju/clock v0.0.0-20190205081909-9c5c9712527c/go.mod h1:nD0vlnrUjcjJhqN5WuCWZyzfd5AHZAC9/ajvbSx69xA=
55
github.com/juju/cmd v0.0.0-20171107070456-e74f39857ca0/go.mod h1:yWJQHl73rdSX4DHVKGqkAip+huBslxRwS8m9CrOLq18=
6+
github.com/juju/collections v0.0.0-20200605021417-0d0ec82b7271 h1:4R626WTwa7pRYQFiIRLVPepMhm05eZMEx+wIurRnMLc=
67
github.com/juju/collections v0.0.0-20200605021417-0d0ec82b7271/go.mod h1:5XgO71dV1JClcOJE+4dzdn4HrI5LiyKd7PlVG6eZYhY=
78
github.com/juju/errors v0.0.0-20150916125642-1b5e39b83d18 h1:Sem5Flzxj8ZdAgY2wfHBUlOYyP4wrpIfM8IZgANNGh8=
89
github.com/juju/errors v0.0.0-20150916125642-1b5e39b83d18/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q=

mgo.go

+44-16
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
"time"
2828

2929
"github.com/juju/clock"
30+
"github.com/juju/collections/set"
3031
"github.com/juju/errors"
3132
"github.com/juju/loggo"
3233
"github.com/juju/retry"
@@ -750,6 +751,10 @@ func clearDatabases(session *mgo.Session) error {
750751
}
751752

752753
func clearCollections(db *mgo.Database) error {
754+
capped, err := listCappedCollections(db)
755+
if err != nil {
756+
return errors.Annotatef(err, "getting capped collection list")
757+
}
753758
collectionNames, err := db.CollectionNames()
754759
if err != nil {
755760
return errors.Trace(err)
@@ -760,11 +765,7 @@ func clearCollections(db *mgo.Database) error {
760765
}
761766
collection := db.C(name)
762767
clearFunc := clearNormalCollection
763-
capped, err := isCapped(collection)
764-
if err != nil {
765-
return errors.Trace(err)
766-
}
767-
if capped {
768+
if capped.Contains(name) {
768769
clearFunc = clearCappedCollection
769770
}
770771
err = clearFunc(collection)
@@ -775,21 +776,48 @@ func clearCollections(db *mgo.Database) error {
775776
return nil
776777
}
777778

778-
func isCapped(collection *mgo.Collection) (bool, error) {
779-
result := bson.M{}
780-
err := collection.Database.Run(bson.D{{"collstats", collection.Name}}, &result)
779+
func listCappedCollections(db *mgo.Database) (set.Strings, error) {
780+
// Mostly pulled from mgo.DB.ListCollections
781+
names := set.NewStrings()
782+
var result struct {
783+
Collections []bson.Raw
784+
Cursor struct {
785+
FirstBatch []bson.Raw `bson:"firstBatch"`
786+
NextBatch []bson.Raw `bson:"nextBatch"`
787+
NS string `bson:"ns"`
788+
ID int64 `bson:"id"`
789+
}
790+
}
791+
err := db.Run(bson.D{{"listCollections", 1}, {"cursor", bson.D{{"batchSize", 10}}}}, &result)
781792
if err != nil {
782-
return false, errors.Trace(err)
793+
return nil, errors.Trace(err)
783794
}
784-
value, found := result["capped"]
785-
if !found {
786-
return false, nil
795+
firstBatch := result.Collections
796+
if firstBatch == nil {
797+
firstBatch = result.Cursor.FirstBatch
787798
}
788-
capped, ok := value.(bool)
789-
if !ok {
790-
return false, errors.Errorf("unexpected type for capped: %v", value)
799+
var iter *mgo.Iter
800+
ns := strings.SplitN(result.Cursor.NS, ".", 2)
801+
if len(ns) < 2 {
802+
iter = db.C("").NewIter(nil, firstBatch, result.Cursor.ID, nil)
803+
} else {
804+
iter = db.Session.DB(ns[0]).C(ns[1]).NewIter(nil, firstBatch, result.Cursor.ID, nil)
805+
}
806+
var coll struct {
807+
Name string `bson:"name"`
808+
Options struct {
809+
Capped bool `bson:"capped"`
810+
} `bson:"options"`
811+
}
812+
for iter.Next(&coll) {
813+
if coll.Options.Capped {
814+
names.Add(coll.Name)
815+
}
816+
}
817+
if err := iter.Close(); err != nil {
818+
return nil, errors.Trace(err)
791819
}
792-
return capped, nil
820+
return names, nil
793821
}
794822

795823
func clearNormalCollection(collection *mgo.Collection) error {

0 commit comments

Comments
 (0)