/
op_query.go
88 lines (77 loc) · 3.41 KB
/
op_query.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
package mongoproto
import (
"fmt"
"io"
"github.com/mongodb/mongo-tools/common/bsonutil"
"github.com/mongodb/mongo-tools/common/json"
"gopkg.in/mgo.v2/bson"
)
const (
_ OpQueryFlags = 1 << iota
OpQueryTailableCursor // Tailable means cursor is not closed when the last data is retrieved. Rather, the cursor marks the final object’s position. You can resume using the cursor later, from where it was located, if more data were received. Like any “latent cursor”, the cursor may become invalid at some point (CursorNotFound) – for example if the final object it references were deleted.
OpQuerySlaveOk // Allow query of replica slave. Normally these return an error except for namespace “local”.
OpQueryOplogReplay // Internal replication use only - driver should not set
OpQueryNoCursorTimeout // The server normally times out idle cursors after an inactivity period (10 minutes) to prevent excess memory use. Set this option to prevent that.
OpQueryAwaitData // Use with TailableCursor. If we are at the end of the data, block for a while rather than returning no data. After a timeout period, we do return as normal.
OpQueryExhaust // Stream the data down full blast in multiple “more” packages, on the assumption that the client will fully read all data queried. Faster when you are pulling a lot of data and know you want to pull it all down. Note: the client is not allowed to not read all the data unless it closes the connection.
OpQueryPartial // Get partial results from a mongos if some shards are down (instead of throwing an error)
)
type OpQueryFlags int32
// OpQuery is used to query the database for documents in a collection.
// http://docs.mongodb.org/meta-driver/latest/legacy/mongodb-wire-protocol/#op-query
type OpQuery struct {
Header MsgHeader
Flags OpQueryFlags
FullCollectionName string // "dbname.collectionname"
NumberToSkip int32 // number of documents to skip
NumberToReturn int32 // number of documents to return
Query []byte // query object
ReturnFieldsSelector []byte // Optional. Selector indicating the fields to return
}
func (op *OpQuery) String() string {
var query interface{}
if err := bson.Unmarshal(op.Query, &query); err != nil {
return "(error unmarshalling)"
}
queryAsJSON, err := bsonutil.ConvertBSONValueToJSON(query)
if err != nil {
return fmt.Sprintf("ConvertBSONValueToJSON err: %#v - %v", op, err)
}
asJSON, err := json.Marshal(queryAsJSON)
if err != nil {
return fmt.Sprintf("json marshal err: %#v - %v", op, err)
}
return fmt.Sprintf("OpQuery %v %v", op.FullCollectionName, string(asJSON))
}
func (op *OpQuery) OpCode() OpCode {
return OpCodeQuery
}
func (op *OpQuery) FromReader(r io.Reader) error {
var b [8]byte
if _, err := io.ReadFull(r, b[:4]); err != nil {
return err
}
op.Flags = OpQueryFlags(getInt32(b[:], 0))
name, err := readCStringFromReader(r)
if err != nil {
return err
}
op.FullCollectionName = string(name)
if _, err := io.ReadFull(r, b[:]); err != nil {
return err
}
op.NumberToSkip = getInt32(b[:], 0)
op.NumberToReturn = getInt32(b[:], 4)
op.Query, err = ReadDocument(r)
if err != nil {
return err
}
currentRead := len(op.Query) + len(op.FullCollectionName) + 1 + 12 + MsgHeaderLen
if int(op.Header.MessageLength) > currentRead {
op.ReturnFieldsSelector, err = ReadDocument(r)
if err != nil {
return err
}
}
return nil
}