diff --git a/arangod/Cluster/ClusterMethods.cpp b/arangod/Cluster/ClusterMethods.cpp index e6634ed058..56a0beb224 100644 --- a/arangod/Cluster/ClusterMethods.cpp +++ b/arangod/Cluster/ClusterMethods.cpp @@ -429,7 +429,7 @@ int modifyDocumentOnCoordinator ( TRI_doc_update_policy_e policy, bool waitForSync, bool isPatch, - string const& keepNull, // only for isPatch == true + bool keepNull, // only counts for isPatch == true TRI_json_t* json, triagens::rest::HttpResponse::HttpResponseCode& responseCode, string& contentType, @@ -493,14 +493,14 @@ int modifyDocumentOnCoordinator ( triagens::rest::HttpRequest::HttpRequestType reqType; if (isPatch) { reqType = triagens::rest::HttpRequest::HTTP_REQUEST_PATCH; - if (!keepNull.empty()) { + if (!keepNull) { if (revstr.empty()) { revstr += "?keepNull="; } else { revstr += "&keepNull="; } - revstr += keepNull; + revstr += "false"; } } else { diff --git a/arangod/Cluster/ClusterMethods.h b/arangod/Cluster/ClusterMethods.h index 36e275138f..385eef3e9e 100644 --- a/arangod/Cluster/ClusterMethods.h +++ b/arangod/Cluster/ClusterMethods.h @@ -101,7 +101,7 @@ namespace triagens { TRI_doc_update_policy_e policy, bool waitForSync, bool isPatch, - string const& keepNull, + bool keepNull, // only counts for isPatch == true TRI_json_t* json, triagens::rest::HttpResponse::HttpResponseCode& responseCode, string& contentType, diff --git a/arangod/RestHandler/RestDocumentHandler.cpp b/arangod/RestHandler/RestDocumentHandler.cpp index a9281c6a20..8670d8ed63 100644 --- a/arangod/RestHandler/RestDocumentHandler.cpp +++ b/arangod/RestHandler/RestDocumentHandler.cpp @@ -1452,7 +1452,10 @@ bool RestDocumentHandler::modifyDocumentCoordinator ( string contentType; string resultBody; - string const keepNull = _request->value("keepNull"); + bool keepNull = true; + if (!strcmp(_request->value("keepNull"),"false")) { + keepNull = false; + } int error = triagens::arango::modifyDocumentOnCoordinator( dbname, collname, key, rev, policy, waitForSync, isPatch, diff --git a/arangod/V8Server/v8-vocbase.cpp b/arangod/V8Server/v8-vocbase.cpp index c369f85d46..50a12a418b 100644 --- a/arangod/V8Server/v8-vocbase.cpp +++ b/arangod/V8Server/v8-vocbase.cpp @@ -220,6 +220,45 @@ static int32_t const WRP_SHAPED_JSON_TYPE = 4; /// @{ //////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +/// @brief cluster coordinator case, parse a key and possible revision +//////////////////////////////////////////////////////////////////////////////// + +static int parseKeyAndRef(v8::Handle arg, string& key, + TRI_voc_rid_t& rev) { + TRI_v8_global_t* v8g = (TRI_v8_global_t*) + v8::Isolate::GetCurrent()->GetData(); + rev = 0; + if (arg->IsString()) { + key = TRI_ObjectToString(arg); + } + else if (arg->IsObject()) { + v8::Handle obj = arg.As(); + if (obj->Has(v8g->_KeyKey) && obj->Get(v8g->_KeyKey)->IsString()) { + key = TRI_ObjectToString(obj->Get(v8g->_KeyKey)); + } + else if (obj->Has(v8g->_IdKey) && obj->Get(v8g->_IdKey)->IsString()) { + key = TRI_ObjectToString(obj->Get(v8g->_IdKey)); + // part after / will be taken below + } + else { + return TRI_ERROR_ARANGO_DOCUMENT_TYPE_INVALID; + } + if (obj->Has(v8g->_RevKey) && obj->Get(v8g->_RevKey)->IsString()) { + rev = TRI_ObjectToUInt64(obj->Get(v8g->_RevKey), true); + } + } + else { + return TRI_ERROR_ARANGO_DOCUMENT_TYPE_INVALID; + } + + size_t pos = key.find('/'); + if (pos != string::npos) { + key = key.substr(pos+1); + } + return TRI_ERROR_NO_ERROR; +} + //////////////////////////////////////////////////////////////////////////////// /// @brief get the name of the current database //////////////////////////////////////////////////////////////////////////////// @@ -1040,8 +1079,7 @@ static v8::Handle EnsureFulltextIndex (v8::Arguments const& argv, #ifdef TRI_ENABLE_CLUSTER static v8::Handle DocumentVocbaseCol_Coordinator ( TRI_vocbase_col_t const* collection, - TRI_voc_key_t key, - TRI_voc_rid_t rid, + v8::Arguments const& argv, bool generateDocument) { v8::HandleScope scope; @@ -1049,12 +1087,19 @@ static v8::Handle DocumentVocbaseCol_Coordinator ( string const dbname(collection->_dbName); string const collname(collection->_name); + string key; + TRI_voc_rid_t rev = 0; + int error = parseKeyAndRef(argv[0], key, rev); + if (error != TRI_ERROR_NO_ERROR) { + TRI_V8_EXCEPTION(scope, error); + } + triagens::rest::HttpResponse::HttpResponseCode responseCode; string contentType; string resultBody; - int error = triagens::arango::getDocumentOnCoordinator( - dbname, collname, key, rid, false, // no "if-none-match" here! + error = triagens::arango::getDocumentOnCoordinator( + dbname, collname, key, rev, false, // no "if-none-match" here! generateDocument, responseCode, contentType, resultBody); @@ -1067,28 +1112,37 @@ static v8::Handle DocumentVocbaseCol_Coordinator ( // For the error processing we have to distinguish whether we are in // the ".exists" case (generateDocument==false) or the ".document" case // (generateDocument==true). - TRI_json_t* json = TRI_JsonString(TRI_UNKNOWN_MEM_ZONE, resultBody.c_str()); + TRI_json_t* json = 0; + if (generateDocument) { + json = TRI_JsonString(TRI_UNKNOWN_MEM_ZONE, resultBody.c_str()); + } if (responseCode >= triagens::rest::HttpResponse::BAD) { if (!TRI_IsArrayJson(json)) { if (generateDocument) { + if (0 != json) { + TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); + } TRI_V8_EXCEPTION(scope, TRI_ERROR_INTERNAL); } else { return scope.Close(v8::False()); } } - int errorNum = 0; - TRI_json_t* subjson = TRI_LookupArrayJson(json, "errorNum"); - if (0 != subjson && TRI_IsNumberJson(subjson)) { - errorNum = static_cast(subjson->_value._number); - } - string errorMessage; - subjson = TRI_LookupArrayJson(json, "errorMessage"); - if (0 != subjson && TRI_IsStringJson(subjson)) { - errorMessage = string(subjson->_value._string.data, - subjson->_value._string.length-1); - } if (generateDocument) { + int errorNum = 0; + string errorMessage; + if (0 != json) { + TRI_json_t* subjson = TRI_LookupArrayJson(json, "errorNum"); + if (0 != subjson && TRI_IsNumberJson(subjson)) { + errorNum = static_cast(subjson->_value._number); + } + subjson = TRI_LookupArrayJson(json, "errorMessage"); + if (0 != subjson && TRI_IsStringJson(subjson)) { + errorMessage = string(subjson->_value._string.data, + subjson->_value._string.length-1); + } + TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); + } TRI_V8_EXCEPTION_MESSAGE(scope, errorNum, errorMessage); } else { @@ -1097,11 +1151,14 @@ static v8::Handle DocumentVocbaseCol_Coordinator ( } if (generateDocument) { v8::Handle ret = TRI_ObjectJson(json); - TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); + if (0 != json) { + TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); + } return scope.Close(ret); } else { // Note that for this case we will never get a 304 "NOT_MODIFIED" + TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); return scope.Close(v8::True()); } } @@ -1144,6 +1201,12 @@ static v8::Handle DocumentVocbaseCol (const bool useCollection, TRI_V8_EXCEPTION(scope, TRI_ERROR_ARANGO_DATABASE_NOT_FOUND); } +#ifdef TRI_ENABLE_CLUSTER + if (ServerState::instance()->isCoordinator()) { + return DocumentVocbaseCol_Coordinator(col, argv, true); + } +#endif + CollectionNameResolver resolver(vocbase); v8::Handle err = TRI_ParseDocumentOrDocumentHandle(resolver, col, key, rid, argv[0]); @@ -1156,12 +1219,6 @@ static v8::Handle DocumentVocbaseCol (const bool useCollection, return scope.Close(v8::ThrowException(err)); } -#ifdef TRI_ENABLE_CLUSTER - if (ServerState::instance()->isCoordinator()) { - return DocumentVocbaseCol_Coordinator(col, key, rid, true); - } -#endif - assert(col != 0); assert(key != 0); @@ -1260,11 +1317,15 @@ static v8::Handle ExistsVocbaseCol (const bool useCollection, TRI_V8_EXCEPTION(scope, TRI_ERROR_ARANGO_DATABASE_NOT_FOUND); } +#ifdef TRI_ENABLE_CLUSTER + if (ServerState::instance()->isCoordinator()) { + return DocumentVocbaseCol_Coordinator(col, argv, false); + } +#endif + CollectionNameResolver resolver(vocbase); v8::Handle err = TRI_ParseDocumentOrDocumentHandle(resolver, col, key, rid, argv[0]); - TRI_SHARDING_COLLECTION_NOT_YET_IMPLEMENTED(scope, col); - if (key == 0) { TRI_V8_EXCEPTION(scope, TRI_ERROR_ARANGO_DOCUMENT_HANDLE_BAD); } @@ -1290,12 +1351,6 @@ static v8::Handle ExistsVocbaseCol (const bool useCollection, return scope.Close(v8::ThrowException(err)); } -#ifdef TRI_ENABLE_CLUSTER - if (ServerState::instance()->isCoordinator()) { - return DocumentVocbaseCol_Coordinator(col, key, rid, false); - } -#endif - assert(col != 0); assert(key != 0); @@ -1334,6 +1389,83 @@ static v8::Handle ExistsVocbaseCol (const bool useCollection, TRI_V8_EXCEPTION(scope, res); } +//////////////////////////////////////////////////////////////////////////////// +/// @brief modifies a document, coordinator case in a cluster +//////////////////////////////////////////////////////////////////////////////// + +#ifdef TRI_ENABLE_CLUSTER +static v8::Handle ModifyVocbaseCol_Coordinator ( + TRI_vocbase_col_t const* collection, + TRI_doc_update_policy_e policy, + bool waitForSync, + bool isPatch, + bool keepNull, // only counts if isPatch==true + v8::Arguments const& argv) { + v8::HandleScope scope; + + // First get the initial data: + string const dbname(collection->_dbName); + string const collname(collection->_name); + + string key; + TRI_voc_rid_t rev = 0; + int error = parseKeyAndRef(argv[0], key, rev); + if (error != TRI_ERROR_NO_ERROR) { + TRI_V8_EXCEPTION(scope, error); + } + + TRI_json_t* json = TRI_ObjectToJson(argv[1]); + if (0 == json || json->_type != TRI_JSON_ARRAY) { + TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); + TRI_V8_EXCEPTION(scope, TRI_ERROR_ARANGO_DOCUMENT_TYPE_INVALID); + } + + triagens::rest::HttpResponse::HttpResponseCode responseCode; + string contentType; + string resultBody; + + error = triagens::arango::modifyDocumentOnCoordinator( + dbname, collname, key, rev, policy, waitForSync, isPatch, + keepNull, json, responseCode, contentType, resultBody); + // Note that the json has been freed inside! + + if (error != TRI_ERROR_NO_ERROR) { + TRI_V8_EXCEPTION(scope, error); + } + + // report what the DBserver told us: this could now be 201/202 or + // 400/404 + json = TRI_JsonString(TRI_UNKNOWN_MEM_ZONE, resultBody.c_str()); + if (responseCode >= triagens::rest::HttpResponse::BAD) { + if (!TRI_IsArrayJson(json)) { + if (0 != json) { + TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); + } + TRI_V8_EXCEPTION(scope, TRI_ERROR_INTERNAL); + } + int errorNum = 0; + TRI_json_t* subjson = TRI_LookupArrayJson(json, "errorNum"); + if (0 != subjson && TRI_IsNumberJson(subjson)) { + errorNum = static_cast(subjson->_value._number); + } + string errorMessage; + subjson = TRI_LookupArrayJson(json, "errorMessage"); + if (0 != subjson && TRI_IsStringJson(subjson)) { + errorMessage = string(subjson->_value._string.data, + subjson->_value._string.length-1); + } + TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); + TRI_V8_EXCEPTION_MESSAGE(scope, errorNum, errorMessage); + } + v8::Handle ret = TRI_ObjectJson(json); + if (0 != json) { + TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); + } + return scope.Close(ret); +} +#endif + + //////////////////////////////////////////////////////////////////////////////// /// @brief replaces a document //////////////////////////////////////////////////////////////////////////////// @@ -1381,11 +1513,18 @@ static v8::Handle ReplaceVocbaseCol (const bool useCollection, TRI_V8_EXCEPTION(scope, TRI_ERROR_ARANGO_DATABASE_NOT_FOUND); } +#ifdef TRI_ENABLE_CLUSTER + if (ServerState::instance()->isCoordinator()) { + return ModifyVocbaseCol_Coordinator(col, policy, forceSync, + false, // isPatch + true, // keepNull, does not matter + argv); + } +#endif + CollectionNameResolver resolver(vocbase); v8::Handle err = TRI_ParseDocumentOrDocumentHandle(resolver, col, key, rid, argv[0]); - TRI_SHARDING_COLLECTION_NOT_YET_IMPLEMENTED(scope, col); - if (key == 0) { TRI_V8_EXCEPTION(scope, TRI_ERROR_ARANGO_DOCUMENT_HANDLE_BAD); } @@ -1701,6 +1840,15 @@ static v8::Handle UpdateVocbaseCol (const bool useCollection, TRI_V8_EXCEPTION(scope, TRI_ERROR_ARANGO_DATABASE_NOT_FOUND); } +#ifdef TRI_ENABLE_CLUSTER + if (ServerState::instance()->isCoordinator()) { + return ModifyVocbaseCol_Coordinator(col, policy, forceSync, + true, // isPatch + !nullMeansRemove, // keepNull + argv); + } +#endif + CollectionNameResolver resolver(vocbase); v8::Handle err = TRI_ParseDocumentOrDocumentHandle(resolver, col, key, rid, argv[0]); @@ -1806,22 +1954,28 @@ static v8::Handle UpdateVocbaseCol (const bool useCollection, #ifdef TRI_ENABLE_CLUSTER static v8::Handle RemoveVocbaseCol_Coordinator ( TRI_vocbase_col_t const* collection, - TRI_voc_key_t key, - TRI_voc_rid_t rid, TRI_doc_update_policy_e policy, - bool waitForSync) { + bool waitForSync, + v8::Arguments const& argv) { v8::HandleScope scope; // First get the initial data: string const dbname(collection->_dbName); string const collname(collection->_name); + string key; + TRI_voc_rid_t rev = 0; + int error = parseKeyAndRef(argv[0], key, rev); + if (error != TRI_ERROR_NO_ERROR) { + TRI_V8_EXCEPTION(scope, error); + } + triagens::rest::HttpResponse::HttpResponseCode responseCode; string contentType; string resultBody; - int error = triagens::arango::deleteDocumentOnCoordinator( - dbname, collname, key, rid, policy, waitForSync, + error = triagens::arango::deleteDocumentOnCoordinator( + dbname, collname, key, rev, policy, waitForSync, responseCode, contentType, resultBody); if (error != TRI_ERROR_NO_ERROR) { @@ -1832,6 +1986,9 @@ static v8::Handle RemoveVocbaseCol_Coordinator ( TRI_json_t* json = TRI_JsonString(TRI_UNKNOWN_MEM_ZONE, resultBody.c_str()); if (responseCode >= triagens::rest::HttpResponse::BAD) { if (!TRI_IsArrayJson(json)) { + if (0 != json) { + TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); + } TRI_V8_EXCEPTION(scope, TRI_ERROR_INTERNAL); } int errorNum = 0; @@ -1845,10 +2002,13 @@ static v8::Handle RemoveVocbaseCol_Coordinator ( errorMessage = string(subjson->_value._string.data, subjson->_value._string.length-1); } + TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); TRI_V8_EXCEPTION_MESSAGE(scope, errorNum, errorMessage); } v8::Handle ret = TRI_ObjectJson(json); - TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); + if (0 != json) { + TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); + } return scope.Close(ret); } #endif @@ -1894,6 +2054,12 @@ static v8::Handle RemoveVocbaseCol (const bool useCollection, TRI_V8_EXCEPTION(scope, TRI_ERROR_ARANGO_DATABASE_NOT_FOUND); } +#ifdef TRI_ENABLE_CLUSTER + if (ServerState::instance()->isCoordinator()) { + return RemoveVocbaseCol_Coordinator(col, policy, forceSync, argv); + } +#endif + CollectionNameResolver resolver(vocbase); v8::Handle err = TRI_ParseDocumentOrDocumentHandle(resolver, col, key, rid, argv[0]); @@ -1906,12 +2072,6 @@ static v8::Handle RemoveVocbaseCol (const bool useCollection, return scope.Close(v8::ThrowException(err)); } -#ifdef TRI_ENABLE_CLUSTER - if (ServerState::instance()->isCoordinator()) { - return RemoveVocbaseCol_Coordinator(col, key, rid, policy, forceSync); - } -#endif - assert(col != 0); assert(key != 0); @@ -6983,8 +7143,10 @@ static v8::Handle JS_SaveVocbaseCol_Coordinator ( } TRI_json_t* json = TRI_ObjectToJson(argv[0]); const bool waitForSync = ExtractForceSync(argv, 2); - if (json->_type != TRI_JSON_ARRAY) { - TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); + if (!TRI_IsArrayJson(json)) { + if (0 != json) { + TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); + } TRI_V8_EXCEPTION(scope, TRI_ERROR_ARANGO_DOCUMENT_TYPE_INVALID); } @@ -7005,6 +7167,9 @@ static v8::Handle JS_SaveVocbaseCol_Coordinator ( json = TRI_JsonString(TRI_UNKNOWN_MEM_ZONE, resultBody.c_str()); if (responseCode >= triagens::rest::HttpResponse::BAD) { if (!TRI_IsArrayJson(json)) { + if (0 != json) { + TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); + } TRI_V8_EXCEPTION(scope, TRI_ERROR_INTERNAL); } int errorNum = 0; @@ -7018,10 +7183,13 @@ static v8::Handle JS_SaveVocbaseCol_Coordinator ( errorMessage = string(subjson->_value._string.data, subjson->_value._string.length-1); } + TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); TRI_V8_EXCEPTION_MESSAGE(scope, errorNum, errorMessage); } v8::Handle ret = TRI_ObjectJson(json); - TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); + if (0 != json) { + TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json); + } return scope.Close(ret); } #endif @@ -7073,8 +7241,6 @@ static v8::Handle JS_SaveVocbaseCol (v8::Arguments const& argv) { } #endif - TRI_SHARDING_COLLECTION_NOT_YET_IMPLEMENTED(scope, collection); - CollectionNameResolver resolver(collection->_vocbase); SingleCollectionWriteTransaction, 1> trx(collection->_vocbase, resolver, collection->_cid);