phoenix-firestorm/indra/llcorehttp/_httpoperation.h

286 lines
9.6 KiB
C++

/**
* @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_