summaryrefslogtreecommitdiff
path: root/src/mongo/db/query/find_common.h
blob: 45f60d2fd51d4aa0344a4cd282b6d7246bf4e0ab (plain)
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/**
 *    Copyright (C) 2018-present MongoDB, Inc.
 *
 *    This program is free software: you can redistribute it and/or modify
 *    it under the terms of the Server Side Public License, version 1,
 *    as published by MongoDB, Inc.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    Server Side Public License for more details.
 *
 *    You should have received a copy of the Server Side Public License
 *    along with this program. If not, see
 *    <http://www.mongodb.com/licensing/server-side-public-license>.
 *
 *    As a special exception, the copyright holders give permission to link the
 *    code of portions of this program with the OpenSSL library under certain
 *    conditions as described in each individual source file and distribute
 *    linked combinations including the program with the OpenSSL library. You
 *    must comply with the Server Side Public License in all respects for
 *    all of the code used other than as permitted herein. If you modify file(s)
 *    with this exception, you may extend this exception to your version of the
 *    file(s), but you are not obligated to do so. If you do not wish to do so,
 *    delete this exception statement from your version. If you delete this
 *    exception statement from all source files in the program, then also delete
 *    it in the license file.
 */

#include "mongo/bson/bsonobj.h"
#include "mongo/db/operation_context.h"
#include "mongo/util/fail_point.h"

namespace mongo {

/**
 * The state associated with tailable cursors.
 */
struct AwaitDataState {
    /**
     * The deadline for how long we wait on the tail of capped collection before returning IS_EOF.
     */
    Date_t waitForInsertsDeadline;

    /**
     * If true, when no results are available from a plan, then instead of returning immediately,
     * the system should wait up to the length of the operation deadline for data to be inserted
     * which causes results to become available.
     */
    bool shouldWaitForInserts;
};

extern const OperationContext::Decoration<AwaitDataState> awaitDataState;

class BSONObj;
class CanonicalQuery;
class FindCommandRequest;

// Failpoint for making find hang.
extern FailPoint waitInFindBeforeMakingBatch;

// Failpoint for making getMore not wait for an awaitdata cursor. Allows us to avoid waiting during
// tests.
extern FailPoint disableAwaitDataForGetMoreCmd;

// Enabling this fail point will cause getMores to busy wait after pinning the cursor
// but before we have started building the batch, until the fail point is disabled.
extern FailPoint waitAfterPinningCursorBeforeGetMoreBatch;

// Enabling this fail point will cause getMores to busy wait after setting up the plan executor and
// before beginning the batch.
extern FailPoint waitWithPinnedCursorDuringGetMoreBatch;

// Enabling this failpoint will cause getMores to wait just before it unpins its cursor after it
// has completed building the current batch.
extern FailPoint waitBeforeUnpinningOrDeletingCursorAfterGetMoreBatch;

// Enabling this failpoint will cause a getMore to fail with a specified exception after it has
// checked out its cursor and the originating command has been made available to CurOp.
extern FailPoint failGetMoreAfterCursorCheckout;

/**
 * Suite of find/getMore related functions used in both the mongod and mongos query paths.
 */
class FindCommon {
public:
    // The maximum amount of user data to return to a client in a single batch.
    //
    // This max may be exceeded by epsilon for output documents that approach the maximum user
    // document size. That is, if we must return a BSONObjMaxUserSize document, then the total
    // response size will be BSONObjMaxUserSize plus the amount of size required for the message
    // header and the cursor response "envelope". (The envolope contains namespace and cursor id
    // info.)
    static const size_t kMaxBytesToReturnToClientAtOnce;

    // The estimated amount of user data in a GetMore command response for a tailable cursor.
    // This amount will be used for memory pre-allocation in this type of requests.
    // Note: as this is an estimate, we request 1KB less than a full power of two, so that the
    // memory allocator will not jump to the next power of two once the envelope size is added in.
    static const size_t kTailableGetMoreReplyBufferSize;

    // The minimum document size we are prepared to consider when preallocating a reply buffer for
    // getMore requests. We use a combination of the batchSize and the the actual size of the first
    // document in the batch to compute the amount of bytes to preallocate. If the document size is
    // below this threshold, we calculate the reply buffer using this constant in order to avoid
    // under-allocating and having to grow the buffer again later.
    static const size_t kMinDocSizeForGetMorePreAllocation;

    // The initial size of the query response buffer.
    static const size_t kInitReplyBufferSize;

    /**
     * Returns true if the batchSize for the initial find has been satisfied.
     *
     * If 'qr' does not have a batchSize, the default batchSize is respected.
     */
    static bool enoughForFirstBatch(const FindCommandRequest& findCommand, long long numDocs);

    /**
     * Returns true if the batchSize for the getMore has been satisfied.
     *
     * An 'effectiveBatchSize' value of zero is interpreted as the absence of a batchSize, in which
     * case this method returns false.
     */
    static bool enoughForGetMore(long long effectiveBatchSize, long long numDocs) {
        return effectiveBatchSize && numDocs >= effectiveBatchSize;
    }

    /**
     * Given the number of docs ('numDocs') and bytes ('bytesBuffered') currently buffered as a
     * response to a cursor-generating command, returns true if there are enough remaining bytes in
     * our budget to fit 'nextDoc'.
     */
    static bool haveSpaceForNext(const BSONObj& nextDoc, long long numDocs, size_t bytesBuffered);

    /**
     * This function wraps waitWhileFailPointEnabled() on waitInFindBeforeMakingBatch.
     *
     * Since query processing happens in three different places, this function makes it easier to
     * check the failpoint for a query's namespace and log a helpful diagnostic message when the
     * failpoint is active.
     */
    static void waitInFindBeforeMakingBatch(OperationContext* opCtx, const CanonicalQuery& cq);

    /**
     * Computes an initial preallocation size for the GetMore reply buffer based on its properties.
     */
    static std::size_t getBytesToReserveForGetMoreReply(bool isTailable,
                                                        size_t firstResultSize,
                                                        size_t batchSize);
};

}  // namespace mongo