summaryrefslogtreecommitdiff
path: root/indra/llcorehttp/_httpoperation.h
blob: ff7efe60e99504773ede63429d44604150d411e4 (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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
/**
 * @file _httpoperation.h
 * @brief Internal declarations for HttpOperation and sub-classes
 *
 * $LicenseInfo:firstyear=2012&license=viewerlgpl$
 * Second Life Viewer Source Code
 * Copyright (C) 2012-2013, Linden Research, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License only.
 *
 * This library 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 GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 * $/LicenseInfo$
 */

#ifndef _LLCORE_HTTP_OPERATION_H_
#define _LLCORE_HTTP_OPERATION_H_


#include "httpcommon.h"
#include "httprequest.h"
#include "_mutex.h"

namespace LLCore
{

class HttpReplyQueue;
class HttpHandler;
class HttpService;

/// HttpOperation is the base class for all request/reply
/// pairs.
///
/// Operations are expected to be of two types:  immediate
/// and queued.  Immediate requests go to the singleton
/// request queue and when picked up by the worker thread
/// are executed immediately and there results placed on
/// the supplied reply queue.  Queued requests (namely for
/// HTTP operations), go to the request queue, are picked
/// up and moved to a ready queue where they're ordered by
/// priority and managed by the policy component, are
/// then activated issuing HTTP requests and moved to an
/// active list managed by the transport (libcurl) component
/// and eventually finalized when a response is available
/// and status and data return via reply queue.
///
/// To manage these transitions, derived classes implement
/// three methods:  stageFromRequest, stageFromReady and
/// stageFromActive.  Immediate requests will only override
/// stageFromRequest which will perform the operation and
/// return the result by invoking addAsReply() to put the
/// request on a reply queue.  Queued requests will involve
/// all three stage methods.
///
/// Threading:  not thread-safe.  Base and derived classes
/// provide no locking.  Instances move across threads
/// via queue-like interfaces that are thread compatible
/// and those interfaces establish the access rules.

class HttpOperation : private boost::noncopyable,
    public std::enable_shared_from_this<HttpOperation>
{
public:
    typedef std::shared_ptr<HttpOperation> ptr_t;
    typedef std::weak_ptr<HttpOperation> wptr_t;
    typedef std::shared_ptr<HttpReplyQueue> HttpReplyQueuePtr_t;

    /// Threading:  called by consumer thread.
    HttpOperation();

    /// Threading:  called by any thread.
    virtual ~HttpOperation();                           // Use release()


public:
    /// Register a reply queue and a handler for completion notifications.
    ///
    /// Invokers of operations that want to receive notification that an
    /// operation has been completed do so by binding a reply queue and
    /// a handler object to the request.
    ///
    /// @param  reply_queue     Pointer to the reply queue where completion
    ///                         notifications are to be queued (typically
    ///                         by addAsReply()).  This will typically be
    ///                         the reply queue referenced by the request
    ///                         object.  This method will increment the
    ///                         refcount on the queue holding the queue
    ///                         until delivery is complete.  Using a reply_queue
    ///                         even if the handler is NULL has some benefits
    ///                         for memory deallocation by keeping it in the
    ///                         originating thread.
    ///
    /// @param  handler         Possibly NULL pointer to a non-refcounted
    ////                        handler object to be invoked (onCompleted)
    ///                         when the operation is finished.  Note that
    ///                         the handler object is never dereferenced
    ///                         by the worker thread.  This is passible data
    ///                         until notification is performed.
    ///
    /// Threading:  called by consumer thread.
    ///
    void setReplyPath(HttpReplyQueuePtr_t reply_queue,
                      HttpHandler::ptr_t handler);

    /// The three possible staging steps in an operation's lifecycle.
    /// Asynchronous requests like HTTP operations move from the
    /// request queue to the ready queue via stageFromRequest.  Then
    /// from the ready queue to the active queue by stageFromReady.  And
    /// when complete, to the reply queue via stageFromActive and the
    /// addAsReply utility.
    ///
    /// Immediate mode operations (everything else) move from the
    /// request queue to the reply queue directly via stageFromRequest
    /// and addAsReply with no existence on the ready or active queues.
    ///
    /// These methods will take out a reference count on the request,
    /// caller only needs to dispose of its reference when done with
    /// the request.
    ///
    /// Threading:  called by worker thread.
    ///
    virtual void stageFromRequest(HttpService *);
    virtual void stageFromReady(HttpService *);
    virtual void stageFromActive(HttpService *);

    /// Delivers a notification to a handler object on completion.
    ///
    /// Once a request is complete and it has been removed from its
    /// reply queue, a handler notification may be delivered by a
    /// call to HttpRequest::update().  This method does the necessary
    /// dispatching.
    ///
    /// Threading:  called by consumer thread.
    ///
    virtual void visitNotifier(HttpRequest *);

    /// Cancels the operation whether queued or active.
    /// Final status of the request becomes canceled (an error) and
    /// that will be delivered to caller via notification scheme.
    ///
    /// Threading:  called by worker thread.
    ///
    virtual HttpStatus cancel();

    /// Retrieves a unique handle for this operation.
    HttpHandle getHandle();

    template< class OPT >
    static std::shared_ptr< OPT > fromHandle(HttpHandle handle)
    {
        ptr_t ptr = findByHandle(handle);
        if (!ptr)
            return std::shared_ptr< OPT >();
        return std::dynamic_pointer_cast< OPT >(ptr);
    }

protected:
    /// Delivers request to reply queue on completion.  After this
    /// call, worker thread no longer accesses the object and it
    /// is owned by the reply queue.
    ///
    /// Threading:  called by worker thread.
    ///
    void addAsReply();

protected:
    HttpReplyQueuePtr_t         mReplyQueue;
    HttpHandler::ptr_t          mUserHandler;

public:
    // Request Data
    HttpRequest::policy_t       mReqPolicy;

    // Reply Data
    HttpStatus                  mStatus;

    // Tracing, debug and metrics
    HttpTime                    mMetricCreated;
    int                         mTracing;

private:
    typedef std::map<HttpHandle, wptr_t>    handleMap_t;

    HttpHandle                  createHandle();
    void                        destroyHandle();
    HttpHandle                  mMyHandle;

    static handleMap_t          mHandleMap;
    static LLCoreInt::HttpMutex mOpMutex;

protected:
    static ptr_t                findByHandle(HttpHandle handle);


};  // end class HttpOperation


/// HttpOpStop requests the servicing thread to shutdown
/// operations, cease pulling requests from the request
/// queue and release shared resources (particularly
/// those shared via reference count).  The servicing
/// thread will then exit.  The underlying thread object
/// remains so that another thread can join on the
/// servicing thread prior to final cleanup.  The
/// request *does* generate a reply on the response
/// queue, if requested.

class HttpOpStop : public HttpOperation
{
public:
    HttpOpStop();

    virtual ~HttpOpStop();

private:
    HttpOpStop(const HttpOpStop &);                 // Not defined
    void operator=(const HttpOpStop &);             // Not defined

public:
    virtual void stageFromRequest(HttpService *);

};  // end class HttpOpStop


/// HttpOpNull is a do-nothing operation used for testing via
/// a basic loopback pattern.  It's executed immediately by
/// the servicing thread which bounces a reply back to the
/// caller without any further delay.

class HttpOpNull : public HttpOperation
{
public:
    HttpOpNull();

    virtual ~HttpOpNull();

private:
    HttpOpNull(const HttpOpNull &);                 // Not defined
    void operator=(const HttpOpNull &);             // Not defined

public:
    virtual void stageFromRequest(HttpService *);

};  // end class HttpOpNull


/// HttpOpSpin is a test-only request that puts the worker
/// thread into a cpu spin.  Used for unit tests and cleanup
/// evaluation.  You do not want to use this in production.
class HttpOpSpin : public HttpOperation
{
public:
    // 0 does a hard spin in the operation
    // 1 does a soft spin continuously requeuing itself
    HttpOpSpin(int mode);

    virtual ~HttpOpSpin();

private:
    HttpOpSpin(const HttpOpSpin &);                 // Not defined
    void operator=(const HttpOpSpin &);             // Not defined

public:
    virtual void stageFromRequest(HttpService *);

protected:
    int         mMode;
};  // end class HttpOpSpin


}   // end namespace LLCore

#endif  // _LLCORE_HTTP_OPERATION_H_