diff --git a/Documentation/ImplementorManual/HttpJob.md b/Documentation/ImplementorManual/HttpJob.md index d92498c5da..14c0e09193 100644 --- a/Documentation/ImplementorManual/HttpJob.md +++ b/Documentation/ImplementorManual/HttpJob.md @@ -95,6 +95,10 @@ Managing Async Results via HTTP {#HttpJobHttp} @anchor HttpJobPut @copydetails triagens::admin::RestJobHandler::putJob +@CLEARPAGE +@anchor HttpJobPutMethod +@copydetails triagens::admin::RestJobHandler::putJobMethod + @CLEARPAGE @anchor HttpJobDelete @copydetails triagens::admin::RestJobHandler::deleteJob diff --git a/Documentation/ImplementorManual/HttpJobTOC.md b/Documentation/ImplementorManual/HttpJobTOC.md index c291960af8..8e354fd23c 100644 --- a/Documentation/ImplementorManual/HttpJobTOC.md +++ b/Documentation/ImplementorManual/HttpJobTOC.md @@ -9,6 +9,7 @@ TOC {#HttpJobTOC} - @ref HttpJobOrder - @ref HttpJobHttp - @ref HttpJobPut "PUT /_api/job/job-id" + - @ref HttpJobPutMethod "PUT /_api/job/cancel/job-id" - @ref HttpJobDelete "DELETE /_api/job/job-id" - @ref HttpJobGetId "GET /_api/job/job-id" - @ref HttpJobGetType "GET /_api/job/job-type" diff --git a/arangod/Actions/RestActionHandler.cpp b/arangod/Actions/RestActionHandler.cpp index 459b4bf5ae..a759b0079d 100644 --- a/arangod/Actions/RestActionHandler.cpp +++ b/arangod/Actions/RestActionHandler.cpp @@ -49,7 +49,9 @@ RestActionHandler::RestActionHandler (HttpRequest* request, : RestVocbaseBaseHandler(request), _action(0), _queue(), - _allowed(false) { + _allowed(false), + _dataLock(), + _data(0) { _action = TRI_LookupActionVocBase(request); @@ -72,8 +74,8 @@ RestActionHandler::RestActionHandler (HttpRequest* request, _queue = data->_queue; } + // must have a queue if (_queue.empty()) { - // must have a queue _queue = "STANDARD"; } } @@ -158,6 +160,20 @@ HttpHandler::status_t RestActionHandler::execute () { } } +//////////////////////////////////////////////////////////////////////////////// +/// {@inheritDoc} +//////////////////////////////////////////////////////////////////////////////// + +bool RestActionHandler::cancel (bool running) { + if (running) { + return _action->cancel(&_dataLock, &_data); + } + else { + generateCanceled(); + return true; + } +} + // ----------------------------------------------------------------------------- // --SECTION-- private methods // ----------------------------------------------------------------------------- @@ -167,11 +183,15 @@ HttpHandler::status_t RestActionHandler::execute () { //////////////////////////////////////////////////////////////////////////////// TRI_action_result_t RestActionHandler::executeAction () { - TRI_action_result_t result = _action->execute(_vocbase, _request); + TRI_action_result_t result = _action->execute(_vocbase, _request, &_dataLock, &_data); if (result.isValid) { _response = result.response; } + else if (result.canceled) { + result.isValid = true; + generateCanceled(); + } else { result.isValid = true; generateNotImplemented(_action->_url); diff --git a/arangod/Actions/RestActionHandler.h b/arangod/Actions/RestActionHandler.h index 5269d84029..c8612ae6dc 100644 --- a/arangod/Actions/RestActionHandler.h +++ b/arangod/Actions/RestActionHandler.h @@ -105,6 +105,12 @@ namespace triagens { status_t execute (); +//////////////////////////////////////////////////////////////////////////////// +/// {@inheritDoc} +//////////////////////////////////////////////////////////////////////////////// + + bool cancel (bool running); + // ----------------------------------------------------------------------------- // --SECTION-- private methods // ----------------------------------------------------------------------------- @@ -140,6 +146,19 @@ namespace triagens { //////////////////////////////////////////////////////////////////////////////// bool _allowed; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief data lock +//////////////////////////////////////////////////////////////////////////////// + + basics::Mutex _dataLock; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief data for cancelation +//////////////////////////////////////////////////////////////////////////////// + + void* _data; + }; } } diff --git a/arangod/Actions/actions.h b/arangod/Actions/actions.h index 5f82ac9abb..c81b11dcdd 100644 --- a/arangod/Actions/actions.h +++ b/arangod/Actions/actions.h @@ -29,6 +29,7 @@ #define TRIAGENS_ACTIONS_ACTIONS_H 1 #include "Basics/Common.h" +#include "Basics/Mutex.h" // ----------------------------------------------------------------------------- // --SECTION-- forward declarations @@ -54,7 +55,7 @@ namespace triagens { class TRI_action_result_t { public: TRI_action_result_t () - : isValid(false), requeue(false), response(0), sleep(0.0) { + : isValid(false), requeue(false), canceled(false), response(0), sleep(0.0) { } // Please be careful here: In the beginning we had "bool requeue" after @@ -65,8 +66,10 @@ class TRI_action_result_t { // In this order it seems to work. // Details: v8-actions.cpp: v8_action_t::execute returns a TRI_action_result_t // to RestActionHandler::executeAction and suddenly requeue is true. + bool isValid; bool requeue; + bool canceled; triagens::rest::HttpResponse* response; @@ -85,7 +88,13 @@ class TRI_action_t { virtual ~TRI_action_t () {} - virtual TRI_action_result_t execute (struct TRI_vocbase_s*, triagens::rest::HttpRequest*) = 0; + virtual TRI_action_result_t execute (struct TRI_vocbase_s*, + triagens::rest::HttpRequest*, + triagens::basics::Mutex* dataLock, + void** data) = 0; + + virtual bool cancel (triagens::basics::Mutex* dataLock, + void** data) = 0; std::string _type; std::string _url; diff --git a/arangod/Cluster/RestShardHandler.cpp b/arangod/Cluster/RestShardHandler.cpp index 9214cebb7e..e7dfcc4c20 100644 --- a/arangod/Cluster/RestShardHandler.cpp +++ b/arangod/Cluster/RestShardHandler.cpp @@ -40,6 +40,7 @@ #include "GeneralServer/GeneralServer.h" using namespace triagens::arango; +using namespace triagens::rest; // ----------------------------------------------------------------------------- // --SECTION-- public constants @@ -60,12 +61,9 @@ const string RestShardHandler::QUEUE_NAME = "STANDARD"; //////////////////////////////////////////////////////////////////////////////// RestShardHandler::RestShardHandler (triagens::rest::HttpRequest* request, - void* data) + Dispatcher* data) : RestBaseHandler(request), - _dispatcher(0) { - - _dispatcher = static_cast(data); - + _dispatcher(data) { assert(_dispatcher != 0); } diff --git a/arangod/Cluster/RestShardHandler.h b/arangod/Cluster/RestShardHandler.h index 6283bac615..8360f6205c 100644 --- a/arangod/Cluster/RestShardHandler.h +++ b/arangod/Cluster/RestShardHandler.h @@ -45,7 +45,7 @@ namespace triagens { /// @brief shard control request handler //////////////////////////////////////////////////////////////////////////////// - class RestShardHandler : public triagens::admin::RestBaseHandler { + class RestShardHandler : public admin::RestBaseHandler { // ----------------------------------------------------------------------------- // --SECTION-- constructors and destructors @@ -57,8 +57,8 @@ namespace triagens { /// @brief constructor //////////////////////////////////////////////////////////////////////////////// - RestShardHandler (triagens::rest::HttpRequest* request, - void*); + RestShardHandler (rest::HttpRequest* request, + rest::Dispatcher*); // ----------------------------------------------------------------------------- // --SECTION-- Handler methods @@ -94,7 +94,7 @@ namespace triagens { /// @brief dispatcher //////////////////////////////////////////////////////////////////////////////// - triagens::rest::Dispatcher* _dispatcher; + rest::Dispatcher* _dispatcher; //////////////////////////////////////////////////////////////////////////////// /// @brief name of the queue diff --git a/arangod/Cluster/ServerJob.cpp b/arangod/Cluster/ServerJob.cpp index 90574b42cd..cef2f00bec 100644 --- a/arangod/Cluster/ServerJob.cpp +++ b/arangod/Cluster/ServerJob.cpp @@ -98,6 +98,14 @@ Job::status_t ServerJob::work () { return status_t(Job::JOB_FAILED); } +//////////////////////////////////////////////////////////////////////////////// +/// {@inheritDoc} +//////////////////////////////////////////////////////////////////////////////// + +bool ServerJob::cancel (bool running) { + return false; +} + // ----------------------------------------------------------------------------- // --SECTION-- private methods // ----------------------------------------------------------------------------- @@ -107,6 +115,7 @@ Job::status_t ServerJob::work () { //////////////////////////////////////////////////////////////////////////////// bool ServerJob::execute () { + // default to system database TRI_vocbase_t* vocbase = TRI_UseDatabaseServer(_server, TRI_VOC_SYSTEM_DATABASE); diff --git a/arangod/Cluster/ServerJob.h b/arangod/Cluster/ServerJob.h index 6376f5826b..49b93a1153 100644 --- a/arangod/Cluster/ServerJob.h +++ b/arangod/Cluster/ServerJob.h @@ -125,6 +125,12 @@ namespace triagens { Job::status_t work (); +//////////////////////////////////////////////////////////////////////////////// +/// {@inheritDoc} +//////////////////////////////////////////////////////////////////////////////// + + bool cancel (bool running); + //////////////////////////////////////////////////////////////////////////////// /// {@inheritDoc} //////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/RestServer/ArangoServer.cpp b/arangod/RestServer/ArangoServer.cpp index c5a60e369e..f01369e334 100644 --- a/arangod/RestServer/ArangoServer.cpp +++ b/arangod/RestServer/ArangoServer.cpp @@ -117,7 +117,7 @@ static void DefineApiHandlers (HttpHandlerFactory* factory, AsyncJobManager* jobManager) { // add "/version" handler - admin->addBasicHandlers(factory, "/_api", (void*) jobManager); + admin->addBasicHandlers(factory, "/_api", dispatcher->dispatcher(), jobManager); // add a upgrade warning factory->addPrefixHandler("/_msg/please-upgrade", @@ -150,8 +150,8 @@ static void DefineApiHandlers (HttpHandlerFactory* factory, #ifdef TRI_ENABLE_CLUSTER // add "/shard-comm" handler factory->addPrefixHandler("/_api/shard-comm", - RestHandlerCreator::createData, - (void*) dispatcher->dispatcher()); + RestHandlerCreator::createData, + dispatcher->dispatcher()); #endif } @@ -166,7 +166,7 @@ static void DefineAdminHandlers (HttpHandlerFactory* factory, ApplicationServer* applicationServer) { // add "/version" handler - admin->addBasicHandlers(factory, "/_admin", (void*) jobManager); + admin->addBasicHandlers(factory, "/_admin", dispatcher->dispatcher(), jobManager); // add "/_admin/shutdown" handler factory->addPrefixHandler("/_admin/shutdown", diff --git a/arangod/V8Server/ApplicationV8.cpp b/arangod/V8Server/ApplicationV8.cpp index 7e92f58267..4676a27c82 100644 --- a/arangod/V8Server/ApplicationV8.cpp +++ b/arangod/V8Server/ApplicationV8.cpp @@ -366,8 +366,6 @@ void ApplicationV8::exitContext (V8Context* context) { CONDITION_LOCKER(guard, _contextCondition); - context->handleGlobalContextMethods(); - // update data for later garbage collection TRI_v8_global_t* v8g = (TRI_v8_global_t*) context->_isolate->GetData(); context->_hasDeadObjects = v8g->_hasDeadObjects; @@ -376,6 +374,24 @@ void ApplicationV8::exitContext (V8Context* context) { // exit the context context->_context->Exit(); context->_isolate->Exit(); + + // try to execute new global context methods + bool runGlobal = false; + { + MUTEX_LOCKER(context->_globalMethodsLock); + runGlobal = ! context->_globalMethods.empty(); + } + + if (runGlobal) { + context->_isolate->Enter(); + context->_context->Enter(); + + context->handleGlobalContextMethods(); + + context->_context->Exit(); + context->_isolate->Exit(); + } + delete context->_locker; diff --git a/arangod/V8Server/V8PeriodicJob.cpp b/arangod/V8Server/V8PeriodicJob.cpp index 6b66126ae0..c964da54a2 100644 --- a/arangod/V8Server/V8PeriodicJob.cpp +++ b/arangod/V8Server/V8PeriodicJob.cpp @@ -56,7 +56,8 @@ V8PeriodicJob::V8PeriodicJob (TRI_vocbase_t* vocbase, _v8Dealer(v8Dealer), _module(module), _func(func), - _parameter(parameter) { + _parameter(parameter), + _canceled(0) { } // ----------------------------------------------------------------------------- @@ -85,6 +86,10 @@ const string& V8PeriodicJob::queue () { //////////////////////////////////////////////////////////////////////////////// Job::status_t V8PeriodicJob::work () { + if (_canceled) { + return status_t(JOB_DONE); + } + ApplicationV8::V8Context* context = _v8Dealer->enterContext(_vocbase, 0, true, false); @@ -118,6 +123,18 @@ Job::status_t V8PeriodicJob::work () { /// {@inheritDoc} //////////////////////////////////////////////////////////////////////////////// +bool V8PeriodicJob::cancel (bool running) { + if (running) { + _canceled = 1; + } + + return true; +} + +//////////////////////////////////////////////////////////////////////////////// +/// {@inheritDoc} +//////////////////////////////////////////////////////////////////////////////// + void V8PeriodicJob::cleanup () { delete this; } diff --git a/arangod/V8Server/V8PeriodicJob.h b/arangod/V8Server/V8PeriodicJob.h index d7fab40315..4b9bc7ddcd 100644 --- a/arangod/V8Server/V8PeriodicJob.h +++ b/arangod/V8Server/V8PeriodicJob.h @@ -84,6 +84,12 @@ namespace triagens { status_t work (); +//////////////////////////////////////////////////////////////////////////////// +/// {@inheritDoc} +//////////////////////////////////////////////////////////////////////////////// + + bool cancel (bool running); + //////////////////////////////////////////////////////////////////////////////// /// {@inheritDoc} //////////////////////////////////////////////////////////////////////////////// @@ -137,6 +143,12 @@ namespace triagens { //////////////////////////////////////////////////////////////////////////////// const std::string _parameter; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief cancel flag +//////////////////////////////////////////////////////////////////////////////// + + volatile sig_atomic_t _canceled; }; } } diff --git a/arangod/V8Server/v8-actions.cpp b/arangod/V8Server/v8-actions.cpp index 6ea3e521f4..3b916fe530 100644 --- a/arangod/V8Server/v8-actions.cpp +++ b/arangod/V8Server/v8-actions.cpp @@ -28,6 +28,7 @@ #include "v8-actions.h" #include "Actions/actions.h" +#include "Basics/MutexLocker.h" #include "Basics/ReadLocker.h" #include "Basics/StringUtils.h" #include "Basics/WriteLocker.h" @@ -38,8 +39,8 @@ #include "Dispatcher/ApplicationDispatcher.h" #include "Rest/HttpRequest.h" #include "Rest/HttpResponse.h" -#include "Scheduler/Scheduler.h" #include "Scheduler/ApplicationScheduler.h" +#include "Scheduler/Scheduler.h" #include "V8/v8-conv.h" #include "V8/v8-utils.h" #include "V8Server/ApplicationV8.h" @@ -117,7 +118,9 @@ class v8_action_t : public TRI_action_t { //////////////////////////////////////////////////////////////////////////////// v8_action_t (set const& contexts) - : TRI_action_t(contexts) { + : TRI_action_t(contexts), + _callbacks(), + _callbacksLock() { _type = "JAVASCRIPT"; } @@ -139,11 +142,13 @@ class v8_action_t : public TRI_action_t { } //////////////////////////////////////////////////////////////////////////////// -/// @brief executes the callback for a request +/// {@inheritDoc} //////////////////////////////////////////////////////////////////////////////// TRI_action_result_t execute (TRI_vocbase_t* vocbase, - HttpRequest* request) { + HttpRequest* request, + Mutex* dataLock, + void** data) { TRI_action_result_t result; // determine whether we should force a re-initialistion of the engine in development mode @@ -187,13 +192,56 @@ class v8_action_t : public TRI_action_t { } // and execute it + { + MUTEX_LOCKER(*dataLock); + + if (*data != 0) { + result.canceled = true; + + GlobalV8Dealer->exitContext(context); + + return result; + } + + *data = (void*) context->_isolate; + } + result = ExecuteActionVocbase(vocbase, context->_isolate, this, i->second, request); + { + MUTEX_LOCKER(*dataLock); + *data = 0; + } + GlobalV8Dealer->exitContext(context); return result; } +//////////////////////////////////////////////////////////////////////////////// +/// {@inheritDoc} +//////////////////////////////////////////////////////////////////////////////// + + bool cancel (Mutex* dataLock, void** data) { + { + MUTEX_LOCKER(*dataLock); + + // either we have not yet reached the execute above or we are already done + if (*data == 0) { + *data = (void*) 1; // mark as canceled + } + + // data is set, cancel the execution + else { + if (! v8::V8::IsExecutionTerminating((v8::Isolate*) *data)) { + v8::V8::TerminateExecution((v8::Isolate*) *data); + } + } + } + + return true; + } + private: //////////////////////////////////////////////////////////////////////////////// @@ -660,20 +708,26 @@ static TRI_action_result_t ExecuteActionVocbase (TRI_vocbase_t* vocbase, result.isValid = true; if (tryCatch.HasCaught()) { - v8::Handle exception = tryCatch.Exception(); - bool isSleepAndRequeue = v8g->SleepAndRequeueFuncTempl->HasInstance(exception); + if (tryCatch.CanContinue()) { + v8::Handle exception = tryCatch.Exception(); + bool isSleepAndRequeue = v8g->SleepAndRequeueFuncTempl->HasInstance(exception); - if (isSleepAndRequeue) { - result.requeue = true; - result.sleep = TRI_ObjectToDouble(exception->ToObject()->Get(v8g->SleepKey)); + if (isSleepAndRequeue) { + result.requeue = true; + result.sleep = TRI_ObjectToDouble(exception->ToObject()->Get(v8g->SleepKey)); + } + else { + string msg = TRI_StringifyV8Exception(&tryCatch); + + HttpResponse* response = new HttpResponse(HttpResponse::SERVER_ERROR, request->compatibility()); + response->body().appendText(msg); + + result.response = response; + } } else { - string msg = TRI_StringifyV8Exception(&tryCatch); - - HttpResponse* response = new HttpResponse(HttpResponse::SERVER_ERROR, request->compatibility()); - response->body().appendText(msg); - - result.response = response; + result.isValid = false; + result.canceled = true; } } diff --git a/js/apps/system/aardvark/frontend/js/bootstrap/errors.js b/js/apps/system/aardvark/frontend/js/bootstrap/errors.js index a9842301e6..3477937b60 100644 --- a/js/apps/system/aardvark/frontend/js/bootstrap/errors.js +++ b/js/apps/system/aardvark/frontend/js/bootstrap/errors.js @@ -36,6 +36,7 @@ "ERROR_LOCK_TIMEOUT" : { "code" : 18, "message" : "lock timeout" }, "ERROR_CANNOT_CREATE_DIRECTORY" : { "code" : 19, "message" : "cannot create directory" }, "ERROR_CANNOT_CREATE_TEMP_FILE" : { "code" : 20, "message" : "cannot create temporary file" }, + "ERROR_REQUEST_CANCELED" : { "code" : 21, "message" : "canceled request" }, "ERROR_HTTP_BAD_PARAMETER" : { "code" : 400, "message" : "bad parameter" }, "ERROR_HTTP_UNAUTHORIZED" : { "code" : 401, "message" : "unauthorized" }, "ERROR_HTTP_FORBIDDEN" : { "code" : 403, "message" : "forbidden" }, diff --git a/js/common/bootstrap/errors.js b/js/common/bootstrap/errors.js index a9842301e6..3477937b60 100644 --- a/js/common/bootstrap/errors.js +++ b/js/common/bootstrap/errors.js @@ -36,6 +36,7 @@ "ERROR_LOCK_TIMEOUT" : { "code" : 18, "message" : "lock timeout" }, "ERROR_CANNOT_CREATE_DIRECTORY" : { "code" : 19, "message" : "cannot create directory" }, "ERROR_CANNOT_CREATE_TEMP_FILE" : { "code" : 20, "message" : "cannot create temporary file" }, + "ERROR_REQUEST_CANCELED" : { "code" : 21, "message" : "canceled request" }, "ERROR_HTTP_BAD_PARAMETER" : { "code" : 400, "message" : "bad parameter" }, "ERROR_HTTP_UNAUTHORIZED" : { "code" : 401, "message" : "unauthorized" }, "ERROR_HTTP_FORBIDDEN" : { "code" : 403, "message" : "forbidden" }, diff --git a/lib/Admin/ApplicationAdminServer.cpp b/lib/Admin/ApplicationAdminServer.cpp index d4abb47f78..bf2939deaf 100644 --- a/lib/Admin/ApplicationAdminServer.cpp +++ b/lib/Admin/ApplicationAdminServer.cpp @@ -123,12 +123,15 @@ void ApplicationAdminServer::allowLogViewer () { void ApplicationAdminServer::addBasicHandlers (HttpHandlerFactory* factory, string const& prefix, - void* jobManager) { + Dispatcher* dispatcher, + AsyncJobManager* jobManager) { factory->addHandler(prefix + "/version", RestHandlerCreator::createNoData, 0); + pair* data = new pair(dispatcher, jobManager); + factory->addPrefixHandler(prefix + "/job", - RestHandlerCreator::createData, - jobManager); + RestHandlerCreator::createData< pair* >, + data); } //////////////////////////////////////////////////////////////////////////////// diff --git a/lib/Admin/ApplicationAdminServer.h b/lib/Admin/ApplicationAdminServer.h index 7f187669c0..08956c01bc 100644 --- a/lib/Admin/ApplicationAdminServer.h +++ b/lib/Admin/ApplicationAdminServer.h @@ -38,6 +38,7 @@ namespace triagens { namespace rest { class ApplicationServer; + class AsyncJobManager; class HttpHandlerFactory; class HttpResponse; class HttpRequest; @@ -119,7 +120,8 @@ namespace triagens { void addBasicHandlers (rest::HttpHandlerFactory*, string const &prefix, - void*); + rest::Dispatcher*, + rest::AsyncJobManager*); //////////////////////////////////////////////////////////////////////////////// /// @brief adds the http handlers for administration diff --git a/lib/Admin/RestBaseHandler.cpp b/lib/Admin/RestBaseHandler.cpp index 8a5172c892..0af025d976 100644 --- a/lib/Admin/RestBaseHandler.cpp +++ b/lib/Admin/RestBaseHandler.cpp @@ -113,6 +113,31 @@ void RestBaseHandler::generateResult (HttpResponse::HttpResponseCode code, } } +//////////////////////////////////////////////////////////////////////////////// +/// @brief generates a cancel message +//////////////////////////////////////////////////////////////////////////////// + +void RestBaseHandler::generateCanceled () { + TRI_json_t* json = TRI_CreateArrayJson(TRI_CORE_MEM_ZONE); + char* msg = TRI_DuplicateString("request canceled"); + + TRI_Insert3ArrayJson(TRI_CORE_MEM_ZONE, json, + "error", TRI_CreateBooleanJson(TRI_CORE_MEM_ZONE, true)); + + TRI_Insert3ArrayJson(TRI_CORE_MEM_ZONE, json, + "code", TRI_CreateNumberJson(TRI_CORE_MEM_ZONE, (int32_t) HttpResponse::REQUEST_TIMEOUT)); + + TRI_Insert3ArrayJson(TRI_CORE_MEM_ZONE, json, + "errorNum", TRI_CreateNumberJson(TRI_CORE_MEM_ZONE, (int32_t) TRI_ERROR_REQUEST_CANCELED)); + + TRI_Insert3ArrayJson(TRI_CORE_MEM_ZONE, json, + "errorMessage", TRI_CreateStringJson(TRI_CORE_MEM_ZONE, msg)); + + generateResult(HttpResponse::REQUEST_TIMEOUT, json); + + TRI_FreeJson(TRI_CORE_MEM_ZONE, json); +} + //////////////////////////////////////////////////////////////////////////////// /// @brief generates an error //////////////////////////////////////////////////////////////////////////////// diff --git a/lib/Admin/RestBaseHandler.h b/lib/Admin/RestBaseHandler.h index 145bd25ea5..97bd79b4da 100644 --- a/lib/Admin/RestBaseHandler.h +++ b/lib/Admin/RestBaseHandler.h @@ -121,6 +121,12 @@ namespace triagens { virtual void generateResult (rest::HttpResponse::HttpResponseCode, TRI_json_t const*); +//////////////////////////////////////////////////////////////////////////////// +/// @brief generates a cancel message +//////////////////////////////////////////////////////////////////////////////// + + virtual void generateCanceled (); + //////////////////////////////////////////////////////////////////////////////// /// @brief generates an error //////////////////////////////////////////////////////////////////////////////// diff --git a/lib/Admin/RestHandlerCreator.h b/lib/Admin/RestHandlerCreator.h index 489c2623ae..182a0bf368 100644 --- a/lib/Admin/RestHandlerCreator.h +++ b/lib/Admin/RestHandlerCreator.h @@ -5,7 +5,7 @@ /// /// DISCLAIMER /// -/// Copyright 2004-2013 triAGENS GmbH, Cologne, Germany +/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. @@ -22,7 +22,7 @@ /// Copyright holder is triAGENS GmbH, Cologne, Germany /// /// @author Dr. Frank Celler -/// @author Copyright 2010-2013, triAGENS GmbH, Cologne, Germany +/// @author Copyright 2010-2014, triAGENS GmbH, Cologne, Germany //////////////////////////////////////////////////////////////////////////////// #ifndef TRIAGENS_ADMIN_REST_HANDLER_CREATOR_H @@ -42,11 +42,6 @@ namespace triagens { // --SECTION-- class RestAdminBaseHandler // ----------------------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup RestServer -/// @{ -//////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// /// @brief creator function //////////////////////////////////////////////////////////////////////////////// @@ -54,19 +49,10 @@ namespace triagens { template class RestHandlerCreator : public H { -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - // ----------------------------------------------------------------------------- // --SECTION-- public static methods // ----------------------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup RestServer -/// @{ -//////////////////////////////////////////////////////////////////////////////// - public: //////////////////////////////////////////////////////////////////////////////// @@ -97,10 +83,6 @@ namespace triagens { } } -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - #endif // Local Variables: diff --git a/lib/Admin/RestJobHandler.cpp b/lib/Admin/RestJobHandler.cpp index 9e4b75bd38..17dcc5789d 100644 --- a/lib/Admin/RestJobHandler.cpp +++ b/lib/Admin/RestJobHandler.cpp @@ -5,7 +5,7 @@ /// /// DISCLAIMER /// -/// Copyright 2004-2013 triAGENS GmbH, Cologne, Germany +/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. @@ -22,7 +22,7 @@ /// Copyright holder is triAGENS GmbH, Cologne, Germany /// /// @author Jan Steemann -/// @author Copyright 2010-2013, triAGENS GmbH, Cologne, Germany +/// @author Copyright 2010-2014, triAGENS GmbH, Cologne, Germany //////////////////////////////////////////////////////////////////////////////// #include "RestJobHandler.h" @@ -30,6 +30,7 @@ #include "Basics/StringUtils.h" #include "BasicsC/conversions.h" #include "BasicsC/tri-strings.h" +#include "Dispatcher/Dispatcher.h" #include "HttpServer/AsyncJobManager.h" #include "Rest/HttpRequest.h" #include "Rest/HttpResponse.h" @@ -46,45 +47,28 @@ using namespace std; //////////////////////////////////////////////////////////////////////////////// /// @brief name of the queue //////////////////////////////////////////////////////////////////////////////// - -const string RestJobHandler::QUEUE_NAME = "STANDARD"; -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// +const string RestJobHandler::QUEUE_NAME = "STANDARD"; // ----------------------------------------------------------------------------- // --SECTION-- constructors and destructors // ----------------------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup RestServer -/// @{ -//////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// /// @brief constructor //////////////////////////////////////////////////////////////////////////////// -RestJobHandler::RestJobHandler (HttpRequest* request, void* data) - : RestBaseHandler(request) { - - _jobManager = static_cast(data); +RestJobHandler::RestJobHandler (HttpRequest* request, + pair* data) + : RestBaseHandler(request), + _dispatcher(data->first), + _jobManager(data->second) { } -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - // ----------------------------------------------------------------------------- // --SECTION-- Handler methods // ----------------------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup RestServer -/// @{ -//////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// /// {@inheritDoc} //////////////////////////////////////////////////////////////////////////////// @@ -106,6 +90,7 @@ string const& RestJobHandler::queue () const { //////////////////////////////////////////////////////////////////////////////// HttpHandler::status_t RestJobHandler::execute () { + // extract the sub-request type HttpRequest::HttpRequestType type = _request->requestType(); @@ -113,7 +98,17 @@ HttpHandler::status_t RestJobHandler::execute () { getJob(); } else if (type == HttpRequest::HTTP_REQUEST_PUT) { - putJob(); + const vector& suffix = _request->suffix(); + + if (suffix.size() == 1) { + putJob(); + } + else if (suffix.size() == 2) { + putJobMethod(); + } + else { + generateError(HttpResponse::BAD, TRI_ERROR_HTTP_BAD_PARAMETER); + } } else if (type == HttpRequest::HTTP_REQUEST_DELETE) { deleteJob(); @@ -125,19 +120,10 @@ HttpHandler::status_t RestJobHandler::execute () { return status_t(HANDLER_DONE); } -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - // ----------------------------------------------------------------------------- // --SECTION-- private methods // ----------------------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup RestServer -/// @{ -//////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// /// @brief fetches a job result and removes it from the queue /// @@ -147,7 +133,7 @@ HttpHandler::status_t RestJobHandler::execute () { /// /// @RESTURLPARAM{job-id,string,required} /// The async job id. -/// +/// /// @RESTDESCRIPTION /// Returns the result of an async job identified by `job-id`. /// If the async job result is present on the server, the result will be removed @@ -155,7 +141,7 @@ HttpHandler::status_t RestJobHandler::execute () { /// `job-id` once. /// /// The method will return the original job result's headers and body, plus -/// the additional HTTP header `x-arango-async-job-id`. If this header is +/// the additional HTTP header `x-arango-async-job-id`. If this header is /// present, then the job was found and the response contains the original job's /// result. If the header is not present, the job was not found and the response /// contains status information from the job amanger. @@ -170,15 +156,15 @@ HttpHandler::status_t RestJobHandler::execute () { /// @RESTRETURNCODE{204} /// is returned if the job requested via `job-id` is still in the queue of /// pending (or not yet finished) jobs. In this case, no `x-arango-async-id` -/// HTTP header will be returned. +/// HTTP header will be returned. /// /// @RESTRETURNCODE{400} /// is returned if no `job-id` was specified in the request. In this case, no /// `x-arango-async-id` HTTP header will be returned. /// /// @RESTRETURNCODE{404} -/// is returned if the job was not found or already deleted or fetched from the -/// job result list. In this case, no `x-arango-async-id` HTTP header will be +/// is returned if the job was not found or already deleted or fetched from the +/// job result list. In this case, no `x-arango-async-id` HTTP header will be /// returned. /// /// @EXAMPLES @@ -187,9 +173,9 @@ HttpHandler::status_t RestJobHandler::execute () { /// /// @EXAMPLE_ARANGOSH_RUN{RestJobHandlerPutNone} /// var url = "/_api/job/"; -/// +/// /// var response = logCurlRequest('PUT', url, ""); -/// +/// /// assert(response.code === 400); /// logRawResponse(response); /// @END_EXAMPLE_ARANGOSH_RUN @@ -198,9 +184,9 @@ HttpHandler::status_t RestJobHandler::execute () { /// /// @EXAMPLE_ARANGOSH_RUN{RestJobHandlerPutInvalid} /// var url = "/_api/job/foobar"; -/// +/// /// var response = logCurlRequest('PUT', url, ""); -/// +/// /// assert(response.code === 404); /// logRawResponse(response); /// @END_EXAMPLE_ARANGOSH_RUN @@ -209,9 +195,9 @@ HttpHandler::status_t RestJobHandler::execute () { /// /// @EXAMPLE_ARANGOSH_RUN{RestJobHandlerPutGet} /// var url = "/_api/version"; -/// +/// /// var response = logCurlRequest('GET', url, "", { "x-arango-async": "store" }); -/// +/// /// assert(response.code === 202); /// logRawResponse(response); /// @@ -228,9 +214,9 @@ HttpHandler::status_t RestJobHandler::execute () { /// /// @EXAMPLE_ARANGOSH_RUN{RestJobHandlerPutFail} /// var url = "/_api/collection"; -/// +/// /// var response = logCurlRequest('POST', url, '{"name":" this name is invalid "}', { "x-arango-async": "store" }); -/// +/// /// assert(response.code === 202); /// logRawResponse(response); /// @@ -242,16 +228,10 @@ HttpHandler::status_t RestJobHandler::execute () { /// assert(response.headers['x-arango-async-id'] === id); /// logRawResponse(response); /// @END_EXAMPLE_ARANGOSH_RUN -/////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// void RestJobHandler::putJob () { - const vector suffix = _request->suffix(); - - if (suffix.size() != 1) { - generateError(HttpResponse::BAD, TRI_ERROR_HTTP_BAD_PARAMETER); - return; - } - + const vector& suffix = _request->suffix(); const string& value = suffix[0]; uint64_t jobId = StringUtils::uint64(value); @@ -263,7 +243,7 @@ void RestJobHandler::putJob () { generateError(HttpResponse::NOT_FOUND, TRI_ERROR_HTTP_NOT_FOUND); return; } - + if (status == AsyncJobResult::JOB_PENDING) { // job is still pending _response = createResponse(HttpResponse::NO_CONTENT); @@ -279,18 +259,80 @@ void RestJobHandler::putJob () { } // return the original response - _response = response; + _response = response; + // plus a new header _response->setHeader("x-arango-async-id", value); } +//////////////////////////////////////////////////////////////////////////////// +/// @brief cancels an async job +/// +/// @RESTHEADER{PUT /_api/job/cancel/`job-id`,Cancels an async job} +/// +/// @RESTURLPARAMETERS +/// +/// @RESTURLPARAM{job-id,string,required} +/// The async job id. +/// +/// @RESTDESCRIPTION +/// Cancels the currently runing job identified by `job-id`. Note that it still +/// might take some time to actually cancel the running async job. +/// +/// @RESTRETURNCODES +/// +/// Any HTTP status code might be returned by this method. To tell the original +/// job response from a job manager response apart, check for the HTTP header +/// `x-arango-async-id`. If it is present, the response contains the original +/// job's result. Otherwise the response is from the job manager. +/// +/// @RESTRETURNCODE{200} +/// cancel has been initiated. +/// +/// @RESTRETURNCODE{400} +/// is returned if no `job-id` was specified in the request. In this case, no +/// `x-arango-async-id` HTTP header will be returned. +/// +/// @RESTRETURNCODE{404} +/// is returned if the job was not found or already deleted or fetched from the +/// job result list. In this case, no `x-arango-async-id` HTTP header will be +/// returned. +//////////////////////////////////////////////////////////////////////////////// + +void RestJobHandler::putJobMethod () { + const vector& suffix = _request->suffix(); + const string& method = suffix[0]; + const string& value = suffix[1]; + uint64_t jobId = StringUtils::uint64(value); + + if (method == "cancel") { + bool status = _dispatcher->cancelJob(jobId); + + // unknown or already fetched job + if (! status) { + generateError(HttpResponse::NOT_FOUND, TRI_ERROR_HTTP_NOT_FOUND); + } + else { + TRI_json_t* json = TRI_CreateArrayJson(TRI_CORE_MEM_ZONE); + + TRI_Insert3ArrayJson(TRI_CORE_MEM_ZONE, json, "result", TRI_CreateBooleanJson(TRI_CORE_MEM_ZONE, true)); + generateResult(json); + TRI_FreeJson(TRI_CORE_MEM_ZONE, json); + } + return; + } + else { + generateError(HttpResponse::BAD, TRI_ERROR_HTTP_BAD_PARAMETER); + } +} + //////////////////////////////////////////////////////////////////////////////// /// @brief trampoline function for HTTP GET requests //////////////////////////////////////////////////////////////////////////////// void RestJobHandler::getJob () { const vector suffix = _request->suffix(); - + if (suffix.size() != 1) { generateError(HttpResponse::BAD, TRI_ERROR_HTTP_BAD_PARAMETER); return; @@ -328,14 +370,14 @@ void RestJobHandler::getJob () { /// /// @RESTRETURNCODE{204} /// is returned if the job requested via `job-id` is still in the queue of -/// pending (or not yet finished) jobs. +/// pending (or not yet finished) jobs. /// /// @RESTRETURNCODE{400} -/// is returned if no `job-id` was specified in the request. +/// is returned if no `job-id` was specified in the request. /// /// @RESTRETURNCODE{404} -/// is returned if the job was not found or already deleted or fetched from the -/// job result list. +/// is returned if the job was not found or already deleted or fetched from the +/// job result list. /// /// @EXAMPLES /// @@ -343,9 +385,9 @@ void RestJobHandler::getJob () { /// /// @EXAMPLE_ARANGOSH_RUN{RestJobHandlerGetIdDone} /// var url = "/_api/version"; -/// +/// /// var response = logCurlRequest('GET', url, "", { "x-arango-async": "store" }); -/// +/// /// assert(response.code === 202); /// var id = response.headers['x-arango-async-id']; /// logRawResponse(response); @@ -364,9 +406,9 @@ void RestJobHandler::getJob () { /// /// @EXAMPLE_ARANGOSH_RUN{RestJobHandlerGetIdPending} /// var url = "/_admin/sleep?duration=3"; -/// +/// /// var response = logCurlRequest('GET', url, "", { "x-arango-async": "store" }); -/// +/// /// assert(response.code === 202); /// var id = response.headers['x-arango-async-id']; /// logRawResponse(response); @@ -377,7 +419,7 @@ void RestJobHandler::getJob () { /// /// response = curlRequest('DELETE', "/_api/job/" + id); /// @END_EXAMPLE_ARANGOSH_RUN -/////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// void RestJobHandler::getJobId (std::string const& value) { uint64_t jobId = StringUtils::uint64(value); @@ -391,13 +433,13 @@ void RestJobHandler::getJobId (std::string const& value) { generateError(HttpResponse::NOT_FOUND, TRI_ERROR_HTTP_NOT_FOUND); return; } - + if (status == AsyncJobResult::JOB_PENDING) { // job is still pending _response = createResponse(HttpResponse::NO_CONTENT); return; } - + _response = createResponse(HttpResponse::OK); } @@ -409,7 +451,7 @@ void RestJobHandler::getJobId (std::string const& value) { /// @RESTURLPARAMETERS /// /// @RESTURLPARAM{type,string,required} -/// The type of jobs to return. The type can be either `done` or `pending`. +/// The type of jobs to return. The type can be either `done` or `pending`. /// Setting the type to `done` will make the method return the ids of already /// completed async jobs for which results can be fetched. /// Setting the type to `pending` will return the ids of not yet finished @@ -420,7 +462,7 @@ void RestJobHandler::getJobId (std::string const& value) { /// @RESTQUERYPARAM{count,number,optional} /// The maximum number of ids to return per call. If not specified, a server-defined /// maximum value will be used. -/// +/// /// @RESTDESCRIPTION /// Returns the list of ids of async jobs with a specific status (either done /// or pending). The list can be used by the client to get an overview of the @@ -441,9 +483,9 @@ void RestJobHandler::getJobId (std::string const& value) { /// /// @EXAMPLE_ARANGOSH_RUN{RestJobHandlerGetDone} /// var url = "/_api/version"; -/// +/// /// var response = logCurlRequest('GET', url, "", { "x-arango-async": "store" }); -/// +/// /// assert(response.code === 202); /// logRawResponse(response); /// @@ -461,9 +503,9 @@ void RestJobHandler::getJobId (std::string const& value) { /// /// @EXAMPLE_ARANGOSH_RUN{RestJobHandlerGetPending} /// var url = "/_api/version"; -/// +/// /// var response = logCurlRequest('GET', url, "", { "x-arango-async": "store" }); -/// +/// /// assert(response.code === 202); /// logRawResponse(response); /// @@ -477,7 +519,7 @@ void RestJobHandler::getJobId (std::string const& value) { /// response = curlRequest('DELETE', "/_api/job/all"); /// assert(response.code === 200); /// @END_EXAMPLE_ARANGOSH_RUN -/////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// void RestJobHandler::getJobType (std::string const& type) { size_t count = 100; @@ -510,7 +552,7 @@ void RestJobHandler::getJobType (std::string const& type) { TRI_PushBack3ListJson(TRI_CORE_MEM_ZONE, json, TRI_CreateStringJson(TRI_CORE_MEM_ZONE, idString)); } - + generateResult(json); TRI_FreeJson(TRI_CORE_MEM_ZONE, json); } @@ -528,7 +570,7 @@ void RestJobHandler::getJobType (std::string const& type) { /// /// @RESTURLPARAM{type,string,required} /// The type of jobs to delete. `type` can be: -/// - `all`: deletes all jobs results. Currently executing or queued async jobs +/// - `all`: deletes all jobs results. Currently executing or queued async jobs /// will not be stopped by this call. /// - `expired`: deletes expired results. To determine the expiration status of /// a result, pass the `stamp` URL parameter. `stamp` needs to be a UNIX @@ -542,10 +584,10 @@ void RestJobHandler::getJobType (std::string const& type) { /// /// @RESTQUERYPARAM{stamp,number,optional} /// A UNIX timestamp specifying the expiration threshold when type is `expired`. -/// +/// /// @RESTDESCRIPTION -/// Deletes either all job results, expired job results, or the result of a -/// specific job. Clients can use this method to perform an eventual garbage +/// Deletes either all job results, expired job results, or the result of a +/// specific job. Clients can use this method to perform an eventual garbage /// collection of job results. /// /// @RESTRETURNCODES @@ -567,9 +609,9 @@ void RestJobHandler::getJobType (std::string const& type) { /// /// @EXAMPLE_ARANGOSH_RUN{RestJobHandlerDeleteAll} /// var url = "/_api/version"; -/// +/// /// var response = logCurlRequest('GET', url, "", { "x-arango-async": "store" }); -/// +/// /// assert(response.code === 202); /// logRawResponse(response); /// @@ -584,9 +626,9 @@ void RestJobHandler::getJobType (std::string const& type) { /// /// @EXAMPLE_ARANGOSH_RUN{RestJobHandlerDeleteExpired} /// var url = "/_api/version"; -/// +/// /// var response = logCurlRequest('GET', url, "", { "x-arango-async": "store" }); -/// +/// /// assert(response.code === 202); /// logRawResponse(response); /// @@ -602,9 +644,9 @@ void RestJobHandler::getJobType (std::string const& type) { /// /// @EXAMPLE_ARANGOSH_RUN{RestJobHandlerDeleteId} /// var url = "/_api/version"; -/// +/// /// var response = logCurlRequest('GET', url, "", { "x-arango-async": "store" }); -/// +/// /// assert(response.code === 202); /// logRawResponse(response); /// @@ -623,7 +665,7 @@ void RestJobHandler::getJobType (std::string const& type) { /// assert(response.code === 404); /// logJsonResponse(response); /// @END_EXAMPLE_ARANGOSH_RUN -/////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// void RestJobHandler::deleteJob () { const vector suffix = _request->suffix(); @@ -632,7 +674,7 @@ void RestJobHandler::deleteJob () { generateError(HttpResponse::BAD, TRI_ERROR_HTTP_BAD_PARAMETER); return; } - + const string& value = suffix[0]; if (value == "all") { @@ -654,7 +696,7 @@ void RestJobHandler::deleteJob () { uint64_t jobId = StringUtils::uint64(value); bool found = _jobManager->deleteJobResult(jobId); - + if (! found) { generateError(HttpResponse::NOT_FOUND, TRI_ERROR_HTTP_NOT_FOUND); return; @@ -665,7 +707,7 @@ void RestJobHandler::deleteJob () { if (json != 0) { TRI_Insert3ArrayJson(TRI_CORE_MEM_ZONE, json, "result", TRI_CreateBooleanJson(TRI_CORE_MEM_ZONE, true)); - + generateResult(json); TRI_FreeJson(TRI_CORE_MEM_ZONE, json); } @@ -674,10 +716,6 @@ void RestJobHandler::deleteJob () { } } -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - // Local Variables: // mode: outline-minor // outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|/// @page\\|// --SECTION--\\|/// @\\}" diff --git a/lib/Admin/RestJobHandler.h b/lib/Admin/RestJobHandler.h index 51d446ae7f..be40adbe1a 100644 --- a/lib/Admin/RestJobHandler.h +++ b/lib/Admin/RestJobHandler.h @@ -5,7 +5,7 @@ /// /// DISCLAIMER /// -/// Copyright 2004-2013 triAGENS GmbH, Cologne, Germany +/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. @@ -22,7 +22,7 @@ /// Copyright holder is triAGENS GmbH, Cologne, Germany /// /// @author Jan Steemann -/// @author Copyright 2010-2013, triAGENS GmbH, Cologne, Germany +/// @author Copyright 2010-2014, triAGENS GmbH, Cologne, Germany //////////////////////////////////////////////////////////////////////////////// #ifndef TRIAGENS_ADMIN_REST_JOB_HANDLER_H @@ -34,6 +34,7 @@ namespace triagens { namespace rest { class AsyncJobManager; + class Dispatcher; } namespace admin { @@ -42,51 +43,29 @@ namespace triagens { // --SECTION-- class RestJobHandler // ----------------------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup RestServer -/// @{ -//////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// /// @brief job control request handler //////////////////////////////////////////////////////////////////////////////// class RestJobHandler : public RestBaseHandler { -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - // ----------------------------------------------------------------------------- // --SECTION-- constructors and destructors // ----------------------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup RestServer -/// @{ -//////////////////////////////////////////////////////////////////////////////// - public: //////////////////////////////////////////////////////////////////////////////// /// @brief constructor //////////////////////////////////////////////////////////////////////////////// - RestJobHandler (rest::HttpRequest* request, void*); - -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// + RestJobHandler (rest::HttpRequest* request, + pair*); // ----------------------------------------------------------------------------- // --SECTION-- Handler methods // ----------------------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup RestServer -/// @{ -//////////////////////////////////////////////////////////////////////////////// - public: //////////////////////////////////////////////////////////////////////////////// @@ -107,25 +86,22 @@ namespace triagens { status_t execute (); -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - // ----------------------------------------------------------------------------- // --SECTION-- private methods // ----------------------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup RestServer -/// @{ -//////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// /// @brief put handler //////////////////////////////////////////////////////////////////////////////// void putJob (); +//////////////////////////////////////////////////////////////////////////////// +/// @brief put method handler +//////////////////////////////////////////////////////////////////////////////// + + void putJobMethod (); + //////////////////////////////////////////////////////////////////////////////// /// @brief get handler //////////////////////////////////////////////////////////////////////////////// @@ -150,26 +126,23 @@ namespace triagens { void deleteJob (); -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - // ----------------------------------------------------------------------------- // --SECTION-- private variables // ----------------------------------------------------------------------------- + private: + //////////////////////////////////////////////////////////////////////////////// -/// @addtogroup RestServer -/// @{ +/// @brief dispatcher //////////////////////////////////////////////////////////////////////////////// - private: + rest::Dispatcher* _dispatcher; //////////////////////////////////////////////////////////////////////////////// /// @brief async job manager //////////////////////////////////////////////////////////////////////////////// - AsyncJobManager* _jobManager; + rest::AsyncJobManager* _jobManager; //////////////////////////////////////////////////////////////////////////////// /// @brief name of the queue @@ -177,18 +150,10 @@ namespace triagens { static const std::string QUEUE_NAME; -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - }; } } -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - #endif // Local Variables: diff --git a/lib/BasicsC/errors.dat b/lib/BasicsC/errors.dat index 38cfaf6c67..d8e27d90ca 100755 --- a/lib/BasicsC/errors.dat +++ b/lib/BasicsC/errors.dat @@ -23,6 +23,7 @@ ERROR_TYPE_ERROR,17,"type error","Will be raised when a type error is unencounte ERROR_LOCK_TIMEOUT,18,"lock timeout","Will be raised when there's a timeout waiting for a lock." ERROR_CANNOT_CREATE_DIRECTORY,19,"cannot create directory","Will be raised when an attempt to create a directory fails." ERROR_CANNOT_CREATE_TEMP_FILE,20,"cannot create temporary file","Will be raised when an attempt to create a temporary file fails." +ERROR_REQUEST_CANCELED,21,"canceled request","Will be raised when a request is canceled by the user." ################################################################################ ## HTTP standard errors diff --git a/lib/BasicsC/voc-errors.c b/lib/BasicsC/voc-errors.c index ca7e7f5469..17d4c451af 100644 --- a/lib/BasicsC/voc-errors.c +++ b/lib/BasicsC/voc-errors.c @@ -32,6 +32,7 @@ void TRI_InitialiseErrorMessages (void) { REG_ERROR(ERROR_LOCK_TIMEOUT, "lock timeout"); REG_ERROR(ERROR_CANNOT_CREATE_DIRECTORY, "cannot create directory"); REG_ERROR(ERROR_CANNOT_CREATE_TEMP_FILE, "cannot create temporary file"); + REG_ERROR(ERROR_REQUEST_CANCELED, "canceled request"); REG_ERROR(ERROR_HTTP_BAD_PARAMETER, "bad parameter"); REG_ERROR(ERROR_HTTP_UNAUTHORIZED, "unauthorized"); REG_ERROR(ERROR_HTTP_FORBIDDEN, "forbidden"); diff --git a/lib/BasicsC/voc-errors.h b/lib/BasicsC/voc-errors.h index b105ea150d..1921c39cc7 100644 --- a/lib/BasicsC/voc-errors.h +++ b/lib/BasicsC/voc-errors.h @@ -53,6 +53,8 @@ extern "C" { /// Will be raised when an attempt to create a directory fails. /// - 20: @LIT{cannot create temporary file} /// Will be raised when an attempt to create a temporary file fails. +/// - 21: @LIT{canceled request} +/// Will be raised when a request is canceled by the user. /// - 400: @LIT{bad parameter} /// Will be raised when the HTTP request does not fulfill the requirements. /// - 401: @LIT{unauthorized} @@ -717,6 +719,16 @@ void TRI_InitialiseErrorMessages (void); #define TRI_ERROR_CANNOT_CREATE_TEMP_FILE (20) +//////////////////////////////////////////////////////////////////////////////// +/// @brief 21: ERROR_REQUEST_CANCELED +/// +/// canceled request +/// +/// Will be raised when a request is canceled by the user. +//////////////////////////////////////////////////////////////////////////////// + +#define TRI_ERROR_REQUEST_CANCELED (21) + //////////////////////////////////////////////////////////////////////////////// /// @brief 400: ERROR_HTTP_BAD_PARAMETER /// diff --git a/lib/Dispatcher/Dispatcher.cpp b/lib/Dispatcher/Dispatcher.cpp index 32f5e54b0e..eccd8e3f76 100644 --- a/lib/Dispatcher/Dispatcher.cpp +++ b/lib/Dispatcher/Dispatcher.cpp @@ -157,14 +157,29 @@ bool Dispatcher::addJob (Job* job) { // add the job to the list of ready jobs if (! queue->addJob(job)) { - // queue full etc. - return false; + return false; // queue full etc. } // indicate success, BUT never access job after it has been added to the queue return true; } +//////////////////////////////////////////////////////////////////////////////// +/// @brief tries to cancel a job +//////////////////////////////////////////////////////////////////////////////// + +bool Dispatcher::cancelJob (uint64_t jobId) { + bool done = false; + + for (map::iterator i = _queues.begin(); i != _queues.end() && ! done; ++i) { + DispatcherQueue* q = i->second; + + done = q->cancelJob(jobId); + } + + return done; +} + //////////////////////////////////////////////////////////////////////////////// /// @brief start the dispatcher //////////////////////////////////////////////////////////////////////////////// @@ -281,7 +296,6 @@ void Dispatcher::reportStatus () { // --SECTION-- protected methods // ----------------------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// /// @brief looks up a queue //////////////////////////////////////////////////////////////////////////////// diff --git a/lib/Dispatcher/Dispatcher.h b/lib/Dispatcher/Dispatcher.h index 8ecb81fb47..cd5f5cff7d 100644 --- a/lib/Dispatcher/Dispatcher.h +++ b/lib/Dispatcher/Dispatcher.h @@ -139,6 +139,12 @@ namespace triagens { bool addJob (Job*); +//////////////////////////////////////////////////////////////////////////////// +/// @brief tries to cancel a job +//////////////////////////////////////////////////////////////////////////////// + + bool cancelJob (uint64_t); + //////////////////////////////////////////////////////////////////////////////// /// @brief starts the dispatcher //////////////////////////////////////////////////////////////////////////////// diff --git a/lib/Dispatcher/DispatcherQueue.cpp b/lib/Dispatcher/DispatcherQueue.cpp index 62ec89371d..4fb9478ac7 100644 --- a/lib/Dispatcher/DispatcherQueue.cpp +++ b/lib/Dispatcher/DispatcherQueue.cpp @@ -55,6 +55,7 @@ DispatcherQueue::DispatcherQueue (Scheduler* scheduler, : _name(name), _accessQueue(), _readyJobs(), + _runningJobs(), _maxSize(maxSize), _stopping(0), _monopolizer(0), @@ -95,8 +96,8 @@ bool DispatcherQueue::addJob (Job* job) { CONDITION_LOCKER(guard, _accessQueue); + // queue is full if (_readyJobs.size() >= _maxSize) { - // queue is full return false; } @@ -111,6 +112,60 @@ bool DispatcherQueue::addJob (Job* job) { return true; } +//////////////////////////////////////////////////////////////////////////////// +/// @brief tries to cancel a job +//////////////////////////////////////////////////////////////////////////////// + +bool DispatcherQueue::cancelJob (uint64_t jobId) { + CONDITION_LOCKER(guard, _accessQueue); + + if (jobId == 0) { + return false; + } + + // job is already running, try to cancel it + for (set::iterator it = _runningJobs.begin(); it != _runningJobs.end(); ++it) { + Job* job = *it; + + if (job->id() == jobId) { + job->cancel(true); + return true; + } + } + + // maybe there is a waiting job with this it, try to remove it + for (list::iterator it = _readyJobs.begin(); it != _readyJobs.end(); ++it) { + Job* job = *it; + + if (job->id() == jobId) { + bool canceled = job->cancel(false); + + if (canceled) { + try { + job->setDispatcherThread(0); + job->cleanup(); + } + catch (...) { +#ifdef TRI_HAVE_POSIX_THREADS + if (_stopping != 0) { + LOG_WARNING("caught cancellation exception during cleanup"); + throw; + } +#endif + + LOG_WARNING("caught error while cleaning up!"); + } + + _readyJobs.erase(it); + } + + return true; + } + } + + return false; +} + //////////////////////////////////////////////////////////////////////////////// /// @brief downgrades the thread to special //////////////////////////////////////////////////////////////////////////////// diff --git a/lib/Dispatcher/DispatcherQueue.h b/lib/Dispatcher/DispatcherQueue.h index 6406c897f4..ea3dc06db2 100644 --- a/lib/Dispatcher/DispatcherQueue.h +++ b/lib/Dispatcher/DispatcherQueue.h @@ -94,6 +94,12 @@ namespace triagens { bool addJob (Job*); +//////////////////////////////////////////////////////////////////////////////// +/// @brief tries to cancel a job +//////////////////////////////////////////////////////////////////////////////// + + bool cancelJob (uint64_t); + //////////////////////////////////////////////////////////////////////////////// /// @brief downgrades the thread to special //////////////////////////////////////////////////////////////////////////////// @@ -160,6 +166,12 @@ namespace triagens { list _readyJobs; +///////////////////////////////////////////////////////////////////////////// +/// @brief current running job +///////////////////////////////////////////////////////////////////////////// + + set _runningJobs; + ///////////////////////////////////////////////////////////////////////////// /// @brief maximum queue size (number of jobs) ///////////////////////////////////////////////////////////////////////////// diff --git a/lib/Dispatcher/DispatcherThread.cpp b/lib/Dispatcher/DispatcherThread.cpp index 2f6eca7596..7e971d41b6 100644 --- a/lib/Dispatcher/DispatcherThread.cpp +++ b/lib/Dispatcher/DispatcherThread.cpp @@ -111,6 +111,9 @@ void DispatcherThread::run () { _queue->_monopolizer = this; } + // set running job + _queue->_runningJobs.insert(job); + // now release the queue lock (initialise is inside the lock, work outside) _queue->_accessQueue.unlock(); @@ -186,6 +189,11 @@ void DispatcherThread::run () { status = Job::status_t(Job::JOB_FAILED); } + // clear running job + _queue->_accessQueue.lock(); + _queue->_runningJobs.erase(job); + _queue->_accessQueue.unlock(); + // trigger GC /* TODO: tick is a no-op. decide whether it should be deleted tick(false); diff --git a/lib/Dispatcher/Job.cpp b/lib/Dispatcher/Job.cpp index 6a5259c970..0b43a9b285 100644 --- a/lib/Dispatcher/Job.cpp +++ b/lib/Dispatcher/Job.cpp @@ -40,7 +40,8 @@ using namespace std; //////////////////////////////////////////////////////////////////////////////// Job::Job (string const& name) - : _name(name) { + : _name(name), + _id(0) { } //////////////////////////////////////////////////////////////////////////////// diff --git a/lib/Dispatcher/Job.h b/lib/Dispatcher/Job.h index 66d9313968..c5d8bc6ef7 100644 --- a/lib/Dispatcher/Job.h +++ b/lib/Dispatcher/Job.h @@ -128,11 +128,27 @@ namespace triagens { public: //////////////////////////////////////////////////////////////////////////////// -/// @brief getter for the name +/// @brief gets the name //////////////////////////////////////////////////////////////////////////////// const string& getName () const; +//////////////////////////////////////////////////////////////////////////////// +/// @brief assign an id to the job. note: the id might be 0 +//////////////////////////////////////////////////////////////////////////////// + + void assignId (uint64_t id) { + _id = id; + } + +//////////////////////////////////////////////////////////////////////////////// +/// @brief assign an id to the job +//////////////////////////////////////////////////////////////////////////////// + + uint64_t id () const { + return _id; + } + // ----------------------------------------------------------------------------- // --SECTION-- virtual public methods // ----------------------------------------------------------------------------- @@ -165,6 +181,12 @@ namespace triagens { virtual status_t work () = 0; +//////////////////////////////////////////////////////////////////////////////// +/// @brief tries to cancel execution +//////////////////////////////////////////////////////////////////////////////// + + virtual bool cancel (bool running) = 0; + //////////////////////////////////////////////////////////////////////////////// /// @brief cleans up after work and delete //////////////////////////////////////////////////////////////////////////////// @@ -194,6 +216,12 @@ namespace triagens { //////////////////////////////////////////////////////////////////////////////// const string& _name; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief job id (only used for detached jobs) +//////////////////////////////////////////////////////////////////////////////// + + uint64_t _id; }; } } diff --git a/lib/GeneralServer/GeneralServerDispatcher.h b/lib/GeneralServer/GeneralServerDispatcher.h index d2901d7911..59574ddd02 100644 --- a/lib/GeneralServer/GeneralServerDispatcher.h +++ b/lib/GeneralServer/GeneralServerDispatcher.h @@ -478,14 +478,13 @@ namespace triagens { /// @brief the dispatcher //////////////////////////////////////////////////////////////////////////////// - Dispatcher* _dispatcher; + Dispatcher* _dispatcher; //////////////////////////////////////////////////////////////////////////////// /// @brief the job manager //////////////////////////////////////////////////////////////////////////////// - AsyncJobManager* _jobManager; - + AsyncJobManager* _jobManager; }; } } diff --git a/lib/GeneralServer/GeneralServerJob.h b/lib/GeneralServer/GeneralServerJob.h index 7c32d636b5..15c9953ff5 100644 --- a/lib/GeneralServer/GeneralServerJob.h +++ b/lib/GeneralServer/GeneralServerJob.h @@ -72,7 +72,6 @@ namespace triagens { : Job("HttpServerJob"), _server(server), _handler(handler), - _id(0), _shutdown(0), _abandon(false), _isDetached(isDetached) { @@ -91,22 +90,6 @@ namespace triagens { public: -//////////////////////////////////////////////////////////////////////////////// -/// @brief assign an id to the job. note: the id might be 0 -//////////////////////////////////////////////////////////////////////////////// - - void assignId (uint64_t id) { - _id = id; - } - -//////////////////////////////////////////////////////////////////////////////// -/// @brief assign an id to the job -//////////////////////////////////////////////////////////////////////////////// - - uint64_t id () const { - return _id; - } - //////////////////////////////////////////////////////////////////////////////// /// @brief abandon job //////////////////////////////////////////////////////////////////////////////// @@ -184,6 +167,14 @@ namespace triagens { return status.jobStatus(); } +//////////////////////////////////////////////////////////////////////////////// +/// {@inheritDoc} +//////////////////////////////////////////////////////////////////////////////// + + bool cancel (bool running) { + return _handler->cancel(running); + } + //////////////////////////////////////////////////////////////////////////////// /// {@inheritDoc} //////////////////////////////////////////////////////////////////////////////// @@ -240,12 +231,6 @@ namespace triagens { H* _handler; -//////////////////////////////////////////////////////////////////////////////// -/// @brief job id (only used for detached jobs) -//////////////////////////////////////////////////////////////////////////////// - - uint64_t _id; - //////////////////////////////////////////////////////////////////////////////// /// @brief shutdown in progress //////////////////////////////////////////////////////////////////////////////// diff --git a/lib/HttpServer/AsyncJobManager.h b/lib/HttpServer/AsyncJobManager.h index cf5bb6d608..28dc89aa27 100644 --- a/lib/HttpServer/AsyncJobManager.h +++ b/lib/HttpServer/AsyncJobManager.h @@ -5,7 +5,7 @@ /// /// DISCLAIMER /// -/// Copyright 2004-2013 triAGENS GmbH, Cologne, Germany +/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. @@ -22,11 +22,11 @@ /// Copyright holder is triAGENS GmbH, Cologne, Germany /// /// @author Jan Steemann -/// @author Copyright 2004-2013, triAGENS GmbH, Cologne, Germany +/// @author Copyright 2004-2014, triAGENS GmbH, Cologne, Germany //////////////////////////////////////////////////////////////////////////////// -#ifndef TRIAGENS_HTTP_SERVER_JOB_MANAGER_H -#define TRIAGENS_HTTP_SERVER_JOB_MANAGER_H 1 +#ifndef TRIAGENS_HTTP_SERVER_ASYNC_JOB_MANAGER_H +#define TRIAGENS_HTTP_SERVER_ASYNC_JOB_MANAGER_H 1 #include "Basics/Common.h" #include "Basics/ReadLocker.h" @@ -43,6 +43,10 @@ namespace triagens { // --SECTION-- class AsyncCallbackContext // ----------------------------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// +/// @brief AsyncCallbackContext +//////////////////////////////////////////////////////////////////////////////// + class AsyncCallbackContext { // ----------------------------------------------------------------------------- @@ -50,11 +54,20 @@ namespace triagens { // ----------------------------------------------------------------------------- public: + +//////////////////////////////////////////////////////////////////////////////// +/// @brief constructor +//////////////////////////////////////////////////////////////////////////////// + AsyncCallbackContext (std::string const& coordHeader) : _coordHeader(coordHeader), _response(0) { } +//////////////////////////////////////////////////////////////////////////////// +/// @brief destructor +//////////////////////////////////////////////////////////////////////////////// + ~AsyncCallbackContext () { if (_response != 0) { delete _response; @@ -67,7 +80,11 @@ namespace triagens { public: - string& getCoordinatorHeader() { +//////////////////////////////////////////////////////////////////////////////// +/// @brief gets the coordinator header +//////////////////////////////////////////////////////////////////////////////// + + string& getCoordinatorHeader () { return _coordHeader; } @@ -77,8 +94,16 @@ namespace triagens { private: +//////////////////////////////////////////////////////////////////////////////// +/// @brief coordinator header +//////////////////////////////////////////////////////////////////////////////// + std::string _coordHeader; +//////////////////////////////////////////////////////////////////////////////// +/// @brief http response +//////////////////////////////////////////////////////////////////////////////// + HttpResponse* _response; }; @@ -86,6 +111,10 @@ namespace triagens { // --SECTION-- class AsyncJobResult // ----------------------------------------------------------------------------- +//////////////////////////////////////////////////////////////////////////////// +/// @brief AsyncJobResult +//////////////////////////////////////////////////////////////////////////////// + struct AsyncJobResult { // ----------------------------------------------------------------------------- @@ -95,7 +124,7 @@ namespace triagens { public: //////////////////////////////////////////////////////////////////////////////// -/// @brief job statuses +/// @brief job states //////////////////////////////////////////////////////////////////////////////// typedef enum { @@ -108,7 +137,7 @@ namespace triagens { //////////////////////////////////////////////////////////////////////////////// /// @brief id typedef //////////////////////////////////////////////////////////////////////////////// - + typedef uint64_t IdType; // ----------------------------------------------------------------------------- @@ -119,7 +148,7 @@ namespace triagens { /// @brief constructor for an unspecified job result //////////////////////////////////////////////////////////////////////////////// - AsyncJobResult () : + AsyncJobResult () : _jobId(0), _response(0), _stamp(0.0), @@ -130,8 +159,8 @@ namespace triagens { //////////////////////////////////////////////////////////////////////////////// /// @brief constructor for a specific job result //////////////////////////////////////////////////////////////////////////////// - - AsyncJobResult (IdType jobId, + + AsyncJobResult (IdType jobId, HttpResponse* response, double stamp, Status status, @@ -158,7 +187,7 @@ namespace triagens { /// @brief job id //////////////////////////////////////////////////////////////////////////////// - IdType _jobId; + IdType _jobId; //////////////////////////////////////////////////////////////////////////////// /// @brief the full HTTP response object of the job, can be 0 @@ -170,20 +199,19 @@ namespace triagens { /// @brief job creation stamp //////////////////////////////////////////////////////////////////////////////// - double _stamp; + double _stamp; //////////////////////////////////////////////////////////////////////////////// /// @brief job status //////////////////////////////////////////////////////////////////////////////// - Status _status; + Status _status; //////////////////////////////////////////////////////////////////////////////// /// @brief callback context object (normally 0, used in cluster operations) //////////////////////////////////////////////////////////////////////////////// AsyncCallbackContext* _ctx; - }; // ----------------------------------------------------------------------------- @@ -197,7 +225,31 @@ namespace triagens { AsyncJobManager& operator= (AsyncJobManager const&); // ----------------------------------------------------------------------------- -// --SECTION-- constructors / destructors +// --SECTION-- public types +// ----------------------------------------------------------------------------- + + public: + +//////////////////////////////////////////////////////////////////////////////// +/// @brief callback typedef +//////////////////////////////////////////////////////////////////////////////// + + typedef void (*callback_fptr)(string&, HttpResponse*); + +//////////////////////////////////////////////////////////////////////////////// +/// @brief generate typedef +//////////////////////////////////////////////////////////////////////////////// + + typedef uint64_t (*generate_fptr)(); + +//////////////////////////////////////////////////////////////////////////////// +/// @brief joblist typedef +//////////////////////////////////////////////////////////////////////////////// + + typedef std::map JobList; + +// ----------------------------------------------------------------------------- +// --SECTION-- constructors / destructors // ----------------------------------------------------------------------------- public: @@ -206,12 +258,12 @@ namespace triagens { /// @brief constructor //////////////////////////////////////////////////////////////////////////////// - AsyncJobManager (uint64_t (*idFunc)(), - void (*callbackFunc)(string&, HttpResponse*)) + AsyncJobManager (generate_fptr idFunc, + callback_fptr callback) : _lock(), _jobs(), generate(idFunc), - callback(callbackFunc) { + callback(callback) { } //////////////////////////////////////////////////////////////////////////////// @@ -221,33 +273,23 @@ namespace triagens { ~AsyncJobManager () { } -// ----------------------------------------------------------------------------- -// --SECTION-- public types -// ----------------------------------------------------------------------------- - - public: - -//////////////////////////////////////////////////////////////////////////////// -/// @brief joblist typedef -//////////////////////////////////////////////////////////////////////////////// - - typedef std::map JobList; - // ----------------------------------------------------------------------------- // --SECTION-- public methods // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// -/// @brief get the result of an async job, and optionally remove it from the -/// list of done jobs if it is completed +/// @brief gets the result of an async job +/// +/// Get the result of an async job, and optionally remove it from the list of +/// done jobs if it is completed. //////////////////////////////////////////////////////////////////////////////// HttpResponse* getJobResult (AsyncJobResult::IdType jobId, AsyncJobResult::Status& status, - bool removeFromList) { + bool removeFromList) { WRITE_LOCKER(_lock); - JobList::iterator it = _jobs.find(jobId); + JobList::iterator it = _jobs.find(jobId); if (it == _jobs.end()) { status = AsyncJobResult::JOB_UNDEFINED; @@ -258,7 +300,7 @@ namespace triagens { status = (*it).second._status; if (status == AsyncJobResult::JOB_PENDING) { - return 0; + return 0; } if (! removeFromList) { @@ -271,13 +313,13 @@ namespace triagens { } //////////////////////////////////////////////////////////////////////////////// -/// @brief delete the result of an async job, without returning it +/// @brief deletes the result of an async job, without returning it //////////////////////////////////////////////////////////////////////////////// bool deleteJobResult (AsyncJobResult::IdType jobId) { WRITE_LOCKER(_lock); - JobList::iterator it = _jobs.find(jobId); + JobList::iterator it = _jobs.find(jobId); if (it == _jobs.end()) { return false; @@ -295,7 +337,7 @@ namespace triagens { } //////////////////////////////////////////////////////////////////////////////// -/// @brief delete all results +/// @brief deletes all results //////////////////////////////////////////////////////////////////////////////// void deleteJobResults () { @@ -317,7 +359,7 @@ namespace triagens { } //////////////////////////////////////////////////////////////////////////////// -/// @brief delete expired results +/// @brief deletes expired results //////////////////////////////////////////////////////////////////////////////// void deleteExpiredJobResults (double stamp) { @@ -344,26 +386,26 @@ namespace triagens { } //////////////////////////////////////////////////////////////////////////////// -/// @brief return the list of pending jobs +/// @brief returns the list of pending jobs //////////////////////////////////////////////////////////////////////////////// - const std::vector pending (size_t maxCount) { + const std::vector pending (size_t maxCount) { return byStatus(AsyncJobResult::JOB_PENDING, maxCount); } //////////////////////////////////////////////////////////////////////////////// -/// @brief return the list of done jobs +/// @brief returns the list of done jobs //////////////////////////////////////////////////////////////////////////////// - const std::vector done (size_t maxCount) { + const std::vector done (size_t maxCount) { return byStatus(AsyncJobResult::JOB_DONE, maxCount); } //////////////////////////////////////////////////////////////////////////////// -/// @brief return the list of jobs by status +/// @brief returns the list of jobs by status //////////////////////////////////////////////////////////////////////////////// - const std::vector byStatus (AsyncJobResult::Status status, + const std::vector byStatus (AsyncJobResult::Status status, size_t maxCount) { vector jobs; size_t n = 0; @@ -392,12 +434,12 @@ namespace triagens { } //////////////////////////////////////////////////////////////////////////////// -/// @brief initialise an async job +/// @brief initialises an async job //////////////////////////////////////////////////////////////////////////////// template - void initAsyncJob (GeneralServerJob* job, - uint64_t* jobId) { + void initAsyncJob (GeneralServerJob* job, + uint64_t* jobId) { if (jobId == 0) { return; } @@ -417,8 +459,11 @@ namespace triagens { ctx = new AsyncCallbackContext(std::string(hdr)); } - AsyncJobResult ajr(*jobId, 0, TRI_microtime(), - AsyncJobResult::JOB_PENDING, ctx); + AsyncJobResult ajr(*jobId, + 0, + TRI_microtime(), + AsyncJobResult::JOB_PENDING, + ctx); WRITE_LOCKER(_lock); @@ -426,13 +471,13 @@ namespace triagens { } //////////////////////////////////////////////////////////////////////////////// -/// @brief finish the execution of an async job +/// @brief finishes the execution of an async job //////////////////////////////////////////////////////////////////////////////// template - void finishAsyncJob (GeneralServerJob* job) { + void finishAsyncJob (GeneralServerJob* job) { assert(job != 0); - + typename HF::GeneralHandler* handler = job->getHandler(); assert(handler != 0); @@ -441,18 +486,18 @@ namespace triagens { if (jobId == 0) { return; } - + const double now = TRI_microtime(); AsyncCallbackContext* ctx = 0; HttpResponse* response = 0; { WRITE_LOCKER(_lock); - JobList::iterator it = _jobs.find(jobId); - + JobList::iterator it = _jobs.find(jobId); + if (it == _jobs.end()) { // job is already deleted. - // do nothing here. the dispatcher will throw away the handler, + // do nothing here. the dispatcher will throw away the handler, // which will also dispose the response return; } @@ -461,7 +506,7 @@ namespace triagens { (*it).second._response = response; (*it).second._status = AsyncJobResult::JOB_DONE; - (*it).second._stamp = now; + (*it).second._stamp = now; ctx = (*it).second._ctx; @@ -497,29 +542,27 @@ namespace triagens { //////////////////////////////////////////////////////////////////////////////// /// @brief lock to protect the _jobs map //////////////////////////////////////////////////////////////////////////////// - - basics::ReadWriteLock _lock; + + basics::ReadWriteLock _lock; //////////////////////////////////////////////////////////////////////////////// /// @brief list of pending/done async jobs //////////////////////////////////////////////////////////////////////////////// - - JobList _jobs; + + JobList _jobs; //////////////////////////////////////////////////////////////////////////////// /// @brief function pointer for id generation //////////////////////////////////////////////////////////////////////////////// - uint64_t (*generate)(); + generate_fptr generate; //////////////////////////////////////////////////////////////////////////////// /// @brief function pointer for callback registered at initialisation //////////////////////////////////////////////////////////////////////////////// - void (*callback)(string& coordinator, HttpResponse* response); - + callback_fptr callback; }; - } } diff --git a/lib/HttpServer/HttpHandler.cpp b/lib/HttpServer/HttpHandler.cpp index 8b757f094e..e831ffdc6a 100644 --- a/lib/HttpServer/HttpHandler.cpp +++ b/lib/HttpServer/HttpHandler.cpp @@ -5,7 +5,7 @@ /// /// DISCLAIMER /// -/// Copyright 2004-2013 triAGENS GmbH, Cologne, Germany +/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. @@ -22,7 +22,7 @@ /// Copyright holder is triAGENS GmbH, Cologne, Germany /// /// @author Dr. Frank Celler -/// @author Copyright 2009-2013, triAGENS GmbH, Cologne, Germany +/// @author Copyright 2009-2014, triAGENS GmbH, Cologne, Germany //////////////////////////////////////////////////////////////////////////////// #include "HttpHandler.h" @@ -40,11 +40,6 @@ using namespace triagens::rest; // --SECTION-- constructors and destructors // ----------------------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup GeneralServer -/// @{ -//////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// /// @brief constructs a new handler //////////////////////////////////////////////////////////////////////////////// @@ -69,19 +64,10 @@ HttpHandler::~HttpHandler () { } } -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - // ----------------------------------------------------------------------------- // --SECTION-- public methods // ----------------------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup GeneralServer -/// @{ -//////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// /// @brief returns the response //////////////////////////////////////////////////////////////////////////////// @@ -110,19 +96,10 @@ HttpRequest* HttpHandler::stealRequest () { return tmp; } -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - // ----------------------------------------------------------------------------- // --SECTION-- Handler methods // ----------------------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup GeneralServer -/// @{ -//////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// /// {@inheritDoc} //////////////////////////////////////////////////////////////////////////////// @@ -130,6 +107,7 @@ HttpRequest* HttpHandler::stealRequest () { Job* HttpHandler::createJob (AsyncJobServer* server, bool isDetached) { HttpServer* httpServer = dynamic_cast(server); + // check if we are an HTTP server at all if (httpServer != 0) { return new GeneralServerJob(httpServer, this, isDetached); @@ -137,6 +115,7 @@ Job* HttpHandler::createJob (AsyncJobServer* server, // check if we are an HTTPs server at all HttpsServer* httpsServer = dynamic_cast(server); + if (httpsServer != 0) { return new GeneralServerJob(httpsServer, this, isDetached); } @@ -145,19 +124,10 @@ Job* HttpHandler::createJob (AsyncJobServer* server, return 0; } -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - // ----------------------------------------------------------------------------- // --SECTION-- protected methods // ----------------------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup GeneralServer -/// @{ -//////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// /// @brief ensure the handler has only one response, otherwise we'd have a leak //////////////////////////////////////////////////////////////////////////////// @@ -174,6 +144,7 @@ void HttpHandler::removePreviousResponse () { //////////////////////////////////////////////////////////////////////////////// HttpResponse* HttpHandler::createResponse (HttpResponse::HttpResponseCode code) { + // avoid having multiple responses. this would be a memleak removePreviousResponse(); @@ -189,10 +160,6 @@ HttpResponse* HttpHandler::createResponse (HttpResponse::HttpResponseCode code) return new HttpResponse(code, apiCompatibility); } -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - // ----------------------------------------------------------------------------- // --SECTION-- END-OF-FILE // ----------------------------------------------------------------------------- diff --git a/lib/HttpServer/HttpHandler.h b/lib/HttpServer/HttpHandler.h index bef1c98909..076d57cbb1 100644 --- a/lib/HttpServer/HttpHandler.h +++ b/lib/HttpServer/HttpHandler.h @@ -5,7 +5,7 @@ /// /// DISCLAIMER /// -/// Copyright 2004-2013 triAGENS GmbH, Cologne, Germany +/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. @@ -22,7 +22,7 @@ /// Copyright holder is triAGENS GmbH, Cologne, Germany /// /// @author Dr. Frank Celler -/// @author Copyright 2009-2013, triAGENS GmbH, Cologne, Germany +/// @author Copyright 2009-2014, triAGENS GmbH, Cologne, Germany //////////////////////////////////////////////////////////////////////////////// #ifndef TRIAGENS_HTTP_SERVER_HTTP_HANDLER_H @@ -46,11 +46,6 @@ namespace triagens { // --SECTION-- class HttpHandler // ----------------------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup HttpServer -/// @{ -//////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// /// @brief abstract class for http handlers //////////////////////////////////////////////////////////////////////////////// @@ -60,19 +55,10 @@ namespace triagens { HttpHandler (HttpHandler const&); HttpHandler& operator= (HttpHandler const&); -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - // ----------------------------------------------------------------------------- // --SECTION-- constructors and destructors // ----------------------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup GeneralServer -/// @{ -//////////////////////////////////////////////////////////////////////////////// - public: //////////////////////////////////////////////////////////////////////////////// @@ -91,19 +77,10 @@ namespace triagens { ~HttpHandler (); -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - // ----------------------------------------------------------------------------- // --SECTION-- public methods // ----------------------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup GeneralServer -/// @{ -//////////////////////////////////////////////////////////////////////////////// - public: //////////////////////////////////////////////////////////////////////////////// @@ -118,19 +95,10 @@ namespace triagens { HttpResponse* stealResponse (); -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - // ----------------------------------------------------------------------------- // --SECTION-- Handler methods // ----------------------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup GeneralServer -/// @{ -//////////////////////////////////////////////////////////////////////////////// - public: //////////////////////////////////////////////////////////////////////////////// @@ -170,19 +138,10 @@ namespace triagens { // nothing by default } -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - // ----------------------------------------------------------------------------- // --SECTION-- protected methods // ----------------------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup GeneralServer -/// @{ -//////////////////////////////////////////////////////////////////////////////// - protected: //////////////////////////////////////////////////////////////////////////////// @@ -197,19 +156,10 @@ namespace triagens { HttpResponse* createResponse (HttpResponse::HttpResponseCode); -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - // ----------------------------------------------------------------------------- // --SECTION-- protected variables // ----------------------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup GeneralServer -/// @{ -//////////////////////////////////////////////////////////////////////////////// - protected: //////////////////////////////////////////////////////////////////////////////// @@ -234,10 +184,6 @@ namespace triagens { } } -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - #endif // ----------------------------------------------------------------------------- diff --git a/lib/Rest/Handler.cpp b/lib/Rest/Handler.cpp index f341d90356..8a04ee50d8 100644 --- a/lib/Rest/Handler.cpp +++ b/lib/Rest/Handler.cpp @@ -5,7 +5,7 @@ /// /// DISCLAIMER /// -/// Copyright 2004-2013 triAGENS GmbH, Cologne, Germany +/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. @@ -22,7 +22,7 @@ /// Copyright holder is triAGENS GmbH, Cologne, Germany /// /// @author Dr. Frank Celler -/// @author Copyright 2009-2013, triAGENS GmbH, Cologne, Germany +/// @author Copyright 2009-2014, triAGENS GmbH, Cologne, Germany //////////////////////////////////////////////////////////////////////////////// #include "Handler.h" @@ -34,11 +34,6 @@ using namespace std; // --SECTION-- constructors and destructors // ----------------------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup GeneralServer -/// @{ -//////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// /// @brief constructor //////////////////////////////////////////////////////////////////////////////// @@ -53,19 +48,10 @@ Handler::Handler () { Handler::~Handler () { } -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - // ----------------------------------------------------------------------------- // --SECTION-- public methods // ----------------------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup GeneralServer -/// @{ -//////////////////////////////////////////////////////////////////////////////// - //////////////////////////////////////////////////////////////////////////////// /// @brief returns the job type //////////////////////////////////////////////////////////////////////////////// @@ -91,9 +77,13 @@ void Handler::setDispatcherThread (DispatcherThread*) { } //////////////////////////////////////////////////////////////////////////////// -/// @} +/// @brief tries to cancel an execution //////////////////////////////////////////////////////////////////////////////// +bool Handler::cancel (bool running) { + return false; +} + // ----------------------------------------------------------------------------- // --SECTION-- END-OF-FILE // ----------------------------------------------------------------------------- diff --git a/lib/Rest/Handler.h b/lib/Rest/Handler.h index f21ff45643..018420738e 100644 --- a/lib/Rest/Handler.h +++ b/lib/Rest/Handler.h @@ -161,6 +161,12 @@ namespace triagens { virtual status_t execute () = 0; +//////////////////////////////////////////////////////////////////////////////// +/// @brief tries to cancel an execution +//////////////////////////////////////////////////////////////////////////////// + + virtual bool cancel (bool running); + //////////////////////////////////////////////////////////////////////////////// /// @brief handles error //////////////////////////////////////////////////////////////////////////////// diff --git a/lib/Rest/HttpResponse.h b/lib/Rest/HttpResponse.h index 1611d2f7f9..4652c00591 100644 --- a/lib/Rest/HttpResponse.h +++ b/lib/Rest/HttpResponse.h @@ -5,7 +5,7 @@ /// /// DISCLAIMER /// -/// Copyright 2004-2013 triAGENS GmbH, Cologne, Germany +/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. @@ -23,7 +23,7 @@ /// /// @author Dr. Frank Celler /// @author Achim Brandt -/// @author Copyright 2008-2013, triAGENS GmbH, Cologne, Germany +/// @author Copyright 2008-2014, triAGENS GmbH, Cologne, Germany //////////////////////////////////////////////////////////////////////////////// #ifndef TRIAGENS_REST_HTTP_RESPONSE_H @@ -38,11 +38,6 @@ // --SECTION-- class HttpResponse // ----------------------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup Rest -/// @{ -//////////////////////////////////////////////////////////////////////////////// - namespace triagens { namespace rest { @@ -59,19 +54,10 @@ namespace triagens { HttpResponse (HttpResponse const&); HttpResponse& operator= (HttpResponse const&); -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - // ----------------------------------------------------------------------------- // --SECTION-- public types // ----------------------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup Rest -/// @{ -//////////////////////////////////////////////////////////////////////////////// - public: //////////////////////////////////////////////////////////////////////////////// @@ -130,25 +116,16 @@ namespace triagens { NOT_EXTENDED = 510 }; -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - // ----------------------------------------------------------------------------- // --SECTION-- static public methods // ----------------------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup Rest -/// @{ -//////////////////////////////////////////////////////////////////////////////// - public: //////////////////////////////////////////////////////////////////////////////// /// @brief whether or not the response is a HTTP HEAD response //////////////////////////////////////////////////////////////////////////////// - + bool isHeadResponse () const { return _isHeadResponse; } @@ -176,19 +153,10 @@ namespace triagens { static const string& getBatchErrorHeader (); -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - // ----------------------------------------------------------------------------- // --SECTION-- constructors and destructors // ----------------------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup Rest -/// @{ -//////////////////////////////////////////////////////////////////////////////// - public: //////////////////////////////////////////////////////////////////////////////// @@ -206,19 +174,10 @@ namespace triagens { virtual ~HttpResponse (); -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - // ----------------------------------------------------------------------------- // --SECTION-- public methods // ----------------------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup Rest -/// @{ -//////////////////////////////////////////////////////////////////////////////// - public: //////////////////////////////////////////////////////////////////////////////// @@ -337,7 +296,7 @@ namespace triagens { /// The name is automatically trimmed. //////////////////////////////////////////////////////////////////////////////// - void setCookie (string const& name, string const& value, + void setCookie (string const& name, string const& value, int lifeTimeSeconds, string const& path, string const& domain, @@ -391,19 +350,10 @@ namespace triagens { int deflate (size_t = 16384); -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - // ----------------------------------------------------------------------------- // --SECTION-- protected variables // ----------------------------------------------------------------------------- -//////////////////////////////////////////////////////////////////////////////// -/// @addtogroup Rest -/// @{ -//////////////////////////////////////////////////////////////////////////////// - protected: //////////////////////////////////////////////////////////////////////////////// @@ -435,7 +385,7 @@ namespace triagens { //////////////////////////////////////////////////////////////////////////////// vector _cookies; - + //////////////////////////////////////////////////////////////////////////////// /// @brief body //////////////////////////////////////////////////////////////////////////////// @@ -457,10 +407,6 @@ namespace triagens { } } -//////////////////////////////////////////////////////////////////////////////// -/// @} -//////////////////////////////////////////////////////////////////////////////// - #endif // -----------------------------------------------------------------------------