diff --git a/arangod/Replication/InitialSyncer.cpp b/arangod/Replication/InitialSyncer.cpp index 43e12699a8..7cd1b95790 100644 --- a/arangod/Replication/InitialSyncer.cpp +++ b/arangod/Replication/InitialSyncer.cpp @@ -1757,7 +1757,7 @@ int InitialSyncer::handleCollection(VPackSlice const& parameters, // regular collection setProgress("dropping " + collectionMsg); - int res = _vocbase->dropCollection(col, true); + int res = _vocbase->dropCollection(col, true, true); if (res != TRI_ERROR_NO_ERROR) { errorMsg = "unable to drop " + collectionMsg + ": " + diff --git a/arangod/Replication/Syncer.cpp b/arangod/Replication/Syncer.cpp index 634fcb92de..0395ae1f29 100644 --- a/arangod/Replication/Syncer.cpp +++ b/arangod/Replication/Syncer.cpp @@ -527,7 +527,7 @@ int Syncer::dropCollection(VPackSlice const& slice, bool reportError) { return TRI_ERROR_NO_ERROR; } - return _vocbase->dropCollection(col, true); + return _vocbase->dropCollection(col, true, true); } //////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/RestHandler/RestReplicationHandler.cpp b/arangod/RestHandler/RestReplicationHandler.cpp index cb38965cd7..2c7e3b98b4 100644 --- a/arangod/RestHandler/RestReplicationHandler.cpp +++ b/arangod/RestHandler/RestReplicationHandler.cpp @@ -1572,7 +1572,7 @@ int RestReplicationHandler::processRestoreCollection( // drop an existing collection if it exists if (col != nullptr) { if (dropExisting) { - int res = _vocbase->dropCollection(col, true); + int res = _vocbase->dropCollection(col, true, true); if (res == TRI_ERROR_FORBIDDEN) { // some collections must not be dropped diff --git a/arangod/StorageEngine/MMFilesEngine.cpp b/arangod/StorageEngine/MMFilesEngine.cpp index b8ba1e28a5..8c772e7af3 100644 --- a/arangod/StorageEngine/MMFilesEngine.cpp +++ b/arangod/StorageEngine/MMFilesEngine.cpp @@ -1200,7 +1200,7 @@ std::string MMFilesEngine::collectionDirectory(TRI_voc_tick_t databaseId, TRI_vo auto it = _collectionPaths.find(databaseId); if (it == _collectionPaths.end()) { - THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "trying to determine directory for unknown collection"); + THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "trying to determine directory for unknown database"); } auto it2 = (*it).second.find(id); @@ -1357,7 +1357,7 @@ void MMFilesEngine::unregisterCollectionPath(TRI_voc_tick_t databaseId, TRI_voc_ if (it == _collectionPaths.end()) { return; } - (*it).second.erase(id); +// (*it).second.erase(id); } void MMFilesEngine::saveCollectionInfo(TRI_vocbase_t* vocbase, diff --git a/arangod/V8Server/v8-collection.cpp b/arangod/V8Server/v8-collection.cpp index dc6c65c9cc..6bf519b771 100644 --- a/arangod/V8Server/v8-collection.cpp +++ b/arangod/V8Server/v8-collection.cpp @@ -843,7 +843,22 @@ static void JS_DropVocbaseCol(v8::FunctionCallbackInfo const& args) { return; } - int res = collection->vocbase()->dropCollection(collection, true); + bool allowDropSystem = false; + if (args.Length() > 0) { + // options + if (args[0]->IsObject()) { + TRI_GET_GLOBALS(); + v8::Handle optionsObject = args[0].As(); + TRI_GET_GLOBAL_STRING(IsSystemKey); + if (optionsObject->Has(IsSystemKey)) { + allowDropSystem = TRI_ObjectToBoolean(optionsObject->Get(IsSystemKey)); + } + } else { + allowDropSystem = TRI_ObjectToBoolean(args[0]); + } + } + + int res = collection->vocbase()->dropCollection(collection, allowDropSystem, true); if (res != TRI_ERROR_NO_ERROR) { TRI_V8_THROW_EXCEPTION_MESSAGE(res, "cannot drop collection"); diff --git a/arangod/VocBase/vocbase.cpp b/arangod/VocBase/vocbase.cpp index ec5b8297b2..bbf8a1eac6 100644 --- a/arangod/VocBase/vocbase.cpp +++ b/arangod/VocBase/vocbase.cpp @@ -915,11 +915,13 @@ int TRI_vocbase_t::unloadCollection(arangodb::LogicalCollection* collection, boo } /// @brief drops a collection -int TRI_vocbase_t::dropCollection(arangodb::LogicalCollection* collection, bool writeMarker) { +int TRI_vocbase_t::dropCollection(arangodb::LogicalCollection* collection, bool allowDropSystem, bool writeMarker) { TRI_ASSERT(collection != nullptr); - if (collection->isSystem() && + if (!allowDropSystem && + collection->isSystem() && !arangodb::wal::LogfileManager::instance()->isInRecovery()) { + // prevent dropping of system collections return TRI_set_errno(TRI_ERROR_FORBIDDEN); } diff --git a/arangod/VocBase/vocbase.h b/arangod/VocBase/vocbase.h index b282046938..e6fcf23d2d 100644 --- a/arangod/VocBase/vocbase.h +++ b/arangod/VocBase/vocbase.h @@ -315,7 +315,7 @@ struct TRI_vocbase_t { bool writeMarker); /// @brief drops a collection - int dropCollection(arangodb::LogicalCollection* collection, bool writeMarker); + int dropCollection(arangodb::LogicalCollection* collection, bool allowDropSystem, bool writeMarker); /// @brief callback for collection dropping static bool DropCollectionCallback(arangodb::LogicalCollection* collection); diff --git a/arangod/Wal/RecoverState.cpp b/arangod/Wal/RecoverState.cpp index 3f72ae4828..2a35962363 100644 --- a/arangod/Wal/RecoverState.cpp +++ b/arangod/Wal/RecoverState.cpp @@ -597,7 +597,7 @@ bool RecoverState::ReplayMarker(TRI_df_marker_t const* marker, void* data, if (other != nullptr) { TRI_voc_cid_t otherCid = other->cid(); state->releaseCollection(otherCid); - vocbase->dropCollection(other, false); + vocbase->dropCollection(other, true, false); } int res = vocbase->renameCollection(collection, name, true, false); @@ -768,7 +768,7 @@ bool RecoverState::ReplayMarker(TRI_df_marker_t const* marker, void* data, if (collection != nullptr) { // drop an existing collection - vocbase->dropCollection(collection, false); + vocbase->dropCollection(collection, true, false); } #ifdef ARANGODB_ENABLE_ROCKSDB @@ -788,7 +788,7 @@ bool RecoverState::ReplayMarker(TRI_df_marker_t const* marker, void* data, TRI_voc_cid_t otherCid = collection->cid(); state->releaseCollection(otherCid); - vocbase->dropCollection(collection, false); + vocbase->dropCollection(collection, true, false); } } else { LOG(WARN) << "empty name attribute in create collection marker for collection " << collectionId << " and database " << databaseId; @@ -973,7 +973,7 @@ bool RecoverState::ReplayMarker(TRI_df_marker_t const* marker, void* data, } if (collection != nullptr) { - vocbase->dropCollection(collection, false); + vocbase->dropCollection(collection, true, false); } #ifdef ARANGODB_ENABLE_ROCKSDB RocksDBFeature::dropCollection(databaseId, collectionId); diff --git a/js/actions/_api/collection/app.js b/js/actions/_api/collection/app.js index 1179bed455..4e6ddbbe3b 100644 --- a/js/actions/_api/collection/app.js +++ b/js/actions/_api/collection/app.js @@ -601,7 +601,15 @@ function delete_api_collection (req, res) { id: collection._id }; - collection.drop(); + var options = {}; + if (req.parameters.hasOwnProperty('isSystem')) { + // are we allowed to drop system collections? + var value = req.parameters.isSystem.toLowerCase(); + if (value === 'true' || value === 'yes' || value === 'on' || value === 'y' || value === '1') { + options.isSystem = true; + } + } + collection.drop(options); actions.resultOk(req, res, actions.HTTP_OK, result); } catch (err) { diff --git a/js/client/modules/@arangodb/arango-collection.js b/js/client/modules/@arangodb/arango-collection.js index 265d903d68..7a8dfd88d9 100644 --- a/js/client/modules/@arangodb/arango-collection.js +++ b/js/client/modules/@arangodb/arango-collection.js @@ -425,8 +425,13 @@ ArangoCollection.prototype.revision = function () { // / @brief drops a collection // ////////////////////////////////////////////////////////////////////////////// -ArangoCollection.prototype.drop = function () { - var requestResult = this._database._connection.DELETE(this._baseurl()); +ArangoCollection.prototype.drop = function (options) { + var requestResult; + if (typeof options === 'object' && options.isSystem) { + requestResult = this._database._connection.DELETE(this._baseurl() + '?isSystem=true'); + } else { + requestResult = this._database._connection.DELETE(this._baseurl()); + } if (requestResult !== null && requestResult.error === true diff --git a/js/client/modules/@arangodb/arango-database.js b/js/client/modules/@arangodb/arango-database.js index d00f3fff9a..7820c4fcbd 100644 --- a/js/client/modules/@arangodb/arango-database.js +++ b/js/client/modules/@arangodb/arango-database.js @@ -386,7 +386,7 @@ ArangoDatabase.prototype._truncate = function (id) { // / @brief drops a collection // ////////////////////////////////////////////////////////////////////////////// -ArangoDatabase.prototype._drop = function (id) { +ArangoDatabase.prototype._drop = function (id, options) { var name; for (name in this) { @@ -395,7 +395,7 @@ ArangoDatabase.prototype._drop = function (id) { if (collection instanceof this._collectionConstructor) { if (collection._id === id || collection._name === id) { - return collection.drop(); + return collection.drop(options); } } } @@ -403,7 +403,7 @@ ArangoDatabase.prototype._drop = function (id) { var c = this._collection(id); if (c) { - return c.drop(); + return c.drop(options); } return undefined; }; diff --git a/js/server/modules/@arangodb/arango-database.js b/js/server/modules/@arangodb/arango-database.js index 6043bb2156..be2eb91c47 100644 --- a/js/server/modules/@arangodb/arango-database.js +++ b/js/server/modules/@arangodb/arango-database.js @@ -118,7 +118,7 @@ ArangoDatabase.prototype._executeTransaction = function (data) { // / @brief was docuBlock collectionDatabaseDrop // ////////////////////////////////////////////////////////////////////////////// -ArangoDatabase.prototype._drop = function (name) { +ArangoDatabase.prototype._drop = function (name, options) { var collection = name; if (!(name instanceof ArangoCollection)) { @@ -130,7 +130,7 @@ ArangoDatabase.prototype._drop = function (name) { } try { - return collection.drop(); + return collection.drop(options); } catch (err) { // ignore if the collection does not exist if (err instanceof ArangoError && diff --git a/js/server/tests/replication/replication-static.js b/js/server/tests/replication/replication-static.js index 899153fa51..154f0bc7ba 100644 --- a/js/server/tests/replication/replication-static.js +++ b/js/server/tests/replication/replication-static.js @@ -187,7 +187,7 @@ function ReplicationSuite() { db._drop(cn); db._drop(cn2); - db._drop("_test"); + db._drop("_test", { isSystem: true }); }, //////////////////////////////////////////////////////////////////////////////// @@ -199,14 +199,14 @@ function ReplicationSuite() { db._drop(cn); db._drop(cn2); - db._drop("_test"); + db._drop("_test", { isSystem: true }); connectToSlave(); replication.applier.stop(); replication.applier.forget(); db._drop(cn); db._drop(cn2); - db._drop("_test"); + db._drop("_test", { isSystem: true }); }, ////////////////////////////////////////////////////////////////////////////////