forked from mongodb/mongo-tools
/
op.go
132 lines (112 loc) · 3.9 KB
/
op.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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// Copyright (C) MongoDB, Inc. 2014-present.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
package mongoreplay
import (
"fmt"
"io"
"github.com/10gen/llmgo"
)
// ErrNotMsg is returned if a provided buffer is too small to contain a Mongo message
var ErrNotMsg = fmt.Errorf("buffer is too small to be a Mongo message")
// OpMetadata stores metadata for an Op
type OpMetadata struct {
// Op represents the actual operation being performed accounting for write
// commands, so this may be "insert" or "update" even when the wire protocol
// message was OP_QUERY.
Op string
// Namespace against which the operation executes.
// If not applicable, will be blank.
Ns string
// Command name is the name of the command, when Op is "command" (otherwise
// will be blank.) For example, this might be "getLastError" or
// "serverStatus".
Command string
// Data contains the payload of the operation.
// For queries: the query selector, limit and sort, etc.
// For inserts: the document(s) to be inserted.
// For updates: the query selector, modifiers, and upsert/multi flags.
// For removes: the query selector for removes.
// For commands: the full set of parameters for the command.
// For killcursors: the list of cursorID's to be killed.
// For getmores: the cursorID for the getmore batch.
Data interface{}
}
// Op is a Mongo operation
type Op interface {
// OpCode returns the OpCode for a particular kind of op.
OpCode() OpCode
// FromReader extracts data from a serialized op into its concrete
// structure.
FromReader(io.Reader) error
// Execute performs the op on a given socket, yielding the reply when
// successful (and an error otherwise).
Execute(*mgo.MongoSocket) (Replyable, error)
// Meta returns metadata about the operation, useful for analysis of traffic.
Meta() OpMetadata
// Abbreviated returns a serialization of the op, abbreviated so it doesn't
// exceed the given number of characters.
Abbreviated(int) string
}
// cursorsRewriteable is an interface for any operation that has cursors
// that should be rewritten during live traffic playback.
type cursorsRewriteable interface {
getCursorIDs() ([]int64, error)
setCursorIDs([]int64) error
}
// Replyable is an interface representing any operation that has the
// functionality of a reply from a mongodb server. This includes both
// ReplyOps and CommandOpReplies.
type Replyable interface {
getCursorID() (int64, error)
Meta() OpMetadata
getLatencyMicros() int64
getNumReturned() int
getErrors() []error
}
// Preprocessable presents a way that for additional data processing to be done
// on an operation before execution. Future iterations may include options that
// allow differential preprocessing of operations depending on desired results.
type Preprocessable interface {
Preprocess()
}
// ErrUnknownOpcode is an error that represents an unrecognized opcode.
type ErrUnknownOpcode int
func (e ErrUnknownOpcode) Error() string {
return fmt.Sprintf("Unknown opcode %d", e)
}
// IsDriverOp checks if an operation is one of the types generated by the driver
// such as 'ismaster', or 'getnonce'. It takes an Op that has already been
// unmarshalled using its 'FromReader' method and checks if it is a command
// matching the ones the driver generates.
func IsDriverOp(op Op) bool {
var commandType string
var opType string
switch castOp := op.(type) {
case *QueryOp:
opType, commandType = extractOpType(castOp.QueryOp.Query)
if opType != "command" {
return false
}
case *CommandOp:
commandType = castOp.CommandName
default:
return false
}
switch commandType {
case "isMaster", "ismaster":
return true
case "getnonce":
return true
case "ping":
return true
case "saslStart":
return true
case "saslContinue":
return true
default:
return false
}
}