Permalink
Browse files

Catch "collection truncated" errors from Mongo 3.2

Running the mongo/oplog_test.go tests that truncate the oplog capped
collection against Mongo 3.2 sometimes produces the following error
instead of mgo.ErrCursor:

&mgo.QueryError{Code:17406, Message:"getMore executor error: OperationFailed: Operation aborted because: collection truncated", Assertion:false}
  • Loading branch information...
1 parent 3c95170 commit 61da79e198d15263579f717da21e0e5925da0f3b @babbageclunk committed May 25, 2016
Showing with 27 additions and 4 deletions.
  1. +27 −4 mongo/oplog.go
View
@@ -5,6 +5,7 @@ package mongo
import (
"reflect"
+ "strings"
"time"
"github.com/juju/errors"
@@ -13,6 +14,14 @@ import (
"launchpad.net/tomb"
)
+const (
+ // Used to identify a "collection truncated" error from Mongo -
+ // sometimes raised when we have an open cursor on a capped
+ // collection and the "emptycapped" command is run.
+ getMoreCode = 17406
+ truncatedMessage = "collection truncated"
+)
+
// OplogDoc represents a document in the oplog.rs collection.
// See: http://www.kchodorow.com/blog/2010/10/12/replication-internals/
//
@@ -216,20 +225,34 @@ func (t *OplogTailer) loop() error {
}
idsForLastTimestamp = append(idsForLastTimestamp, doc.OperationId)
} else {
- if err := iter.Err(); err != nil && err != mgo.ErrCursor {
+ if err := iter.Err(); err != nil && !isExpiredCursor(err) {
return err
}
if iter.Timeout() {
continue
}
- // No timeout and no error so cursor must have
- // expired. Force it to be recreated next loop by marking
- // it as nil.
+ // Either there's no error or the error is an expired
+ // cursor. Force recreating the iterator next loop by
+ // marking it as nil.
iter = nil
}
}
}
+func isExpiredCursor(err error) bool {
+ if err == mgo.ErrCursor {
+ return true
+ }
+ // Mongo 3.2 will return these errors when a capped collection is truncated.
+ // TODO(babbageclunk) - PR for mgo to raise a nicer one?
+ queryError, ok := err.(*mgo.QueryError)
+ if !ok {
+ return false
+ }
+ return queryError.Code == getMoreCode &&
+ strings.HasSuffix(queryError.Message, truncatedMessage)
+}
+
func isRealOplog(c *mgo.Collection) bool {
return c.Database.Name == "local" && c.Name == "oplog.rs"
}

0 comments on commit 61da79e

Please sign in to comment.