diff --git a/arangod/Utils/Transaction.h b/arangod/Utils/Transaction.h index 3b8246a584..cc1e08b616 100644 --- a/arangod/Utils/Transaction.h +++ b/arangod/Utils/Transaction.h @@ -306,7 +306,19 @@ namespace triagens { TRI_vocbase_col_t* collection = TRI_CheckCollectionTransaction(this->_trx, cid, type); if (collection == 0) { - return _setupError = TRI_ERROR_TRANSACTION_UNREGISTERED_COLLECTION; + // adding an unknown collection... + int res = TRI_ERROR_NO_ERROR; + + if (type == TRI_TRANSACTION_READ && this->isReadOnlyTransaction()) { + res = TRI_AddDelayedReadCollectionTransaction(this->_trx, cid); + } + else { + res = TRI_ERROR_TRANSACTION_UNREGISTERED_COLLECTION; + } + + if (res != TRI_ERROR_NO_ERROR) { + return _setupError = res; + } } return TRI_ERROR_NO_ERROR; diff --git a/arangod/VocBase/transaction.c b/arangod/VocBase/transaction.c index 7c110cf65a..42122af9eb 100644 --- a/arangod/VocBase/transaction.c +++ b/arangod/VocBase/transaction.c @@ -427,7 +427,7 @@ void TRI_FreeTransactionContext (TRI_transaction_context_t* const context) { //////////////////////////////////////////////////////////////////////////////// /// @brief free all data associated with a specific collection -/// TODO: this function must be called for all collections that are dropped +/// this function gets called for all collections that are dropped //////////////////////////////////////////////////////////////////////////////// void TRI_RemoveCollectionTransactionContext (TRI_transaction_context_t* const context, @@ -1158,7 +1158,6 @@ TRI_vocbase_col_t* TRI_CheckCollectionTransaction (TRI_transaction_t* const trx, // the vector is sorted by collection names n = trx->_collections._length; for (i = 0; i < n; ++i) { - collection = TRI_AtVectorPointer(&trx->_collections, i); if (cid < collection->_cid) { @@ -1240,6 +1239,48 @@ int TRI_AddCollectionTransaction (TRI_transaction_t* const trx, return TRI_ERROR_NO_ERROR; } +//////////////////////////////////////////////////////////////////////////////// +/// @brief add a collection to an already running transaction +/// opens it and locks it in read-only mode +//////////////////////////////////////////////////////////////////////////////// + +int TRI_AddDelayedReadCollectionTransaction (TRI_transaction_t* const trx, + const TRI_transaction_cid_t cid) { + TRI_transaction_collection_t* collection; + size_t i, n; + int res; + + n = trx->_collections._length; + for (i = 0; i < n; ++i) { + collection = TRI_AtVectorPointer(&trx->_collections, i); + + if (cid < collection->_cid) { + // collection is not contained in vector + collection = CreateCollection(cid, TRI_TRANSACTION_READ); + if (collection == NULL) { + // out of memory + return TRI_ERROR_OUT_OF_MEMORY; + } + + TRI_InsertVectorPointer(&trx->_collections, collection, i); + + collection->_collection = TRI_UseCollectionByIdVocBase(trx->_context->_vocbase, collection->_cid); + if (collection->_collection == NULL) { + return TRI_errno(); + } + + res = LockCollection(collection, TRI_TRANSACTION_READ); + + return res; + } + } + + // we should not get here. Otherwise this is a logic error + LOG_WARNING("logic error. should have inserted collection"); + + return TRI_ERROR_INTERNAL; +} + //////////////////////////////////////////////////////////////////////////////// /// @brief start a transaction //////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/VocBase/transaction.h b/arangod/VocBase/transaction.h index 11ffd9e82e..944966f90e 100644 --- a/arangod/VocBase/transaction.h +++ b/arangod/VocBase/transaction.h @@ -401,6 +401,13 @@ int TRI_AddCollectionTransaction (TRI_transaction_t* const, const TRI_transaction_cid_t, const TRI_transaction_type_e); +//////////////////////////////////////////////////////////////////////////////// +/// @brief add a collection to an already running transaction, read-only mode +//////////////////////////////////////////////////////////////////////////////// + +int TRI_AddDelayedReadCollectionTransaction (TRI_transaction_t* const, + const TRI_transaction_cid_t); + //////////////////////////////////////////////////////////////////////////////// /// @brief request a lock for a collection //////////////////////////////////////////////////////////////////////////////// diff --git a/arangod/VocBase/vocbase.c b/arangod/VocBase/vocbase.c index 3c123fbf76..57d11ff2c8 100644 --- a/arangod/VocBase/vocbase.c +++ b/arangod/VocBase/vocbase.c @@ -279,12 +279,14 @@ static bool DropCollectionCallback (TRI_collection_t* col, void* data) { TRI_document_collection_t* document; TRI_vocbase_col_t* collection; TRI_vocbase_t* vocbase; + TRI_voc_cid_t cid; regmatch_t matches[3]; regex_t re; int res; size_t i; collection = data; + cid = 0; TRI_WRITE_LOCK_STATUS_VOCBASE_COL(collection); @@ -308,6 +310,8 @@ static bool DropCollectionCallback (TRI_collection_t* col, void* data) { return false; } + cid = collection->_cid; + document = (TRI_document_collection_t*) collection->_collection; res = TRI_CloseDocumentCollection(document); @@ -432,6 +436,10 @@ static bool DropCollectionCallback (TRI_collection_t* col, void* data) { regfree(&re); } + if (cid > 0) { + TRI_RemoveCollectionTransactionContext(vocbase->_transactionContext, cid); + } + return true; } diff --git a/js/server/modules/org/arangodb/ahuacatl.js b/js/server/modules/org/arangodb/ahuacatl.js index 2fc3da7e33..2b3d8a5448 100644 --- a/js/server/modules/org/arangodb/ahuacatl.js +++ b/js/server/modules/org/arangodb/ahuacatl.js @@ -2697,7 +2697,7 @@ function TRAVERSAL_FUNC (func, vertexCollection, edgeCollection, startVertex, di var v = null; var result = [ ]; try { - v = vertexCollection.document(startVertex); + v = INTERNAL.db._document(startVertex); } catch (err) { } diff --git a/js/server/tests/ahuacatl-cross.js b/js/server/tests/ahuacatl-cross.js index 875c9c1926..fbe16370cc 100644 --- a/js/server/tests/ahuacatl-cross.js +++ b/js/server/tests/ahuacatl-cross.js @@ -183,14 +183,18 @@ function ahuacatlCrossCollection () { //////////////////////////////////////////////////////////////////////////////// testTraversal1 : function () { - var d1 = vertex1.save({ _key: "test1" }); - var d2 = vertex1.save({ _key: "test2" }); - var d3 = vertex2.save({ _key: "test3" }); + var d1 = vertex1.save({ _key: "test1", a: 1 }); + var d2 = vertex1.save({ _key: "test2", a: 2 }); + var d3 = vertex2.save({ _key: "test3", a: 3 }); var e1 = edge.save(d1._id, d2._id, { }); var e2 = edge.save(d2._id, d3._id, { }); var actual = getQueryResults("FOR t IN TRAVERSAL(" + vn1 + ", " + en + ", " + JSON.stringify(d1._id) + ", 'outbound', { }) RETURN t"); - assertEqual(2, actual.length); + assertEqual(3, actual.length); + + assertEqual(1, actual[0].vertex.a); + assertEqual(2, actual[1].vertex.a); + assertEqual(3, actual[2].vertex.a); }, //////////////////////////////////////////////////////////////////////////////// @@ -198,12 +202,16 @@ function ahuacatlCrossCollection () { //////////////////////////////////////////////////////////////////////////////// testTraversal2 : function () { - var d1 = vertex1.save({ _key: "test1" }); - var d2 = vertex2.save({ _key: "test2" }); + var d1 = vertex1.save({ _key: "test1", a: 1 }); + var d2 = vertex2.save({ _key: "test2", a: 2 }); + var d3 = vertex2.save({ _key: "test3", a: 3 }); var e1 = edge.save(d1._id, d2._id, { }); + var e2 = edge.save(d2._id, d3._id, { }); var actual = getQueryResults("FOR t IN TRAVERSAL(" + vn1 + ", " + en + ", " + JSON.stringify(d2._id) + ", 'outbound', { }) RETURN t"); - assertEqual(0, actual.length); + assertEqual(2, actual.length); + assertEqual(2, actual[0].vertex.a); + assertEqual(3, actual[1].vertex.a); } };