From bae9f097fc01b2108d1b184178e47e9174a11307 Mon Sep 17 00:00:00 2001 From: Jan Steemann Date: Mon, 2 Sep 2013 18:04:19 +0200 Subject: [PATCH] added _dropDatabase() --- arangod/RestServer/ArangoServer.cpp | 2 +- arangod/RestServer/VocbaseManager.cpp | 54 +++++- arangod/RestServer/VocbaseManager.h | 45 ++++- arangod/V8Server/v8-vocbase.cpp | 154 +++++++++++------ arangod/VocBase/vocbase.c | 156 +++++++++++++++--- arangod/VocBase/vocbase.h | 27 ++- js/actions/api-database.js | 14 ++ .../org/arangodb/arango-collection-common.js | 3 +- .../modules/org/arangodb/arango-database.js | 23 ++- .../modules/org/arangodb/arango-database.js | 23 ++- .../org/arangodb/arango-collection-common.js | 3 +- .../modules/org/arangodb/arango-database.js | 12 +- 12 files changed, 424 insertions(+), 92 deletions(-) diff --git a/arangod/RestServer/ArangoServer.cpp b/arangod/RestServer/ArangoServer.cpp index 5910ae05e5..c2aed514d9 100644 --- a/arangod/RestServer/ArangoServer.cpp +++ b/arangod/RestServer/ArangoServer.cpp @@ -1346,7 +1346,7 @@ void ArangoServer::openDatabases () { void ArangoServer::closeDatabases () { TRI_CleanupActions(); - TRI_DestroyVocBase(_vocbase); + TRI_DestroyVocBase(_vocbase, 0); TRI_Free(TRI_UNKNOWN_MEM_ZONE, _vocbase); _vocbase = 0; diff --git a/arangod/RestServer/VocbaseManager.cpp b/arangod/RestServer/VocbaseManager.cpp index 93a1c98e1f..58a9aa7eda 100644 --- a/arangod/RestServer/VocbaseManager.cpp +++ b/arangod/RestServer/VocbaseManager.cpp @@ -138,8 +138,9 @@ void VocbaseManager::closeUserVocbases () { std::map::iterator i = _vocbases.begin(); for (; i != _vocbases.end(); ++i) { - TRI_vocbase_t* vocbase = i->second; - TRI_DestroyVocBase(vocbase); + TRI_vocbase_t* vocbase = (*i).second; + + TRI_DestroyVocBase(vocbase, 0); TRI_Free(TRI_UNKNOWN_MEM_ZONE, vocbase); } @@ -147,7 +148,7 @@ void VocbaseManager::closeUserVocbases () { } //////////////////////////////////////////////////////////////////////////////// -/// @brief look vocbase by name +/// @brief look up vocbase by name //////////////////////////////////////////////////////////////////////////////// TRI_vocbase_t* VocbaseManager::lookupVocbaseByName (string const& name) { @@ -219,6 +220,53 @@ bool VocbaseManager::isValidName (std::string const& name) const { return TRI_IsAllowedCollectionName(false, name.c_str()); } +//////////////////////////////////////////////////////////////////////////////// +/// @brief remove a vocbase by name +//////////////////////////////////////////////////////////////////////////////// + +int VocbaseManager::deleteVocbase (string const& name) { + if (name == TRI_VOC_SYSTEM_DATABASE) { + // cannot delete _system database + return TRI_ERROR_FORBIDDEN; + } + + TRI_vocbase_t* vocbase = 0; + + { + WRITE_LOCKER(_rwLock); + + map::iterator find = _vocbases.find(name); + if (find == _vocbases.end()) { + // database does not exist + return TRI_ERROR_ARANGO_DOCUMENT_NOT_FOUND; + } + + // ok, we found it + vocbase = (*find).second; + + // remove from the list + _vocbases.erase(name); + } + + assert(vocbase != 0); + + const string path = string(vocbase->_path); + LOGGER_INFO("removing database '" << name << "', path '" << path << "'"); + + // destroy the vocbase, but not its collections + // there might be JavaScript objects referencing the collections somehow, + // so we must not free them yet + // putting the collections in this vector will allow us freeing them later + TRI_DestroyVocBase(vocbase, _freeCollections); + // same for the vocbase + _freeVocbases.push_back(vocbase); + + // ok, now delete the data in the file system + int res = TRI_RemoveDirectory(path.c_str()); + + return res; +} + //////////////////////////////////////////////////////////////////////////////// /// @brief run version check /// @return bool returns false if the version check fails diff --git a/arangod/RestServer/VocbaseManager.h b/arangod/RestServer/VocbaseManager.h index aa4d70563d..2dab49956a 100644 --- a/arangod/RestServer/VocbaseManager.h +++ b/arangod/RestServer/VocbaseManager.h @@ -40,9 +40,12 @@ #include "VocBase/vocbase.h" #include #include +#include #include "v8.h" +struct TRI_vector_pointer_s; + namespace triagens { namespace rest { class ApplicationEndpointServer; @@ -79,9 +82,31 @@ namespace triagens { _rwLock(), _authCache(), _startupLoader(0), - _endpointServer(0) { + _endpointServer(0), + _freeCollections(0), + _freeVocbases() { + + // allocate some space for collection pointers that we need to remove later + _freeCollections = (TRI_vector_pointer_t*) TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_vector_pointer_t), false); + + if (_freeCollections != 0) { + TRI_InitVectorPointer(_freeCollections, TRI_UNKNOWN_MEM_ZONE); + } }; + ~VocbaseManager () { + // if we have buffered some collections, we must now free them + if (_freeCollections != 0) { + TRI_FreeCollectionsVocBase(_freeCollections); + TRI_FreeVectorPointer(TRI_UNKNOWN_MEM_ZONE, _freeCollections); + } + + // on shutdown, we'll free all vocbases we had collected + for (size_t i = 0; i < _freeVocbases.size(); ++i) { + TRI_Free(TRI_UNKNOWN_MEM_ZONE, _freeVocbases[i]); + } + } + VocbaseManager (const VocbaseManager&); VocbaseManager& operator= (const VocbaseManager&); @@ -158,6 +183,12 @@ namespace triagens { bool isValidName (std::string const&) const; +//////////////////////////////////////////////////////////////////////////////// +/// @brief remove a vocbase by name +//////////////////////////////////////////////////////////////////////////////// + + int deleteVocbase (string const&); + //////////////////////////////////////////////////////////////////////////////// /// @brief add the startup loader //////////////////////////////////////////////////////////////////////////////// @@ -310,6 +341,18 @@ namespace triagens { //////////////////////////////////////////////////////////////////////////////// triagens::rest::ApplicationEndpointServer* _endpointServer; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief a vector of collections that we own and must free at the end +//////////////////////////////////////////////////////////////////////////////// + + struct TRI_vector_pointer_s* _freeCollections; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief a vector of vocbases that we own and must free at the end +//////////////////////////////////////////////////////////////////////////////// + + std::vector _freeVocbases; }; } diff --git a/arangod/V8Server/v8-vocbase.cpp b/arangod/V8Server/v8-vocbase.cpp index 6d3237b268..31396b0fc9 100644 --- a/arangod/V8Server/v8-vocbase.cpp +++ b/arangod/V8Server/v8-vocbase.cpp @@ -843,19 +843,6 @@ static v8::Handle EnsureFulltextIndex (v8::Arguments const& argv, return scope.Close(index); } -//////////////////////////////////////////////////////////////////////////////// -/// @brief extracts a vocbase from a javascript object -//////////////////////////////////////////////////////////////////////////////// - -static TRI_vocbase_t* UnwrapVocBase (v8::Handle vocbaseObject) { - if (false) { - return TRI_UnwrapClass(vocbaseObject, WRP_VOCBASE_TYPE); - } - else { - return GetContextVocBase(); - } -} - //////////////////////////////////////////////////////////////////////////////// /// @brief looks up a document and returns it //////////////////////////////////////////////////////////////////////////////// @@ -888,7 +875,7 @@ static v8::Handle DocumentVocbaseCol (const bool useCollection, } else { // called as db._document() - vocbase = UnwrapVocBase(argv.Holder()); + vocbase = GetContextVocBase(); } assert(vocbase); @@ -994,7 +981,7 @@ static v8::Handle ExistsVocbaseCol (const bool useCollection, } else { // called as db._exists() - vocbase = UnwrapVocBase(argv.Holder()); + vocbase = GetContextVocBase(); } assert(vocbase); @@ -1097,8 +1084,7 @@ static v8::Handle ReplaceVocbaseCol (const bool useCollection, } else { // called as db._replace() - //vocbase = TRI_UnwrapClass(argv.Holder(), WRP_VOCBASE_TYPE); - vocbase = UnwrapVocBase(argv.Holder()); + vocbase = GetContextVocBase(); } assert(vocbase); @@ -1396,8 +1382,7 @@ static v8::Handle UpdateVocbaseCol (const bool useCollection, } else { // called as db._update() - //vocbase = TRI_UnwrapClass(argv.Holder(), WRP_VOCBASE_TYPE); - vocbase = UnwrapVocBase(argv.Holder()); + vocbase = GetContextVocBase(); } assert(vocbase); @@ -1517,7 +1502,7 @@ static v8::Handle RemoveVocbaseCol (const bool useCollection, } else { // called as db._remove() - vocbase = UnwrapVocBase(argv.Holder()); + vocbase = GetContextVocBase(); } assert(vocbase); @@ -1565,8 +1550,7 @@ static v8::Handle RemoveVocbaseCol (const bool useCollection, static v8::Handle CreateVocBase (v8::Arguments const& argv, TRI_col_type_e collectionType) { v8::HandleScope scope; - //TRI_vocbase_t* vocbase = TRI_UnwrapClass(argv.Holder(), WRP_VOCBASE_TYPE); - TRI_vocbase_t* vocbase = UnwrapVocBase(argv.Holder()); + TRI_vocbase_t* vocbase = GetContextVocBase(); if (vocbase == 0) { TRI_V8_EXCEPTION_INTERNAL(scope, "cannot extract vocbase"); @@ -4555,7 +4539,7 @@ static v8::Handle JS_CountVocbaseCol (v8::Arguments const& argv) { int res = trx.begin(); if (res != TRI_ERROR_NO_ERROR) { - TRI_V8_EXCEPTION_MESSAGE(scope, res, "cannot count documents"); + TRI_V8_EXCEPTION(scope, res); } TRI_primary_collection_t* primary = trx.primaryCollection(); @@ -5895,6 +5879,7 @@ static v8::Handle JS_NameVocbaseCol (v8::Arguments const& argv) { // if we wouldn't do this, we would risk other threads modifying the name while // we're reading it char* name = TRI_GetCollectionNameByIdVocBase(collection->_vocbase, collection->_cid); + if (name == 0) { return scope.Close(v8::Undefined()); } @@ -6919,8 +6904,7 @@ static v8::Handle MapGetVocBase (v8::Local name, v8::HandleScope scope; v8::Handle holder = info.Holder()->ToObject(); - //TRI_vocbase_t* vocbase = TRI_UnwrapClass(holder, WRP_VOCBASE_TYPE); - TRI_vocbase_t* vocbase = UnwrapVocBase(holder); + TRI_vocbase_t* vocbase = GetContextVocBase(); if (vocbase == 0) { TRI_V8_EXCEPTION_INTERNAL(scope, "cannot extract vocbase"); @@ -7027,7 +7011,7 @@ static v8::Handle MapGetVocBase (v8::Local name, static v8::Handle JS_CollectionVocbase (v8::Arguments const& argv) { v8::HandleScope scope; - TRI_vocbase_t* vocbase = UnwrapVocBase(argv.Holder()); + TRI_vocbase_t* vocbase = GetContextVocBase(); if (vocbase == 0) { TRI_V8_EXCEPTION_INTERNAL(scope, "cannot extract vocbase"); @@ -7081,8 +7065,7 @@ static v8::Handle JS_CollectionVocbase (v8::Arguments const& argv) { static v8::Handle JS_CollectionsVocbase (v8::Arguments const& argv) { v8::HandleScope scope; - //TRI_vocbase_t* vocbase = TRI_UnwrapClass(argv.Holder(), WRP_VOCBASE_TYPE); - TRI_vocbase_t* vocbase = UnwrapVocBase(argv.Holder()); + TRI_vocbase_t* vocbase = GetContextVocBase(); if (vocbase == 0) { TRI_V8_EXCEPTION_INTERNAL(scope, "cannot extract vocbase"); @@ -7091,10 +7074,10 @@ static v8::Handle JS_CollectionsVocbase (v8::Arguments const& argv) { TRI_vector_pointer_t colls = TRI_CollectionsVocBase(vocbase); bool error = false; - uint32_t n = (uint32_t) colls._length; // already create an array of the correct size - v8::Handle result = v8::Array::New(n); + v8::Handle result = v8::Array::New(); + uint32_t n = (uint32_t) colls._length; for (uint32_t i = 0; i < n; ++i) { TRI_vocbase_col_t const* collection = (TRI_vocbase_col_t const*) colls._buffer[i]; @@ -7104,7 +7087,7 @@ static v8::Handle JS_CollectionsVocbase (v8::Arguments const& argv) { error = true; break; } - + result->Set(i, c); } @@ -7124,8 +7107,7 @@ static v8::Handle JS_CollectionsVocbase (v8::Arguments const& argv) { static v8::Handle JS_CompletionsVocbase (v8::Arguments const& argv) { v8::HandleScope scope; - // TRI_vocbase_t* vocbase = TRI_UnwrapClass(argv.Holder(), WRP_VOCBASE_TYPE); - TRI_vocbase_t* vocbase = UnwrapVocBase(argv.Holder()); + TRI_vocbase_t* vocbase = GetContextVocBase(); if (vocbase == 0) { return scope.Close(v8::Array::New()); @@ -7158,20 +7140,24 @@ static v8::Handle JS_CompletionsVocbase (v8::Arguments const& argv) { result->Set(j++, v8::String::New("_collection()")); result->Set(j++, v8::String::New("_collections()")); result->Set(j++, v8::String::New("_create()")); + result->Set(j++, v8::String::New("_createDatabase()")); result->Set(j++, v8::String::New("_createDocumentCollection()")); result->Set(j++, v8::String::New("_createEdgeCollection()")); result->Set(j++, v8::String::New("_createStatement()")); result->Set(j++, v8::String::New("_document()")); result->Set(j++, v8::String::New("_drop()")); + result->Set(j++, v8::String::New("_dropDatabase()")); result->Set(j++, v8::String::New("_executeTransaction()")); result->Set(j++, v8::String::New("_exists()")); result->Set(j++, v8::String::New("_isSystem()")); + result->Set(j++, v8::String::New("_listDatabases()")); result->Set(j++, v8::String::New("_name()")); result->Set(j++, v8::String::New("_path()")); result->Set(j++, v8::String::New("_query()")); result->Set(j++, v8::String::New("_remove()")); result->Set(j++, v8::String::New("_replace()")); result->Set(j++, v8::String::New("_update()")); + result->Set(j++, v8::String::New("_useDatabase()")); result->Set(j++, v8::String::New("_version()")); return scope.Close(result); @@ -7552,7 +7538,7 @@ static v8::Handle JS_VersionVocbase (v8::Arguments const& argv) { static v8::Handle JS_PathVocbase (v8::Arguments const& argv) { v8::HandleScope scope; - TRI_vocbase_t* vocbase = UnwrapVocBase(argv.Holder()); + TRI_vocbase_t* vocbase = GetContextVocBase(); return scope.Close(v8::String::New(vocbase->_path)); } @@ -7568,7 +7554,7 @@ static v8::Handle JS_PathVocbase (v8::Arguments const& argv) { static v8::Handle JS_NameVocbase (v8::Arguments const& argv) { v8::HandleScope scope; - TRI_vocbase_t* vocbase = UnwrapVocBase(argv.Holder()); + TRI_vocbase_t* vocbase = GetContextVocBase(); return scope.Close(v8::String::New(vocbase->_name)); } @@ -7584,7 +7570,7 @@ static v8::Handle JS_NameVocbase (v8::Arguments const& argv) { static v8::Handle JS_IsSystemVocbase (v8::Arguments const& argv) { v8::HandleScope scope; - TRI_vocbase_t* vocbase = UnwrapVocBase(argv.Holder()); + TRI_vocbase_t* vocbase = GetContextVocBase(); return scope.Close(v8::Boolean::New(vocbase->_isSystem)); } @@ -7708,14 +7694,14 @@ static v8::Handle saveToCollection (TRI_vocbase_t* vocbase, res = trx.finish(res); if (res != TRI_ERROR_NO_ERROR) { - TRI_V8_EXCEPTION_MESSAGE(scope, res, "cannot save document"); + TRI_V8_EXCEPTION(scope, res); } // return OK return scope.Close(result); } - TRI_V8_EXCEPTION_MESSAGE(scope, res, "cannot save document into collection"); + TRI_V8_EXCEPTION(scope, res); } //////////////////////////////////////////////////////////////////////////////// @@ -7733,7 +7719,11 @@ static v8::Handle JS_CreateUserVocbase (v8::Arguments const& argv) { TRI_V8_EXCEPTION_USAGE(scope, "CREATE_DATABASE(, , )"); } - TRI_vocbase_t* vocbase = UnwrapVocBase(argv.Holder()); + TRI_vocbase_t* vocbase = GetContextVocBase(); + + if (vocbase == 0) { + TRI_V8_EXCEPTION_INTERNAL(scope, "cannot extract vocbase"); + } if (! vocbase->_isSystem) { TRI_V8_EXCEPTION(scope, TRI_ERROR_ARANGO_USE_SYSTEM_DATABASE); @@ -7827,7 +7817,7 @@ static v8::Handle JS_CreateUserVocbase (v8::Arguments const& argv) { if (! vocbaseOk) { VocbaseManager::manager.unlockCreation(); // unload vocbase - TRI_DestroyVocBase(userVocbase); + TRI_DestroyVocBase(userVocbase, 0); TRI_Free(TRI_UNKNOWN_MEM_ZONE, userVocbase); userVocbase = 0; @@ -7869,7 +7859,7 @@ static v8::Handle JS_CreateUserVocbase (v8::Arguments const& argv) { VocbaseManager::manager.unlockCreation(); // unload vocbase - TRI_DestroyVocBase(userVocbase); + TRI_DestroyVocBase(userVocbase, 0); TRI_Free(TRI_UNKNOWN_MEM_ZONE, userVocbase); userVocbase = 0; @@ -7882,6 +7872,73 @@ static v8::Handle JS_CreateUserVocbase (v8::Arguments const& argv) { return scope.Close(result); } +//////////////////////////////////////////////////////////////////////////////// +/// @brief delete an existing database +/// +/// @FUN{DELETE_DATABASE} +//////////////////////////////////////////////////////////////////////////////// + +static v8::Handle JS_DeleteUserVocbase (v8::Arguments const& argv) { + v8::HandleScope scope; + + if (argv.Length() != 1) { + TRI_V8_EXCEPTION_USAGE(scope, "DELETE_DATABASE()"); + } + + TRI_vocbase_t* vocbase = GetContextVocBase(); + + if (vocbase == 0) { + TRI_V8_EXCEPTION_INTERNAL(scope, "cannot extract vocbase"); + } + + if (! vocbase->_isSystem) { + TRI_V8_EXCEPTION(scope, TRI_ERROR_ARANGO_USE_SYSTEM_DATABASE); + } + + const string name = TRI_ObjectToString(argv[0]); + + // exclusive lock start + // --------------------------------------------------------- + + VocbaseManager::manager.lockCreation(); + + int res = VocbaseManager::manager.deleteVocbase(name); + + if (res == TRI_ERROR_NO_ERROR) { + TRI_vocbase_col_t* col = TRI_LookupCollectionByNameVocBase(vocbase, TRI_COL_NAME_DATABASES); + + if (col == 0) { + VocbaseManager::manager.unlockCreation(); + TRI_V8_EXCEPTION_INTERNAL(scope, "cannot extract collection"); + } + + CollectionNameResolver resolver(col->_vocbase); + SingleCollectionWriteTransaction, 1> trx(col->_vocbase, resolver, col->_cid); + + res = trx.begin(); + + if (res != TRI_ERROR_NO_ERROR) { + VocbaseManager::manager.unlockCreation(); + TRI_V8_EXCEPTION(scope, res); + } + + trx.deleteDocument(name.c_str(), TRI_DOC_UPDATE_LAST_WRITE, false, 0, 0); + + res = trx.finish(res); + } + + VocbaseManager::manager.unlockCreation(); + + // exclusive lock end + // --------------------------------------------------------- + + if (res != TRI_ERROR_NO_ERROR) { + TRI_V8_EXCEPTION(scope, res); + } + + return scope.Close(v8::True()); +} + //////////////////////////////////////////////////////////////////////////////// /// @brief add a new endpoint /// @@ -7897,7 +7954,11 @@ static v8::Handle JS_AddEndpoint (v8::Arguments const& argv) { TRI_V8_EXCEPTION_USAGE(scope, "ADD_ENDPOINT(, )"); } - TRI_vocbase_t* vocbase = UnwrapVocBase(argv.Holder()); + TRI_vocbase_t* vocbase = GetContextVocBase(); + + if (vocbase == 0) { + TRI_V8_EXCEPTION_INTERNAL(scope, "cannot extract vocbase"); + } if (! vocbase->_isSystem) { TRI_V8_EXCEPTION(scope, TRI_ERROR_ARANGO_USE_SYSTEM_DATABASE); @@ -8765,13 +8826,14 @@ void TRI_InitV8VocBridge (v8::Handle context, TRI_AddGlobalFunctionVocbase(context, "FORMAT_DATETIME", JS_formatDatetime); TRI_AddGlobalFunctionVocbase(context, "PARSE_DATETIME", JS_parseDatetime); - TRI_AddGlobalFunctionVocbase(context, "RELOAD_AUTH", JS_ReloadAuth); - TRI_AddGlobalFunctionVocbase(context, "TRANSACTION", JS_Transaction); + TRI_AddGlobalFunctionVocbase(context, "RELOAD_AUTH", JS_ReloadAuth, true); + TRI_AddGlobalFunctionVocbase(context, "TRANSACTION", JS_Transaction, true); - TRI_AddGlobalFunctionVocbase(context, "USE_DATABASE", JS_UseVocbase); + TRI_AddGlobalFunctionVocbase(context, "USE_DATABASE", JS_UseVocbase, true); TRI_AddGlobalFunctionVocbase(context, "LIST_DATABASES", JS_ListVocbases, true); TRI_AddGlobalFunctionVocbase(context, "CREATE_DATABASE", JS_CreateUserVocbase, true); - TRI_AddGlobalFunctionVocbase(context, "ADD_ENDPOINT", JS_AddEndpoint); + TRI_AddGlobalFunctionVocbase(context, "DELETE_DATABASE", JS_DeleteUserVocbase, true); + TRI_AddGlobalFunctionVocbase(context, "ADD_ENDPOINT", JS_AddEndpoint, true); // ............................................................................. // create global variables diff --git a/arangod/VocBase/vocbase.c b/arangod/VocBase/vocbase.c index 2784c636aa..b7ccb84826 100644 --- a/arangod/VocBase/vocbase.c +++ b/arangod/VocBase/vocbase.c @@ -445,16 +445,6 @@ static int WriteShutdownInfo (char const* filename) { return TRI_ERROR_NO_ERROR; } -//////////////////////////////////////////////////////////////////////////////// -/// @brief free the memory associated with a collection -//////////////////////////////////////////////////////////////////////////////// - -static void FreeCollection (TRI_vocbase_t* vocbase, TRI_vocbase_col_t* collection) { - TRI_DestroyReadWriteLock(&collection->_lock); - - TRI_Free(TRI_UNKNOWN_MEM_ZONE, collection); -} - //////////////////////////////////////////////////////////////////////////////// /// @brief removes a collection name from the global list of collections /// @@ -488,16 +478,20 @@ static bool UnregisterCollection (TRI_vocbase_t* vocbase, static bool UnloadCollectionCallback (TRI_collection_t* col, void* data) { TRI_vocbase_col_t* collection; +#if 0 TRI_vocbase_t* vocbase; TRI_voc_cid_t cid; +#endif TRI_document_collection_t* document; int res; collection = data; TRI_WRITE_LOCK_STATUS_VOCBASE_COL(collection); +#if 0 cid = collection->_cid; vocbase = collection->_vocbase; +#endif if (collection->_status != TRI_VOC_COL_STATUS_UNLOADING) { TRI_WRITE_UNLOCK_STATUS_VOCBASE_COL(collection); @@ -550,9 +544,11 @@ static bool UnloadCollectionCallback (TRI_collection_t* col, void* data) { collection->_status = TRI_VOC_COL_STATUS_UNLOADED; collection->_collection = NULL; +#if 0 if (cid > 0) { TRI_RemoveCollectionTransactionContext(vocbase->_transactionContext, cid); } +#endif TRI_WRITE_UNLOCK_STATUS_VOCBASE_COL(collection); return true; @@ -562,18 +558,23 @@ static bool UnloadCollectionCallback (TRI_collection_t* col, void* data) { /// @brief drops a collection //////////////////////////////////////////////////////////////////////////////// -static bool DropCollectionCallback (TRI_collection_t* col, void* data) { +static bool DropCollectionCallback (TRI_collection_t* col, + void* data) { TRI_document_collection_t* document; TRI_vocbase_col_t* collection; TRI_vocbase_t* vocbase; +#if 0 TRI_voc_cid_t cid; +#endif regmatch_t matches[3]; regex_t re; int res; size_t i; collection = data; +#if 0 cid = 0; +#endif #ifdef _WIN32 // ......................................................................... @@ -618,7 +619,9 @@ static bool DropCollectionCallback (TRI_collection_t* col, void* data) { return false; } +#if 0 cid = collection->_cid; +#endif document = (TRI_document_collection_t*) collection->_collection; @@ -737,9 +740,11 @@ static bool DropCollectionCallback (TRI_collection_t* col, void* data) { regfree(&re); +#if 0 if (cid > 0) { TRI_RemoveCollectionTransactionContext(vocbase->_transactionContext, cid); } +#endif return true; } @@ -1137,6 +1142,10 @@ static int ScanPath (TRI_vocbase_t* vocbase, static int LoadCollectionVocBase (TRI_vocbase_t* vocbase, TRI_vocbase_col_t* collection) { TRI_col_type_e type; + + if (! TRI_CanUseVocBase(vocbase)) { + return TRI_ERROR_ARANGO_DATABASE_NOT_FOUND; + } // ............................................................................. // read lock @@ -1337,6 +1346,46 @@ size_t PageSize; /// @{ //////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +/// @brief free the memory associated with a collection +//////////////////////////////////////////////////////////////////////////////// + +void TRI_FreeCollectionVocBase (TRI_vocbase_col_t* collection) { + TRI_DestroyReadWriteLock(&collection->_lock); + + TRI_Free(TRI_UNKNOWN_MEM_ZONE, collection); +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief free the memory associated with all collections in a vector +//////////////////////////////////////////////////////////////////////////////// + +void TRI_FreeCollectionsVocBase (TRI_vector_pointer_t* collections) { + size_t i, n; + + n = TRI_LengthVectorPointer(collections); + + for (i = 0; i < n; ++i) { + TRI_vocbase_col_t* c = TRI_AtVectorPointer(collections, i); + + TRI_FreeCollectionVocBase(c); + } +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief returns whether or not the vocbase can be used +//////////////////////////////////////////////////////////////////////////////// + +bool TRI_CanUseVocBase (TRI_vocbase_t* vocbase) { + bool canUse; + + TRI_READ_LOCK_COLLECTIONS_VOCBASE(vocbase); + canUse = vocbase->_canUse; + TRI_READ_UNLOCK_COLLECTIONS_VOCBASE(vocbase); + + return canUse; +} + //////////////////////////////////////////////////////////////////////////////// /// @brief checks if a collection name is allowed /// @@ -1734,6 +1783,8 @@ TRI_vocbase_t* TRI_OpenVocBase (char const* path, } } } + + vocbase->_canUse = true; // we are done return vocbase; @@ -1743,14 +1794,20 @@ TRI_vocbase_t* TRI_OpenVocBase (char const* path, /// @brief closes a database and all collections //////////////////////////////////////////////////////////////////////////////// -void TRI_DestroyVocBase (TRI_vocbase_t* vocbase) { +void TRI_DestroyVocBase (TRI_vocbase_t* vocbase, + TRI_vector_pointer_t* reuseCollections) { TRI_vector_pointer_t collections; size_t i; TRI_InitVectorPointer(&collections, TRI_UNKNOWN_MEM_ZONE); - TRI_READ_LOCK_COLLECTIONS_VOCBASE(vocbase); + + TRI_WRITE_LOCK_COLLECTIONS_VOCBASE(vocbase); + // cannot use this vocbase from now on + vocbase->_canUse = false; TRI_CopyDataVectorPointer(&collections, &vocbase->_collections); - TRI_READ_UNLOCK_COLLECTIONS_VOCBASE(vocbase); + TRI_WRITE_UNLOCK_COLLECTIONS_VOCBASE(vocbase); + + // from here on, the vocbase is unusable, i.e. no collections can be created/loaded etc. // starts unloading of collections for (i = 0; i < collections._length; ++i) { @@ -1791,14 +1848,15 @@ void TRI_DestroyVocBase (TRI_vocbase_t* vocbase) { vocbase->_replicationLogger = NULL; - // free dead collections (already dropped but pointers still around) for (i = 0; i < vocbase->_deadCollections._length; ++i) { TRI_vocbase_col_t* collection; collection = (TRI_vocbase_col_t*) vocbase->_deadCollections._buffer[i]; - TRI_RemoveCollectionTransactionContext(vocbase->_transactionContext, collection->_cid); - FreeCollection(vocbase, collection); + + if (vocbase->_isSystem) { + TRI_FreeCollectionVocBase(collection); + } } // free collections @@ -1806,8 +1864,19 @@ void TRI_DestroyVocBase (TRI_vocbase_t* vocbase) { TRI_vocbase_col_t* collection; collection = (TRI_vocbase_col_t*) vocbase->_collections._buffer[i]; +#if 0 TRI_RemoveCollectionTransactionContext(vocbase->_transactionContext, collection->_cid); - FreeCollection(vocbase, collection); +#endif + + if (reuseCollections != 0) { + // the pointer to the collection is transferred to the other vector, + // which is then responsible to free the collection later + TRI_PushBackVectorPointer(reuseCollections, collection); + } + else { + // instantly free the collection + TRI_FreeCollectionVocBase(collection); + } } // we are just before terminating the server. we can now write out a file with the @@ -2006,7 +2075,6 @@ TRI_json_t* TRI_InventoryCollectionsVocBase (TRI_vocbase_t* vocbase, return json; } - //////////////////////////////////////////////////////////////////////////////// /// @brief gets a collection name by a collection id /// @@ -2022,6 +2090,11 @@ char* TRI_GetCollectionNameByIdVocBase (TRI_vocbase_t* vocbase, TRI_READ_LOCK_COLLECTIONS_VOCBASE(vocbase); + if (! vocbase->_canUse) { + TRI_READ_UNLOCK_COLLECTIONS_VOCBASE(vocbase); + return NULL; + } + found = CONST_CAST(TRI_LookupByKeyAssociativePointer(&vocbase->_collectionsById, &id)); if (found == NULL) { @@ -2040,10 +2113,11 @@ char* TRI_GetCollectionNameByIdVocBase (TRI_vocbase_t* vocbase, /// @brief looks up a (document) collection by name //////////////////////////////////////////////////////////////////////////////// -TRI_vocbase_col_t* TRI_LookupCollectionByNameVocBase (TRI_vocbase_t* vocbase, char const* name) { +TRI_vocbase_col_t* TRI_LookupCollectionByNameVocBase (TRI_vocbase_t* vocbase, + char const* name) { TRI_vocbase_col_t* found; const char c = *name; - + // if collection name is passed as a stringified id, we'll use the lookupbyid function // this is safe because collection names must not start with a digit if (c >= '0' && c <= '9') { @@ -2052,7 +2126,12 @@ TRI_vocbase_col_t* TRI_LookupCollectionByNameVocBase (TRI_vocbase_t* vocbase, ch // otherwise we'll look up the collection by name TRI_READ_LOCK_COLLECTIONS_VOCBASE(vocbase); - found = CONST_CAST(TRI_LookupByKeyAssociativePointer(&vocbase->_collectionsByName, name)); + if (vocbase->_canUse) { + found = CONST_CAST(TRI_LookupByKeyAssociativePointer(&vocbase->_collectionsByName, name)); + } + else { + found = NULL; + } TRI_READ_UNLOCK_COLLECTIONS_VOCBASE(vocbase); return found; @@ -2064,9 +2143,14 @@ TRI_vocbase_col_t* TRI_LookupCollectionByNameVocBase (TRI_vocbase_t* vocbase, ch TRI_vocbase_col_t* TRI_LookupCollectionByIdVocBase (TRI_vocbase_t* vocbase, TRI_voc_cid_t id) { TRI_vocbase_col_t* found; - + TRI_READ_LOCK_COLLECTIONS_VOCBASE(vocbase); - found = CONST_CAST(TRI_LookupByKeyAssociativePointer(&vocbase->_collectionsById, &id)); + if (vocbase->_canUse) { + found = CONST_CAST(TRI_LookupByKeyAssociativePointer(&vocbase->_collectionsById, &id)); + } + else { + found = NULL; + } TRI_READ_UNLOCK_COLLECTIONS_VOCBASE(vocbase); return found; @@ -2081,9 +2165,14 @@ TRI_vocbase_col_t* TRI_FindCollectionByNameOrCreateVocBase (TRI_vocbase_t* vocba const TRI_col_type_t type, TRI_server_id_t generatingServer) { TRI_vocbase_col_t* found; - + TRI_READ_LOCK_COLLECTIONS_VOCBASE(vocbase); - found = CONST_CAST(TRI_LookupByKeyAssociativePointer(&vocbase->_collectionsByName, name)); + if (vocbase->_canUse) { + found = CONST_CAST(TRI_LookupByKeyAssociativePointer(&vocbase->_collectionsByName, name)); + } + else { + found = NULL; + } TRI_READ_UNLOCK_COLLECTIONS_VOCBASE(vocbase); if (found != NULL) { @@ -2139,6 +2228,11 @@ TRI_vocbase_col_t* TRI_CreateCollectionVocBase (TRI_vocbase_t* vocbase, return NULL; } + if (! TRI_CanUseVocBase(vocbase)) { + TRI_set_errno(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND); + return NULL; + } + type = (TRI_col_type_e) parameter->_type; if (! TRI_IS_DOCUMENT_COLLECTION(type)) { @@ -2307,10 +2401,14 @@ int TRI_DropCollectionVocBase (TRI_vocbase_t* vocbase, TRI_server_id_t generatingServer) { int res; + if (! TRI_CanUseVocBase(vocbase)) { + return TRI_set_errno(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND); + } + if (! collection->_canDrop) { return TRI_set_errno(TRI_ERROR_FORBIDDEN); } - + TRI_ReadLockReadWriteLock(&vocbase->_inventoryLock); // mark collection as deleted @@ -2451,6 +2549,10 @@ int TRI_RenameCollectionVocBase (TRI_vocbase_t* vocbase, bool isSystem; int res; + if (! TRI_CanUseVocBase(vocbase)) { + return TRI_set_errno(TRI_ERROR_ARANGO_DATABASE_NOT_FOUND); + } + if (! collection->_canRename) { return TRI_set_errno(TRI_ERROR_FORBIDDEN); } diff --git a/arangod/VocBase/vocbase.h b/arangod/VocBase/vocbase.h index 4357080b9a..2ca2962f8c 100644 --- a/arangod/VocBase/vocbase.h +++ b/arangod/VocBase/vocbase.h @@ -52,6 +52,7 @@ struct TRI_replication_applier_s; struct TRI_replication_logger_s; struct TRI_shadow_store_s; struct TRI_transaction_context_s; +struct TRI_vector_pointer_s; // ----------------------------------------------------------------------------- // --SECTION-- public macros @@ -333,6 +334,8 @@ typedef struct TRI_vocbase_s { bool _isSystem; bool _requireAuthentication; bool _authenticateSystemOnly; + + bool _canUse; // this is set to false during deletion of a database char* _name; // database name @@ -460,11 +463,30 @@ TRI_vocbase_defaults_t; /// @{ //////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +/// @brief free the memory associated with a collection +//////////////////////////////////////////////////////////////////////////////// + +void TRI_FreeCollectionVocBase (TRI_vocbase_col_t*); + +//////////////////////////////////////////////////////////////////////////////// +/// @brief free the memory associated with all collections in a vector +//////////////////////////////////////////////////////////////////////////////// + +void TRI_FreeCollectionsVocBase (struct TRI_vector_pointer_s*); + +//////////////////////////////////////////////////////////////////////////////// +/// @brief returns whether or not the vocbase can be used +//////////////////////////////////////////////////////////////////////////////// + +bool TRI_CanUseVocBase (TRI_vocbase_t*); + //////////////////////////////////////////////////////////////////////////////// /// @brief checks if a collection is allowed //////////////////////////////////////////////////////////////////////////////// -bool TRI_IsAllowedCollectionName (bool, char const*); +bool TRI_IsAllowedCollectionName (bool, + char const*); //////////////////////////////////////////////////////////////////////////////// /// @brief create a new tick @@ -525,7 +547,8 @@ TRI_vocbase_t* TRI_OpenVocBase (char const*, /// @brief closes a database and all collections //////////////////////////////////////////////////////////////////////////////// -void TRI_DestroyVocBase (TRI_vocbase_t*); +void TRI_DestroyVocBase (TRI_vocbase_t*, + struct TRI_vector_pointer_s*); //////////////////////////////////////////////////////////////////////////////// /// @brief set the system defaults diff --git a/js/actions/api-database.js b/js/actions/api-database.js index 3ff596489e..1615cb9199 100644 --- a/js/actions/api-database.js +++ b/js/actions/api-database.js @@ -82,6 +82,17 @@ function post_api_database (req, res) { actions.resultOk(req, res, actions.HTTP_OK, { result : result }); } +function delete_api_database (req, res) { + if (req.suffix.length !== 1) { + actions.resultBad(req, res, arangodb.ERROR_HTTP_BAD_PARAMETER); + return; + } + + var result = arangodb.db._deleteDatabase(req.suffix[0]); + + actions.resultOk(req, res, actions.HTTP_OK, { result : result }); +} + //////////////////////////////////////////////////////////////////////////////// /// @brief handles a database request //////////////////////////////////////////////////////////////////////////////// @@ -98,6 +109,9 @@ actions.defineHttp({ else if (req.requestType === actions.POST) { post_api_database(req, res); } + else if (req.requestType === actions.DELETE) { + delete_api_database(req, res); + } else { actions.resultUnsupported(req, res); } diff --git a/js/apps/aardvark/frontend/js/modules/org/arangodb/arango-collection-common.js b/js/apps/aardvark/frontend/js/modules/org/arangodb/arango-collection-common.js index 63e16417e8..dd967eea2f 100644 --- a/js/apps/aardvark/frontend/js/modules/org/arangodb/arango-collection-common.js +++ b/js/apps/aardvark/frontend/js/modules/org/arangodb/arango-collection-common.js @@ -130,6 +130,7 @@ ArangoCollection.TYPE_EDGE = 3; ArangoCollection.prototype._PRINT = function (context) { var status = "unknown"; var type = "unknown"; + var name = this.name(); switch (this.status()) { case ArangoCollection.STATUS_NEW_BORN: status = "new born"; break; @@ -154,7 +155,7 @@ ArangoCollection.prototype._PRINT = function (context) { if (useColor) { context.output += colors.COLOR_RESET; } context.output += ", \""; if (useColor) { context.output += colors.COLOR_STRING; } - context.output += this.name(); + context.output += name ? name : "unknown"; if (useColor) { context.output += colors.COLOR_RESET; } context.output += "\" (type " + type + ", status " + status + ")]"; }; diff --git a/js/apps/aardvark/frontend/js/modules/org/arangodb/arango-database.js b/js/apps/aardvark/frontend/js/modules/org/arangodb/arango-database.js index 938c7ddf88..53f0f2cad3 100644 --- a/js/apps/aardvark/frontend/js/modules/org/arangodb/arango-database.js +++ b/js/apps/aardvark/frontend/js/modules/org/arangodb/arango-database.js @@ -243,7 +243,7 @@ ArangoDatabase.prototype._help = function () { //////////////////////////////////////////////////////////////////////////////// ArangoDatabase.prototype.toString = function () { - return "[object ArangoDatabase '" + this._name() + "']"; + return "[object ArangoDatabase \"" + this._name() + "\"]"; }; //////////////////////////////////////////////////////////////////////////////// @@ -263,9 +263,8 @@ ArangoDatabase.prototype.toString = function () { /// @brief return all collections from the database //////////////////////////////////////////////////////////////////////////////// -ArangoDatabase.prototype._collections = function (excludeSystem) { - var append = (excludeSystem ? "?excludeSystem=true" : ""); - var requestResult = this._connection.GET(this._collectionurl() + append); +ArangoDatabase.prototype._collections = function () { + var requestResult = this._connection.GET(this._collectionurl()); arangosh.checkRequestResult(requestResult); @@ -829,6 +828,22 @@ ArangoDatabase.prototype._createDatabase = function (name, path, options) { return requestResult.result; }; +//////////////////////////////////////////////////////////////////////////////// +/// @brief drop an existing database +//////////////////////////////////////////////////////////////////////////////// + +ArangoDatabase.prototype._dropDatabase = function (name) { + var requestResult = this._connection.DELETE("/_api/database/" + encodeURIComponent(name)); + + if (requestResult !== null && requestResult.error === true) { + throw new ArangoError(requestResult); + } + + arangosh.checkRequestResult(requestResult); + + return requestResult.result; +}; + //////////////////////////////////////////////////////////////////////////////// /// @brief list all existing databases //////////////////////////////////////////////////////////////////////////////// diff --git a/js/client/modules/org/arangodb/arango-database.js b/js/client/modules/org/arangodb/arango-database.js index 1cfef99130..bc18113675 100644 --- a/js/client/modules/org/arangodb/arango-database.js +++ b/js/client/modules/org/arangodb/arango-database.js @@ -242,7 +242,7 @@ ArangoDatabase.prototype._help = function () { //////////////////////////////////////////////////////////////////////////////// ArangoDatabase.prototype.toString = function () { - return "[object ArangoDatabase '" + this._name() + "']"; + return "[object ArangoDatabase \"" + this._name() + "\"]"; }; //////////////////////////////////////////////////////////////////////////////// @@ -262,9 +262,8 @@ ArangoDatabase.prototype.toString = function () { /// @brief return all collections from the database //////////////////////////////////////////////////////////////////////////////// -ArangoDatabase.prototype._collections = function (excludeSystem) { - var append = (excludeSystem ? "?excludeSystem=true" : ""); - var requestResult = this._connection.GET(this._collectionurl() + append); +ArangoDatabase.prototype._collections = function () { + var requestResult = this._connection.GET(this._collectionurl()); arangosh.checkRequestResult(requestResult); @@ -828,6 +827,22 @@ ArangoDatabase.prototype._createDatabase = function (name, path, options) { return requestResult.result; }; +//////////////////////////////////////////////////////////////////////////////// +/// @brief drop an existing database +//////////////////////////////////////////////////////////////////////////////// + +ArangoDatabase.prototype._dropDatabase = function (name) { + var requestResult = this._connection.DELETE("/_api/database/" + encodeURIComponent(name)); + + if (requestResult !== null && requestResult.error === true) { + throw new ArangoError(requestResult); + } + + arangosh.checkRequestResult(requestResult); + + return requestResult.result; +}; + //////////////////////////////////////////////////////////////////////////////// /// @brief list all existing databases //////////////////////////////////////////////////////////////////////////////// diff --git a/js/common/modules/org/arangodb/arango-collection-common.js b/js/common/modules/org/arangodb/arango-collection-common.js index 18b8483ec2..b77dd34022 100644 --- a/js/common/modules/org/arangodb/arango-collection-common.js +++ b/js/common/modules/org/arangodb/arango-collection-common.js @@ -129,6 +129,7 @@ ArangoCollection.TYPE_EDGE = 3; ArangoCollection.prototype._PRINT = function (context) { var status = "unknown"; var type = "unknown"; + var name = this.name(); switch (this.status()) { case ArangoCollection.STATUS_NEW_BORN: status = "new born"; break; @@ -153,7 +154,7 @@ ArangoCollection.prototype._PRINT = function (context) { if (useColor) { context.output += colors.COLOR_RESET; } context.output += ", \""; if (useColor) { context.output += colors.COLOR_STRING; } - context.output += this.name(); + context.output += name ? name : "unknown"; if (useColor) { context.output += colors.COLOR_RESET; } context.output += "\" (type " + type + ", status " + status + ")]"; }; diff --git a/js/server/modules/org/arangodb/arango-database.js b/js/server/modules/org/arangodb/arango-database.js index 4dd0ad2983..284f0067e5 100644 --- a/js/server/modules/org/arangodb/arango-database.js +++ b/js/server/modules/org/arangodb/arango-database.js @@ -83,7 +83,7 @@ ArangoDatabase.prototype._PRINT = function (context) { //////////////////////////////////////////////////////////////////////////////// ArangoDatabase.prototype.toString = function(seen, path, names, level) { - return "[ArangoDatabase \"" + this._path() + "\"]"; + return "[ArangoDatabase \"" + this._name() + "\"]"; }; //////////////////////////////////////////////////////////////////////////////// @@ -143,6 +143,14 @@ ArangoDatabase.prototype._createDatabase = function (name, path, options) { return CREATE_DATABASE(name, path, options); } +//////////////////////////////////////////////////////////////////////////////// +/// @brief delete an existing database +//////////////////////////////////////////////////////////////////////////////// + +ArangoDatabase.prototype._dropDatabase = function (name) { + return DELETE_DATABASE(name); +} + //////////////////////////////////////////////////////////////////////////////// /// @brief lists all existing databases //////////////////////////////////////////////////////////////////////////////// @@ -156,7 +164,7 @@ ArangoDatabase.prototype._listDatabases = function () { //////////////////////////////////////////////////////////////////////////////// ArangoDatabase.prototype._useDatabase = function (name) { - return USE_DATABASES(name); + return USE_DATABASE(name); } ////////////////////////////////////////////////////////////////////////////////