From d8bb698030f58b35e395dac751c403fe8e70f342 Mon Sep 17 00:00:00 2001 From: Frank Celler Date: Sun, 15 Apr 2012 00:02:08 +0200 Subject: [PATCH] added isSystem, cleanup of graph module --- .gitignore | 4 + RestServer/rest-edge.dox | 20 +++ V8/v8-vocbase.cpp | 6 +- VocBase/collection.c | 3 +- VocBase/collection.h | 2 + VocBase/query-parse.c | 6 +- VocBase/vocbase.c | 14 ++- VocBase/vocbase.h | 2 +- js/common/modules/graph.js | 247 +++++++++++++------------------------ 9 files changed, 133 insertions(+), 171 deletions(-) diff --git a/.gitignore b/.gitignore index c063c83c76..d76d240f38 100644 --- a/.gitignore +++ b/.gitignore @@ -74,3 +74,7 @@ Makefile.local *.gcno *.gcda COVERAGE +3rdParty/ptmalloc3/libptmalloc3.a +3rdParty/ptmalloc3/t-test1 +3rdParty/ptmalloc3/t-test2 +3rdParty/ptmalloc3/tst-independent-alloc diff --git a/RestServer/rest-edge.dox b/RestServer/rest-edge.dox index d37401c568..d05a03aa3a 100644 --- a/RestServer/rest-edge.dox +++ b/RestServer/rest-edge.dox @@ -55,6 +55,26 @@ /// /// This is an introduction to AvocadoDB's REST interface for edges. /// +/// AvocacadoDB offers also some graph functionality. A graph consists of nodes, +/// edges and properties. AvocadoDB stores the information how the nodes relate +/// to each other aside from the properties. +/// +/// So a graph data model always consists of two collections: the relations +/// between the nodes in the graphs are stored in an "edges collection", the +/// nodes in the graph are stored in documents in regular collections. +/// +/// Example: +/// - the edge collection stores the information that a company's reception is +/// sub-unit to the services unit and the services unit is sub-unit to the +/// CEO. You would express this relationship with the @LIT{_from} and +/// @LIT{_to} property +/// +/// - the "normal" collection stores all the properties about the reception, +/// e.g. that 20 people are working there and the room number etc. +/// +/// @LIT{_from} is the document handle of the linked vertex (incoming relation), +/// @LIT{_to} is the document handle of the linked vertex (outgoing relation). +/// ///
/// @copydoc RestEdgeTOC ///
diff --git a/V8/v8-vocbase.cpp b/V8/v8-vocbase.cpp index df03073479..38cfe83005 100644 --- a/V8/v8-vocbase.cpp +++ b/V8/v8-vocbase.cpp @@ -918,6 +918,7 @@ static v8::Handle CreateVocBase (v8::Arguments const& argv, bool edge v8::Handle p = argv[1]->ToObject(); v8::Handle waitForSyncKey = v8::String::New("waitForSync"); v8::Handle journalSizeKey = v8::String::New("journalSize"); + v8::Handle isSystemKey = v8::String::New("isSystem"); if (p->Has(journalSizeKey)) { double s = TRI_ObjectToDouble(p->Get(journalSizeKey)); @@ -938,6 +939,9 @@ static v8::Handle CreateVocBase (v8::Arguments const& argv, bool edge parameter._waitForSync = TRI_ObjectToBoolean(p->Get(waitForSyncKey)); } + if (p->Has(isSystemKey)) { + parameter._isSystem = TRI_ObjectToBoolean(p->Get(isSystemKey)); + } } else { TRI_InitParameterCollection(¶meter, name.c_str(), vocbase->_defaultMaximalSize); @@ -1810,7 +1814,7 @@ static v8::Handle JS_WithinQuery (v8::Arguments const& argv) { return scope.Close(v8::ThrowException(CreateErrorObject(TRI_ERROR_INTERNAL, "unknown collection type"))); } - // expect: NEAR(, , , ) + // expect: WITHIN(, , , ) if (argv.Length() != 4) { ReleaseCollection(collection); return scope.Close(v8::ThrowException( diff --git a/VocBase/collection.c b/VocBase/collection.c index 6a6eb1fe35..9c06de3b20 100644 --- a/VocBase/collection.c +++ b/VocBase/collection.c @@ -367,9 +367,10 @@ void TRI_InitParameterCollection (TRI_col_parameter_t* parameter, parameter->_type = TRI_COL_TYPE_SIMPLE_DOCUMENT; parameter->_waitForSync = false; - parameter->_maximalSize = (maximalSize / PageSize) * PageSize; + parameter->_isSystem = false; + if (parameter->_maximalSize == 0 && maximalSize != 0) { parameter->_maximalSize = PageSize; } diff --git a/VocBase/collection.h b/VocBase/collection.h index 2c7935297d..e47c4e927e 100644 --- a/VocBase/collection.h +++ b/VocBase/collection.h @@ -162,6 +162,8 @@ typedef struct TRI_col_parameter_s { TRI_voc_size_t _maximalSize; // maximal size of memory mapped file bool _waitForSync; // if true, wait for msync + + bool _isSystem; // if true, this is a system collection } TRI_col_parameter_t; diff --git a/VocBase/query-parse.c b/VocBase/query-parse.c index da87140fad..b36bfb05f7 100644 --- a/VocBase/query-parse.c +++ b/VocBase/query-parse.c @@ -316,7 +316,11 @@ void TRI_ParseQueryPopIntoRhs (TRI_query_node_t* node, //////////////////////////////////////////////////////////////////////////////// bool TRI_ParseQueryValidateCollectionName (const char* name) { - if (TRI_IsAllowedCollectionName(name) != 0) { + TRI_col_parameter_t parameter; + + parameter._isSystem = true; + + if (TRI_IsAllowedCollectionName(¶meter, name) != 0) { return false; } diff --git a/VocBase/vocbase.c b/VocBase/vocbase.c index fec208dac8..954dca383f 100644 --- a/VocBase/vocbase.c +++ b/VocBase/vocbase.c @@ -571,6 +571,7 @@ static int ScanPath (TRI_vocbase_t* vocbase, char const* path) { static TRI_vocbase_col_t* BearCollectionVocBase (TRI_vocbase_t* vocbase, char const* name) { union { void const* v; TRI_vocbase_col_t* c; } found; TRI_vocbase_col_t* collection; + TRI_col_parameter_t parameter; char wrong; TRI_WRITE_LOCK_COLLECTIONS_VOCBASE(vocbase); @@ -598,7 +599,8 @@ static TRI_vocbase_col_t* BearCollectionVocBase (TRI_vocbase_t* vocbase, char co } // check that the name does not contain any strange characters - wrong = TRI_IsAllowedCollectionName(name); + parameter._isSystem = false; + wrong = TRI_IsAllowedCollectionName(¶meter, name); if (wrong != 0) { TRI_WRITE_UNLOCK_COLLECTIONS_VOCBASE(vocbase); @@ -866,12 +868,12 @@ size_t PageSize; /// Returns 0 for success or the offending character. //////////////////////////////////////////////////////////////////////////////// -char TRI_IsAllowedCollectionName (char const* name) { +char TRI_IsAllowedCollectionName (TRI_col_parameter_t* paramater, char const* name) { bool ok; char const* ptr; for (ptr = name; *ptr; ++ptr) { - if (name < ptr) { + if (name < ptr || paramater->_isSystem) { ok = (*ptr == '_') || (*ptr == '-') || ('0' <= *ptr && *ptr <= '9') || ('a' <= *ptr && *ptr <= 'z') || ('A' <= *ptr && *ptr <= 'Z'); } else { @@ -1248,7 +1250,7 @@ TRI_vocbase_col_t* TRI_CreateCollectionVocBase (TRI_vocbase_t* vocbase, TRI_col_ } // check that the name does not contain any strange characters - wrong = TRI_IsAllowedCollectionName(name); + wrong = TRI_IsAllowedCollectionName(parameter, name); if (wrong != 0) { TRI_WRITE_UNLOCK_COLLECTIONS_VOCBASE(vocbase); @@ -1484,6 +1486,7 @@ int TRI_DropCollectionVocBase (TRI_vocbase_t* vocbase, TRI_vocbase_col_t* collec int TRI_RenameCollectionVocBase (TRI_vocbase_t* vocbase, TRI_vocbase_col_t* collection, char const* newName) { union { TRI_vocbase_col_t* v; TRI_vocbase_col_t const* c; } cnv; TRI_col_info_t info; + TRI_col_parameter_t parameter; void const* found; char wrong; char const* oldName; @@ -1501,7 +1504,8 @@ int TRI_RenameCollectionVocBase (TRI_vocbase_t* vocbase, TRI_vocbase_col_t* coll return TRI_set_errno(TRI_ERROR_AVOCADO_ILLEGAL_NAME); } - wrong = TRI_IsAllowedCollectionName(newName); + parameter._isSystem = (*oldName == '_'); + wrong = TRI_IsAllowedCollectionName(¶meter, newName); if (wrong != 0) { LOG_DEBUG("found illegal character in name: %c", wrong); diff --git a/VocBase/vocbase.h b/VocBase/vocbase.h index f0b4d6dd78..8e969890cd 100644 --- a/VocBase/vocbase.h +++ b/VocBase/vocbase.h @@ -345,7 +345,7 @@ TRI_vocbase_col_t; /// @brief checks if a collection is allowed //////////////////////////////////////////////////////////////////////////////// -char TRI_IsAllowedCollectionName (char const*); +char TRI_IsAllowedCollectionName (struct TRI_col_parameter_s*, char const*); //////////////////////////////////////////////////////////////////////////////// /// @brief create a new tick diff --git a/js/common/modules/graph.js b/js/common/modules/graph.js index 280f9e4959..2785daa4ea 100644 --- a/js/common/modules/graph.js +++ b/js/common/modules/graph.js @@ -5,7 +5,7 @@ /// /// DISCLAIMER /// -/// Copyright 2010-2011 triagens GmbH, Cologne, Germany +/// Copyright 2010-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. @@ -22,7 +22,7 @@ /// Copyright holder is triAGENS GmbH, Cologne, Germany /// /// @author Dr. Frank Celler -/// @author Copyright 2011, triAGENS GmbH, Cologne, Germany +/// @author Copyright 2011-2012, triAGENS GmbH, Cologne, Germany //////////////////////////////////////////////////////////////////////////////// var internal = require("internal"); @@ -32,7 +32,7 @@ var AvocadoCollection = internal.AvocadoCollection; var AvocadoEdgesCollection = internal.AvocadoEdgesCollection; // ----------------------------------------------------------------------------- -// --SECTION-- EDGE +// --SECTION-- Edge // ----------------------------------------------------------------------------- // ----------------------------------------------------------------------------- @@ -58,15 +58,12 @@ function Edge (graph, id) { // extract the custom identifier, label, edges if (props) { - this._eid = props.$eid; - this._label = props.$label; - this._from = props._from; - this._to = props._to; + this._properties = props; } // deleted else { - this._id = undefined; + throw "accessing a deleted edge"; } } @@ -95,8 +92,8 @@ function Edge (graph, id) { /// @verbinclude graph13 //////////////////////////////////////////////////////////////////////////////// -Edge.prototype.getId = function (name) { - return this._eid; +Edge.prototype.getId = function () { + return this._properties.$id; } //////////////////////////////////////////////////////////////////////////////// @@ -112,11 +109,7 @@ Edge.prototype.getId = function (name) { //////////////////////////////////////////////////////////////////////////////// Edge.prototype.getInVertex = function () { - if (! this._id) { - throw "accessing a deleted edge"; - } - - return this._graph.constructVertex(this._to); + return this._graph.constructVertex(this._properties._to); } //////////////////////////////////////////////////////////////////////////////// @@ -132,11 +125,7 @@ Edge.prototype.getInVertex = function () { //////////////////////////////////////////////////////////////////////////////// Edge.prototype.getLabel = function () { - if (! this._id) { - throw "accessing a deleted edge"; - } - - return this._label; + return this._properties.$label; } //////////////////////////////////////////////////////////////////////////////// @@ -152,11 +141,7 @@ Edge.prototype.getLabel = function () { //////////////////////////////////////////////////////////////////////////////// Edge.prototype.getOutVertex = function () { - if (! this._id) { - throw "accessing a deleted edge"; - } - - return this._graph.constructVertex(this._from); + return this._graph.constructVertex(this._properties._from); } //////////////////////////////////////////////////////////////////////////////// @@ -172,11 +157,7 @@ Edge.prototype.getOutVertex = function () { //////////////////////////////////////////////////////////////////////////////// Edge.prototype.getProperty = function (name) { - if (! this._id) { - throw "accessing a deleted edge"; - } - - return this.properties()[name]; + return this._properties[name]; } //////////////////////////////////////////////////////////////////////////////// @@ -192,11 +173,7 @@ Edge.prototype.getProperty = function (name) { //////////////////////////////////////////////////////////////////////////////// Edge.prototype.getPropertyKeys = function () { - if (! this._id) { - throw "accessing a deleted edge"; - } - - return propertyKeys(this.properties()); + return propertyKeys(this._properties); } //////////////////////////////////////////////////////////////////////////////// @@ -212,27 +189,14 @@ Edge.prototype.getPropertyKeys = function () { //////////////////////////////////////////////////////////////////////////////// Edge.prototype.setProperty = function (name, value) { - var props; - var shallow; + var shallow = shallowCopy(this._properties); + shallow[name] = value; - if (! this._id) { - throw "accessing a deleted edge"; - } + // TODO use "update" if this becomes available + var id = this._graph._edges.replace(this._properties, shallow); + this._properties = this._graph._edges.document(id); - props = this._graph._edges.document(this._id); // TODO use "update" - - if (props !== undefined) { - shallow = shallowCopy(props); - - shallow[name] = value; - - this._graph._edges.replace(this._id, shallow); - - return value; - } - else { - return undefined; - } + return value; } //////////////////////////////////////////////////////////////////////////////// @@ -248,20 +212,17 @@ Edge.prototype.setProperty = function (name, value) { //////////////////////////////////////////////////////////////////////////////// Edge.prototype.properties = function () { - var result; + var shallow = shallowCopy(this._properties); - if (! this._id) { - throw "accessing a deleted edge"; - } + delete shallow.$id; + delete shallow.$label; - props = this._graph._edges.document(this._id); + delete shallow._id; + delete shallow._rev; + delete shallow._from; + delete shallow._to; - if (! props) { - this._id = undefined; - throw "accessing a deleted edge"; - } - - return shallowCopy(props); + return shallow; } //////////////////////////////////////////////////////////////////////////////// @@ -285,16 +246,16 @@ Edge.prototype._PRINT = function (seen, path, names) { if (! this._id) { internal.output("[deleted Edge]"); } - else if (this._eid !== undefined) { - if (typeof this._eid === "string") { - internal.output("Edge(\"", this._eid, "\")"); + else if (this._properties.$id !== undefined) { + if (typeof this._properties.$id === "string") { + internal.output("Edge(\"", this._properties.$id, "\")"); } else { - internal.output("Edge(", this._eid, ")"); + internal.output("Edge(", this._properties.$id, ")"); } } else { - internal.output("Edge(\"", this._id, "\")"); + internal.output("Edge(<", this._id, ">)"); } } @@ -329,12 +290,12 @@ function Vertex (graph, id) { // extract the custom identifier if (props) { - this._vid = props.$vid; + this._properties = props; } // deleted else { - this._id = undefined; + throw "accessing a deleted edge"; } } @@ -379,10 +340,6 @@ function Vertex (graph, id) { //////////////////////////////////////////////////////////////////////////////// Vertex.prototype.addInEdge = function (id, out, label, data) { - if (! this._id) { - throw "accessing a deleted vertex"; - } - return this._graph.addEdge(id, out, this, label, data); } @@ -414,10 +371,6 @@ Vertex.prototype.addInEdge = function (id, out, label, data) { //////////////////////////////////////////////////////////////////////////////// Vertex.prototype.addOutEdge = function (id, ine, label, data) { - if (! this._id) { - throw "accessing a deleted vertex"; - } - return this._graph.addEdge(id, this, ine, label, data); } @@ -438,10 +391,6 @@ Vertex.prototype.edges = function () { var result; var graph; - if (! this._id) { - throw "accessing a deleted vertex"; - } - graph = this._graph; query = graph._edges.edges(this._id); @@ -468,7 +417,7 @@ Vertex.prototype.edges = function () { //////////////////////////////////////////////////////////////////////////////// Vertex.prototype.getId = function (name) { - return this._vid; + return this._properties.$id; } //////////////////////////////////////////////////////////////////////////////// @@ -489,10 +438,6 @@ Vertex.prototype.getInEdges = function () { var result; var edge; - if (! this._id) { - throw "accessing a deleted vertex"; - } - if (arguments.length == 0) { return this.inbound(); } @@ -534,10 +479,6 @@ Vertex.prototype.getOutEdges = function () { var result; var edge; - if (! this._id) { - throw "accessing a deleted vertex"; - } - if (arguments.length == 0) { return this.outbound(); } @@ -574,11 +515,7 @@ Vertex.prototype.getOutEdges = function () { //////////////////////////////////////////////////////////////////////////////// Vertex.prototype.getProperty = function (name) { - if (! this._id) { - throw "accessing a deleted vertex"; - } - - return this.properties()[name]; + return this._properties[name]; } //////////////////////////////////////////////////////////////////////////////// @@ -594,11 +531,7 @@ Vertex.prototype.getProperty = function (name) { //////////////////////////////////////////////////////////////////////////////// Vertex.prototype.getPropertyKeys = function () { - if (! this._id) { - throw "accessing a deleted vertex"; - } - - return propertyKeys(this.properties()); + return propertyKeys(this._properties); } //////////////////////////////////////////////////////////////////////////////// @@ -618,10 +551,6 @@ Vertex.prototype.inbound = function () { var result; var graph; - if (! this._id) { - throw "accessing a deleted vertex"; - } - graph = this._graph; query = graph._edges.inEdges(this._id); @@ -651,10 +580,6 @@ Vertex.prototype.outbound = function () { var result; var graph; - if (! this._id) { - throw "accessing a deleted vertex"; - } - graph = this._graph; query = graph._edges.outEdges(this._id); @@ -680,21 +605,14 @@ Vertex.prototype.outbound = function () { //////////////////////////////////////////////////////////////////////////////// Vertex.prototype.properties = function () { - var props; - var result; + var shallow = shallowCopy(this._properties); - if (! this._id) { - throw "accessing a deleted vertex"; - } + delete shallow.$id; - props = this._graph._vertices.document(this._id); + delete shallow._id; + delete shallow._rev; - if (! props) { - this._id = undefined; - throw "accessing a deleted vertex"; - } - - return shallowCopy(props); + return shallow; } //////////////////////////////////////////////////////////////////////////////// @@ -710,29 +628,14 @@ Vertex.prototype.properties = function () { //////////////////////////////////////////////////////////////////////////////// Vertex.prototype.setProperty = function (name, value) { - var props; - var shallow; + var shallow = shallowCopy(this._properties); + shallow[name] = value; - if (! this._id) { - throw "accessing a deleted vertex"; - } + // TODO use "update" if this becomes available + var id = this._graph._vertices.replace(this._id, shallow); + this._properties = this._graph._vertices.document(id); - delete this._properties; - - props = this._graph._vertices.document(this._id); // TODO use "update" - - if (props !== undefined) { - shallow = shallowCopy(props); - - shallow[name] = value; - - this._graph._vertices.replace(this._id, shallow); - - return value; - } - else { - return undefined; - } + return value; } //////////////////////////////////////////////////////////////////////////////// @@ -756,16 +659,16 @@ Vertex.prototype._PRINT = function (seen, path, names) { if (! this._id) { internal.output("[deleted Vertex]"); } - else if (this._vid !== undefined) { - if (typeof this._vid === "string") { - internal.output("Vertex(\"", this._vid, "\")"); + else if (this._properties.$id !== undefined) { + if (typeof this._properties.$id === "string") { + internal.output("Vertex(\"", this._properties.$id, "\")"); } else { - internal.output("Vertex(", this._vid, ")"); + internal.output("Vertex(", this._properties.$id, ")"); } } else { - internal.output("Vertex(\"", this._id, "\")"); + internal.output("Vertex(<", this._id, ">)"); } } @@ -801,27 +704,47 @@ Vertex.prototype._PRINT = function (seen, path, names) { /// @verbinclude graph1 //////////////////////////////////////////////////////////////////////////////// -function Graph (vertices, edg) { +function Graph (vertices, edge) { + + + // get the vertices collection if (typeof vertices === "string") { - vertices = db[vertices]; - vertices.ensureUniqueConstraint("$vid"); + var col = db._collection(vertices); + + if (col == null) { + col = db._create(vertices); + } + + col.ensureUniqueConstraint("$id"); + + vertices = col; } if (! vertices instanceof AvocadoCollection) { throw " must be a document collection"; } - if (typeof edg === "string") { - edg = edges[edg]; - edg.ensureUniqueConstraint("$eid"); + // get the edges collection + if (typeof edge === "string") { + var col = edges._collection(edge); + + if (col == null) { + col = db._create(edge); + } + + col.ensureUniqueConstraint("$id"); + col.ensureUniqueConstraint("$label"); + + edge = col; } - if (! edg instanceof AvocadoEdgesCollection) { + if (! edge instanceof AvocadoEdgesCollection) { throw " must be an edges collection"; } + // and store the collections this._vertices = vertices; - this._edges = edg; + this._edges = edge; } //////////////////////////////////////////////////////////////////////////////// @@ -892,7 +815,7 @@ Graph.prototype.addEdge = function (id, out, ine, label, data) { shallow = shallowCopy(data); - shallow.$eid = id || null; + shallow.$id = id || null; shallow.$label = label || null; ref = this._edges.save(out._id, ine._id, shallow); @@ -934,7 +857,7 @@ Graph.prototype.addVertex = function (id, data) { shallow = shallowCopy(data); - shallow.$vid = id || null; + shallow.$id = id || null; ref = this._vertices.save(shallow); @@ -956,7 +879,7 @@ Graph.prototype.addVertex = function (id, data) { Graph.prototype.getVertex = function (id) { var ref; - ref = this._vertices.select({ $vid : id }); + ref = this._vertices.select({ $id : id }); if (ref.count() == 1) { return this.constructVertex(ref.next()._id); @@ -1076,7 +999,7 @@ Graph.prototype.removeVertex = function (vertex) { } edges = vertex.edges(); - result = this._vertices.delete(vertex._id); + result = this._vertices.delete(vertex._properties); if (! result) { throw "cannot delete vertex"; @@ -1108,7 +1031,7 @@ Graph.prototype.removeEdge = function (edge) { return; } - result = this._edges.delete(edge._id); + result = this._edges.delete(edge._properties); if (! result) { throw "cannot delete edge";