1
0
Fork 0

fix collection name handling in the face of parallel renames

This commit is contained in:
Jan Steemann 2013-02-01 13:43:14 +01:00
parent 3b547f9416
commit ca8935ae2a
25 changed files with 858 additions and 690 deletions

View File

@ -280,12 +280,13 @@ bool RestDocumentHandler::createDocument () {
return false;
}
if (! checkCreateCollection(collection, getCollectionType())) {
CollectionNameResolver resolver(_vocbase);
if (! checkCreateCollection(resolver, collection, getCollectionType())) {
return false;
}
// find and load collection given by name or identifier
SelfContainedWriteTransaction<RestTransactionContext> trx(_vocbase, collection);
SingleCollectionWriteTransaction<StandaloneTransaction<RestTransactionContext>, 1> trx(_vocbase, resolver.getCollectionId(collection));
// .............................................................................
// inside write transaction
@ -407,7 +408,8 @@ bool RestDocumentHandler::readSingleDocument (bool generateBody) {
string key = suffix[1];
// find and load collection given by name or identifier
SingleCollectionReadOnlyTransaction<StandaloneTransaction<RestTransactionContext> > trx(_vocbase, collection);
CollectionNameResolver resolver(_vocbase);
SingleCollectionReadOnlyTransaction<StandaloneTransaction<RestTransactionContext> > trx(_vocbase, resolver.getCollectionId(collection));
// .............................................................................
// inside read transaction
@ -445,7 +447,7 @@ bool RestDocumentHandler::readSingleDocument (bool generateBody) {
if (ifNoneRid == 0) {
if (ifRid == 0 || ifRid == rid) {
generateDocument(collection, document, trx.vocbase(), trx.shaper(), generateBody);
generateDocument(resolver, collection, document, trx.shaper(), generateBody);
}
else {
generatePreconditionFailed(collection, document->_key, rid);
@ -461,7 +463,7 @@ bool RestDocumentHandler::readSingleDocument (bool generateBody) {
}
else {
if (ifRid == 0 || ifRid == rid) {
generateDocument(collection, document, trx.vocbase(), trx.shaper(), generateBody);
generateDocument(resolver, collection, document, trx.shaper(), generateBody);
}
else {
generatePreconditionFailed(collection, document->_key, rid);
@ -491,7 +493,8 @@ bool RestDocumentHandler::readAllDocuments () {
string collection = _request->value("collection", found);
// find and load collection given by name or identifier
SingleCollectionReadOnlyTransaction<StandaloneTransaction<RestTransactionContext> > trx(_vocbase, collection);
CollectionNameResolver resolver(_vocbase);
SingleCollectionReadOnlyTransaction<StandaloneTransaction<RestTransactionContext> > trx(_vocbase, resolver.getCollectionId(collection));
vector<string> ids;
@ -522,7 +525,7 @@ bool RestDocumentHandler::readAllDocuments () {
string result("{ \"documents\" : [\n");
bool first = true;
string prefix = '"' + DOCUMENT_PATH + '/' + trx.collectionName() + '/';
string prefix = '"' + DOCUMENT_PATH + '/' + collection + '/';
for (vector<string>::iterator i = ids.begin(); i != ids.end(); ++i) {
// collection names do not need to be JSON-escaped
@ -764,11 +767,12 @@ bool RestDocumentHandler::modifyDocument (bool isPatch) {
// extract or chose the update policy
TRI_doc_update_policy_e policy = extractUpdatePolicy();
// find and load collection given by name or identifier
SelfContainedWriteTransaction<RestTransactionContext> trx(_vocbase, collection);
TRI_doc_mptr_t* document = 0;
// find and load collection given by name or identifier
CollectionNameResolver resolver(_vocbase);
SingleCollectionWriteTransaction<StandaloneTransaction<RestTransactionContext>, 1> trx(_vocbase, resolver.getCollectionId(collection));
// .............................................................................
// inside write transaction
@ -915,7 +919,7 @@ bool RestDocumentHandler::deleteDocument () {
// extract the revision
TRI_voc_rid_t revision = extractRevision("if-match", "rev");
// extract or chose the update policy
// extract or choose the update policy
TRI_doc_update_policy_e policy = extractUpdatePolicy();
if (policy == TRI_DOC_UPDATE_ILLEGAL) {
@ -925,7 +929,8 @@ bool RestDocumentHandler::deleteDocument () {
return false;
}
SelfContainedWriteTransaction<RestTransactionContext> trx(_vocbase, collection);
CollectionNameResolver resolver(_vocbase);
SingleCollectionWriteTransaction<StandaloneTransaction<RestTransactionContext>, 1> trx(_vocbase, resolver.getCollectionId(collection));
// .............................................................................
// inside write transaction

View File

@ -153,12 +153,13 @@ bool RestEdgeHandler::createDocument () {
return false;
}
if (! checkCreateCollection(collection, getCollectionType())) {
CollectionNameResolver resolver(_vocbase);
if (! checkCreateCollection(resolver, collection, getCollectionType())) {
return false;
}
// find and load collection given by name or identifier
SelfContainedWriteTransaction<RestTransactionContext> trx(_vocbase, collection);
SingleCollectionWriteTransaction<StandaloneTransaction<RestTransactionContext>, 1> trx(_vocbase, resolver.getCollectionId(collection));
// .............................................................................
// inside write transaction

View File

@ -31,7 +31,6 @@
#include "BasicsC/string-buffer.h"
#include "BasicsC/strings.h"
#include "Rest/HttpRequest.h"
#include "Utils/ImportTransaction.h"
#include "Utilities/ResourceHolder.h"
#include "VocBase/document-collection.h"
#include "VocBase/vocbase.h"
@ -215,12 +214,13 @@ bool RestImportHandler::createByDocumentsLines () {
return false;
}
if (! checkCreateCollection(collection, TRI_COL_TYPE_DOCUMENT)) {
CollectionNameResolver resolver(_vocbase);
if (! checkCreateCollection(resolver, collection, TRI_COL_TYPE_DOCUMENT)) {
return false;
}
// find and load collection given by name or identifier
ImportTransaction<StandaloneTransaction<RestTransactionContext> > trx(_vocbase, collection);
SingleCollectionWriteTransaction<StandaloneTransaction<RestTransactionContext>, UINT64_MAX> trx(_vocbase, resolver.getCollectionId(collection));
// .............................................................................
// inside write transaction
@ -362,12 +362,13 @@ bool RestImportHandler::createByDocumentsList () {
return false;
}
if (! checkCreateCollection(collection, TRI_COL_TYPE_DOCUMENT)) {
CollectionNameResolver resolver(_vocbase);
if (! checkCreateCollection(resolver, collection, TRI_COL_TYPE_DOCUMENT)) {
return false;
}
// find and load collection given by name or identifier
ImportTransaction<StandaloneTransaction<RestTransactionContext> > trx(_vocbase, collection);
SingleCollectionWriteTransaction<StandaloneTransaction<RestTransactionContext>, UINT64_MAX> trx(_vocbase, resolver.getCollectionId(collection));
// .............................................................................
// inside write transaction
@ -513,12 +514,13 @@ bool RestImportHandler::createByKeyValueList () {
return false;
}
if (! checkCreateCollection(collection, TRI_COL_TYPE_DOCUMENT)) {
CollectionNameResolver resolver(_vocbase);
if (! checkCreateCollection(resolver, collection, TRI_COL_TYPE_DOCUMENT)) {
return false;
}
// find and load collection given by name or identifier
ImportTransaction<StandaloneTransaction<RestTransactionContext> > trx(_vocbase, collection);
SingleCollectionWriteTransaction<StandaloneTransaction<RestTransactionContext>, UINT64_MAX> trx(_vocbase, resolver.getCollectionId(collection));
// .............................................................................
// inside write transaction

View File

@ -164,7 +164,8 @@ RestVocbaseBaseHandler::~RestVocbaseBaseHandler () {
/// happen, and the collection name will not be checked
////////////////////////////////////////////////////////////////////////////////
bool RestVocbaseBaseHandler::checkCreateCollection (const string& name,
bool RestVocbaseBaseHandler::checkCreateCollection (const CollectionNameResolver& resolver,
const string& name,
const TRI_col_type_e type) {
bool found;
char const* valueStr = _request->value("createCollection", found);
@ -355,9 +356,9 @@ void RestVocbaseBaseHandler::generateNotModified (const string& etag) {
/// @brief generates next entry from a result set
////////////////////////////////////////////////////////////////////////////////
void RestVocbaseBaseHandler::generateDocument (const string& collectionName,
void RestVocbaseBaseHandler::generateDocument (const triagens::arango::CollectionNameResolver& resolver,
const string& collectionName,
TRI_doc_mptr_t const* document,
TRI_vocbase_t* const vocbase,
TRI_shaper_t* shaper,
const bool generateBody) {
if (document == 0) {
@ -399,8 +400,8 @@ void RestVocbaseBaseHandler::generateDocument (const string& collectionName,
if (type == TRI_DOC_MARKER_KEY_EDGE) {
TRI_doc_edge_key_marker_t* marker = (TRI_doc_edge_key_marker_t*) document->_data;
const string from = DocumentHelper::assembleDocumentId(vocbase, marker->_fromCid, string((char*) marker + marker->_offsetFromKey));
const string to = DocumentHelper::assembleDocumentId(vocbase, marker->_toCid, string((char*) marker + marker->_offsetToKey));
const string from = DocumentHelper::assembleDocumentId(resolver.getCollectionName(marker->_fromCid), string((char*) marker + marker->_offsetFromKey));
const string to = DocumentHelper::assembleDocumentId(resolver.getCollectionName(marker->_toCid), string((char*) marker + marker->_offsetToKey));
TRI_Insert3ArrayJson(TRI_UNKNOWN_MEM_ZONE, &augmented, "_from", TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, from.c_str()));
TRI_Insert3ArrayJson(TRI_UNKNOWN_MEM_ZONE, &augmented, "_to", TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, to.c_str()));

View File

@ -35,9 +35,10 @@
#include "Logger/Logger.h"
#include "Rest/HttpResponse.h"
#include "Utils/CollectionNameResolver.h"
#include "Utils/RestTransactionContext.h"
#include "Utils/SelfContainedWriteTransaction.h"
#include "Utils/SingleCollectionReadOnlyTransaction.h"
#include "Utils/SingleCollectionWriteTransaction.h"
#include "Utils/StandaloneTransaction.h"
// -----------------------------------------------------------------------------
@ -173,7 +174,9 @@ namespace triagens {
/// happen, and the collection name will not be checked
////////////////////////////////////////////////////////////////////////////////
bool checkCreateCollection (const string&, const TRI_col_type_e);
bool checkCreateCollection (const triagens::arango::CollectionNameResolver&,
const string&,
const TRI_col_type_e);
////////////////////////////////////////////////////////////////////////////////
/// @brief generates a HTTP 201 or 202 response
@ -256,9 +259,9 @@ namespace triagens {
/// @brief generates first entry from a result set
////////////////////////////////////////////////////////////////////////////////
void generateDocument (const string&,
void generateDocument (const triagens::arango::CollectionNameResolver&,
const string&,
TRI_doc_mptr_t const*,
TRI_vocbase_t* const,
TRI_shaper_t*,
const bool);

View File

@ -0,0 +1,188 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief collection name resolver
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2004-2012 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.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Jan Steemann
/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#ifndef TRIAGENS_ARANGOD_UTILS_COLLECTION_NAME_RESOLVER_H
#define TRIAGENS_ARANGOD_UTILS_COLLECTION_NAME_RESOLVER_H 1
#include "BasicsC/common.h"
#include "VocBase/vocbase.h"
namespace triagens {
namespace arango {
// -----------------------------------------------------------------------------
// --SECTION-- class CollectionNameResolver
// -----------------------------------------------------------------------------
class CollectionNameResolver {
// -----------------------------------------------------------------------------
// --SECTION-- constructors / destructors
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoDB
/// @{
////////////////////////////////////////////////////////////////////////////////
public:
////////////////////////////////////////////////////////////////////////////////
/// @brief create the resolver
////////////////////////////////////////////////////////////////////////////////
CollectionNameResolver (TRI_vocbase_t* vocbase) :
_vocbase(vocbase), _resolvedNames(), _resolvedIds() {
}
////////////////////////////////////////////////////////////////////////////////
/// @brief destroy the resolver
////////////////////////////////////////////////////////////////////////////////
~CollectionNameResolver () {
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- public methods
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoDB
/// @{
////////////////////////////////////////////////////////////////////////////////
public:
////////////////////////////////////////////////////////////////////////////////
/// @brief look up a collection id for a collection name
////////////////////////////////////////////////////////////////////////////////
TRI_voc_cid_t getCollectionId (const string& name) {
const TRI_vocbase_col_t* collection = getCollectionStruct(name);
if (collection != 0) {
return collection->_cid;
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief look up a collection struct for a collection name
////////////////////////////////////////////////////////////////////////////////
const TRI_vocbase_col_t* getCollectionStruct (const string& name) const {
map<string, const TRI_vocbase_col_t*>::iterator it = _resolvedNames.find(name);
if (it != _resolvedNames.end()) {
return (*it).second;
}
const TRI_vocbase_col_t* collection = TRI_LookupCollectionByNameVocBase(_vocbase, name.c_str());
if (collection != 0) {
_resolvedNames[name] = collection;
}
return collection;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief look up a collection name for a collection id
////////////////////////////////////////////////////////////////////////////////
string getCollectionName (const TRI_voc_cid_t cid) const {
map<TRI_voc_cid_t, string>::iterator it = _resolvedIds.find(cid);
if (it != _resolvedIds.end()) {
return (*it).second;
}
char* n = TRI_GetCollectionNameByIdVocBase(_vocbase, cid);
if (n == 0) {
return "_unknown";
}
string name(n);
_resolvedIds[cid] = name;
TRI_Free(TRI_UNKNOWN_MEM_ZONE, n);
return name;
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- private variables
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoDB
/// @{
////////////////////////////////////////////////////////////////////////////////
private:
////////////////////////////////////////////////////////////////////////////////
/// @brief vocbase base pointer
////////////////////////////////////////////////////////////////////////////////
TRI_vocbase_t* _vocbase;
////////////////////////////////////////////////////////////////////////////////
/// @brief collection id => collection struct map
////////////////////////////////////////////////////////////////////////////////
mutable std::map<std::string, const TRI_vocbase_col_t*> _resolvedNames;
////////////////////////////////////////////////////////////////////////////////
/// @brief collection id => collection name map
////////////////////////////////////////////////////////////////////////////////
mutable std::map<TRI_voc_cid_t, std::string> _resolvedIds;
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
};
}
}
#endif
// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)"
// End:

View File

@ -1,5 +1,5 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief document utilitiy functions
/// @brief document utility functions
///
/// @file
///
@ -28,8 +28,6 @@
#ifndef TRIAGENS_ARANGOD_UTILS_DOCUMENT_HELPER_H
#define TRIAGENS_ARANGOD_UTILS_DOCUMENT_HELPER_H 1
#include "VocBase/vocbase.h"
namespace triagens {
namespace arango {
@ -93,40 +91,6 @@ namespace triagens {
return assembleDocumentId(collectionName, string(key));
}
////////////////////////////////////////////////////////////////////////////////
/// @brief assemble a document id from a collection id and a string key
////////////////////////////////////////////////////////////////////////////////
static string assembleDocumentId (TRI_vocbase_t* const vocbase,
const TRI_voc_cid_t cid,
const string& key) {
static const string UnknownCollection = "_unknown";
TRI_vocbase_col_t const* collection = TRI_LookupCollectionByIdVocBase(vocbase, cid);
if (collection == 0) {
return assembleDocumentId(UnknownCollection, key);
}
// TODO: can the name be deleted while we're using it?
return assembleDocumentId(collection->_name, key);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief assemble a document id from a collection id and a char* key
////////////////////////////////////////////////////////////////////////////////
static string assembleDocumentId (TRI_vocbase_t* const vocbase,
const TRI_voc_cid_t cid,
const TRI_voc_key_t key) {
static const string UnknownKey = "_deleted";
if (key == 0) {
return assembleDocumentId(vocbase, cid, UnknownKey);
}
return assembleDocumentId(vocbase, cid, string(key));
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

View File

@ -1,89 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief wrapper for single collection, multi-operation write transactions
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2004-2012 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.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Jan Steemann
/// @author Copyright 2011-2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#ifndef TRIAGENS_UTILS_IMPORT_TRANSACTION_H
#define TRIAGENS_UTILS_IMPORT_TRANSACTION_H 1
#include "Utils/SingleCollectionWriteTransaction.h"
struct TRI_vocbase_s;
namespace triagens {
namespace arango {
template<typename T>
class ImportTransaction : public SingleCollectionWriteTransaction<T, UINT64_MAX> {
// -----------------------------------------------------------------------------
// --SECTION-- class ImportTransaction
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// --SECTION-- constructors and destructors
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoDB
/// @{
////////////////////////////////////////////////////////////////////////////////
public:
////////////////////////////////////////////////////////////////////////////////
/// @brief create the transaction, using a collection object
///
/// An import transaction operates on a single collection and may execute any
/// number of writes on it.
////////////////////////////////////////////////////////////////////////////////
ImportTransaction (struct TRI_vocbase_s* const vocbase,
const string& name) :
SingleCollectionWriteTransaction<T, UINT64_MAX>(vocbase, name) {
}
////////////////////////////////////////////////////////////////////////////////
/// @brief end the transaction
////////////////////////////////////////////////////////////////////////////////
~ImportTransaction () {
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
};
}
}
#endif
// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|/// @page\\|// --SECTION--\\|/// @\\}\\)"
// End:

View File

@ -1,91 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief wrapper for single collection, single operation write transactions
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2004-2012 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.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Jan Steemann
/// @author Copyright 2011-2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#ifndef TRIAGENS_UTILS_SELF_CONTAINED_WRITE_TRANSACTION_H
#define TRIAGENS_UTILS_SELF_CONTAINED_WRITE_TRANSACTION_H 1
#include "Utils/SingleCollectionWriteTransaction.h"
#include "Utils/StandaloneTransaction.h"
struct TRI_vocbase_s;
namespace triagens {
namespace arango {
template<typename C>
class SelfContainedWriteTransaction : public SingleCollectionWriteTransaction<StandaloneTransaction<C>, 1> {
// -----------------------------------------------------------------------------
// --SECTION-- class SelfContainedWriteTransaction
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// --SECTION-- constructors and destructors
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoDB
/// @{
////////////////////////////////////////////////////////////////////////////////
public:
////////////////////////////////////////////////////////////////////////////////
/// @brief create the transaction, using a collection object
///
/// A self contained write transaction operates on a single collection and may
/// execute at most one write operation
////////////////////////////////////////////////////////////////////////////////
SelfContainedWriteTransaction (struct TRI_vocbase_s* const vocbase,
const string& name) :
SingleCollectionWriteTransaction<StandaloneTransaction<C>, 1>(vocbase, name) {
}
////////////////////////////////////////////////////////////////////////////////
/// @brief end the transaction
////////////////////////////////////////////////////////////////////////////////
~SelfContainedWriteTransaction () {
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
};
}
}
#endif
// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|/// @page\\|// --SECTION--\\|/// @\\}\\)"
// End:

View File

@ -63,8 +63,8 @@ namespace triagens {
////////////////////////////////////////////////////////////////////////////////
SingleCollectionReadOnlyTransaction (struct TRI_vocbase_s* const vocbase,
const string& name) :
SingleCollectionTransaction<T>(vocbase, name, TRI_TRANSACTION_READ) {
const TRI_transaction_cid_t cid) :
SingleCollectionTransaction<T>(vocbase, cid, TRI_TRANSACTION_READ) {
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -66,18 +66,16 @@ namespace triagens {
/// @brief create the transaction, using a collection object
///
/// A single collection transaction operates on a single collection (you guessed
/// it), and may execute at most one write operation if it is a write
/// transaction. It may execute multiple reads, though.
/// it)
////////////////////////////////////////////////////////////////////////////////
SingleCollectionTransaction (TRI_vocbase_t* const vocbase,
const string& name,
const TRI_transaction_cid_t cid,
const TRI_transaction_type_e accessType) :
Transaction<T>(vocbase, new TransactionCollectionsList(vocbase, name, accessType)),
_name(name),
_collection(0) {
Transaction<T>(vocbase, new TransactionCollectionsList(vocbase, cid, accessType)),
_cid(cid) {
}
////////////////////////////////////////////////////////////////////////////////
/// @brief end the transaction
////////////////////////////////////////////////////////////////////////////////
@ -100,27 +98,25 @@ namespace triagens {
public:
////////////////////////////////////////////////////////////////////////////////
/// @brief return the name of the underlying collection
////////////////////////////////////////////////////////////////////////////////
const string collectionName () const {
return _name;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief get the underlying primary collection
////////////////////////////////////////////////////////////////////////////////
inline TRI_primary_collection_t* primaryCollection () {
if (_collection == 0) {
const vector<TransactionCollection*> collections = this->_collections->getCollections();
_collection = TRI_GetCollectionTransaction(this->_trx, collections[0]->getName().c_str());
}
assert(this->_cid > 0);
TRI_vocbase_col_t* collection = TRI_LookupCollectionByIdVocBase(this->_vocbase, this->_cid);
assert(_collection != 0);
assert(_collection->_collection != 0);
return _collection->_collection;
assert(collection != 0);
assert(collection->_collection != 0);
return collection->_collection;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief get the underlying collection's id
////////////////////////////////////////////////////////////////////////////////
inline TRI_voc_cid_t cid () {
return this->_cid;
}
////////////////////////////////////////////////////////////////////////////////
@ -139,19 +135,6 @@ namespace triagens {
return &primaryCollection()->_barrierList;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief get the underlying collection's id
////////////////////////////////////////////////////////////////////////////////
inline TRI_voc_cid_t cid () {
if (_collection == 0) {
_collection = TRI_GetCollectionTransaction(this->_trx, this->collectionName().c_str());
}
assert(_collection != 0);
return _collection->_cid;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief read any (random) document within a transaction
////////////////////////////////////////////////////////////////////////////////
@ -211,17 +194,7 @@ namespace triagens {
private:
////////////////////////////////////////////////////////////////////////////////
/// @brief name of the collection used
////////////////////////////////////////////////////////////////////////////////
string _name;
////////////////////////////////////////////////////////////////////////////////
/// @brief data structure for the single collection used
////////////////////////////////////////////////////////////////////////////////
TRI_vocbase_col_t* _collection;
TRI_transaction_cid_t _cid;
////////////////////////////////////////////////////////////////////////////////
/// @}

View File

@ -70,8 +70,8 @@ namespace triagens {
////////////////////////////////////////////////////////////////////////////////
SingleCollectionWriteTransaction (TRI_vocbase_t* const vocbase,
const string& name) :
SingleCollectionTransaction<T>(vocbase, name, TRI_TRANSACTION_WRITE),
const TRI_transaction_cid_t cid) :
SingleCollectionTransaction<T>(vocbase, cid, TRI_TRANSACTION_WRITE),
_numWrites(0),
_synchronous(false) {
@ -182,6 +182,9 @@ namespace triagens {
return this->createCollectionShaped(primary, TRI_DOC_MARKER_KEY_EDGE, key, mptr, shaped, data, forceSync);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief update (replace!) a single document within a transaction,
/// using json
////////////////////////////////////////////////////////////////////////////////
int updateDocument (const string& key,

View File

@ -262,14 +262,6 @@ namespace triagens {
return res;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief get the "vocbase"
////////////////////////////////////////////////////////////////////////////////
inline TRI_vocbase_t* vocbase () const {
return this->_vocbase;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief get the status of the transaction
////////////////////////////////////////////////////////////////////////////////
@ -653,7 +645,7 @@ namespace triagens {
for (size_t i = 0; i < collections.size(); ++i) {
TransactionCollection* c = collections[i];
TRI_vocbase_col_t* collection = TRI_CheckCollectionTransaction(this->_trx, c->getName().c_str(), c->getAccessType());
TRI_vocbase_col_t* collection = TRI_CheckCollectionTransaction(this->_trx, c->getId(), c->getAccessType());
if (collection == 0) {
return TRI_ERROR_TRANSACTION_UNREGISTERED_COLLECTION;
@ -681,8 +673,8 @@ namespace triagens {
for (size_t i = 0; i < collections.size(); ++i) {
TransactionCollection* c = collections[i];
TRX_LOG << "adding collection " << c->getName();
int res = TRI_AddCollectionTransaction(this->_trx, c->getName().c_str(), c->getAccessType());
TRX_LOG << "adding collection " << c->getId();
int res = TRI_AddCollectionTransaction(this->_trx, c->getId(), c->getAccessType());
if (res != TRI_ERROR_NO_ERROR) {
return res;

View File

@ -65,9 +65,9 @@ namespace triagens {
/// @brief create a collection instance
////////////////////////////////////////////////////////////////////////////////
TransactionCollection (const string& name,
TransactionCollection (const TRI_transaction_cid_t cid,
TRI_transaction_type_e accessType) :
_name(name),
_cid(cid),
_accessType(accessType) {
}
@ -94,11 +94,11 @@ namespace triagens {
public:
////////////////////////////////////////////////////////////////////////////////
/// @brief get the name of the collection
/// @brief get the id of the collection
////////////////////////////////////////////////////////////////////////////////
inline const string getName () const {
return _name;
inline const TRI_transaction_cid_t getId () const {
return _cid;
}
////////////////////////////////////////////////////////////////////////////////
@ -133,10 +133,10 @@ namespace triagens {
private:
////////////////////////////////////////////////////////////////////////////////
/// @brief collection name
/// @brief collection id
////////////////////////////////////////////////////////////////////////////////
const string _name;
const TRI_transaction_cid_t _cid;
////////////////////////////////////////////////////////////////////////////////
/// @brief collection access type (read or write)

View File

@ -58,7 +58,7 @@ namespace triagens {
/// @brief typedef for contained collections list
////////////////////////////////////////////////////////////////////////////////
typedef map<string, TransactionCollection*> ListType;
typedef map<TRI_transaction_cid_t, TransactionCollection*> ListType;
////////////////////////////////////////////////////////////////////////////////
/// @}
@ -93,11 +93,25 @@ namespace triagens {
}
////////////////////////////////////////////////////////////////////////////////
/// @brief create a list with a single collection
/// @brief create a list with a single collection, based on the collection id
////////////////////////////////////////////////////////////////////////////////
TransactionCollectionsList (TRI_vocbase_t* const vocbase,
const string& name,
const TRI_transaction_cid_t cid,
TRI_transaction_type_e accessType) :
_vocbase(vocbase),
_collections(),
_error(TRI_ERROR_NO_ERROR) {
addCollection(cid, accessType);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief create a list with a single collection, based on the collection name
////////////////////////////////////////////////////////////////////////////////
TransactionCollectionsList (TRI_vocbase_t* const vocbase,
const string& name,
TRI_transaction_type_e accessType) :
_vocbase(vocbase),
_collections(),
@ -107,7 +121,27 @@ namespace triagens {
}
////////////////////////////////////////////////////////////////////////////////
/// @brief create a list with multiple collections
/// @brief create a list from multiple collection ids
////////////////////////////////////////////////////////////////////////////////
TransactionCollectionsList (TRI_vocbase_t* const vocbase,
const vector<TRI_transaction_cid_t>& readCollections,
const vector<TRI_transaction_cid_t>& writeCollections) :
_vocbase(vocbase),
_collections(),
_error(TRI_ERROR_NO_ERROR) {
for (size_t i = 0; i < readCollections.size(); ++i) {
addCollection(readCollections[i], TRI_TRANSACTION_READ);
}
for (size_t i = 0; i < writeCollections.size(); ++i) {
addCollection(writeCollections[i], TRI_TRANSACTION_WRITE);
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief create a list with multiple collection names
////////////////////////////////////////////////////////////////////////////////
TransactionCollectionsList (TRI_vocbase_t* const vocbase,
@ -178,6 +212,14 @@ namespace triagens {
return collections;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief get the number of collections
////////////////////////////////////////////////////////////////////////////////
inline size_t size () const {
return _collections.size();
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
@ -194,42 +236,15 @@ namespace triagens {
private:
////////////////////////////////////////////////////////////////////////////////
/// @brief add a collection to the list
/// @brief add a collection to the list, using the collection id
////////////////////////////////////////////////////////////////////////////////
void addCollection (const string& name,
TRI_transaction_type_e type) {
TransactionCollection* addCollection (const TRI_transaction_cid_t cid,
TRI_transaction_type_e type) {
ListType::iterator it;
string realName;
if (name.empty()) {
_error = TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND;
return;
}
const char c = name[0];
if (c >= '0' && c <= '9') {
// name is passed as a string with the collection id inside
// look up the collection name for the id
TRI_voc_cid_t id = triagens::basics::StringUtils::uint64(name);
char* n = TRI_GetCollectionNameByIdVocBase(_vocbase, id);
if (n == 0) {
_error = TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND;
return;
}
realName = string(n);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, n);
}
else {
// name is passed as a "real" name
realName = name;
}
// check if we already have the collection in our list
it = _collections.find(realName);
it = _collections.find(cid);
if (it != _collections.end()) {
// yes, now update the collection in the list
TransactionCollection* c = (*it).second;
@ -239,14 +254,60 @@ namespace triagens {
c->setAccessType(type);
}
// TODO: we probably prefer raising an error here
return c;
}
else {
// collection not yet contained in our list
_collections[realName] = new TransactionCollection(realName, type);
// collection not yet contained in the list
_collections[cid] = new TransactionCollection(cid, type);
return _collections[cid];
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief add a collection to the list, using the collection name
////////////////////////////////////////////////////////////////////////////////
TransactionCollection* addCollection (const string& name,
TRI_transaction_type_e type) {
if (name.empty()) {
_error = TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND;
return 0;
}
TRI_transaction_cid_t cid;
// look at the first character in the collection name
const char first = name[0];
if (first >= '0' && first <= '9') {
// name is passed as a string with the collection id inside
// look up the collection name for the id
cid = triagens::basics::StringUtils::uint64(name);
char* n = TRI_GetCollectionNameByIdVocBase(_vocbase, cid);
if (n == 0) {
_error = TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND;
return 0;
}
TRI_Free(TRI_UNKNOWN_MEM_ZONE, n);
}
else {
// name is passed as a "real" name
TRI_vocbase_col_t* col = TRI_LookupCollectionByNameVocBase(_vocbase, name.c_str());
if (col == 0) {
_error = TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND;
return 0;
}
cid = col->_cid;
}
return addCollection(cid, type);
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

View File

@ -35,6 +35,7 @@
#include "HashIndex/hashindex.h"
#include "SkipLists/skiplistIndex.h"
#include "Utilities/ResourceHolder.h"
#include "Utils/CollectionNameResolver.h"
#include "Utils/EmbeddableTransaction.h"
#include "Utils/SingleCollectionReadOnlyTransaction.h"
#include "Utils/V8TransactionContext.h"
@ -929,8 +930,7 @@ static int SetupExampleObjectIndex (TRI_hash_index_t* hashIndex,
static v8::Handle<v8::Value> ExecuteSkiplistQuery (v8::Arguments const& argv,
std::string const& signature,
const query_t type,
const bool lock) {
const query_t type) {
v8::HandleScope scope;
// extract and use the simple collection
@ -938,24 +938,19 @@ static v8::Handle<v8::Value> ExecuteSkiplistQuery (v8::Arguments const& argv,
TRI_vocbase_col_t const* collection;
TRI_document_collection_t* document = 0;
if (lock) {
document = TRI_ExtractAndUseSimpleCollection(argv, collection, &err);
}
else {
document = TRI_ExtractSimpleCollection(argv, collection, &err);
}
document = TRI_ExtractAndUseSimpleCollection(argv, collection, &err);
if (document == 0) {
return scope.Close(v8::ThrowException(err));
}
assert(collection != 0);
TRI_primary_collection_t* primary = &document->base;
// expecting index, example, skip, and limit
if (argv.Length() < 2) {
if (lock) {
TRI_ReleaseCollection(collection);
}
TRI_ReleaseCollection(collection);
std::string usage("Usage: ");
usage += signature;
@ -965,9 +960,7 @@ static v8::Handle<v8::Value> ExecuteSkiplistQuery (v8::Arguments const& argv,
}
if (! argv[1]->IsObject()) {
if (lock) {
TRI_ReleaseCollection(collection);
}
TRI_ReleaseCollection(collection);
std::string msg;
if (type == QUERY_EXAMPLE) {
@ -993,33 +986,28 @@ static v8::Handle<v8::Value> ExecuteSkiplistQuery (v8::Arguments const& argv,
v8::Handle<v8::Array> documents = v8::Array::New();
result->Set(v8::String::New("documents"), documents);
// .............................................................................
// inside a read transaction
// .............................................................................
if (lock) {
primary->beginRead(primary);
}
primary->beginRead(primary);
// extract the index
TRI_index_t* idx = TRI_LookupIndexByHandle(document->base.base._vocbase, collection, argv[0], false, &err);
CollectionNameResolver resolver(collection->_vocbase);
TRI_index_t* idx = TRI_LookupIndexByHandle(resolver, document->base.base._vocbase, collection, argv[0], false, &err);
if (idx == 0) {
primary->endRead(primary);
if (lock) {
TRI_ReleaseCollection(collection);
}
TRI_ReleaseCollection(collection);
return scope.Close(v8::ThrowException(err));
}
if (idx->_type != TRI_IDX_TYPE_SKIPLIST_INDEX) {
if (lock) {
primary->endRead(primary);
primary->endRead(primary);
TRI_ReleaseCollection(collection);
TRI_ReleaseCollection(collection);
}
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER, "index must be a skiplist index")));
}
@ -1033,11 +1021,9 @@ static v8::Handle<v8::Value> ExecuteSkiplistQuery (v8::Arguments const& argv,
}
if (! skiplistOperator) {
if (lock) {
primary->endRead(primary);
primary->endRead(primary);
TRI_ReleaseCollection(collection);
TRI_ReleaseCollection(collection);
}
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER, "setting up skiplist operator failed")));
}
@ -1066,7 +1052,7 @@ static v8::Handle<v8::Value> ExecuteSkiplistQuery (v8::Arguments const& argv,
}
}
v8::Handle<v8::Value> doc = TRI_WrapShapedJson(collection, (TRI_doc_mptr_t const*) indexElement->data, barrier);
v8::Handle<v8::Value> doc = TRI_WrapShapedJson(resolver, collection, (TRI_doc_mptr_t const*) indexElement->data, barrier);
if (doc.IsEmpty()) {
error = true;
@ -1080,9 +1066,7 @@ static v8::Handle<v8::Value> ExecuteSkiplistQuery (v8::Arguments const& argv,
}
}
if (lock) {
primary->endRead(primary);
}
primary->endRead(primary);
// .............................................................................
// outside a write transaction
@ -1094,9 +1078,7 @@ static v8::Handle<v8::Value> ExecuteSkiplistQuery (v8::Arguments const& argv,
result->Set(v8::String::New("total"), v8::Number::New((double) total));
result->Set(v8::String::New("count"), v8::Number::New(count));
if (lock) {
TRI_ReleaseCollection(collection);
}
TRI_ReleaseCollection(collection);
if (error) {
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(TRI_ERROR_OUT_OF_MEMORY)));
@ -1141,8 +1123,7 @@ static bool BitarrayFilterExample(TRI_index_iterator_t* indexIterator) {
static v8::Handle<v8::Value> ExecuteBitarrayQuery (v8::Arguments const& argv,
std::string const& signature,
const query_t type,
const bool lock) {
const query_t type) {
v8::HandleScope scope;
v8::Handle<v8::Object> err;
const TRI_vocbase_col_t* collection;
@ -1155,19 +1136,15 @@ static v8::Handle<v8::Value> ExecuteBitarrayQuery (v8::Arguments const& argv,
TRI_document_collection_t* document = 0;
if (lock) {
document = TRI_ExtractAndUseSimpleCollection(argv, collection, &err);
}
else {
document = TRI_ExtractSimpleCollection(argv, collection, &err);
}
document = TRI_ExtractAndUseSimpleCollection(argv, collection, &err);
if (document == 0) {
return scope.Close(v8::ThrowException(err));
}
assert(collection != 0);
TRI_primary_collection_t* primary = &document->base;
// ...........................................................................
// Check the parameters, expecting index, example, skip, and limit
@ -1175,9 +1152,7 @@ static v8::Handle<v8::Value> ExecuteBitarrayQuery (v8::Arguments const& argv,
// ...........................................................................
if (argv.Length() < 2) {
if (lock) {
TRI_ReleaseCollection(collection);
}
TRI_ReleaseCollection(collection);
std::string usage("Usage: ");
usage += signature;
@ -1190,9 +1165,8 @@ static v8::Handle<v8::Value> ExecuteBitarrayQuery (v8::Arguments const& argv,
// ...........................................................................
if (! argv[1]->IsObject()) {
if (lock) {
TRI_ReleaseCollection(collection);
}
TRI_ReleaseCollection(collection);
std::string msg;
if (type == QUERY_EXAMPLE) {
@ -1234,32 +1208,26 @@ static v8::Handle<v8::Value> ExecuteBitarrayQuery (v8::Arguments const& argv,
// inside a read transaction
// .............................................................................
if (lock) {
primary->beginRead(primary);
}
primary->beginRead(primary);
// .............................................................................
// extract the index
// .............................................................................
TRI_index_t* idx = TRI_LookupIndexByHandle(document->base.base._vocbase, collection, argv[0], false, &err);
CollectionNameResolver resolver(collection->_vocbase);
TRI_index_t* idx = TRI_LookupIndexByHandle(resolver, document->base.base._vocbase, collection, argv[0], false, &err);
if (idx == 0) {
primary->endRead(primary);
TRI_ReleaseCollection(collection);
if (lock) {
TRI_ReleaseCollection(collection);
}
return scope.Close(v8::ThrowException(err));
}
if (idx->_type != TRI_IDX_TYPE_BITARRAY_INDEX) {
if (lock) {
primary->endRead(primary);
TRI_ReleaseCollection(collection);
}
primary->endRead(primary);
TRI_ReleaseCollection(collection);
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER, "index must be a skiplist index")));
}
@ -1275,11 +1243,8 @@ static v8::Handle<v8::Value> ExecuteBitarrayQuery (v8::Arguments const& argv,
if (indexOperator == 0) { // something wrong
if (lock) {
primary->endRead(primary);
TRI_ReleaseCollection(collection);
}
primary->endRead(primary);
TRI_ReleaseCollection(collection);
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER, "setting up bitarray index operator failed")));
}
@ -1324,7 +1289,7 @@ static v8::Handle<v8::Value> ExecuteBitarrayQuery (v8::Arguments const& argv,
}
}
v8::Handle<v8::Value> doc = TRI_WrapShapedJson(collection, data, barrier);
v8::Handle<v8::Value> doc = TRI_WrapShapedJson(resolver, collection, data, barrier);
if (doc.IsEmpty()) {
error = true;
@ -1348,9 +1313,7 @@ static v8::Handle<v8::Value> ExecuteBitarrayQuery (v8::Arguments const& argv,
// return an empty list
}
if (lock) {
primary->endRead(primary);
}
primary->endRead(primary);
// .............................................................................
// outside a write transaction
@ -1360,9 +1323,7 @@ static v8::Handle<v8::Value> ExecuteBitarrayQuery (v8::Arguments const& argv,
result->Set(v8::String::New("total"), v8::Number::New((double) total));
result->Set(v8::String::New("count"), v8::Number::New(count));
if (lock) {
TRI_ReleaseCollection(collection);
}
TRI_ReleaseCollection(collection);
if (error) {
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(TRI_ERROR_OUT_OF_MEMORY)));
@ -1464,10 +1425,12 @@ static int StoreGeoResult (TRI_vocbase_col_t const* collection,
return TRI_ERROR_OUT_OF_MEMORY;
}
CollectionNameResolver resolver(collection->_vocbase);
// copy the documents
for (gtr = tmp, i = 0; gtr < gnd; ++gtr, ++i) {
documents->Set(i, TRI_WrapShapedJson(collection, (TRI_doc_mptr_t const*) gtr->_data, barrier));
documents->Set(i, TRI_WrapShapedJson(resolver, collection, (TRI_doc_mptr_t const*) gtr->_data, barrier));
distances->Set(i, v8::Number::New(gtr->_distance));
}
@ -1509,6 +1472,8 @@ static v8::Handle<v8::Value> EdgesQuery (TRI_edge_direction_e direction, v8::Arg
return scope.Close(v8::ThrowException(err));
}
assert(collection != 0);
TRI_primary_collection_t* primary = &document->base;
if (collection->_type != TRI_COL_TYPE_EDGE) {
@ -1555,6 +1520,8 @@ static v8::Handle<v8::Value> EdgesQuery (TRI_edge_direction_e direction, v8::Arg
TRI_barrier_t* barrier = 0;
uint32_t count = 0;
bool error = false;
CollectionNameResolver resolver(collection->_vocbase);
// argument is a list of vertices
if (argv[0]->IsArray()) {
@ -1568,13 +1535,9 @@ static v8::Handle<v8::Value> EdgesQuery (TRI_edge_direction_e direction, v8::Arg
TRI_voc_key_t key = 0;
TRI_vocbase_col_t const* vertexCollection = 0;
v8::Handle<v8::Value> errMsg = TRI_ParseDocumentOrDocumentHandle(collection->_vocbase, vertexCollection, key, rid, true, vertices->Get(i));
v8::Handle<v8::Value> errMsg = TRI_ParseDocumentOrDocumentHandle(resolver, vertexCollection, key, rid, vertices->Get(i));
if (! errMsg.IsEmpty()) {
if (vertexCollection != 0) {
TRI_ReleaseCollection(vertexCollection);
}
if (key) {
TRI_FreeString(TRI_CORE_MEM_ZONE, key);
key = 0;
@ -1583,8 +1546,9 @@ static v8::Handle<v8::Value> EdgesQuery (TRI_edge_direction_e direction, v8::Arg
continue;
}
assert(vertexCollection != 0);
cid = vertexCollection->_cid;
TRI_ReleaseCollection(vertexCollection);
edges = TRI_LookupEdgesDocumentCollection(document, direction, cid, key);
@ -1601,7 +1565,7 @@ static v8::Handle<v8::Value> EdgesQuery (TRI_edge_direction_e direction, v8::Arg
}
}
v8::Handle<v8::Value> doc = TRI_WrapShapedJson(collection, (TRI_doc_mptr_t const*) edges._buffer[j], barrier);
v8::Handle<v8::Value> doc = TRI_WrapShapedJson(resolver, collection, (TRI_doc_mptr_t const*) edges._buffer[j], barrier);
if (doc.IsEmpty()) {
// error
@ -1631,28 +1595,27 @@ static v8::Handle<v8::Value> EdgesQuery (TRI_edge_direction_e direction, v8::Arg
TRI_voc_key_t key = 0;
TRI_vocbase_col_t const* vertexCollection = 0;
v8::Handle<v8::Value> errMsg = TRI_ParseDocumentOrDocumentHandle(collection->_vocbase, vertexCollection, key, rid, true, argv[0]);
v8::Handle<v8::Value> errMsg = TRI_ParseDocumentOrDocumentHandle(resolver, vertexCollection, key, rid, argv[0]);
if (! errMsg.IsEmpty()) {
if (vertexCollection != 0) {
TRI_ReleaseCollection(vertexCollection);
}
primary->endRead(primary);
TRI_ReleaseCollection(collection);
if (key) {
TRI_FreeString(TRI_CORE_MEM_ZONE, key);
}
TRI_ReleaseCollection(collection);
return scope.Close(v8::ThrowException(errMsg));
}
assert(vertexCollection != 0);
cid = vertexCollection->_cid;
TRI_ReleaseCollection(vertexCollection);
edges = TRI_LookupEdgesDocumentCollection(document, direction, cid, key);
if (key) TRI_FreeString(TRI_CORE_MEM_ZONE, key);
if (key) {
TRI_FreeString(TRI_CORE_MEM_ZONE, key);
}
for (size_t j = 0; j < edges._length; ++j) {
if (barrier == 0) {
@ -1663,7 +1626,7 @@ static v8::Handle<v8::Value> EdgesQuery (TRI_edge_direction_e direction, v8::Arg
}
}
v8::Handle<v8::Value> doc = TRI_WrapShapedJson(collection, (TRI_doc_mptr_t const*) edges._buffer[j], barrier);
v8::Handle<v8::Value> doc = TRI_WrapShapedJson(resolver, collection, (TRI_doc_mptr_t const*) edges._buffer[j], barrier);
if (doc.IsEmpty()) {
error = true;
@ -1735,7 +1698,8 @@ static v8::Handle<v8::Value> JS_AllQuery (v8::Arguments const& argv) {
uint32_t total = 0;
vector<TRI_doc_mptr_t*> docs;
SingleCollectionReadOnlyTransaction<EmbeddableTransaction<V8TransactionContext> > trx(col->_vocbase, col->_name);
CollectionNameResolver resolver(col->_vocbase);
SingleCollectionReadOnlyTransaction<EmbeddableTransaction<V8TransactionContext> > trx(col->_vocbase, col->_cid);
int res = trx.begin();
if (res != TRI_ERROR_NO_ERROR) {
@ -1759,7 +1723,7 @@ static v8::Handle<v8::Value> JS_AllQuery (v8::Arguments const& argv) {
result->Set(v8::String::New("documents"), documents);
for (size_t i = 0; i < n; ++i) {
v8::Handle<v8::Value> document = TRI_WrapShapedJson(col, docs[i], barrier);
v8::Handle<v8::Value> document = TRI_WrapShapedJson(resolver, col, docs[i], barrier);
if (document.IsEmpty()) {
// error
@ -1804,7 +1768,8 @@ static v8::Handle<v8::Value> JS_AnyQuery (v8::Arguments const& argv) {
TRI_barrier_t* barrier = 0;
TRI_doc_mptr_t* doc = 0;
SingleCollectionReadOnlyTransaction<EmbeddableTransaction<V8TransactionContext> > trx(col->_vocbase, col->_name);
CollectionNameResolver resolver(col->_vocbase);
SingleCollectionReadOnlyTransaction<EmbeddableTransaction<V8TransactionContext> > trx(col->_vocbase, col->_cid);
int res = trx.begin();
if (res != TRI_ERROR_NO_ERROR) {
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(res, "cannot fetch document", true)));
@ -1821,7 +1786,7 @@ static v8::Handle<v8::Value> JS_AnyQuery (v8::Arguments const& argv) {
return scope.Close(v8::Null());
}
else {
return scope.Close(TRI_WrapShapedJson(col, doc, barrier));
return scope.Close(TRI_WrapShapedJson(resolver, col, doc, barrier));
}
}
@ -1831,7 +1796,7 @@ static v8::Handle<v8::Value> JS_AnyQuery (v8::Arguments const& argv) {
static v8::Handle<v8::Value> JS_ByExampleQuery (v8::Arguments const& argv) {
v8::HandleScope scope;
// extract and use the simple collection
v8::Handle<v8::Object> err;
TRI_vocbase_col_t const* collection;
@ -1841,6 +1806,8 @@ static v8::Handle<v8::Value> JS_ByExampleQuery (v8::Arguments const& argv) {
return scope.Close(v8::ThrowException(err));
}
assert(collection != 0);
TRI_shaper_t* shaper = document->base._shaper;
// expecting example, skip, limit
@ -1859,6 +1826,7 @@ static v8::Handle<v8::Value> JS_ByExampleQuery (v8::Arguments const& argv) {
"<example> must be an object")));
}
CollectionNameResolver resolver(collection->_vocbase);
v8::Handle<v8::Object> example = argv[0]->ToObject();
// extract skip and limit
@ -1919,7 +1887,7 @@ static v8::Handle<v8::Value> JS_ByExampleQuery (v8::Arguments const& argv) {
else {
for (size_t j = s; j < e; ++j) {
TRI_doc_mptr_t* mptr = (TRI_doc_mptr_t*) TRI_AtVector(&filtered, j);
v8::Handle<v8::Value> doc = TRI_WrapShapedJson(collection, mptr, barrier);
v8::Handle<v8::Value> doc = TRI_WrapShapedJson(resolver, collection, mptr, barrier);
if (doc.IsEmpty()) {
error = true;
@ -1996,9 +1964,10 @@ static v8::Handle<v8::Value> ByExampleHashIndexQuery (TRI_document_collection_t*
v8::Handle<v8::Array> documents = v8::Array::New();
result->Set(v8::String::New("documents"), documents);
// extract the index
TRI_index_t* idx = TRI_LookupIndexByHandle(document->base.base._vocbase, collection, argv[0], false, err);
CollectionNameResolver resolver(collection->_vocbase);
TRI_index_t* idx = TRI_LookupIndexByHandle(resolver, document->base.base._vocbase, collection, argv[0], false, err);
if (idx == 0) {
return scope.Close(v8::ThrowException(*err));
@ -2020,7 +1989,7 @@ static v8::Handle<v8::Value> ByExampleHashIndexQuery (TRI_document_collection_t*
if (res != TRI_ERROR_NO_ERROR) {
return scope.Close(v8::ThrowException(*err));
}
// find the matches
TRI_hash_index_elements_t* list = TRI_LookupShapedJsonHashIndex(idx, values);
@ -2042,7 +2011,7 @@ static v8::Handle<v8::Value> ByExampleHashIndexQuery (TRI_document_collection_t*
}
else {
for (size_t i = s; i < e; ++i) {
v8::Handle<v8::Value> doc = TRI_WrapShapedJson(collection, (TRI_doc_mptr_t const*) list->_elements[i].data, barrier);
v8::Handle<v8::Value> doc = TRI_WrapShapedJson(resolver, collection, (TRI_doc_mptr_t const*) list->_elements[i].data, barrier);
if (doc.IsEmpty()) {
error = true;
@ -2088,6 +2057,8 @@ static v8::Handle<v8::Value> JS_ByExampleHashIndex (v8::Arguments const& argv) {
if (document == 0) {
return scope.Close(v8::ThrowException(err));
}
assert(collection != 0);
// .............................................................................
// inside a read transaction
@ -2115,7 +2086,7 @@ static v8::Handle<v8::Value> JS_ByExampleHashIndex (v8::Arguments const& argv) {
static v8::Handle<v8::Value> JS_ByConditionSkiplist (v8::Arguments const& argv) {
std::string signature("BY_CONDITION_SKIPLIST(<index>, <conditions>, <skip>, <limit>)");
return ExecuteSkiplistQuery(argv, signature, QUERY_CONDITION, true);
return ExecuteSkiplistQuery(argv, signature, QUERY_CONDITION);
}
////////////////////////////////////////////////////////////////////////////////
@ -2125,7 +2096,7 @@ static v8::Handle<v8::Value> JS_ByConditionSkiplist (v8::Arguments const& argv)
static v8::Handle<v8::Value> JS_ByExampleSkiplist (v8::Arguments const& argv) {
std::string signature("BY_EXAMPLE_SKIPLIST(<index>, <example>, <skip>, <limit>)");
return ExecuteSkiplistQuery(argv, signature, QUERY_EXAMPLE, true);
return ExecuteSkiplistQuery(argv, signature, QUERY_EXAMPLE);
}
////////////////////////////////////////////////////////////////////////////////
@ -2135,13 +2106,13 @@ static v8::Handle<v8::Value> JS_ByExampleSkiplist (v8::Arguments const& argv) {
static v8::Handle<v8::Value> JS_ByExampleBitarray (v8::Arguments const& argv) {
std::string signature("BY_EXAMPLE_BITARRAY(<index>, <example>, <skip>, <limit>)");
return ExecuteBitarrayQuery(argv, signature, QUERY_EXAMPLE, true);
return ExecuteBitarrayQuery(argv, signature, QUERY_EXAMPLE);
}
static v8::Handle<v8::Value> JS_ByConditionBitarray (v8::Arguments const& argv) {
std::string signature("BY_CONDITION_BITARRAY(<index>, <conditions>, <skip>, <limit>)");
return ExecuteBitarrayQuery(argv, signature, QUERY_CONDITION, true);
return ExecuteBitarrayQuery(argv, signature, QUERY_CONDITION);
}
////////////////////////////////////////////////////////////////////////////////
@ -2208,7 +2179,8 @@ static v8::Handle<v8::Value> FulltextQuery (TRI_document_collection_t* document,
}
// extract the index
TRI_index_t* idx = TRI_LookupIndexByHandle(document->base.base._vocbase, collection, argv[0], false, err);
CollectionNameResolver resolver(collection->_vocbase);
TRI_index_t* idx = TRI_LookupIndexByHandle(resolver, document->base.base._vocbase, collection, argv[0], false, err);
if (idx == 0) {
return scope.Close(v8::ThrowException(*err));
@ -2217,7 +2189,7 @@ static v8::Handle<v8::Value> FulltextQuery (TRI_document_collection_t* document,
if (idx->_type != TRI_IDX_TYPE_FULLTEXT_INDEX) {
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(TRI_ERROR_BAD_PARAMETER, "index must be a fulltext index")));
}
const string queryString = TRI_ObjectToString(argv[1]);
bool isSubstringQuery = false;
@ -2257,7 +2229,7 @@ static v8::Handle<v8::Value> FulltextQuery (TRI_document_collection_t* document,
result->Set(v8::String::New("documents"), documents);
for (uint32_t i = 0; i < queryResult->_numDocuments; ++i) {
documents->Set(i, TRI_WrapShapedJson(collection, (TRI_doc_mptr_t const*) queryResult->_documents[i], barrier));
documents->Set(i, TRI_WrapShapedJson(resolver, collection, (TRI_doc_mptr_t const*) queryResult->_documents[i], barrier));
}
TRI_FreeResultFulltextIndex(queryResult);
@ -2299,6 +2271,8 @@ static v8::Handle<v8::Value> JS_FulltextQuery (v8::Arguments const& argv) {
return scope.Close(v8::ThrowException(err));
}
assert(collection != 0);
// .............................................................................
// inside a read transaction
// .............................................................................
@ -2338,7 +2312,8 @@ static v8::Handle<v8::Value> NearQuery (TRI_document_collection_t* document,
}
// extract the index
TRI_index_t* idx = TRI_LookupIndexByHandle(document->base.base._vocbase, collection, argv[0], false, err);
CollectionNameResolver resolver(collection->_vocbase);
TRI_index_t* idx = TRI_LookupIndexByHandle(resolver, document->base.base._vocbase, collection, argv[0], false, err);
if (idx == 0) {
return scope.Close(v8::ThrowException(*err));
@ -2392,6 +2367,8 @@ static v8::Handle<v8::Value> JS_NearQuery (v8::Arguments const& argv) {
if (document == 0) {
return scope.Close(v8::ThrowException(err));
}
assert(collection != 0);
// .............................................................................
// inside a read transaction
@ -2454,7 +2431,8 @@ static v8::Handle<v8::Value> WithinQuery (TRI_document_collection_t* document,
}
// extract the index
TRI_index_t* idx = TRI_LookupIndexByHandle(document->base.base._vocbase, collection, argv[0], false, err);
CollectionNameResolver resolver(collection->_vocbase);
TRI_index_t* idx = TRI_LookupIndexByHandle(resolver, document->base.base._vocbase, collection, argv[0], false, err);
if (idx == 0) {
return scope.Close(v8::ThrowException(*err));
@ -2509,6 +2487,8 @@ static v8::Handle<v8::Value> JS_WithinQuery (v8::Arguments const& argv) {
return scope.Close(v8::ThrowException(err));
}
assert(collection != 0);
// .............................................................................
// inside a read transaction
// .............................................................................

View File

@ -48,6 +48,7 @@
#include "ShapedJson/shape-accessor.h"
#include "ShapedJson/shaped-json.h"
#include "Utils/AhuacatlGuard.h"
#include "Utils/CollectionNameResolver.h"
#include "Utils/DocumentHelper.h"
#include "Utils/EmbeddableTransaction.h"
#include "Utils/SingleCollectionReadOnlyTransaction.h"
@ -206,22 +207,6 @@ static inline v8::Handle<v8::Value> V8DocumentId (const string& collectionName,
return scope.Close(result);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief create a v8 document id value from the parameters
////////////////////////////////////////////////////////////////////////////////
static v8::Handle<v8::Value> V8DocumentId (TRI_vocbase_t* const vocbase,
const TRI_voc_cid_t cid,
const string& key) {
v8::HandleScope scope;
const string id = DocumentHelper::assembleDocumentId(vocbase, cid, key);
v8::Handle<v8::Value> result = v8::String::New(id.c_str(), id.size());
return scope.Close(result);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief extract the forceSync flag from the arguments
/// must specify the argument index starting from 1
@ -319,10 +304,9 @@ static inline TRI_vocbase_t* GetContextVocBase () {
/// @brief checks if argument is a document identifier
////////////////////////////////////////////////////////////////////////////////
static bool IsDocumentHandle (TRI_vocbase_t* const vocbase,
v8::Handle<v8::Value> arg,
string& collectionName,
TRI_voc_key_t& key) {
static bool ParseDocumentHandle (v8::Handle<v8::Value> arg,
string& collectionName,
TRI_voc_key_t& key) {
assert(collectionName == "");
if (! arg->IsString()) {
@ -786,7 +770,8 @@ static v8::Handle<v8::Value> DocumentVocbaseCol (const bool useCollection,
assert(vocbase);
v8::Handle<v8::Value> err = TRI_ParseDocumentOrDocumentHandle(vocbase, col, key, rid, false, argv[0]);
CollectionNameResolver resolver(vocbase);
v8::Handle<v8::Value> err = TRI_ParseDocumentOrDocumentHandle(resolver, col, key, rid, argv[0]);
if (! holder.registerString(TRI_CORE_MEM_ZONE, key)) {
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(TRI_ERROR_ARANGO_DOCUMENT_HANDLE_BAD)));
}
@ -799,7 +784,7 @@ static v8::Handle<v8::Value> DocumentVocbaseCol (const bool useCollection,
assert(key);
SingleCollectionReadOnlyTransaction<EmbeddableTransaction<V8TransactionContext> > trx(vocbase, col->_name);
SingleCollectionReadOnlyTransaction<EmbeddableTransaction<V8TransactionContext> > trx(vocbase, col->_cid);
int res = trx.begin();
if (res != TRI_ERROR_NO_ERROR) {
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(res, "cannot fetch document", true)));
@ -813,7 +798,7 @@ static v8::Handle<v8::Value> DocumentVocbaseCol (const bool useCollection,
assert(document);
TRI_barrier_t* barrier = TRI_CreateBarrierElement(trx.barrierList());
result = TRI_WrapShapedJson(col, document, barrier);
result = TRI_WrapShapedJson(resolver, col, document, barrier);
}
res = trx.finish(res);
@ -871,7 +856,8 @@ static v8::Handle<v8::Value> ReplaceVocbaseCol (const bool useCollection,
assert(vocbase);
v8::Handle<v8::Value> err = TRI_ParseDocumentOrDocumentHandle(vocbase, col, key, rid, false, argv[0]);
CollectionNameResolver resolver(vocbase);
v8::Handle<v8::Value> err = TRI_ParseDocumentOrDocumentHandle(resolver, col, key, rid, argv[0]);
if (! holder.registerString(TRI_CORE_MEM_ZONE, key)) {
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(TRI_ERROR_ARANGO_DOCUMENT_HANDLE_BAD)));
}
@ -884,7 +870,7 @@ static v8::Handle<v8::Value> ReplaceVocbaseCol (const bool useCollection,
assert(key);
SingleCollectionWriteTransaction<EmbeddableTransaction<V8TransactionContext>, 1> trx(vocbase, col->_name);
SingleCollectionWriteTransaction<EmbeddableTransaction<V8TransactionContext>, 1> trx(vocbase, col->_cid);
int res = trx.begin();
if (res != TRI_ERROR_NO_ERROR) {
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(res, "cannot replace document", true)));
@ -911,7 +897,7 @@ static v8::Handle<v8::Value> ReplaceVocbaseCol (const bool useCollection,
TRI_v8_global_t* v8g = (TRI_v8_global_t*) v8::Isolate::GetCurrent()->GetData();
v8::Handle<v8::Object> result = v8::Object::New();
result->Set(v8g->DidKey, V8DocumentId(trx.collectionName(), document->_key));
result->Set(v8g->DidKey, V8DocumentId(resolver.getCollectionName(col->_cid), document->_key));
result->Set(v8g->RevKey, V8RevisionId(document->_rid));
result->Set(v8g->OldRevKey, V8RevisionId(actualRevision));
result->Set(v8g->KeyKey, v8::String::New(document->_key));
@ -952,6 +938,7 @@ static v8::Handle<v8::Value> ReplaceVocbaseCol (const bool useCollection,
////////////////////////////////////////////////////////////////////////////////
static v8::Handle<v8::Value> SaveVocbaseCol (SingleCollectionWriteTransaction<EmbeddableTransaction<V8TransactionContext>, 1>* trx,
TRI_vocbase_col_t* col,
v8::Arguments const& argv) {
v8::HandleScope scope;
@ -961,11 +948,12 @@ static v8::Handle<v8::Value> SaveVocbaseCol (SingleCollectionWriteTransaction<Em
"usage: save(<data>, <waitForSync>)")));
}
TRI_v8_global_t* v8g = (TRI_v8_global_t*) v8::Isolate::GetCurrent()->GetData();
CollectionNameResolver resolver(col->_vocbase);
ResourceHolder holder;
// set document key
TRI_voc_key_t key = 0;
TRI_v8_global_t* v8g = (TRI_v8_global_t*) v8::Isolate::GetCurrent()->GetData();
if (argv[0]->IsObject()) {
v8::Handle<v8::Object> obj = argv[0]->ToObject();
@ -999,7 +987,7 @@ static v8::Handle<v8::Value> SaveVocbaseCol (SingleCollectionWriteTransaction<Em
assert(document->_key);
v8::Handle<v8::Object> result = v8::Object::New();
result->Set(v8g->DidKey, V8DocumentId(trx->collectionName(), document->_key));
result->Set(v8g->DidKey, V8DocumentId(resolver.getCollectionName(col->_cid), document->_key));
result->Set(v8g->RevKey, V8RevisionId(document->_rid));
result->Set(v8g->KeyKey, v8::String::New(document->_key));
@ -1033,6 +1021,7 @@ static v8::Handle<v8::Value> SaveVocbaseCol (SingleCollectionWriteTransaction<Em
////////////////////////////////////////////////////////////////////////////////
static v8::Handle<v8::Value> SaveEdgeCol (SingleCollectionWriteTransaction<EmbeddableTransaction<V8TransactionContext>, 1>* trx,
TRI_vocbase_col_t* col,
v8::Arguments const& argv) {
v8::HandleScope scope;
TRI_v8_global_t* v8g = (TRI_v8_global_t*) v8::Isolate::GetCurrent()->GetData();
@ -1043,6 +1032,7 @@ static v8::Handle<v8::Value> SaveEdgeCol (SingleCollectionWriteTransaction<Embed
"usage: save(<from>, <to>, <data>, <waitForSync>)")));
}
CollectionNameResolver resolver(col->_vocbase);
ResourceHolder holder;
// set document key
@ -1073,7 +1063,7 @@ static v8::Handle<v8::Value> SaveEdgeCol (SingleCollectionWriteTransaction<Embed
TRI_vocbase_col_t const* fromCollection = 0;
TRI_voc_rid_t fromRid;
err = TRI_ParseDocumentOrDocumentHandle(trx->vocbase(), fromCollection, edge._fromKey, fromRid, false, argv[0]);
err = TRI_ParseDocumentOrDocumentHandle(resolver, fromCollection, edge._fromKey, fromRid, argv[0]);
holder.registerString(TRI_CORE_MEM_ZONE, edge._fromKey);
if (! err.IsEmpty()) {
@ -1085,7 +1075,7 @@ static v8::Handle<v8::Value> SaveEdgeCol (SingleCollectionWriteTransaction<Embed
TRI_vocbase_col_t const* toCollection = 0;
TRI_voc_rid_t toRid;
err = TRI_ParseDocumentOrDocumentHandle(trx->vocbase(), toCollection, edge._toKey, toRid, false, argv[1]);
err = TRI_ParseDocumentOrDocumentHandle(resolver, toCollection, edge._toKey, toRid, argv[1]);
holder.registerString(TRI_CORE_MEM_ZONE, edge._toKey);
if (! err.IsEmpty()) {
@ -1114,7 +1104,7 @@ static v8::Handle<v8::Value> SaveEdgeCol (SingleCollectionWriteTransaction<Embed
assert(document->_key);
v8::Handle<v8::Object> result = v8::Object::New();
result->Set(v8g->DidKey, V8DocumentId(trx->collectionName(), document->_key));
result->Set(v8g->DidKey, V8DocumentId(resolver.getCollectionName(col->_cid), document->_key));
result->Set(v8g->RevKey, V8RevisionId(document->_rid));
result->Set(v8g->KeyKey, v8::String::New(document->_key));
@ -1166,7 +1156,8 @@ static v8::Handle<v8::Value> UpdateVocbaseCol (const bool useCollection,
assert(vocbase);
v8::Handle<v8::Value> err = TRI_ParseDocumentOrDocumentHandle(vocbase, col, key, rid, false, argv[0]);
CollectionNameResolver resolver(vocbase);
v8::Handle<v8::Value> err = TRI_ParseDocumentOrDocumentHandle(resolver, col, key, rid, argv[0]);
if (! holder.registerString(TRI_CORE_MEM_ZONE, key)) {
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(TRI_ERROR_ARANGO_DOCUMENT_HANDLE_BAD)));
}
@ -1185,7 +1176,7 @@ static v8::Handle<v8::Value> UpdateVocbaseCol (const bool useCollection,
}
SingleCollectionWriteTransaction<EmbeddableTransaction<V8TransactionContext>, 1> trx(vocbase, col->_name);
SingleCollectionWriteTransaction<EmbeddableTransaction<V8TransactionContext>, 1> trx(vocbase, col->_cid);
int res = trx.begin();
if (res != TRI_ERROR_NO_ERROR) {
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(res, "cannot update document", true)));
@ -1225,7 +1216,7 @@ static v8::Handle<v8::Value> UpdateVocbaseCol (const bool useCollection,
TRI_v8_global_t* v8g = (TRI_v8_global_t*) v8::Isolate::GetCurrent()->GetData();
v8::Handle<v8::Object> result = v8::Object::New();
result->Set(v8g->DidKey, V8DocumentId(trx.collectionName(), document->_key));
result->Set(v8g->DidKey, V8DocumentId(resolver.getCollectionName(col->_cid), document->_key));
result->Set(v8g->RevKey, V8RevisionId(document->_rid));
result->Set(v8g->OldRevKey, V8RevisionId(actualRevision));
result->Set(v8g->KeyKey, v8::String::New(document->_key));
@ -1273,7 +1264,8 @@ static v8::Handle<v8::Value> RemoveVocbaseCol (const bool useCollection,
assert(vocbase);
v8::Handle<v8::Value> err = TRI_ParseDocumentOrDocumentHandle(vocbase, col, key, rid, false, argv[0]);
CollectionNameResolver resolver(vocbase);
v8::Handle<v8::Value> err = TRI_ParseDocumentOrDocumentHandle(resolver, col, key, rid, argv[0]);
if (! holder.registerString(TRI_CORE_MEM_ZONE, key)) {
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(TRI_ERROR_ARANGO_DOCUMENT_HANDLE_BAD)));
}
@ -1286,7 +1278,7 @@ static v8::Handle<v8::Value> RemoveVocbaseCol (const bool useCollection,
assert(key);
SingleCollectionWriteTransaction<EmbeddableTransaction<V8TransactionContext>, 1> trx(vocbase, col->_name);
SingleCollectionWriteTransaction<EmbeddableTransaction<V8TransactionContext>, 1> trx(vocbase, col->_cid);
int res = trx.begin();
if (res != TRI_ERROR_NO_ERROR) {
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(res, "cannot delete document", true)));
@ -3445,6 +3437,8 @@ static v8::Handle<v8::Value> JS_DropIndexVocbaseCol (v8::Arguments const& argv)
return scope.Close(v8::ThrowException(err));
}
CollectionNameResolver resolver(collection->_vocbase);
TRI_primary_collection_t* primary = collection->_collection;
if (! TRI_IS_DOCUMENT_COLLECTION(collection->_type)) {
@ -3459,7 +3453,7 @@ static v8::Handle<v8::Value> JS_DropIndexVocbaseCol (v8::Arguments const& argv)
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(TRI_ERROR_ILLEGAL_OPTION, "usage: dropIndex(<index-handle>)")));
}
TRI_index_t* idx = TRI_LookupIndexByHandle(collection->_vocbase, collection, argv[0], true, &err);
TRI_index_t* idx = TRI_LookupIndexByHandle(resolver, collection->_vocbase, collection, argv[0], true, &err);
if (idx == 0) {
if (err.IsEmpty()) {
@ -4514,8 +4508,18 @@ static v8::Handle<v8::Value> JS_NameVocbaseCol (v8::Arguments const& argv) {
return scope.Close(v8::ThrowException(v8::String::New("illegal collection pointer")));
}
// TODO: protect this against race conditions (parallel rename operation)
return scope.Close(v8::String::New(collection->_name));
// this copies the name into a new place so we can safely access it later
// 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());
}
v8::Handle<v8::Value> result = v8::String::New(name);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, name);
return scope.Close(result);
}
////////////////////////////////////////////////////////////////////////////////
@ -4933,7 +4937,7 @@ static v8::Handle<v8::Value> JS_SaveVocbaseCol (v8::Arguments const& argv) {
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(TRI_ERROR_INTERNAL)));
}
SingleCollectionWriteTransaction<EmbeddableTransaction<V8TransactionContext>, 1> trx(col->_vocbase, col->_name);
SingleCollectionWriteTransaction<EmbeddableTransaction<V8TransactionContext>, 1> trx(col->_vocbase, col->_cid);
int res = trx.begin();
if (res != TRI_ERROR_NO_ERROR) {
@ -4943,10 +4947,10 @@ static v8::Handle<v8::Value> JS_SaveVocbaseCol (v8::Arguments const& argv) {
v8::Handle<v8::Value> result;
if ((TRI_col_type_e) col->_type == TRI_COL_TYPE_DOCUMENT) {
result = SaveVocbaseCol(&trx, argv);
result = SaveVocbaseCol(&trx, col, argv);
}
else if ((TRI_col_type_e) col->_type == TRI_COL_TYPE_EDGE) {
result = SaveEdgeCol(&trx, argv);
result = SaveEdgeCol(&trx, col, argv);
}
return scope.Close(result);
@ -5083,7 +5087,7 @@ static v8::Handle<v8::Value> JS_TruncateVocbaseCol (v8::Arguments const& argv) {
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(TRI_ERROR_INTERNAL)));
}
SingleCollectionWriteTransaction<EmbeddableTransaction<V8TransactionContext>, UINT64_MAX> trx(col->_vocbase, col->_name);
SingleCollectionWriteTransaction<EmbeddableTransaction<V8TransactionContext>, UINT64_MAX> trx(col->_vocbase, col->_cid);
int res = trx.begin();
if (res != TRI_ERROR_NO_ERROR) {
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(res, "cannot truncate collection", true)));
@ -5425,6 +5429,7 @@ static v8::Handle<v8::Value> JS_CompletionsVocbase (v8::Arguments const& argv) {
if (vocbase == 0) {
return scope.Close(v8::Array::New());
}
TRI_vector_pointer_t colls = TRI_CollectionsVocBase(vocbase);
@ -5435,8 +5440,15 @@ static v8::Handle<v8::Value> JS_CompletionsVocbase (v8::Arguments const& argv) {
// add collection names
for (uint32_t i = 0; i < n; ++i) {
TRI_vocbase_col_t const* collection = (TRI_vocbase_col_t const*) colls._buffer[i];
result->Set(j++, v8::String::New(collection->_name));
// this copies the name into a new place so we can safely access it later
// 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) {
result->Set(j++, v8::String::New(name));
TRI_Free(TRI_UNKNOWN_MEM_ZONE, name);
}
}
TRI_DestroyVectorPointer(&colls);
@ -6088,17 +6100,54 @@ void TRI_ReleaseCollection (TRI_vocbase_col_t const* collection) {
}
////////////////////////////////////////////////////////////////////////////////
/// @brief parse document or document handle
///
/// @note this will lock (aka "use") the collection. You must release the
/// collection yourself.
/// @brief parse document or document handle from a v8 value (string | object)
////////////////////////////////////////////////////////////////////////////////
v8::Handle<v8::Value> TRI_ParseDocumentOrDocumentHandle (TRI_vocbase_t* vocbase,
bool ExtractDocumentHandle (v8::Handle<v8::Value> val,
string& collectionName,
TRI_voc_key_t& key,
TRI_voc_rid_t& rid) {
// reset the collection identifier and the revision
collectionName = "";
rid = 0;
// extract the document identifier and revision from a string
if (val->IsString() || val->IsStringObject()) {
return ParseDocumentHandle(val, collectionName, key);
}
// extract the document identifier and revision from a document object
if (val->IsObject()) {
TRI_v8_global_t* v8g = (TRI_v8_global_t*) v8::Isolate::GetCurrent()->GetData();
v8::Handle<v8::Object> obj = val->ToObject();
v8::Handle<v8::Value> didVal = obj->Get(v8g->DidKey);
if (! ParseDocumentHandle(didVal, collectionName, key)) {
return false;
}
rid = TRI_ObjectToUInt64(obj->Get(v8g->RevKey), true);
if (rid == 0) {
return false;
}
return true;
}
// unknown value type. give up
return false;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief parse document or document handle from a v8 value (string | object)
////////////////////////////////////////////////////////////////////////////////
v8::Handle<v8::Value> TRI_ParseDocumentOrDocumentHandle (const CollectionNameResolver& resolver,
TRI_vocbase_col_t const*& collection,
TRI_voc_key_t& key,
TRI_voc_rid_t& rid,
const bool use,
v8::Handle<v8::Value> val) {
v8::HandleScope scope;
@ -6108,57 +6157,34 @@ v8::Handle<v8::Value> TRI_ParseDocumentOrDocumentHandle (TRI_vocbase_t* vocbase,
string collectionName = "";
rid = 0;
// extract the document identifier and revision from a string
if (val->IsString() || val->IsStringObject()) {
if (! IsDocumentHandle(vocbase, val, collectionName, key)) {
return scope.Close(TRI_CreateErrorObject(TRI_ERROR_ARANGO_DOCUMENT_HANDLE_BAD,
"<document-handle> must be a document-handle"));
}
}
// extract the document identifier and revision from a string
else if (val->IsObject()) {
TRI_v8_global_t* v8g = (TRI_v8_global_t*) v8::Isolate::GetCurrent()->GetData();
v8::Handle<v8::Object> obj = val->ToObject();
v8::Handle<v8::Value> didVal = obj->Get(v8g->DidKey);
if (! IsDocumentHandle(vocbase, didVal, collectionName, key)) {
return scope.Close(TRI_CreateErrorObject(TRI_ERROR_ARANGO_DOCUMENT_HANDLE_BAD,
"expecting a document-handle in _id"));
}
rid = TRI_ObjectToUInt64(obj->Get(v8g->RevKey), true);
if (rid == 0) {
return scope.Close(TRI_CreateErrorObject(TRI_ERROR_ARANGO_DOCUMENT_HANDLE_BAD,
"expecting a revision identifier in _rev"));
}
}
// give up
else {
// try to extract the collection name, key, and revision from the object passed
if (! ExtractDocumentHandle(val, collectionName, key, rid)) {
return scope.Close(TRI_CreateErrorObject(TRI_ERROR_ARANGO_DOCUMENT_HANDLE_BAD,
"<document-handle> must be a document-handle"));
"<document-handle> must be a valid document-handle"));
}
// we have at least a key, we also might have a collection name
assert(key != 0);
if (collectionName == "") {
// only a document id without collection name was passed
// only a document key without collection name was passed
if (collection == 0) {
// we do not know the collection
return scope.Close(TRI_CreateErrorObject(TRI_ERROR_ARANGO_DOCUMENT_HANDLE_BAD,
"<document-handle> must be a document-handle"));
}
// we use the current collection
collectionName = collection->_name;
// we use the current collection's name
collectionName = resolver.getCollectionName(collection->_cid);
}
else {
// we read a collection name from the document id
// check cross-collection requests
if (collection != 0 && collectionName != collection->_name) {
return scope.Close(TRI_CreateErrorObject(TRI_ERROR_ARANGO_CROSS_COLLECTION_REQUEST,
"cannot execute cross collection query"));
if (collection != 0) {
if (collectionName != resolver.getCollectionName(collection->_cid)) {
return scope.Close(TRI_CreateErrorObject(TRI_ERROR_ARANGO_CROSS_COLLECTION_REQUEST,
"cannot execute cross collection query"));
}
}
}
@ -6166,30 +6192,17 @@ v8::Handle<v8::Value> TRI_ParseDocumentOrDocumentHandle (TRI_vocbase_t* vocbase,
if (collection == 0) {
// no collection object was passed, now check the user-supplied collection name
TRI_vocbase_col_t* const col = TRI_LookupCollectionByNameVocBase(vocbase, collectionName.c_str());
const TRI_vocbase_col_t* col = resolver.getCollectionStruct(collectionName);
if (col == 0) {
// collection not found
return scope.Close(TRI_CreateErrorObject(TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND,
"collection of <document-handle> is unknown"));;
}
if (use) {
// use the collection
int res = TRI_UseCollectionVocBase(vocbase, col);
if (res == TRI_ERROR_NO_ERROR && col->_collection == 0) {
res = TRI_ERROR_INTERNAL;
}
if (res != TRI_ERROR_NO_ERROR) {
return scope.Close(TRI_CreateErrorObject(res, "cannot use/load collection", true));
}
}
collection = col;
}
assert(collection);
assert(collection != 0);
v8::Handle<v8::Value> empty;
return scope.Close(empty);
@ -6199,7 +6212,8 @@ v8::Handle<v8::Value> TRI_ParseDocumentOrDocumentHandle (TRI_vocbase_t* vocbase,
/// @brief looks up an index identifier
////////////////////////////////////////////////////////////////////////////////
TRI_index_t* TRI_LookupIndexByHandle (TRI_vocbase_t* vocbase,
TRI_index_t* TRI_LookupIndexByHandle (const CollectionNameResolver& resolver,
TRI_vocbase_t* vocbase,
TRI_vocbase_col_t const*& collection,
v8::Handle<v8::Value> val,
bool ignoreNotFound,
@ -6208,6 +6222,10 @@ TRI_index_t* TRI_LookupIndexByHandle (TRI_vocbase_t* vocbase,
string collectionName = "";
TRI_idx_iid_t iid = 0;
// assume we are already loaded
assert(collection != 0);
assert(collection->_collection != 0);
// extract the document identifier and revision from a string
if (val->IsString() || val->IsStringObject()) {
if (! IsIndexHandle(val, collectionName, iid)) {
@ -6232,17 +6250,14 @@ TRI_index_t* TRI_LookupIndexByHandle (TRI_vocbase_t* vocbase,
}
if (collectionName == "") {
assert(false);
// no collection name passed by user
if (collection == 0) {
*err = TRI_CreateErrorObject(TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND,
"collection of <index-handle> unknown");
return 0;
}
collectionName = collection->_name;
*err = TRI_CreateErrorObject(TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND,
"collection of <index-handle> unknown");
return 0;
}
else {
if (collection != 0 && collectionName != collection->_name) {
if (collectionName != collection->_name) {
// I wish this error provided me with more information!
// e.g. 'cannot access index outside the collection it was defined in'
*err = TRI_CreateErrorObject(TRI_ERROR_ARANGO_CROSS_COLLECTION_REQUEST,
@ -6253,35 +6268,6 @@ TRI_index_t* TRI_LookupIndexByHandle (TRI_vocbase_t* vocbase,
assert(collectionName != "");
// lookup the collection
if (collection == 0) {
TRI_vocbase_col_t* const col = TRI_LookupCollectionByNameVocBase(vocbase, collectionName.c_str());
if (col == 0) {
*err = TRI_CreateErrorObject(TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND,
"collection of <index-handle> is unknown");
return 0;
}
// use the collection
int res = TRI_UseCollectionVocBase(vocbase, col);
if (res != TRI_ERROR_NO_ERROR) {
*err = TRI_CreateErrorObject(res, "cannot use/load collection", true);
return 0;
}
if (col->_collection == 0) {
*err = TRI_CreateErrorObject(TRI_ERROR_INTERNAL, "cannot use/load collection");
return 0;
}
collection = col;
}
assert(collection);
assert(collection->_collection);
TRI_index_t* idx = TRI_LookupIndex(collection->_collection, iid);
if (idx == 0) {
@ -6333,7 +6319,8 @@ v8::Handle<v8::Object> TRI_WrapCollection (TRI_vocbase_col_t const* collection)
/// @brief wraps a TRI_shaped_json_t
////////////////////////////////////////////////////////////////////////////////
v8::Handle<v8::Value> TRI_WrapShapedJson (TRI_vocbase_col_t const* collection,
v8::Handle<v8::Value> TRI_WrapShapedJson (const CollectionNameResolver& resolver,
TRI_vocbase_col_t const* collection,
TRI_doc_mptr_t const* document,
TRI_barrier_t* barrier) {
v8::HandleScope scope;
@ -6369,8 +6356,7 @@ v8::Handle<v8::Value> TRI_WrapShapedJson (TRI_vocbase_col_t const* collection,
// store the document reference
TRI_voc_rid_t rid = document->_rid;
// TODO: protect this against race conditions (parallel rename)
result->Set(v8g->DidKey, V8DocumentId(collection->_name, document->_key), v8::ReadOnly);
result->Set(v8g->DidKey, V8DocumentId(resolver.getCollectionName(collection->_cid), document->_key), v8::ReadOnly);
result->Set(v8g->RevKey, V8RevisionId(rid), v8::ReadOnly);
result->Set(v8g->KeyKey, v8::String::New(document->_key), v8::ReadOnly);
@ -6378,11 +6364,9 @@ v8::Handle<v8::Value> TRI_WrapShapedJson (TRI_vocbase_col_t const* collection,
if (type == TRI_DOC_MARKER_KEY_EDGE) {
TRI_doc_edge_key_marker_t* marker = (TRI_doc_edge_key_marker_t*) document->_data;
TRI_vocbase_t* const vocbase = collection->_vocbase;
// unidirectional edge
result->Set(v8g->FromKey, V8DocumentId(vocbase, marker->_fromCid, ((char*) marker) + marker->_offsetFromKey));
result->Set(v8g->ToKey, V8DocumentId(vocbase, marker->_toCid, ((char*) marker) + marker->_offsetToKey));
result->Set(v8g->FromKey, V8DocumentId(resolver.getCollectionName(marker->_fromCid), ((char*) marker) + marker->_offsetFromKey));
result->Set(v8g->ToKey, V8DocumentId(resolver.getCollectionName(marker->_toCid), ((char*) marker) + marker->_offsetToKey));
}
// and return

View File

@ -30,6 +30,7 @@
#include "V8/v8-globals.h"
#include "ShapedJson/shaped-json.h"
#include "Utils/CollectionNameResolver.h"
#include "VocBase/document-collection.h"
// -----------------------------------------------------------------------------
@ -71,18 +72,18 @@ void TRI_ReleaseCollection (TRI_vocbase_col_t const*);
/// @brief parse document or document handle
////////////////////////////////////////////////////////////////////////////////
v8::Handle<v8::Value> TRI_ParseDocumentOrDocumentHandle (TRI_vocbase_t*,
v8::Handle<v8::Value> TRI_ParseDocumentOrDocumentHandle (const triagens::arango::CollectionNameResolver&,
TRI_vocbase_col_t const*&,
TRI_voc_key_t&,
TRI_voc_rid_t&,
const bool,
v8::Handle<v8::Value>);
////////////////////////////////////////////////////////////////////////////////
/// @brief looks up a index identifier
////////////////////////////////////////////////////////////////////////////////
TRI_index_t* TRI_LookupIndexByHandle (TRI_vocbase_t*,
TRI_index_t* TRI_LookupIndexByHandle (const triagens::arango::CollectionNameResolver&,
TRI_vocbase_t*,
TRI_vocbase_col_t const*&,
v8::Handle<v8::Value>,
bool,
@ -104,7 +105,8 @@ v8::Handle<v8::Object> TRI_WrapCollection (TRI_vocbase_col_t const*);
/// @brief wraps a TRI_shaped_json_t
////////////////////////////////////////////////////////////////////////////////
v8::Handle<v8::Value> TRI_WrapShapedJson (TRI_vocbase_col_t const*,
v8::Handle<v8::Value> TRI_WrapShapedJson (const triagens::arango::CollectionNameResolver&,
TRI_vocbase_col_t const*,
TRI_doc_mptr_t const*,
TRI_barrier_t*);

View File

@ -53,19 +53,19 @@ static uint64_t HashCollection (TRI_associative_pointer_t* array,
void const* element) {
TRI_transaction_collection_global_t* collection = (TRI_transaction_collection_global_t*) element;
return TRI_FnvHashString(collection->_name);
return TRI_FnvHashPointer((void const*) &(collection->_cid), sizeof(TRI_transaction_cid_t));
}
////////////////////////////////////////////////////////////////////////////////
/// @brief comparison function used to determine collection equality
////////////////////////////////////////////////////////////////////////////////
static bool IsEqualCollectionName (TRI_associative_pointer_t* array,
void const* key,
void const* element) {
static bool IsEqualCollectionId (TRI_associative_pointer_t* array,
void const* key,
void const* element) {
TRI_transaction_collection_global_t* collection = (TRI_transaction_collection_global_t*) element;
return TRI_EqualString(key, collection->_name);
return *((TRI_transaction_cid_t*) key) == collection->_cid;
}
////////////////////////////////////////////////////////////////////////////////
@ -314,13 +314,7 @@ TRI_transaction_collection_global_t* CreateCollectionGlobalInstance (const TRI_t
return NULL;
}
globalInstance->_name = TRI_DuplicateStringZ(TRI_UNKNOWN_MEM_ZONE, collection->_name);
if (globalInstance->_name == NULL) {
// OOM
TRI_Free(TRI_UNKNOWN_MEM_ZONE, globalInstance);
return NULL;
}
globalInstance->_cid = collection->_cid;
TRI_InitMutex(&globalInstance->_writeLock);
InitTransactionList(&globalInstance->_writeTransactions);
@ -336,8 +330,6 @@ void FreeCollectionGlobalInstance (TRI_transaction_collection_global_t* const gl
DestroyTransactionList(&globalInstance->_writeTransactions);
TRI_DestroyMutex(&globalInstance->_writeLock);
TRI_FreeString(TRI_UNKNOWN_MEM_ZONE, (char*) globalInstance->_name);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, globalInstance);
}
@ -375,7 +367,7 @@ TRI_transaction_context_t* TRI_CreateTransactionContext (TRI_vocbase_t* const vo
TRI_UNKNOWN_MEM_ZONE,
TRI_HashStringKeyAssociativePointer,
HashCollection,
IsEqualCollectionName,
IsEqualCollectionId,
NULL);
// setup global transaction lists
@ -438,14 +430,14 @@ void TRI_FreeTransactionContext (TRI_transaction_context_t* const context) {
////////////////////////////////////////////////////////////////////////////////
void TRI_RemoveCollectionTransactionContext (TRI_transaction_context_t* const context,
const char* const name) {
const TRI_transaction_cid_t cid) {
TRI_transaction_collection_global_t* collection;
// start critical section -----------------------------------------
TRI_LockMutex(&context->_collectionLock);
// TODO: must not remove collections with transactions going on
collection = (TRI_transaction_collection_global_t*) TRI_RemoveKeyAssociativePointer(&context->_collections, name);
collection = (TRI_transaction_collection_global_t*) TRI_RemoveKeyAssociativePointer(&context->_collections, &cid);
TRI_UnlockMutex(&context->_collectionLock);
// end critical section -----------------------------------------
@ -504,7 +496,7 @@ void TRI_DumpTransactionContext (TRI_transaction_context_t* const context) {
/// @brief create a transaction collection container
////////////////////////////////////////////////////////////////////////////////
static TRI_transaction_collection_t* CreateCollection (const char* const name,
static TRI_transaction_collection_t* CreateCollection (const TRI_transaction_cid_t cid,
const TRI_transaction_type_e type) {
TRI_transaction_collection_t* collection;
@ -514,15 +506,8 @@ static TRI_transaction_collection_t* CreateCollection (const char* const name,
return NULL;
}
collection->_name = TRI_DuplicateStringZ(TRI_UNKNOWN_MEM_ZONE, name);
if (collection->_name == NULL) {
// OOM
TRI_Free(TRI_UNKNOWN_MEM_ZONE, collection);
return NULL;
}
// initialise collection properties
collection->_cid = cid;
collection->_type = type;
collection->_collection = NULL;
collection->_globalInstance = NULL;
@ -540,10 +525,7 @@ static TRI_transaction_collection_t* CreateCollection (const char* const name,
static void FreeCollection (TRI_transaction_collection_t* collection) {
assert(collection);
assert(collection->_name);
TRI_FreeString(TRI_UNKNOWN_MEM_ZONE, (char*) collection->_name);
DestroyTransactionList(&collection->_writeTransactions);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, collection);
@ -561,11 +543,11 @@ static TRI_transaction_collection_global_t* GetGlobalCollection (TRI_transaction
// start critical section -----------------------------------------
TRI_LockMutex(&context->_collectionLock);
globalInstance = (TRI_transaction_collection_global_t*) TRI_LookupByKeyAssociativePointer(&context->_collections, collection->_name);
globalInstance = (TRI_transaction_collection_global_t*) TRI_LookupByKeyAssociativePointer(&context->_collections, &(collection->_cid));
if (globalInstance == NULL) {
globalInstance = CreateCollectionGlobalInstance(collection);
if (globalInstance != NULL) {
TRI_InsertKeyAssociativePointer(&context->_collections, collection->_name, globalInstance, false);
TRI_InsertKeyAssociativePointer(&context->_collections, &(collection->_cid), globalInstance, false);
}
}
@ -576,10 +558,10 @@ static TRI_transaction_collection_global_t* GetGlobalCollection (TRI_transaction
}
////////////////////////////////////////////////////////////////////////////////
/// @brief acquire collection locks for a transaction
/// @brief use all participating collections of a transaction
////////////////////////////////////////////////////////////////////////////////
static int AcquireCollectionLocks (TRI_transaction_t* const trx) {
static int UseCollections (TRI_transaction_t* const trx) {
TRI_transaction_context_t* context;
size_t i, n;
@ -594,12 +576,13 @@ static int AcquireCollectionLocks (TRI_transaction_t* const trx) {
TRI_transaction_collection_t* collection;
collection = (TRI_transaction_collection_t*) TRI_AtVectorPointer(&trx->_collections, i);
collection->_collection = TRI_UseCollectionByNameVocBase(trx->_context->_vocbase, collection->_name);
LOG_DEBUG("using collection %llu", (unsigned long long) collection->_cid);
collection->_collection = TRI_UseCollectionByIdVocBase(trx->_context->_vocbase, collection->_cid);
if (collection->_collection == NULL) {
return TRI_errno();
}
collection->_globalInstance = GetGlobalCollection(context, collection);
if (collection->_globalInstance == NULL) {
@ -607,7 +590,7 @@ static int AcquireCollectionLocks (TRI_transaction_t* const trx) {
}
if (collection->_type == TRI_TRANSACTION_WRITE) {
LOG_DEBUG("acquiring write-lock on collection '%s'", collection->_name);
LOG_DEBUG("acquiring write-lock on collection %llu", (unsigned long long) collection->_cid);
// acquire write-lock on collection
TRI_LockMutex(&collection->_globalInstance->_writeLock);
@ -622,11 +605,11 @@ static int AcquireCollectionLocks (TRI_transaction_t* const trx) {
/// @brief release collection locks for a transaction
////////////////////////////////////////////////////////////////////////////////
static int ReleaseCollectionLocks (TRI_transaction_t* const trx) {
static int ReleaseCollections (TRI_transaction_t* const trx) {
size_t i;
int res;
LOG_DEBUG("releasing collection locks");
LOG_DEBUG("releasing collections");
res = TRI_ERROR_NO_ERROR;
@ -642,7 +625,7 @@ static int ReleaseCollectionLocks (TRI_transaction_t* const trx) {
}
if (collection->_type == TRI_TRANSACTION_WRITE && collection->_locked) {
LOG_DEBUG("releasing write-lock on collection '%s'", collection->_name);
LOG_DEBUG("releasing trx exclusive lock on collection %llu", (unsigned long long) collection->_cid);
// release write-lock on collection
TRI_UnlockMutex(&collection->_globalInstance->_writeLock);
@ -651,6 +634,7 @@ static int ReleaseCollectionLocks (TRI_transaction_t* const trx) {
}
// unuse collection
LOG_DEBUG("unusing collection %llu", (unsigned long long) collection->_cid);
TRI_ReleaseCollectionVocBase(trx->_context->_vocbase, collection->_collection);
collection->_collection = NULL;
@ -930,7 +914,7 @@ void TRI_FreeTransaction (TRI_transaction_t* const trx) {
TRI_AbortTransaction(trx);
}
ReleaseCollectionLocks(trx);
ReleaseCollections(trx);
// free all collections
i = trx->_collections._length;
@ -1025,7 +1009,7 @@ void TRI_DumpTransaction (TRI_transaction_t* const trx) {
TRI_transaction_collection_t* collection = TRI_AtVectorPointer(&trx->_collections, i);
LOG_INFO("- collection: %s, type: %s", collection->_name, TypeString(collection->_type));
LOG_INFO("- collection: %llu, type: %s", (unsigned long long) collection->_cid, TypeString(collection->_type));
for (j = 0; j < collection->_writeTransactions._vector._length; ++j) {
TRI_transaction_list_entry_t* entry;
@ -1042,29 +1026,26 @@ void TRI_DumpTransaction (TRI_transaction_t* const trx) {
////////////////////////////////////////////////////////////////////////////////
TRI_vocbase_col_t* TRI_CheckCollectionTransaction (TRI_transaction_t* const trx,
const char* const name,
const TRI_transaction_cid_t cid,
const TRI_transaction_type_e type) {
TRI_transaction_collection_t* collection;
size_t i, n;
assert(trx->_status == TRI_TRANSACTION_CREATED ||
trx->_status == TRI_TRANSACTION_RUNNING);
assert(name);
// check if we already have got this collection in the _collections vector
// the vector is sorted by collection names
n = trx->_collections._length;
for (i = 0; i < n; ++i) {
int res;
collection = TRI_AtVectorPointer(&trx->_collections, i);
res = strcmp(name, collection->_name);
if (res < 0) {
if (cid < collection->_cid) {
// collection is not contained in vector
break;
}
else if (res == 0) {
else if (cid == collection->_cid) {
// collection is already contained in vector
// check if access type matches
@ -1084,13 +1065,12 @@ TRI_vocbase_col_t* TRI_CheckCollectionTransaction (TRI_transaction_t* const trx,
////////////////////////////////////////////////////////////////////////////////
int TRI_AddCollectionTransaction (TRI_transaction_t* const trx,
const char* const name,
const TRI_transaction_cid_t cid,
const TRI_transaction_type_e type) {
TRI_transaction_collection_t* collection;
size_t i, n;
assert(trx->_status == TRI_TRANSACTION_CREATED);
assert(name);
// upgrade transaction type if required
if (type == TRI_TRANSACTION_WRITE && trx->_type == TRI_TRANSACTION_READ) {
@ -1102,14 +1082,11 @@ int TRI_AddCollectionTransaction (TRI_transaction_t* const trx,
// the vector is sorted by collection names
n = trx->_collections._length;
for (i = 0; i < n; ++i) {
int res;
collection = TRI_AtVectorPointer(&trx->_collections, i);
res = strcmp(name, collection->_name);
if (res < 0) {
if (cid < collection->_cid) {
// collection is not contained in vector
collection = CreateCollection(name, type);
collection = CreateCollection(cid, type);
if (collection == NULL) {
// out of memory
return TRI_ERROR_OUT_OF_MEMORY;
@ -1119,7 +1096,7 @@ int TRI_AddCollectionTransaction (TRI_transaction_t* const trx,
return TRI_ERROR_NO_ERROR;
}
else if (res == 0) {
else if (cid == collection->_cid) {
// collection is already contained in vector
// upgrade collection type if required
@ -1132,7 +1109,7 @@ int TRI_AddCollectionTransaction (TRI_transaction_t* const trx,
}
// collection was not contained. now insert it
collection = CreateCollection(name, type);
collection = CreateCollection(cid, type);
if (collection == NULL) {
// out of memory
return TRI_ERROR_OUT_OF_MEMORY;
@ -1154,11 +1131,11 @@ int TRI_StartTransaction (TRI_transaction_t* const trx, TRI_transaction_hint_t h
trx->_hints = hints;
res = AcquireCollectionLocks(trx);
res = UseCollections(trx);
if (res != TRI_ERROR_NO_ERROR) {
// free what we have got so far
trx->_status = TRI_TRANSACTION_FAILED;
ReleaseCollectionLocks(trx);
ReleaseCollections(trx);
return res;
}
@ -1167,7 +1144,7 @@ int TRI_StartTransaction (TRI_transaction_t* const trx, TRI_transaction_hint_t h
if (res != TRI_ERROR_NO_ERROR) {
// free what we have got so far
trx->_status = TRI_TRANSACTION_FAILED;
ReleaseCollectionLocks(trx);
ReleaseCollections(trx);
return res;
}
@ -1187,7 +1164,7 @@ int TRI_CommitTransaction (TRI_transaction_t* const trx) {
assert(trx->_status == TRI_TRANSACTION_RUNNING);
res = UpdateTransactionStatus(trx, TRI_TRANSACTION_COMMITTED);
ReleaseCollectionLocks(trx);
ReleaseCollections(trx);
return res;
}
@ -1202,7 +1179,7 @@ int TRI_AbortTransaction (TRI_transaction_t* const trx) {
assert(trx->_status == TRI_TRANSACTION_RUNNING);
res = UpdateTransactionStatus(trx, TRI_TRANSACTION_ABORTED);
ReleaseCollectionLocks(trx);
ReleaseCollections(trx);
return res;
}
@ -1228,7 +1205,7 @@ int TRI_FinishTransaction (TRI_transaction_t* const trx) {
res = UpdateTransactionStatus(trx, status);
ReleaseCollectionLocks(trx);
ReleaseCollections(trx);
return res;
}
@ -1238,7 +1215,7 @@ int TRI_FinishTransaction (TRI_transaction_t* const trx) {
////////////////////////////////////////////////////////////////////////////////
TRI_vocbase_col_t* TRI_GetCollectionTransaction (const TRI_transaction_t* const trx,
const char* const name) {
const TRI_transaction_cid_t cid) {
size_t i, n;
assert(trx->_status == TRI_TRANSACTION_RUNNING);
@ -1250,7 +1227,7 @@ TRI_vocbase_col_t* TRI_GetCollectionTransaction (const TRI_transaction_t* const
TRI_transaction_collection_t* collection;
collection = (TRI_transaction_collection_t*) TRI_AtVectorPointer(&trx->_collections, i);
if (TRI_EqualString(name, collection->_name)) {
if (cid == collection->_cid) {
return collection->_collection;
}
}

View File

@ -60,6 +60,8 @@ struct TRI_vocbase_col_s;
/// @{
////////////////////////////////////////////////////////////////////////////////
typedef uint64_t TRI_transaction_cid_t;
////////////////////////////////////////////////////////////////////////////////
/// @brief local transaction id typedef
////////////////////////////////////////////////////////////////////////////////
@ -196,7 +198,7 @@ TRI_transaction_context_t;
////////////////////////////////////////////////////////////////////////////////
typedef struct TRI_transaction_collection_global_s {
const char* _name; // collection name
TRI_transaction_cid_t _cid; // collection id
TRI_transaction_list_t _writeTransactions; // list of write-transactions currently going on for the collection
TRI_mutex_t _writeLock; // write lock for the collection, used to serialize writes on the same collection
}
@ -247,7 +249,7 @@ void TRI_FreeTransactionContext (TRI_transaction_context_t*);
////////////////////////////////////////////////////////////////////////////////
void TRI_RemoveCollectionTransactionContext (TRI_transaction_context_t* const,
const char* const);
const TRI_transaction_cid_t);
////////////////////////////////////////////////////////////////////////////////
/// @brief dump transaction context data
@ -277,7 +279,7 @@ void TRI_DumpTransactionContext (TRI_transaction_context_t* const);
////////////////////////////////////////////////////////////////////////////////
typedef struct TRI_transaction_collection_s {
const char* _name; // collection name
TRI_transaction_cid_t _cid; // collection id
TRI_transaction_type_e _type; // access type (read|write)
TRI_transaction_list_t _writeTransactions; // private copy of other write transactions at transaction start
struct TRI_vocbase_col_s* _collection; // vocbase collection pointer
@ -385,7 +387,7 @@ void TRI_DumpTransaction (TRI_transaction_t* const);
////////////////////////////////////////////////////////////////////////////////
struct TRI_vocbase_col_s* TRI_CheckCollectionTransaction (TRI_transaction_t* const,
const char* const,
const TRI_transaction_cid_t,
const TRI_transaction_type_e);
////////////////////////////////////////////////////////////////////////////////
@ -393,7 +395,7 @@ struct TRI_vocbase_col_s* TRI_CheckCollectionTransaction (TRI_transaction_t* con
////////////////////////////////////////////////////////////////////////////////
int TRI_AddCollectionTransaction (TRI_transaction_t* const,
const char* const,
const TRI_transaction_cid_t,
const TRI_transaction_type_e);
////////////////////////////////////////////////////////////////////////////////
@ -425,7 +427,7 @@ int TRI_FinishTransaction (TRI_transaction_t* const);
////////////////////////////////////////////////////////////////////////////////
struct TRI_vocbase_col_s* TRI_GetCollectionTransaction (const TRI_transaction_t* const,
const char* const);
const TRI_transaction_cid_t);
////////////////////////////////////////////////////////////////////////////////
/// @}

View File

@ -1885,6 +1885,38 @@ int TRI_UseCollectionVocBase (TRI_vocbase_t* vocbase, TRI_vocbase_col_t* collect
return LoadCollectionVocBase(vocbase, collection);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief locks a (document) collection for usage by id
////////////////////////////////////////////////////////////////////////////////
TRI_vocbase_col_t* TRI_UseCollectionByIdVocBase (TRI_vocbase_t* vocbase, const TRI_voc_cid_t cid) {
union { TRI_vocbase_col_t const* c; TRI_vocbase_col_t* v; } cnv;
TRI_vocbase_col_t const* collection;
int res;
// .............................................................................
// check that we have an existing name
// .............................................................................
TRI_READ_LOCK_COLLECTIONS_VOCBASE(vocbase);
collection = TRI_LookupByKeyAssociativePointer(&vocbase->_collectionsById, &cid);
TRI_READ_UNLOCK_COLLECTIONS_VOCBASE(vocbase);
if (collection == NULL) {
TRI_set_errno(TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND);
return NULL;
}
// .............................................................................
// try to load the collection
// .............................................................................
cnv.c = collection;
res = LoadCollectionVocBase(vocbase, cnv.v);
return res == TRI_ERROR_NO_ERROR ? cnv.v : NULL;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief locks a (document) collection for usage by name
////////////////////////////////////////////////////////////////////////////////

View File

@ -570,6 +570,16 @@ int TRI_RenameCollectionVocBase (TRI_vocbase_t*, TRI_vocbase_col_t*, char const*
int TRI_UseCollectionVocBase (TRI_vocbase_t*, TRI_vocbase_col_t*);
////////////////////////////////////////////////////////////////////////////////
/// @brief locks a (document) collection for usage by id
///
/// Note that this will READ lock the collection you have to release the
/// collection lock by yourself and call @ref TRI_ReleaseCollectionVocBase
/// when you are done with the collection.
////////////////////////////////////////////////////////////////////////////////
TRI_vocbase_col_t* TRI_UseCollectionByIdVocBase (TRI_vocbase_t*, const TRI_voc_cid_t);
////////////////////////////////////////////////////////////////////////////////
/// @brief locks a (document) collection for usage by name
///

View File

@ -290,6 +290,41 @@ function CollectionEdgeSuite () {
assertTypeOf("string", doc._id);
assertTypeOf("string", doc._rev);
assertMatch(/^UnitTestsCollectionEdge\//, doc._id);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief create an edge that reference non-existing vertex collections
////////////////////////////////////////////////////////////////////////////////
testSaveEdgeInvalidVertexCollection : function () {
[ "UnitTestsCollectionNonExistingVertex/12345", "UnitTestsCollectionNonExistingVertex/456745" ].forEach(function(key) {
try {
edge.save(key, key, { });
fail();
}
catch (err) {
assertEqual(ERRORS.ERROR_ARANGO_COLLECTION_NOT_FOUND.code, err.errorNum);
}
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief create an edge that reference an unloaded collection
////////////////////////////////////////////////////////////////////////////////
testSaveEdgeUnloadedVertexCollection : function () {
vertex.unload();
wait(4);
var e = edge.save(v1._id, v2._id, { });
assertMatch(/^UnitTestsCollectionEdge\//, e._id);
var doc = edge.document(e._id);
assertMatch(/^UnitTestsCollectionEdge\//, doc._id);
assertMatch(/^UnitTestsCollectionVertex\//, doc._from);
assertMatch(/^UnitTestsCollectionVertex\//, doc._to);
},
////////////////////////////////////////////////////////////////////////////////
@ -462,6 +497,54 @@ function CollectionEdgeSuite () {
assertEqual(1, e.length);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief edges query
////////////////////////////////////////////////////////////////////////////////
testReadEdgesUnloaded : function () {
var d1 = edge.save(v1, v2, { "Hallo" : "World" })._id;
var d2 = edge.save(v2, v1, { "World" : "Hallo" })._id;
var e1 = edge.document(d1);
var e2 = edge.document(d2);
assertMatch(/^UnitTestsCollectionEdge\//, e1._id);
assertMatch(/^UnitTestsCollectionVertex\//, e1._from);
assertMatch(/^UnitTestsCollectionVertex\//, e1._to);
assertMatch(/^UnitTestsCollectionEdge\//, e2._id);
assertMatch(/^UnitTestsCollectionVertex\//, e2._from);
assertMatch(/^UnitTestsCollectionVertex\//, e2._to);
e1 = null;
e2 = null;
vertex.unload();
edge.unload();
wait(4);
var e = edge.edges(v1);
assertEqual(2, e.length);
if (e[0]._id == d1) {
assertEqual(v2._id, e[0]._to);
assertEqual(v1._id, e[0]._from);
assertEqual(d2, e[1]._id);
assertEqual(v1._id, e[1]._to);
assertEqual(v2._id, e[1]._from);
}
else {
assertEqual(v1._id, e[0]._to);
assertEqual(v2._id, e[0]._from);
assertEqual(d1, e[1]._id);
assertEqual(v2._id, e[1]._to);
assertEqual(v1._id, e[1]._from);
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief edges query invalid
////////////////////////////////////////////////////////////////////////////////

View File

@ -36,6 +36,7 @@
var jsunity = require("jsunity");
var internal = require("internal");
var console = require("console");
var errors = internal.errors;
// -----------------------------------------------------------------------------
// --SECTION-- basic methods
@ -204,7 +205,37 @@ function HashIndexSuite() {
assertEqual(2, s.total);
assertEqual(2, s.count);
assertEqual([d11,d12], s.documents.map(fun));
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test: documents of an unloaded collection
////////////////////////////////////////////////////////////////////////////////
testReadDocumentsUnloaded : function () {
var idx = collection.ensureHashIndex("a");
var d1 = collection.save({ a : 1, b : 1 })._id;
var d2 = collection.save({ a : 2, b : 1 })._id;
var d3 = collection.save({ a : 3, b : 1 })._id;
collection.unload();
internal.wait(4);
var s = collection.BY_EXAMPLE_HASH(idx.id, { a : 2, b : 1 });
assertEqual(1, s.total);
assertEqual(d2, s.documents[0]._id);
collection.drop();
try {
s = collection.BY_EXAMPLE_HASH(idx.id, { a : 2, b : 1 });
fail();
}
catch (err) {
assertEqual(errors.ERROR_ARANGO_COLLECTION_NOT_FOUND.code, err.errorNum);
}
}
};
}

View File

@ -36,6 +36,7 @@
var jsunity = require("jsunity");
var internal = require("internal");
var console = require("console");
var errors = internal.errors;
// -----------------------------------------------------------------------------
// --SECTION-- basic methods
@ -133,7 +134,60 @@ function indexSuite() {
res = internal.db._dropIndex(id);
assertEqual(false, res);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief access a non-existing index
////////////////////////////////////////////////////////////////////////////////
testGetNonExistingIndexes : function () {
tests = [ "yippie", "9999999999999", -1 ].forEach(function (id) {
var idx = collection.index(id);
assertEqual(null, idx);
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief access an existing index of an unloaded collection
////////////////////////////////////////////////////////////////////////////////
testGetIndexUnloaded : function () {
var idx = collection.ensureHashIndex("test");
collection.unload();
internal.wait(4);
assertEqual(idx.id, collection.index(idx.id).id);
assertEqual(idx.id, collection.getIndexes()[1].id);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief access an existing index of a dropped collection
////////////////////////////////////////////////////////////////////////////////
testGetIndexDropped : function () {
var idx = collection.ensureHashIndex("test");
collection.drop();
try {
collection.index(idx.id).id;
fail();
}
catch (e1) {
assertEqual(errors.ERROR_ARANGO_COLLECTION_NOT_FOUND.code, e1.errorNum);
}
try {
collection.getIndexes();
fail();
}
catch (e2) {
assertEqual(errors.ERROR_ARANGO_COLLECTION_NOT_FOUND.code, e2.errorNum);
}
}
};
}