1
0
Fork 0

added temporary attribute entries in shaper

This commit is contained in:
Frank Celler 2014-06-26 12:50:50 +02:00
parent ae53a8c7c9
commit 4ae1f0cd4a
19 changed files with 889 additions and 670 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
/* A Bison parser, made by GNU Bison 3.0. */
/* A Bison parser, made by GNU Bison 3.0.2. */
/* Bison interface for Yacc-like parsers in C
@ -110,14 +110,14 @@ extern int Ahuacatldebug;
typedef union YYSTYPE YYSTYPE;
union YYSTYPE
{
#line 26 "arangod/Ahuacatl/ahuacatl-grammar.y" /* yacc.c:1909 */
#line 26 "arangod/Ahuacatl/ahuacatl-grammar.y" /* yacc.c:1915 */
TRI_aql_node_t* node;
char* strval;
bool boolval;
int64_t intval;
#line 121 "arangod/Ahuacatl/ahuacatl-grammar.h" /* yacc.c:1909 */
#line 121 "arangod/Ahuacatl/ahuacatl-grammar.h" /* yacc.c:1915 */
};
# define YYSTYPE_IS_TRIVIAL 1
# define YYSTYPE_IS_DECLARED 1

View File

@ -179,6 +179,8 @@ typedef enum {
TRI_WAL_MARKER_CREATE_DATABASE = 4040,
TRI_WAL_MARKER_DROP_DATABASE = 4041,
TRI_TEMP_MARKER_ATTRIBUTE = 9000,
TRI_MARKER_MAX // again, this is not a real
// marker, but we use it for
// bounds checking

View File

@ -3507,7 +3507,8 @@ static int PidNamesByAttributeNames (TRI_vector_pointer_t const* attributes,
TRI_vector_t* pids,
TRI_vector_pointer_t* names,
bool sorted,
bool create) {
bool create,
bool isTemporary) {
pid_name_t* pidnames;
// .............................................................................
@ -3527,7 +3528,7 @@ static int PidNamesByAttributeNames (TRI_vector_pointer_t const* attributes,
pidnames[j]._name = static_cast<char*>(attributes->_buffer[j]);
if (create) {
pidnames[j]._pid = shaper->findOrCreateAttributePathByName(shaper, pidnames[j]._name, true);
pidnames[j]._pid = shaper->findOrCreateAttributePathByName(shaper, pidnames[j]._name, true, isTemporary);
}
else {
pidnames[j]._pid = shaper->lookupAttributePathByName(shaper, pidnames[j]._name);
@ -3568,7 +3569,7 @@ static int PidNamesByAttributeNames (TRI_vector_pointer_t const* attributes,
TRI_shape_pid_t pid;
if (create) {
pid = shaper->findOrCreateAttributePathByName(shaper, name, true);
pid = shaper->findOrCreateAttributePathByName(shaper, name, true, isTemporary);
}
else {
pid = shaper->lookupAttributePathByName(shaper, name);
@ -3805,7 +3806,7 @@ static TRI_index_t* CreateGeoIndexDocumentCollection (TRI_document_collection_t*
shaper = document->getShaper(); // ONLY IN INDEX, PROTECTED by RUNTIME
if (location != NULL) {
loc = shaper->findOrCreateAttributePathByName(shaper, location, true);
loc = shaper->findOrCreateAttributePathByName(shaper, location, true, true);
if (loc == 0) {
TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY);
@ -3814,7 +3815,7 @@ static TRI_index_t* CreateGeoIndexDocumentCollection (TRI_document_collection_t*
}
if (latitude != NULL) {
lat = shaper->findOrCreateAttributePathByName(shaper, latitude, true);
lat = shaper->findOrCreateAttributePathByName(shaper, latitude, true, true);
if (lat == 0) {
TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY);
@ -3823,7 +3824,7 @@ static TRI_index_t* CreateGeoIndexDocumentCollection (TRI_document_collection_t*
}
if (longitude != NULL) {
lon = shaper->findOrCreateAttributePathByName(shaper, longitude, true);
lon = shaper->findOrCreateAttributePathByName(shaper, longitude, true, true);
if (lon == 0) {
TRI_set_errno(TRI_ERROR_OUT_OF_MEMORY);
@ -4251,6 +4252,7 @@ static TRI_index_t* CreateHashIndexDocumentCollection (TRI_document_collection_t
&paths,
&fields,
true,
true,
true);
if (res != TRI_ERROR_NO_ERROR) {
@ -4359,7 +4361,8 @@ TRI_index_t* TRI_LookupHashIndexDocumentCollection (TRI_document_collection_t* d
&paths,
&fields,
true,
false);
false,
true);
if (res != TRI_ERROR_NO_ERROR) {
return nullptr;
@ -4444,6 +4447,7 @@ static TRI_index_t* CreateSkiplistIndexDocumentCollection (TRI_document_collecti
&paths,
&fields,
false,
true,
true);
if (res != TRI_ERROR_NO_ERROR) {
@ -4546,7 +4550,8 @@ TRI_index_t* TRI_LookupSkiplistIndexDocumentCollection (TRI_document_collection_
&paths,
&fields,
false,
false);
false,
true);
if (res != TRI_ERROR_NO_ERROR) {
return NULL;
@ -4884,6 +4889,7 @@ static TRI_index_t* CreateBitarrayIndexDocumentCollection (TRI_document_collecti
&paths,
&fields,
false,
true,
true);
if (res != TRI_ERROR_NO_ERROR) {
@ -5018,7 +5024,8 @@ TRI_index_t* TRI_LookupBitarrayIndexDocumentCollection (TRI_document_collection_
&paths,
&fields,
false,
false);
false,
true);
if (result != TRI_ERROR_NO_ERROR) {
return NULL;

View File

@ -1826,7 +1826,7 @@ TRI_index_t* TRI_CreateFulltextIndex (TRI_document_collection_t* document,
// look up the attribute
shaper = document->getShaper(); // ONLY IN INDEX, PROTECTED by RUNTIME
attribute = shaper->findOrCreateAttributePathByName(shaper, attributeName, true);
attribute = shaper->findOrCreateAttributePathByName(shaper, attributeName, true, true);
if (attribute == 0) {
return nullptr;

View File

@ -79,14 +79,20 @@ voc_shaper_t;
/// @brief extracts an attribute id from a marker
////////////////////////////////////////////////////////////////////////////////
static inline TRI_shape_aid_t GetAttributeId (void const* marker) {
static inline TRI_shape_aid_t GetAttributeId (void const* marker, bool* isTemporary) {
TRI_df_marker_t const* p = static_cast<TRI_df_marker_t const*>(marker);
if (p != nullptr) {
if (p->_type == TRI_DF_MARKER_ATTRIBUTE) {
*isTemporary = false;
return reinterpret_cast<TRI_df_attribute_marker_t const*>(p)->_aid;
}
else if (p->_type == TRI_WAL_MARKER_ATTRIBUTE) {
*isTemporary = false;
return reinterpret_cast<triagens::wal::attribute_marker_t const*>(p)->_attributeId;
}
else if (p->_type == TRI_TEMP_MARKER_ATTRIBUTE) {
*isTemporary = true;
return reinterpret_cast<triagens::wal::attribute_marker_t const*>(p)->_attributeId;
}
}
@ -108,6 +114,9 @@ static inline char const* GetAttributeName (void const* marker) {
else if (p->_type == TRI_WAL_MARKER_ATTRIBUTE) {
return reinterpret_cast<char const*>(p) + sizeof(triagens::wal::attribute_marker_t);
}
else if (p->_type == TRI_TEMP_MARKER_ATTRIBUTE) {
return reinterpret_cast<char const*>(p) + sizeof(triagens::wal::attribute_marker_t);
}
}
return nullptr;
@ -142,7 +151,7 @@ static bool EqualKeyAttributeName (TRI_associative_synced_t* array, void const*
}
////////////////////////////////////////////////////////////////////////////////
/// @brief finds an attribute identifier by name
/// @brief looks up an attribute identifier by name
////////////////////////////////////////////////////////////////////////////////
static TRI_shape_aid_t LookupAttributeByName (TRI_shaper_t* shaper,
@ -153,55 +162,96 @@ static TRI_shape_aid_t LookupAttributeByName (TRI_shaper_t* shaper,
void const* p = TRI_LookupByKeyAssociativeSynced(&s->_attributeNames, name);
if (p != nullptr) {
return GetAttributeId(p);
bool isTemporary;
return GetAttributeId(p, &isTemporary);
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief finds an attribute identifier by name
/// @brief looks up an attribute identifier by name
////////////////////////////////////////////////////////////////////////////////
static TRI_shape_aid_t LookupAttributeByName (TRI_shaper_t* shaper,
char const* name,
bool* isTemporary) {
TRI_ASSERT(name != nullptr);
voc_shaper_t* s = reinterpret_cast<voc_shaper_t*>(shaper);
void const* p = TRI_LookupByKeyAssociativeSynced(&s->_attributeNames, name);
if (p != nullptr) {
return GetAttributeId(p, isTemporary);
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief finds or creates an attribute identifier by name
////////////////////////////////////////////////////////////////////////////////
static TRI_shape_aid_t FindOrCreateAttributeByName (TRI_shaper_t* shaper,
char const* name) {
// check if the attribute exists
TRI_shape_aid_t aid = LookupAttributeByName(shaper, name);
char const* name,
bool isTemporary) {
voc_shaper_t* s = reinterpret_cast<voc_shaper_t*>(shaper);
if (aid != 0) {
// yes
// get a lock for the attributes (TODO: replace assoc sync be normal unordered_map, maybe use RW lock?)
MUTEX_LOCKER(s->_attributeLock);
// check if the attribute exists
bool temp;
TRI_shape_aid_t aid = LookupAttributeByName(shaper, name, &temp);
// yes, we found found - check the temporary flag
if (aid != 0 && ((temp && isTemporary) || ! temp)) {
return aid;
}
// we need to create a new attribute marker
// we need to remove the old entries
if (temp) {
void* old;
// increase attribute id value
voc_shaper_t* s = reinterpret_cast<voc_shaper_t*>(shaper);
aid = s->_nextAid++;
TRI_ASSERT(aid != 0);
TRI_document_collection_t* document = s->_collection;
old = TRI_RemoveKeyAssociativeSynced(&s->_attributeIds, &aid);
TRI_ASSERT(old != nullptr);
old = TRI_RemoveKeyAssociativeSynced(&s->_attributeNames, name);
TRI_ASSERT(old != nullptr);
if (old != nullptr) {
delete[] static_cast<char*>(old);
}
}
// increase attribute id value, if we do not already know it
if (aid == 0) {
aid = s->_nextAid++;
}
// try to create an entry, either temporary or permanently
int res = TRI_ERROR_NO_ERROR;
try {
TRI_document_collection_t* document = s->_collection;
triagens::wal::AttributeMarker marker(document->_vocbase->_id, document->_info._cid, aid, std::string(name));
// lock the index and check that the element is still missing
{
MUTEX_LOCKER(s->_attributeLock);
TRI_IF_FAILURE("ShaperWriteAttributeMarker") {
THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG);
}
void const* p = TRI_LookupByKeyAssociativeSynced(&s->_attributeNames, name);
void* ptr;
// if the element appeared, return the aid
if (p != nullptr) {
return GetAttributeId(p);
}
// create a temporary entry
if (isTemporary) {
marker.setType(TRI_TEMP_MARKER_ATTRIBUTE);
ptr = marker.steal();
}
TRI_IF_FAILURE("ShaperWriteAttributeMarker") {
THROW_ARANGO_EXCEPTION(TRI_ERROR_DEBUG);
}
// write marker into wal
// create a permanent entry, write marker into wal
else {
triagens::wal::SlotInfoCopy slotInfo = triagens::wal::LogfileManager::instance()->allocateAndWrite(marker, false);
if (slotInfo.errorCode != TRI_ERROR_NO_ERROR) {
@ -209,14 +259,16 @@ static TRI_shape_aid_t FindOrCreateAttributeByName (TRI_shaper_t* shaper,
THROW_ARANGO_EXCEPTION(slotInfo.errorCode);
}
void* f TRI_UNUSED = TRI_InsertKeyAssociativeSynced(&s->_attributeIds, &aid, const_cast<void*>(slotInfo.mem), false);
TRI_ASSERT(f == nullptr);
// enter into the dictionaries
f = TRI_InsertKeyAssociativeSynced(&s->_attributeNames, name, const_cast<void*>(slotInfo.mem), false);
TRI_ASSERT(f == nullptr);
ptr = const_cast<void*>(slotInfo.mem);
}
void* f TRI_UNUSED = TRI_InsertKeyAssociativeSynced(&s->_attributeIds, &aid, ptr, false);
TRI_ASSERT(f == nullptr);
// enter into the dictionaries
f = TRI_InsertKeyAssociativeSynced(&s->_attributeNames, name, ptr, false);
TRI_ASSERT(f == nullptr);
return aid;
}
catch (triagens::arango::Exception const& ex) {
@ -246,7 +298,8 @@ static uint64_t HashKeyAttributeId (TRI_associative_synced_t* array, void const*
////////////////////////////////////////////////////////////////////////////////
static uint64_t HashElementAttributeId (TRI_associative_synced_t* array, void const* element) {
TRI_shape_aid_t aid = GetAttributeId(element);
bool isTemporary;
TRI_shape_aid_t aid = GetAttributeId(element, &isTemporary);
return TRI_FnvHashPointer(&aid, sizeof(TRI_shape_aid_t));
}
@ -257,7 +310,8 @@ static uint64_t HashElementAttributeId (TRI_associative_synced_t* array, void co
static bool EqualKeyAttributeId (TRI_associative_synced_t* array, void const* key, void const* element) {
TRI_shape_aid_t const* k = static_cast<TRI_shape_aid_t const*>(key);
TRI_shape_aid_t aid = GetAttributeId(element);
bool isTemporary;
TRI_shape_aid_t aid = GetAttributeId(element, &isTemporary);
return *k == aid;
}
@ -688,6 +742,7 @@ int TRI_MoveMarkerVocShaper (TRI_shaper_t* s,
// remove the old marker
// and re-insert the marker with the new pointer
f = TRI_InsertKeyAssociativeSynced(&shaper->_shapeIds, &l->_sid, l, true);
// note: this assertion is wrong if the recovery collects the shape in the WAL and it has not been transferred
// into the collection datafile yet
// TRI_ASSERT(f != nullptr);
@ -698,6 +753,7 @@ int TRI_MoveMarkerVocShaper (TRI_shaper_t* s,
// same for the shape dictionary
// delete and re-insert
f = TRI_InsertElementAssociativeSynced(&shaper->_shapeDictionary, l, true);
// note: this assertion is wrong if the recovery collects the shape in the WAL and it has not been transferred
// into the collection datafile yet
// TRI_ASSERT(f != nullptr);
@ -716,6 +772,7 @@ int TRI_MoveMarkerVocShaper (TRI_shaper_t* s,
// are identical in old and new marker)
// and re-insert same attribute with adjusted pointer
f = TRI_InsertKeyAssociativeSynced(&shaper->_attributeNames, p, m, true);
// note: this assertion is wrong if the recovery collects the attribute in the WAL and it has not been transferred
// into the collection datafile yet
// TRI_ASSERT(f != nullptr);
@ -726,6 +783,7 @@ int TRI_MoveMarkerVocShaper (TRI_shaper_t* s,
// same for attribute ids
// delete and re-insert same attribute with adjusted pointer
f = TRI_InsertKeyAssociativeSynced(&shaper->_attributeIds, &m->_aid, m, true);
// note: this assertion is wrong if the recovery collects the attribute in the WAL and it has not been transferred
// into the collection datafile yet
// TRI_ASSERT(f != nullptr);

View File

@ -186,6 +186,20 @@ AttributeMarker::AttributeMarker (TRI_voc_tick_t databaseId,
AttributeMarker::~AttributeMarker () {
}
// -----------------------------------------------------------------------------
// --SECTION-- public methods
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief change the type
////////////////////////////////////////////////////////////////////////////////
void AttributeMarker::setType (TRI_df_marker_type_t type) {
TRI_df_marker_t* m = reinterpret_cast<attribute_marker_t*>(begin());
m->_type = type;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief dump marker
////////////////////////////////////////////////////////////////////////////////

View File

@ -365,6 +365,8 @@ namespace triagens {
return begin() + sizeof(attribute_marker_t);
}
void setType (TRI_df_marker_type_t);
void dump () const;
};

View File

@ -16,6 +16,10 @@ AC_CONFIG_AUX_DIR([config])
AC_CONFIG_MACRO_DIR([m4])
CURRENT_DIR=`pwd`
CFLAGS="$CFLAGS $RPM_OPT_FLAGS"
CXXFLAGS="$CXXFLAGS $RPM_OPT_FLAGS"
AC_MSG_NOTICE([configure started in '$CURRENT_DIR])
AC_MSG_NOTICE([with CPPFLAGS='$CPPFLAGS'])
AC_MSG_NOTICE([with CFLAGS='$CFLAGS'])

View File

@ -268,17 +268,21 @@ ArangoCollection.prototype.all = function () {
/// Use *toArray* to get all documents at once:
///
/// @EXAMPLE_ARANGOSH_OUTPUT{collectionByExample}
/// ~ db._create("users");
/// db.users.all().toArray();
/// db.users.byExample({ "id" : 323 }).toArray();
/// db.users.byExample({ "name" : "Peter" }).toArray();
/// db.users.byExample({ "name" : "Peter", "id" : 535 }).toArray();
/// ~ db._drop("users");
/// @END_EXAMPLE_ARANGOSH_OUTPUT
///
/// Use *next* to loop over all documents:
///
/// @EXAMPLE_ARANGOSH_OUTPUT{collectionByExampleNext}
/// ~ db._create("users");
/// var a = db.users.byExample( {"name" : "Peter" } );
/// while (a.hasNext()) print(a.next());
/// ~ db._drop("users");
/// @END_EXAMPLE_ARANGOSH_OUTPUT
///
/// @endDocuBlock
@ -513,7 +517,9 @@ ArangoCollection.prototype.byConditionBitarray = function (index, condition) {
/// Use *toArray* to get all documents at once:
///
/// @EXAMPLE_ARANGOSH_OUTPUT{collectionRange}
/// l = db.skip.range("age", 10, 13).toArray();
/// ~ db._create("example");
/// l = db.example.range("age", 10, 13).toArray();
/// ~ db._drop("example")
/// @END_EXAMPLE_ARANGOSH_OUTPUT
///
/// @endDocuBlock
@ -693,12 +699,17 @@ ArangoCollection.prototype.geo = function(loc, order) {
///
/// To get the nearst two locations:
///
/// @TINYEXAMPLE{simple-query-near,nearest two location}
/// @EXAMPLE_ARANGOSH_OUTPUT{collectionNear}
/// db.geo.near(0,0).limit(2).toArray();
/// @END_EXAMPLE_ARANGOSH_OUTPUT
///
/// If you need the distance as well, then you can use the *distance*
/// operator:
///
/// @TINYEXAMPLE{simple-query-near2,nearest two location with distance in meter}
/// @EXAMPLE_ARANGOSH_OUTPUT{collectionNearDistance}
/// db.geo.near(0,0).distance().limit(2).toArray();
/// @END_EXAMPLE_ARANGOSH_OUTPUT
///
/// @endDocuBlock
////////////////////////////////////////////////////////////////////////////////
@ -734,7 +745,10 @@ ArangoCollection.prototype.near = function (lat, lon) {
///
/// To find all documents within a radius of 2000 km use:
///
/// @TINYEXAMPLE{simple-query-within,within a radius}
/// @EXAMPLE_ARANGOSH_OUTPUT{collectionWithin}
/// db.geo.within(0, 0, 2000 * 1000).distance().toArray();
/// @END_EXAMPLE_ARANGOSH_OUTPUT
///
/// @endDocuBlock
////////////////////////////////////////////////////////////////////////////////
@ -750,7 +764,7 @@ ArangoCollection.prototype.within = function (lat, lon, radius) {
/// This will find the documents from the collection's fulltext index that match the search
/// query.
///
/// In order to use the @FN{fulltext} operator, a fulltext index must be defined for the
/// In order to use the *fulltext* operator, a fulltext index must be defined for the
/// collection, for the specified attribute. If multiple fulltext indexes are defined
/// for the collection and attribute, the most capable one will be selected.
///
@ -758,7 +772,9 @@ ArangoCollection.prototype.within = function (lat, lon, radius) {
///
/// To find all documents which contain the terms *text* and *word*:
///
/// @TINYEXAMPLE{simple-query-fulltext,complete match query}
/// @EXAMPLE_ARANGOSH_OUTPUT{collectionFulltext}
/// db.emails.fulltext("text", "word").toArray();
/// @END_EXAMPLE_ARANGOSH_OUTPUT
/// @endDocuBlock
////////////////////////////////////////////////////////////////////////////////
@ -909,7 +925,8 @@ ArangoCollection.prototype.iterate = function (iterator, options) {
///
/// @EXAMPLE_ARANGOSH_OUTPUT{documentsCollectionRemoveByExample}
/// ~ db._create("example");
/// db.content.removeByExample({ "domain": "de.celler" })
/// ~ db.example.save({ Hello : "world" });
/// db.example.removeByExample( {Hello : "world"} );
/// ~ db._drop("example");
/// @END_EXAMPLE_ARANGOSH_OUTPUT
/// @endDocuBlock
@ -953,7 +970,8 @@ ArangoCollection.prototype.removeByExample = function (example, waitForSync, lim
///
/// @EXAMPLE_ARANGOSH_OUTPUT{documentsCollectionReplaceByExample}
/// ~ db._create("example");
/// db.content.replaceByExample({ "domain": "de.celler" }, { "foo": "someValue }, false, 5)
/// ~ db.example.save({ Hello : "world" });
/// db.example.replaceByExample({ Hello: "world" }, {Hello: "mars"}, false, 5);
/// ~ db._drop("example");
/// @END_EXAMPLE_ARANGOSH_OUTPUT
/// @endDocuBlock
@ -966,7 +984,7 @@ ArangoCollection.prototype.replaceByExample = function (example, newValue, waitF
////////////////////////////////////////////////////////////////////////////////
/// @brief partially updates documents matching an example
/// @startDocuBlock documentsCollectionUpdateByExample
/// `collection.updateByExample(example, newValue`
/// `collection.updateByExample(example, newValue)`
///
/// Partially updates all documents matching an example with a new document body.
/// Specific attributes in the document body of each document matching the
@ -1004,10 +1022,11 @@ ArangoCollection.prototype.replaceByExample = function (example, newValue, waitF
///
/// @EXAMPLE_ARANGOSH_OUTPUT{documentsCollectionUpdateByExample}
/// ~ db._create("example");
/// arangod> db.content.updateByExample({ "domain": "de.celler" }, { "foo": "someValue, "domain": null }, false)
/// ~ db.example.save({ Hello : "world" });
/// db.example.updateByExample({ Hello: "world" }, { Hello: "foo", Hello: "bar" }, false);
/// ~ db._drop("example");
/// @END_EXAMPLE_ARANGOSH_OUTPUT
/// endDocuBlock
/// @endDocuBlock
////////////////////////////////////////////////////////////////////////////////
ArangoCollection.prototype.updateByExample = function (example, newValue, keepNull, waitForSync, limit) {

View File

@ -424,12 +424,15 @@ AQLGenerator.prototype._edges = function(edgeExample, options) {
/// `graph_query.edges(examples)`
/// *Select all edges for the vertices selected before.*
///
///
/// Creates an AQL statement to select all edges for each of the vertices selected
/// in the step before.
/// This will include *inbound* as well as *outbound* edges.
/// The resulting set of edges can be filtered by defining one or more *examples*.
///
/// The complexity of this method is **O(n\*m^x)** with *n* being the vertices defined by the
/// parameter vertexExamplex, *m* the average amount of edges of a vertex and *x* the maximal depths.
/// Hence the default call would have a complexity of **O(n\*m)**;
///
/// *Parameter*
///
/// * *examples*: See [Definition of examples](#definition_of_examples)
@ -1455,6 +1458,11 @@ var _list = function() {
};
var _listObjects = function() {
return getGraphCollection().toArray();
};
////////////////////////////////////////////////////////////////////////////////
@ -1706,6 +1714,7 @@ var _create = function (graphName, edgeDefinitions, orphanCollections) {
findOrCreateCollectionByName(oC, ArangoCollection.TYPE_DOCUMENT);
}
);
edgeDefinitions.forEach(
function(eD, index) {
var tmp = sortEdgeDefinition(eD);
@ -1714,7 +1723,7 @@ var _create = function (graphName, edgeDefinitions, orphanCollections) {
);
orphanCollections = orphanCollections.sort();
gdb.save({
gdb.save({
'orphanCollections' : orphanCollections,
'edgeDefinitions' : edgeDefinitions,
'_key' : graphName
@ -2682,6 +2691,9 @@ Graph.prototype._getVertexCollectionByName = function(name) {
///
/// The function accepts an id, an example, a list of examples or even an empty
/// example as parameter for vertexExample.
/// The complexity of this method is **O(n\*m^x)** with *n* being the vertices defined by the
/// parameter vertexExamplex, *m* the average amount of neighbors and *x* the maximal depths.
/// Hence the default call would have a complexity of **O(n\*m)**;
///
/// *Parameter*
///
@ -2739,6 +2751,11 @@ Graph.prototype._neighbors = function(vertexExample, options) {
/// and *graph_module._neighbors(vertex2Example, optionsVertex2)*.
/// For parameter documentation see [_neighbors](#_neighbors).
///
/// The complexity of this method is **O(n\*m^x)** with *n* being the maximal amount of vertices
/// defined by the parameters vertexExamples, *m* the average amount of neighbors and *x* the
/// maximal depths.
/// Hence the default call would have a complexity of **O(n\*m)**;
///
/// *Examples*
///
/// A route planner example, all common neighbors of capitals.
@ -2868,6 +2885,9 @@ Graph.prototype._countCommonNeighbors = function(vertex1Example, vertex2Example,
/// The function accepts an id, an example, a list of examples or even an empty
/// example as parameter for vertex1Example and vertex2Example.
///
/// The complexity of this method is **O(n)** with *n* being the maximal amount of vertices
/// defined by the parameters vertexExamples.
///
/// *Parameter*
///
/// * *vertex1Examples*: Filter the set of source vertices, see [Definition of examples](#definition_of_examples)
@ -2991,6 +3011,9 @@ Graph.prototype._countCommonProperties = function(vertex1Example, vertex2Example
///
/// This function determines all available paths in a graph.
///
/// The complexity of this method is **O(n\*n\*m)** with *n* being the amount of vertices in
/// the graph and *m* the average amount of connected edges;
///
/// *Parameters*
///
/// * *options* (optional) : An object containing options, see below:
@ -3060,6 +3083,9 @@ Graph.prototype._paths = function(options) {
/// an end vertex. The option weight allows the user to define an edge attribute
/// representing the length.
///
/// The complexity of the function is described
/// [here](../Aql/GraphOperations.html#the_complexity_of_the_shortest_path_algorithms).
///
/// *Parameters*
///
/// * *startVertexExample* (optional) : An example for the desired start Vertices
@ -3203,6 +3229,9 @@ Graph.prototype._distanceTo = function(startVertexExample, endVertexExample, opt
/// The function accepts an id, an example, a list of examples or even an empty
/// example as parameter for vertexExample.
///
/// The complexity of the function is described
/// [here](../Aql/GraphOperations.html#the_complexity_of_the_shortest_path_algorithms).
///
/// *Parameter*
///
/// * *vertexExample*: Filter the vertices, see [Definition of examples](#definition_of_examples)
@ -3285,6 +3314,9 @@ Graph.prototype._absoluteEccentricity = function(vertexExample, options) {
///
/// Similar to [_absoluteEccentricity](#_absoluteeccentricity) but returns a normalized result.
///
/// The complexity of the function is described
/// [here](../Aql/GraphOperations.html#the_complexity_of_the_shortest_path_algorithms).
///
/// @EXAMPLES
///
/// A route planner example, the eccentricity of all locations.
@ -3332,6 +3364,9 @@ Graph.prototype._eccentricity = function(options) {
/// The function accepts an id, an example, a list of examples or even an empty
/// example as parameter for *vertexExample*.
///
/// The complexity of the function is described
/// [here](../Aql/GraphOperations.html#the_complexity_of_the_shortest_path_algorithms).
///
/// *Parameter*
///
/// * *vertexExample*: Filter the vertices, see [Definition of examples](#definition_of_examples)
@ -3412,6 +3447,9 @@ Graph.prototype._absoluteCloseness = function(vertexExample, options) {
///
/// Similar to [_absoluteCloseness](#_absolutecloseness) but returns a normalized value.
///
/// The complexity of the function is described
/// [here](../Aql/GraphOperations.html#the_complexity_of_the_shortest_path_algorithms).
///
/// @EXAMPLES
///
/// A route planner example, the normalized closeness of all locations.
@ -3467,6 +3505,9 @@ Graph.prototype._closeness = function(options) {
/// [betweenness](http://en.wikipedia.org/wiki/Betweenness_centrality)
/// *of all vertices in the graph.*
///
/// The complexity of the function is described
/// [here](../Aql/GraphOperations.html#the_complexity_of_the_shortest_path_algorithms).
///
/// *Parameter*
///
/// * *options* (optional): An object defining further options. Can have the following values:
@ -3589,6 +3630,9 @@ Graph.prototype._betweenness = function(options) {
/// [radius](http://en.wikipedia.org/wiki/Eccentricity_%28graph_theory%29)
/// *of a graph.*
///
/// The complexity of the function is described
/// [here](../Aql/GraphOperations.html#the_complexity_of_the_shortest_path_algorithms).
///
/// *Parameter*
///
/// * *options* (optional): An object defining further options. Can have the following values:
@ -3658,6 +3702,9 @@ Graph.prototype._radius = function(options) {
/// [diameter](http://en.wikipedia.org/wiki/Eccentricity_%28graph_theory%29)
/// *of a graph.*
///
/// The complexity of the function is described
/// [here](../Aql/GraphOperations.html#the_complexity_of_the_shortest_path_algorithms).
///
/// *Parameter*
///
/// * *options* (optional): An object defining further options. Can have the following values:
@ -4206,6 +4253,7 @@ exports._create = _create;
exports._drop = _drop;
exports._exists = _exists;
exports._list = _list;
exports._listObjects = _listObjects;
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE

View File

@ -314,27 +314,31 @@ SimpleQuery.prototype.clone = function () {
////////////////////////////////////////////////////////////////////////////////
/// @brief executes a query
/// @startDocuBlock queryExecute
/// `query.execute(batchSize)`
///
/// @FUN{@FA{query}.execute(@FA{batchSize})}
/// Executes a simple query. If the optional batchSize value is specified,
/// the server will return at most batchSize values in one roundtrip.
/// The batchSize cannot be adjusted after the query is first executed.
///
/// Executes a simple query. If the optional @FA{batchSize} value is specified,
/// the server will return at most @FN{batchSize} values in one roundtrip.
/// The @FA{batchSize} cannot be adjusted after the query is first executed.
///
/// Note that there is no need to explicitly call the execute method if another
/// **Note**: There is no need to explicitly call the execute method if another
/// means of fetching the query results is chosen. The following two approaches
/// lead to the same result:
/// @code
///
/// @EXAMPLE_ARANGOSH_OUTPUT{executeQuery}
/// result = db.users.all().toArray();
/// q = db.users.all(); q.execute(); result = [ ]; while (q.hasNext()) { result.push(q.next()); }
/// @endcode
/// @END_EXAMPLE_ARANGOSH_OUTPUT
///
/// The following two alternatives both use a @FA{batchSize} and return the same
/// The following two alternatives both use a batchSize and return the same
/// result:
/// @code
///
/// @EXAMPLE_ARANGOSH_OUTPUT{executeQueryBatchSize}
/// q = db.users.all(); q.setBatchSize(20); q.execute(); while (q.hasNext()) { print(q.next()); }
/// q = db.users.all(); q.execute(20); while (q.hasNext()) { print(q.next()); }
/// @endcode
/// @END_EXAMPLE_ARANGOSH_OUTPUT
///
/// @endDocuBlock
////////////////////////////////////////////////////////////////////////////////
SimpleQuery.prototype.execute = function () {
@ -356,19 +360,21 @@ SimpleQuery.prototype.execute = function () {
////////////////////////////////////////////////////////////////////////////////
/// @brief limit
/// @startDocuBlock queryLimit
/// `query.limit(number)`
///
/// @FUN{@FA{query}.limit(@FA{number})}
///
/// Limits a result to the first @FA{number} documents. Specifying a limit of
/// @LIT{0} returns no documents at all. If you do not need a limit, just do
/// Limits a result to the first *number* documents. Specifying a limit of
/// *0* returns no documents at all. If you do not need a limit, just do
/// not add the limit operator. The limit must be non-negative.
///
/// In general the input to @FN{limit} should be sorted. Otherwise it will be
/// In general the input to *limit* should be sorted. Otherwise it will be
/// unclear which documents are used in the result set.
///
/// *Examples*
/// @EXAMPLES
///
/// @verbinclude simple2
///
/// @endDocuBlock
////////////////////////////////////////////////////////////////////////////////
SimpleQuery.prototype.limit = function (limit) {
@ -388,20 +394,22 @@ SimpleQuery.prototype.limit = function (limit) {
////////////////////////////////////////////////////////////////////////////////
/// @brief skip
/// @startDocuBlock queySkip
/// `query.skip(number)`
///
/// @FUN{@FA{query}.skip(@FA{number})}
///
/// Skips the first @FA{number} documents. If @FA{number} is positive, then skip
/// the number of documents. If @FA{number} is negative, then the total amount N
/// Skips the first *number* documents. If *number* is positive, then skip
/// the number of documents. If *number* is negative, then the total amount N
/// of documents must be known and the results starts at position (N +
/// @FA{number}).
/// *number*).
///
/// In general the input to @FN{limit} should be sorted. Otherwise it will be
/// In general the input to *limit* should be sorted. Otherwise it will be
/// unclear which documents are used in the result set.
///
/// *Examples*
/// @EXAMPLES
///
/// @verbinclude simple8
///
/// @endDocuBlock
////////////////////////////////////////////////////////////////////////////////
SimpleQuery.prototype.skip = function (skip) {
@ -460,11 +468,12 @@ SimpleQuery.prototype.toArray = function () {
////////////////////////////////////////////////////////////////////////////////
/// @brief returns the batch size
///
/// @FUN{@FA{cursor}.getBatchSize()}
/// @startDocuBlock cursorGetBatchSize
/// `cursor.getBatchSize()`
///
/// Returns the batch size for queries. If the returned value is undefined, the
/// server will determine a sensible batch size for any following requests.
/// @endDocuBlock
////////////////////////////////////////////////////////////////////////////////
SimpleQuery.prototype.getBatchSize = function () {
@ -473,11 +482,12 @@ SimpleQuery.prototype.getBatchSize = function () {
////////////////////////////////////////////////////////////////////////////////
/// @brief sets the batch size for any following requests
///
/// @FUN{@FA{cursor}.setBatchSize(@FA{number})}
/// @startDocuBlock cursorSetBatchSize
/// `cursor.setBatchSize(number)`
///
/// Sets the batch size for queries. The batch size determines how many results
/// are at most transferred from the server to the client in one chunk.
/// @endDocuBlock
////////////////////////////////////////////////////////////////////////////////
SimpleQuery.prototype.setBatchSize = function (value) {
@ -488,27 +498,27 @@ SimpleQuery.prototype.setBatchSize = function (value) {
////////////////////////////////////////////////////////////////////////////////
/// @brief counts the number of documents
/// @startDocuBlock cursorCount
/// `cursor.count()`
///
/// @FUN{@FA{cursor}.count()}
///
/// The @FN{count} operator counts the number of document in the result set and
/// returns that number. The @FN{count} operator ignores any limits and returns
/// The *count* operator counts the number of document in the result set and
/// returns that number. The *count* operator ignores any limits and returns
/// the total number of documents found.
///
/// @note Not all simple queries support counting. In this case @LIT{null} is
/// **Note**: Not all simple queries support counting. In this case *null* is
/// returned.
///
/// @FUN{@FA{cursor}.count(@LIT{true})}
/// `cursor.count(true)`
///
/// If the result set was limited by the @FN{limit} operator or documents were
/// skiped using the @FN{skip} operator, the @FN{count} operator with argument
/// @LIT{true} will use the number of elements in the final result set - after
/// applying @FN{limit} and @FN{skip}.
/// If the result set was limited by the *limit* operator or documents were
/// skiped using the *skip* operator, the *count* operator with argument
/// *true* will use the number of elements in the final result set - after
/// applying *limit* and *skip*.
///
/// @note Not all simple queries support counting. In this case @LIT{null} is
/// **Note**: Not all simple queries support counting. In this case *null* is
/// returned.
///
/// *Examples*
/// @EXAMPLES
///
/// Ignore any limit:
///
@ -517,6 +527,8 @@ SimpleQuery.prototype.setBatchSize = function (value) {
/// Counting any limit or skip:
///
/// @verbinclude simple10
///
/// @endDocuBlock
////////////////////////////////////////////////////////////////////////////////
SimpleQuery.prototype.count = function (applyPagination) {
@ -531,16 +543,17 @@ SimpleQuery.prototype.count = function (applyPagination) {
////////////////////////////////////////////////////////////////////////////////
/// @brief checks if the cursor is exhausted
/// @startDocuBlock cursorHasNext
/// `cursor.hasNext()`
///
/// @FUN{@FA{cursor}.hasNext()}
/// The *hasNext* operator returns *true*, then the cursor still has
/// documents. In this case the next document can be accessed using the
/// *next* operator, which will advance the cursor.
///
/// The @FN{hasNext} operator returns @LIT{true}, then the cursor still has
/// documents. In this case the next document can be accessed using the
/// @FN{next} operator, which will advance the cursor.
///
/// *Examples*
/// @EXAMPLES
///
/// @verbinclude simple7
/// @endDocuBlock
////////////////////////////////////////////////////////////////////////////////
SimpleQuery.prototype.hasNext = function () {
@ -551,18 +564,19 @@ SimpleQuery.prototype.hasNext = function () {
////////////////////////////////////////////////////////////////////////////////
/// @brief returns the next result document
/// @startDocuBlock cursorNext
/// `cursor.next()`
///
/// @FUN{@FA{cursor}.next()}
///
/// If the @FN{hasNext} operator returns @LIT{true}, then the underlying
/// If the *hasNext* operator returns *true*, then the underlying
/// cursor of the simple query still has documents. In this case the
/// next document can be accessed using the @FN{next} operator, which
/// will advance the underlying cursor. If you use @FN{next} on an
/// exhausted cursor, then @LIT{undefined} is returned.
/// next document can be accessed using the *next* operator, which
/// will advance the underlying cursor. If you use *next* on an
/// exhausted cursor, then *undefined* is returned.
///
/// *Examples*
/// @EXAMPLES
///
/// @verbinclude simple5
/// @endDocuBlock
////////////////////////////////////////////////////////////////////////////////
SimpleQuery.prototype.next = function () {
@ -573,12 +587,13 @@ SimpleQuery.prototype.next = function () {
////////////////////////////////////////////////////////////////////////////////
/// @brief disposes the result
///
/// @FUN{@FA{cursor}.dispose()}
/// @startDocuBlock cursorDispose
/// `cursor.dispose()`
///
/// If you are no longer interested in any further results, you should call
/// @FN{dispose} in order to free any resources associated with the cursor.
/// After calling @FN{dispose} you can no longer access the cursor.
/// *dispose* in order to free any resources associated with the cursor.
/// After calling *dispose* you can no longer access the cursor.
/// @endDocuBlock
////////////////////////////////////////////////////////////////////////////////
SimpleQuery.prototype.dispose = function() {

View File

@ -223,6 +223,11 @@ namespace triagens {
return 0;
}
static TRI_shape_aid_t FailureFunction (TRI_shaper_t*, char const*, bool) {
TRI_ASSERT(false);
return 0;
}
static TRI_shape_t const* FailureFunction (TRI_shaper_t*, TRI_shape_t*, bool) {
TRI_ASSERT(false);
return 0;
@ -238,7 +243,7 @@ namespace triagens {
return 0;
}
static TRI_shape_pid_t FailureFunction2 (TRI_shaper_t*, char const*, bool) {
static TRI_shape_pid_t FailureFunction2 (TRI_shaper_t*, char const*, bool, bool) {
TRI_ASSERT(false);
return 0;
}

View File

@ -128,7 +128,7 @@ static bool EqualPidKeyAttributePath (TRI_associative_synced_t* array, void cons
/// @brief looks up an attribute path by identifier
////////////////////////////////////////////////////////////////////////////////
static TRI_shape_path_t const* LookupPidAttributePath (TRI_shaper_t* shaper, TRI_shape_pid_t pid) {
static TRI_shape_path_t const* LookupAttributePathByPid (TRI_shaper_t* shaper, TRI_shape_pid_t pid) {
return static_cast<TRI_shape_path_t const*>(TRI_LookupByKeyAssociativeSynced(&shaper->_attributePathsByPid, &pid));
}
@ -182,7 +182,8 @@ static bool EqualNameKeyAttributePath (TRI_associative_synced_t* array, void con
static TRI_shape_path_t const* FindShapePathByName (TRI_shaper_t* shaper,
char const* name,
bool create,
bool isLocked) {
bool isLocked,
bool isTemporary) {
TRI_shape_aid_t* aids;
TRI_shape_path_t* result;
size_t count;
@ -245,7 +246,7 @@ static TRI_shape_path_t const* FindShapePathByName (TRI_shaper_t* shaper,
if (ptr != prev) {
if (create) {
aids[count++] = shaper->findOrCreateAttributeByName(shaper, prev);
aids[count++] = shaper->findOrCreateAttributeByName(shaper, prev, isTemporary);
}
else {
aids[count] = shaper->lookupAttributeByName(shaper, prev);
@ -304,8 +305,11 @@ static TRI_shape_path_t const* FindShapePathByName (TRI_shaper_t* shaper,
static TRI_shape_pid_t FindOrCreateAttributePathByName (TRI_shaper_t* shaper,
char const* name,
bool isLocked) {
TRI_shape_path_t const* path = FindShapePathByName(shaper, name, true, isLocked);
bool isLocked,
bool isTemporary) {
// TODO: is isTemporary always true?
TRI_shape_path_t const* path = FindShapePathByName(shaper, name, true, isLocked, isTemporary);
return path == nullptr ? 0 : path->_pid;
}
@ -316,7 +320,9 @@ static TRI_shape_pid_t FindOrCreateAttributePathByName (TRI_shaper_t* shaper,
static TRI_shape_pid_t LookupAttributePathByName (TRI_shaper_t* shaper,
char const* name) {
TRI_shape_path_t const* path = FindShapePathByName(shaper, name, false, true);
// do not create an unknown attribute (therefore isTemporary will be ignored)
TRI_shape_path_t const* path = FindShapePathByName(shaper, name, false, true, false);
return path == nullptr ? 0 : path->_pid;
}
@ -385,7 +391,7 @@ int TRI_InitShaper (TRI_shaper_t* shaper, TRI_memory_zone_t* zone) {
shaper->_nextPid = 1;
shaper->lookupAttributePathByPid = LookupPidAttributePath;
shaper->lookupAttributePathByPid = LookupAttributePathByPid;
shaper->findOrCreateAttributePathByName = FindOrCreateAttributePathByName;
shaper->lookupAttributePathByName = LookupAttributePathByName;

View File

@ -92,14 +92,14 @@ TRI_basic_shapes_t;
////////////////////////////////////////////////////////////////////////////////
typedef struct TRI_shaper_s {
TRI_shape_aid_t (*findOrCreateAttributeByName) (struct TRI_shaper_s*, char const*);
TRI_shape_aid_t (*findOrCreateAttributeByName) (struct TRI_shaper_s*, char const*, bool);
TRI_shape_aid_t (*lookupAttributeByName) (struct TRI_shaper_s*, char const*);
char const* (*lookupAttributeId) (struct TRI_shaper_s*, TRI_shape_aid_t);
TRI_shape_t const* (*findShape) (struct TRI_shaper_s*, TRI_shape_t*, bool);
TRI_shape_t const* (*lookupShapeId) (struct TRI_shaper_s*, TRI_shape_sid_t);
int64_t (*lookupAttributeWeight) (struct TRI_shaper_s*, TRI_shape_aid_t);
TRI_shape_path_t const* (*lookupAttributePathByPid) (struct TRI_shaper_s*, TRI_shape_pid_t);
TRI_shape_pid_t (*findOrCreateAttributePathByName) (struct TRI_shaper_s*, char const*, bool);
TRI_shape_pid_t (*findOrCreateAttributePathByName) (struct TRI_shaper_s*, char const*, bool, bool);
TRI_shape_pid_t (*lookupAttributePathByName) (struct TRI_shaper_s*, char const*);
TRI_associative_synced_t _attributePathsByName;

View File

@ -834,7 +834,7 @@ static bool FillShapeValueArray (TRI_shaper_t* shaper,
}
// first find an identifier for the name
p->_aid = shaper->findOrCreateAttributeByName(shaper, key->_value._string.data);
p->_aid = shaper->findOrCreateAttributeByName(shaper, key->_value._string.data, false);
// convert value
if (p->_aid == 0) {

View File

@ -634,7 +634,7 @@ static int FillShapeValueArray (TRI_shaper_t* shaper,
}
if (create) {
p->_aid = shaper->findOrCreateAttributeByName(shaper, *keyStr);
p->_aid = shaper->findOrCreateAttributeByName(shaper, *keyStr, false);
}
else {
p->_aid = shaper->lookupAttributeByName(shaper, *keyStr);

View File

@ -136,6 +136,7 @@ AM_PROG_CC_C_O
AC_PROG_INSTALL
AC_PROG_LN_S
AC_PROG_MAKE_SET
AX_CXX_COMPILE_STDCXX_11(noext, mandatory)
AC_ARG_ENABLE(error-on-warning,