diff --git a/BasicsC/json.c b/BasicsC/json.c
index 592784afb0..f40cfe8ce7 100644
--- a/BasicsC/json.c
+++ b/BasicsC/json.c
@@ -100,7 +100,7 @@ static void StringifyJson (TRI_string_buffer_t* buffer, TRI_json_t const* object
}
StringifyJson(buffer, TRI_AtVector(&object->_value._objects, i), true);
- TRI_AppendStringStringBuffer(buffer, ":");
+ TRI_AppendCharStringBuffer(buffer, ':');
StringifyJson(buffer, TRI_AtVector(&object->_value._objects, i + 1), true);
}
diff --git a/Demos/Scripts/demo.js b/Demos/Scripts/demo.js
new file mode 100644
index 0000000000..3bd53a6a1c
--- /dev/null
+++ b/Demos/Scripts/demo.js
@@ -0,0 +1,19 @@
+#! avocsh
+
+var console = require("console");
+var name = "demo";
+
+var collection = db[name];
+
+collection.drop(name);
+
+collection.save({ hallo : "world" });
+
+collection.save({ world : "hallo" });
+
+collection.save({ name : "Hugo",
+ firstName : "Egon",
+ address : {
+ street : "Neue Strasse",
+ city : "Hier" },
+ hobbies : [ "swimming", "programming" ]});
diff --git a/Demos/Scripts/five.js b/Demos/Scripts/five.js
new file mode 100644
index 0000000000..0468aad68d
--- /dev/null
+++ b/Demos/Scripts/five.js
@@ -0,0 +1,16 @@
+#! avocsh
+
+var console = require("console");
+var name = "five";
+
+var collection = db[name];
+
+collection.drop(name);
+collection.ensureUniqueConstraint("a");
+collection.ensureUniqueConstraint("b");
+
+collection.save({ a : 1, b : "One" });
+collection.save({ a : 2, b : "Two" });
+collection.save({ a : 3, b : "Three" });
+collection.save({ a : 4, b : "Four" });
+collection.save({ a : 5, b : "Five" });
diff --git a/Demos/Scripts/geo.js b/Demos/Scripts/geo.js
new file mode 100644
index 0000000000..55fb9f34f0
--- /dev/null
+++ b/Demos/Scripts/geo.js
@@ -0,0 +1,22 @@
+#! avocsh
+
+var console = require("console");
+var name = "geo";
+
+var collection = db[name];
+
+collection.drop(name);
+
+db.geo.ensureGeoIndex("home");
+db.geo.ensureGeoIndex("work.l", "work.b");
+
+for (i = -90; i <= 90; i += 10) {
+ for (j = -180; j <= 180; j += 10) {
+ db.geo.save({
+ name : "Name/" + i + "/" + j,
+ home : [ i, j ],
+ work : { b : i, l : j }
+ });
+ }
+}
+
diff --git a/Doxygen/Examples.AvocadoDB/key-value_delete-key-bad b/Doxygen/Examples.AvocadoDB/key-value_delete-key-bad
new file mode 100644
index 0000000000..dd76583c16
--- /dev/null
+++ b/Doxygen/Examples.AvocadoDB/key-value_delete-key-bad
@@ -0,0 +1,4 @@
+ HTTP/1.1 404 Bad Request
+ ...
+
+ {"error":true,"code":404,"errorNum":41404,"errorMessage":"Key value pair not found"}
diff --git a/Doxygen/Examples.AvocadoDB/key-value_delete-key-ok b/Doxygen/Examples.AvocadoDB/key-value_delete-key-ok
new file mode 100644
index 0000000000..897d562daa
--- /dev/null
+++ b/Doxygen/Examples.AvocadoDB/key-value_delete-key-ok
@@ -0,0 +1,4 @@
+ HTTP/1.1 200 OK
+ ...
+
+ {"removed":true,"error":false,"code":202}
diff --git a/Doxygen/Examples.AvocadoDB/key-value_delete-key-request b/Doxygen/Examples.AvocadoDB/key-value_delete-key-request
new file mode 100644
index 0000000000..2b56fdf3ec
--- /dev/null
+++ b/Doxygen/Examples.AvocadoDB/key-value_delete-key-request
@@ -0,0 +1,2 @@
+ DELETE /_api/key/example_collection/example_key1 HTTP/1.1
+ Host: localhost:9000
diff --git a/Doxygen/Examples.AvocadoDB/key-value_get-key-bad b/Doxygen/Examples.AvocadoDB/key-value_get-key-bad
new file mode 100644
index 0000000000..e714b22472
--- /dev/null
+++ b/Doxygen/Examples.AvocadoDB/key-value_get-key-bad
@@ -0,0 +1,4 @@
+ HTTP/1.1 404 Bad Request
+ ...
+
+ {"error":true,"code":404,"errorNum":41404,"errorMessage":"Key value pair not found"}
diff --git a/Doxygen/Examples.AvocadoDB/key-value_get-key-ok b/Doxygen/Examples.AvocadoDB/key-value_get-key-ok
new file mode 100644
index 0000000000..aeeb6cbc58
--- /dev/null
+++ b/Doxygen/Examples.AvocadoDB/key-value_get-key-ok
@@ -0,0 +1,7 @@
+ HTTP/1.1 200 OK
+ x-voc-created: 2010-09-15T09:35:01Z
+ x-voc-expires: 2011-09-29T08:00:00Z
+ x-voc-extended: {"option1":35,"option2":"x"}
+ ...
+
+ 13
diff --git a/Doxygen/Examples.AvocadoDB/key-value_get-key-request b/Doxygen/Examples.AvocadoDB/key-value_get-key-request
new file mode 100644
index 0000000000..9872f8b706
--- /dev/null
+++ b/Doxygen/Examples.AvocadoDB/key-value_get-key-request
@@ -0,0 +1,2 @@
+ GET /_api/key/example_collection/example_key1 HTTP/1.1
+ Host: localhost:9000
diff --git a/Doxygen/Examples.AvocadoDB/key-value_get-keys-bad b/Doxygen/Examples.AvocadoDB/key-value_get-keys-bad
new file mode 100644
index 0000000000..6ee71f2ebd
--- /dev/null
+++ b/Doxygen/Examples.AvocadoDB/key-value_get-keys-bad
@@ -0,0 +1,4 @@
+ HTTP/1.1 404 Bad Request
+ ...
+
+ {"error":true,"code":404,"errorNum":41404,"errorMessage":"Collection not found"}
diff --git a/Doxygen/Examples.AvocadoDB/key-value_get-keys-ok b/Doxygen/Examples.AvocadoDB/key-value_get-keys-ok
new file mode 100644
index 0000000000..45f2e798f2
--- /dev/null
+++ b/Doxygen/Examples.AvocadoDB/key-value_get-keys-ok
@@ -0,0 +1,4 @@
+ HTTP/1.1 200 OK
+ ...
+
+ ["example_keyboard","example_keystone"]
diff --git a/Doxygen/Examples.AvocadoDB/key-value_get-keys-request b/Doxygen/Examples.AvocadoDB/key-value_get-keys-request
new file mode 100644
index 0000000000..af36ab66aa
--- /dev/null
+++ b/Doxygen/Examples.AvocadoDB/key-value_get-keys-request
@@ -0,0 +1,2 @@
+ GET /_api/keys/example_collection/example_key HTTP/1.1
+ Host: localhost:9000
diff --git a/Doxygen/Examples.AvocadoDB/key-value_post-key-bad b/Doxygen/Examples.AvocadoDB/key-value_post-key-bad
new file mode 100644
index 0000000000..d12a74f399
--- /dev/null
+++ b/Doxygen/Examples.AvocadoDB/key-value_post-key-bad
@@ -0,0 +1,7 @@
+ HTTP/1.1 404 Bad Request
+ content-type: application/json
+ connection: Keep-Alive
+ server: triagens GmbH High-Performance HTTP Server
+ content-length: 75
+
+ {"error":true,"code":404,"errorNum":41304,"errorMessage":"Use PUT to change value"}
diff --git a/Doxygen/Examples.AvocadoDB/key-value_post-key-ok b/Doxygen/Examples.AvocadoDB/key-value_post-key-ok
new file mode 100644
index 0000000000..7c8e52725e
--- /dev/null
+++ b/Doxygen/Examples.AvocadoDB/key-value_post-key-ok
@@ -0,0 +1,7 @@
+ HTTP/1.1 201 Created
+ connection: Keep-Alive
+ content-type: application/json
+ server: triagens GmbH High-Performance HTTP Server
+ content-length: 62
+
+ {"saved":true,"_id":"155630:9500735","error":false,"code":201}
diff --git a/Doxygen/Examples.AvocadoDB/key-value_post-key-request b/Doxygen/Examples.AvocadoDB/key-value_post-key-request
new file mode 100644
index 0000000000..ed51457e60
--- /dev/null
+++ b/Doxygen/Examples.AvocadoDB/key-value_post-key-request
@@ -0,0 +1,7 @@
+ POST /_api/key/example_collection/example_key1 HTTP/1.1
+ Host: localhost:9000
+ x-voc-expires: 2011-09-29T08:00:00Z
+ x-voc-extended: {"option1":35,"option2":"x"}
+ Content-Length: 2
+
+ 12
\ No newline at end of file
diff --git a/Doxygen/Examples.AvocadoDB/key-value_put-key-bad b/Doxygen/Examples.AvocadoDB/key-value_put-key-bad
new file mode 100644
index 0000000000..e714b22472
--- /dev/null
+++ b/Doxygen/Examples.AvocadoDB/key-value_put-key-bad
@@ -0,0 +1,4 @@
+ HTTP/1.1 404 Bad Request
+ ...
+
+ {"error":true,"code":404,"errorNum":41404,"errorMessage":"Key value pair not found"}
diff --git a/Doxygen/Examples.AvocadoDB/key-value_put-key-ok b/Doxygen/Examples.AvocadoDB/key-value_put-key-ok
new file mode 100644
index 0000000000..e1888156d9
--- /dev/null
+++ b/Doxygen/Examples.AvocadoDB/key-value_put-key-ok
@@ -0,0 +1,7 @@
+ HTTP/1.1 202 Accepted
+ connection: Keep-Alive
+ content-type: application/json
+ server: triagens GmbH High-Performance HTTP Server
+ content-length: 41
+
+ {"changed":true,"error":false,"code":202}
\ No newline at end of file
diff --git a/Doxygen/Examples.AvocadoDB/key-value_put-key-request b/Doxygen/Examples.AvocadoDB/key-value_put-key-request
new file mode 100644
index 0000000000..8870a8f83f
--- /dev/null
+++ b/Doxygen/Examples.AvocadoDB/key-value_put-key-request
@@ -0,0 +1,7 @@
+ PUT /_api/key/example_collection/example_key1 HTTP/1.1
+ Host: localhost:9000
+ x-voc-expires: 2011-09-29T08:00:00Z
+ x-voc-extended: {"option1":35,"option2":"x"}
+ Content-Length: 2
+
+ 13
diff --git a/Doxygen/Examples.Durham/demo1 b/Doxygen/Examples.Durham/demo1
new file mode 100644
index 0000000000..bf2e5b2af3
--- /dev/null
+++ b/Doxygen/Examples.Durham/demo1
@@ -0,0 +1,29 @@
+avocsh> db.demo.all();
+[
+ {
+ _id : "161039/4323870",
+ _rev : 4323870,
+ name : "Hugo",
+ firstName : "Egon",
+ address : {
+ city : "Hier",
+ street : "Neue Strasse"
+ },
+ hobbies : [
+ "swimming",
+ "programming"
+ ]
+ },
+
+ {
+ _id : "161039/4192798",
+ _rev : 4192798,
+ hallo : "world"
+ },
+
+ {
+ _id : "161039/4258334",
+ _rev : 4258334,
+ world : "hallo"
+ }
+]
diff --git a/Doxygen/Examples.Durham/five1 b/Doxygen/Examples.Durham/five1
new file mode 100644
index 0000000000..458e7ed751
--- /dev/null
+++ b/Doxygen/Examples.Durham/five1
@@ -0,0 +1,37 @@
+avocsh> db.five.all();
+[
+ {
+ _id : "138663/2631399",
+ _rev : 2631399,
+ a : 2,
+ b : "Two"
+ },
+
+ {
+ _id : "138663/2828007",
+ _rev : 2828007,
+ a : 5,
+ b : "Five"
+ },
+
+ {
+ _id : "138663/2696935",
+ _rev : 2696935,
+ a : 3,
+ b : "Three"
+ },
+
+ {
+ _id : "138663/2565863",
+ _rev : 2565863,
+ a : 1,
+ b : "One"
+ },
+
+ {
+ _id : "138663/2762471",
+ _rev : 2762471,
+ a : 4,
+ b : "Four"
+ }
+]
diff --git a/Doxygen/Examples.Durham/geojs1 b/Doxygen/Examples.Durham/geojs1
new file mode 100644
index 0000000000..be3139003e
--- /dev/null
+++ b/Doxygen/Examples.Durham/geojs1
@@ -0,0 +1,44 @@
+[
+ {
+ _id : "154092/301894631",
+ _rev : 301894631,
+ work : {
+ b : -70,
+ l : -30
+ },
+ name : "Name/-70/-30",
+ home : [
+ -70,
+ -30
+ ]
+ },
+
+ {
+ _id : "154092/305433575",
+ _rev : 305433575,
+ work : {
+ b : -60,
+ l : 140
+ },
+ name : "Name/-60/140",
+ home : [
+ -60,
+ 140
+ ]
+ },
+
+ {
+ _id : "154092/314215399",
+ _rev : 314215399,
+ work : {
+ b : -20,
+ l : 0
+ },
+ name : "Name/-20/0",
+ home : [
+ -20,
+ 0
+ ]
+ },
+ ...
+]
\ No newline at end of file
diff --git a/Doxygen/avocado.doxy.in b/Doxygen/avocado.doxy.in
index 63d524102c..361839f436 100644
--- a/Doxygen/avocado.doxy.in
+++ b/Doxygen/avocado.doxy.in
@@ -206,7 +206,7 @@ ALIASES += CMDOPT{1}="\1"
ALIASES += CA{1}="\1"
ALIASES += CO{1}="\1"
ALIASES += REST{1}="\1"
-ALIASES += GE{1}="\1"
+ALIASES += GE{1}="\1"
ALIASES += EXAMPLES="Examples
"
# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
@@ -689,7 +689,8 @@ EXCLUDE_SYMBOLS =
EXAMPLE_PATH = \
@srcdir@/Doxygen/Examples.AvocadoDB \
@srcdir@/Doxygen/Examples.Durham \
- @srcdir@/Doxygen/Examples.Fyn
+ @srcdir@/Doxygen/Examples.Fyn \
+ @srcdir@/Demos/Scripts
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
diff --git a/HashIndex/hashindex.c b/HashIndex/hashindex.c
index 84fd08eb01..3b515f055f 100755
--- a/HashIndex/hashindex.c
+++ b/HashIndex/hashindex.c
@@ -124,9 +124,6 @@ static bool isEqualJsonJson (const TRI_json_t* left, const TRI_json_t* right) {
static bool isEqualShapedJsonShapedJson (const TRI_shaped_json_t* left, const TRI_shaped_json_t* right) {
-
- int result;
-
if (left == NULL && right == NULL) {
return true;
}
@@ -478,7 +475,6 @@ static bool isMultiEqualElementElement (struct TRI_multi_array_s* multiArray,
void* leftElement, void* rightElement) {
HashIndexElement* hLeftElement = (HashIndexElement*)(leftElement);
HashIndexElement* hRightElement = (HashIndexElement*)(rightElement);
- int result;
if (leftElement == NULL || rightElement == NULL) {
return false;
@@ -495,7 +491,6 @@ static bool isMultiEqualKeyElement (struct TRI_multi_array_s* multiArray,
void* leftElement, void* rightElement) {
HashIndexElement* hLeftElement = (HashIndexElement*)(leftElement);
HashIndexElement* hRightElement = (HashIndexElement*)(rightElement);
- int result;
size_t j;
if (leftElement == NULL || rightElement == NULL) {
diff --git a/Logger/Logger.cpp b/Logger/Logger.cpp
index 6fa7dbf225..5a864f6d29 100644
--- a/Logger/Logger.cpp
+++ b/Logger/Logger.cpp
@@ -440,8 +440,6 @@ static void OutputMachine (string const& text, LoggerData::Info const& info) {
}
}
- line.appendChar('\0');
-
TRI_RawLog(info._level, info._severity, line.c_str(), line.length() - 1);
line.free();
diff --git a/Makefile.files b/Makefile.files
index 5784de380f..780e31405f 100644
--- a/Makefile.files
+++ b/Makefile.files
@@ -139,7 +139,7 @@ avocado_SOURCES = \
QL/parser.c \
QL/tokens.c \
RestHandler/RestActionHandler.cpp \
- RestHandler/RestCollectionHandler.cpp \
+ RestHandler/RestDocumentHandler.cpp \
RestHandler/RestVocbaseBaseHandler.cpp \
RestServer/ActionDispatcherThread.cpp \
RestServer/AvocadoHttpServer.cpp \
@@ -294,6 +294,7 @@ WIKI = \
Doxygen/xml/CommandLineScheduler.md \
Doxygen/xml/Compiling.md \
Doxygen/xml/DefineAction.md \
+ Doxygen/xml/ExamplesSetup.md \
Doxygen/xml/Glossary.md \
Doxygen/xml/Graphs.md \
Doxygen/xml/HttpInterface.md \
diff --git a/Makefile.in b/Makefile.in
index 7a2fe21527..c3bef29154 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -241,7 +241,7 @@ am_avocado_OBJECTS = Admin/ApplicationAdminServer.$(OBJEXT) \
QL/formatter.$(OBJEXT) QL/optimize.$(OBJEXT) \
QL/parser.$(OBJEXT) QL/tokens.$(OBJEXT) \
RestHandler/RestActionHandler.$(OBJEXT) \
- RestHandler/RestCollectionHandler.$(OBJEXT) \
+ RestHandler/RestDocumentHandler.$(OBJEXT) \
RestHandler/RestVocbaseBaseHandler.$(OBJEXT) \
RestServer/ActionDispatcherThread.$(OBJEXT) \
RestServer/AvocadoHttpServer.$(OBJEXT) \
@@ -687,7 +687,7 @@ avocado_SOURCES = \
QL/parser.c \
QL/tokens.c \
RestHandler/RestActionHandler.cpp \
- RestHandler/RestCollectionHandler.cpp \
+ RestHandler/RestDocumentHandler.cpp \
RestHandler/RestVocbaseBaseHandler.cpp \
RestServer/ActionDispatcherThread.cpp \
RestServer/AvocadoHttpServer.cpp \
@@ -823,6 +823,7 @@ WIKI = \
Doxygen/xml/CommandLineScheduler.md \
Doxygen/xml/Compiling.md \
Doxygen/xml/DefineAction.md \
+ Doxygen/xml/ExamplesSetup.md \
Doxygen/xml/Glossary.md \
Doxygen/xml/Graphs.md \
Doxygen/xml/HttpInterface.md \
@@ -1426,7 +1427,7 @@ RestHandler/$(DEPDIR)/$(am__dirstamp):
@: > RestHandler/$(DEPDIR)/$(am__dirstamp)
RestHandler/RestActionHandler.$(OBJEXT): RestHandler/$(am__dirstamp) \
RestHandler/$(DEPDIR)/$(am__dirstamp)
-RestHandler/RestCollectionHandler.$(OBJEXT): \
+RestHandler/RestDocumentHandler.$(OBJEXT): \
RestHandler/$(am__dirstamp) \
RestHandler/$(DEPDIR)/$(am__dirstamp)
RestHandler/RestVocbaseBaseHandler.$(OBJEXT): \
@@ -1713,7 +1714,7 @@ mostlyclean-compile:
-rm -f Rest/SslInterface.$(OBJEXT)
-rm -f Rest/Url.$(OBJEXT)
-rm -f RestHandler/RestActionHandler.$(OBJEXT)
- -rm -f RestHandler/RestCollectionHandler.$(OBJEXT)
+ -rm -f RestHandler/RestDocumentHandler.$(OBJEXT)
-rm -f RestHandler/RestVocbaseBaseHandler.$(OBJEXT)
-rm -f RestServer/ActionDispatcherThread.$(OBJEXT)
-rm -f RestServer/AvocadoHttpServer.$(OBJEXT)
@@ -1910,7 +1911,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@Rest/$(DEPDIR)/SslInterface.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@Rest/$(DEPDIR)/Url.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@RestHandler/$(DEPDIR)/RestActionHandler.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@RestHandler/$(DEPDIR)/RestCollectionHandler.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@RestHandler/$(DEPDIR)/RestDocumentHandler.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@RestHandler/$(DEPDIR)/RestVocbaseBaseHandler.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@RestServer/$(DEPDIR)/ActionDispatcherThread.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@RestServer/$(DEPDIR)/AvocadoHttpServer.Po@am__quote@
diff --git a/RestHandler/RestCollectionHandler.cpp b/RestHandler/RestDocumentHandler.cpp
similarity index 79%
rename from RestHandler/RestCollectionHandler.cpp
rename to RestHandler/RestDocumentHandler.cpp
index d755c2b57a..f07f9152a5 100644
--- a/RestHandler/RestCollectionHandler.cpp
+++ b/RestHandler/RestDocumentHandler.cpp
@@ -25,7 +25,7 @@
/// @author Copyright 2010-2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
-#include "RestCollectionHandler.h"
+#include "RestDocumentHandler.h"
#include "Basics/StringUtils.h"
#include "BasicsC/string-buffer.h"
@@ -51,7 +51,7 @@ using namespace triagens::avocado;
/// @brief constructor
////////////////////////////////////////////////////////////////////////////////
-RestCollectionHandler::RestCollectionHandler (HttpRequest* request, TRI_vocbase_t* vocbase)
+RestDocumentHandler::RestDocumentHandler (HttpRequest* request, TRI_vocbase_t* vocbase)
: RestVocbaseBaseHandler(request, vocbase) {
}
@@ -72,7 +72,7 @@ RestCollectionHandler::RestCollectionHandler (HttpRequest* request, TRI_vocbase_
/// {@inheritDoc}
////////////////////////////////////////////////////////////////////////////////
-bool RestCollectionHandler::isDirect () {
+bool RestDocumentHandler::isDirect () {
return false;
}
@@ -80,7 +80,7 @@ bool RestCollectionHandler::isDirect () {
/// {@inheritDoc}
////////////////////////////////////////////////////////////////////////////////
-string const& RestCollectionHandler::queue () {
+string const& RestDocumentHandler::queue () {
static string const client = "CLIENT";
return client;
@@ -90,7 +90,7 @@ string const& RestCollectionHandler::queue () {
/// {@inheritDoc}
////////////////////////////////////////////////////////////////////////////////
-HttpHandler::status_e RestCollectionHandler::execute () {
+HttpHandler::status_e RestDocumentHandler::execute () {
// extract the sub-request type
HttpRequest::HttpRequestType type = request->requestType();
@@ -160,7 +160,7 @@ HttpHandler::status_e RestCollectionHandler::execute () {
////////////////////////////////////////////////////////////////////////////////
/// @brief creates a document
///
-/// @REST{POST /collection/@FA{collection-identifier}}
+/// @REST{POST /document?collection=@FA{collection-identifier}}
///
/// Creates a new document in the collection identified by the
/// @FA{collection-identifier}. A JSON representation of the document must be
@@ -168,21 +168,27 @@ HttpHandler::status_e RestCollectionHandler::execute () {
///
/// If the document was created successfully, then a @LIT{HTTP 201} is returned
/// and the "Location" header contains the path to the newly created
-/// document. The "ETag" header field contains the revision of the newly created
-/// document.
+/// document. The "ETag" header field contains the revision of the document.
+///
+/// The body of the response contains a JSON object with the same information.
+/// The attribute @LIT{_id} contains the document handle of the newly created
+/// document, the attribute @LIT{_rev} contains the document revision.
///
/// If the collection parameter @LIT{waitForSync} is @LIT{false}, then a
/// @LIT{HTTP 202} is returned in order to indicate that the document has been
/// accepted but not yet stored.
///
/// If the @FA{collection-identifier} is unknown, then a @LIT{HTTP 404} is
-/// returned.
+/// returned and the body of the response contains an error document.
///
/// If the body does not contain a valid JSON representation of an document,
-/// then a @LIT{HTTP 400} is returned.
+/// then a @LIT{HTTP 400} is returned and the body of the response contains
+/// an error document.
///
-/// Instead of a @FA{collection-identifier}, a collection name can be
-/// given.
+/// @REST{POST /document?collection=@FA{collection-identifier}&createCollection=@FA{create}}
+///
+/// Instead of a @FA{collection-identifier}, a collection name can be used. If
+/// @FA{create} is true, then the collection is created if it does not exists.
///
/// @EXAMPLES
///
@@ -203,7 +209,7 @@ HttpHandler::status_e RestCollectionHandler::execute () {
/// @verbinclude rest6
////////////////////////////////////////////////////////////////////////////////
-bool RestCollectionHandler::createDocument () {
+bool RestDocumentHandler::createDocument () {
vector const& suffix = request->suffix();
if (suffix.size() != 1) {
@@ -277,16 +283,16 @@ bool RestCollectionHandler::createDocument () {
/// Either readSingleDocument or readAllDocuments.
////////////////////////////////////////////////////////////////////////////////
-bool RestCollectionHandler::readDocument () {
+bool RestDocumentHandler::readDocument () {
switch (request->suffix().size()) {
- case 1:
+ case 0:
return readAllDocuments();
- case 2:
+ case 1:
return readSingleDocument(true);
default:
- generateError(HttpResponse::BAD, "superfluous identifier");
+ generateError(HttpResponse::BAD, "expecting URI /document/");
return false;
}
}
@@ -294,26 +300,18 @@ bool RestCollectionHandler::readDocument () {
////////////////////////////////////////////////////////////////////////////////
/// @brief reads a single document
///
-/// @REST{GET /collection/@FA{collection-identifier}/@FA{document-identifier}}
+/// @REST{GET /document/@FA{document-handle}}
///
-/// Returns the document identified by @FA{document-identifier} from the
-/// collection identified by @FA{collection-identifier}.
+/// Returns the document identified by @FA{document-handle}. The returned
+/// document contains two special attributes: @LIT{_id} containing the document
+/// handle and @LIT{_rev} containing the revision.
///
/// If the document exists, then a @LIT{HTTP 200} is returned and the JSON
/// representation of the document is the body of the response.
///
-/// If the collection identifier points to a non-existing collection, then a
+/// If the @FA{document-handle} points to a non-existing document, then a
/// @LIT{HTTP 404} is returned and the body contains an error document.
///
-/// If the document identifier points to a non-existing document, then a
-/// @LIT{HTTP 404} is returned and the body contains an error document.
-///
-/// Instead of a @FA{document-identifier}, a document reference can be given. A
-/// @LIT{HTTP 400} is returned, if there is a mismatch between the
-/// @FA{collection-identifier} and the @FA{document-reference}.
-///
-/// Instead of a @FA{collection-identifier}, a collection name can be given.
-///
/// @EXAMPLES
///
/// Use a collection and document identfier:
@@ -333,19 +331,21 @@ bool RestCollectionHandler::readDocument () {
/// @verbinclude rest17
////////////////////////////////////////////////////////////////////////////////
-bool RestCollectionHandler::readSingleDocument (bool generateBody) {
+bool RestDocumentHandler::readSingleDocument (bool generateBody) {
vector const& suffix = request->suffix();
- // find and load collection given by name oder identifier
- bool ok = findCollection(suffix[0]) && loadCollection();
+ // split the document reference
+ string cid;
+ string did;
+
+ bool ok = splitDocumentReference(suffix[0], cid, did);
if (! ok) {
return false;
}
- // split the document reference
- string did;
- ok = splitDocumentReference(suffix[1], did);
+ // find and load collection given by name oder identifier
+ bool ok = findCollection(cid) && loadCollection();
if (! ok) {
return false;
@@ -366,7 +366,7 @@ bool RestCollectionHandler::readSingleDocument (bool generateBody) {
// .............................................................................
if (document == 0) {
- generateDocumentNotFound(suffix[0], did);
+ generateDocumentNotFound(suffix[0]);
return false;
}
@@ -377,10 +377,10 @@ bool RestCollectionHandler::readSingleDocument (bool generateBody) {
////////////////////////////////////////////////////////////////////////////////
/// @brief reads all documents
///
-/// @REST{GET /collection/@FA{collection-identifier}}
+/// @REST{GET /document?collection=@FA{collection-identifier}}
///
-/// Returns the URI for all documents from the collection identified by
-/// @FA{collection-identifier}.
+/// Returns a list of all URI for all documents from the collection identified
+/// by @FA{collection-identifier}.
///
/// Instead of a @FA{collection-identifier}, a collection name can be given.
///
@@ -389,7 +389,7 @@ bool RestCollectionHandler::readSingleDocument (bool generateBody) {
/// @verbinclude rest20
////////////////////////////////////////////////////////////////////////////////
-bool RestCollectionHandler::readAllDocuments () {
+bool RestDocumentHandler::readAllDocuments () {
vector const& suffix = request->suffix();
// find and load collection given by name oder identifier
@@ -470,48 +470,64 @@ bool RestCollectionHandler::readAllDocuments () {
////////////////////////////////////////////////////////////////////////////////
/// @brief reads a single document head
///
-/// @REST{HEAD /collection/@FA{collection-identifier}/@FA{document-identifier}}
+/// @REST{HEAD /document/@FA{document-handle}}
///
-/// Like @FN{GET}, but does not return the body.
+/// Like @FN{GET}, but only returns the header fields and not the body. You
+/// can use this call to get the current revision of a document or check if
+/// the document was deleted.
///
/// @EXAMPLES
///
/// @verbinclude rest19
////////////////////////////////////////////////////////////////////////////////
-bool RestCollectionHandler::checkDocument () {
- return readSingleDocument(false);
+bool RestDocumentHandler::checkDocument () {
+ if (suffix.size() != 1) {
+ generateError(HttpResponse::BAD, "expecting URI /document/");
+ return false;
+ }
+
+ return readDocument(false);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief updates a document
///
-/// @REST{PUT /collection/@FA{collection-identifier}/@FA{document-identifier}}
+/// @REST{PUT /document/@FA{document-handle}}
///
-/// Updates the document identified by @FA{document-identifier} in the
-/// collection identified by @FA{collection-identifier}. If the document exists
-/// and could be updated, then a @LIT{HTTP 201} is returned and the "ETag"
-/// header field contains the new revision of the document.
+/// Updates the document identified by @FA{document-handle}. If the document exists
+/// and can be updated, then a @LIT{HTTP 201} is returned and the "ETag" header
+/// field contains the new revision of the document.
///
-/// If the document does not exists, then a @LIT{HTTP 404} is returned.
+/// Note the updated document passed in the body of the request normally also
+/// contains the @FA{document-handle} in the attribute @LIT{_id} and the
+/// revision in @LIT{_rev}. These attributes, however, are ignored. Only the URI
+/// and the "ETag" header are relevant in order to avoid confusion when using
+/// proxies.
///
-/// If an etag is supplied in the "ETag" field, then the AvocadoDB checks that
-/// the revision of the document is equal to the etag. If there is a mismatch,
-/// then a @LIT{HTTP 409} conflict is returned and no update is performed.
+/// The body of the response contains a JSON object with the information about
+/// the handle and the revision. The attribute @LIT{_id} contains the known
+/// @FA{document-handle} of the updated document, the attribute @LIT{_rev}
+/// contains the new document revision.
///
-/// Instead of a @FA{document-identifier}, a document reference can be given.
+/// If the document does not exists, then a @LIT{HTTP 404} is returned and the
+/// body of the response contains an error document.
///
-/// Instead of a @FA{collection-identifier}, a collection name can be given.
+/// If an etag is supplied in the "If-Match" header field, then the AvocadoDB
+/// checks that the revision of the document is equal to the etag. If there is a
+/// mismatch, then a @LIT{HTTP 409} conflict is returned and no update is
+/// performed.
///
-/// @REST{PUT /collection/@FA{collection-identifier}/@FA{document-identifier}?policy=@FA{policy}}
+/// @REST{PUT /document/@FA{document-handle}?policy=@FA{policy}}
///
/// As before, if @FA{policy} is @LIT{error}. If @FA{policy} is @LIT{last},
/// then the last write will win.
///
-/// @REST{PUT /collection/@FA{collection-identifier}/@FA{document-identifier}?_rev=@FA{etag}}
+/// @REST{PUT /document/@FA{collection-identifier}/@FA{document-identifier}?rev=@FA{etag}}
///
-/// You can also supply the etag using the parameter "_rev" instead of an "ETag"
-/// header.
+/// You can also supply the etag using the parameter @LIT{rev} instead of an "ETag"
+/// header. You must never supply both the "ETag" header and the @LIT{rev}
+/// parameter.
///
/// @EXAMPLES
///
@@ -536,7 +552,7 @@ bool RestCollectionHandler::checkDocument () {
/// @verbinclude rest11
////////////////////////////////////////////////////////////////////////////////
-bool RestCollectionHandler::updateDocument () {
+bool RestDocumentHandler::updateDocument () {
vector const& suffix = request->suffix();
// find and load collection given by name oder identifier
@@ -615,31 +631,35 @@ bool RestCollectionHandler::updateDocument () {
////////////////////////////////////////////////////////////////////////////////
/// @brief deletes a document
///
-/// @REST{DELETE /collection/@FA{collection-identifier}/@FA{document-identifier}}
+/// @REST{DELETE /document/@FA{document-handle}}
///
-/// Deletes the document identified by @FA{document-identifier} from the
-/// collection identified by @FA{collection-identifier}. If the document exists
-/// and could be deleted, then a @LIT{HTTP 204} is returned.
+/// Deletes the document identified by @FA{document-handle} from the collection
+/// identified by @FA{collection-identifier}. If the document exists and could
+/// be deleted, then a @LIT{HTTP 204} is returned.
///
-/// If the document does not exists, then a @LIT{HTTP 404} is returned.
+/// The body of the response contains a JSON object with the information about
+/// the handle and the revision. The attribute @LIT{_id} contains the known
+/// @FA{document-handle} of the updated document, the attribute @LIT{_rev}
+/// contains the known document revision.
///
-/// If an etag is supplied in the "ETag" field, then the AvocadoDB checks that
-/// the revision of the document is equal to the etag. If there is a mismatch,
-/// then a @LIT{HTTP 409} conflict is returned and no delete is performed.
+/// If the document does not exists, then a @LIT{HTTP 404} is returned and the
+/// body of the response contains an error document.
///
-/// Instead of a @FA{document-identifier}, a document reference can be given.
+/// If an etag is supplied in the "If-Match" field, then the AvocadoDB checks
+/// that the revision of the document is equal to the tag. If there is a
+/// mismatch, then a @LIT{HTTP 409} conflict is returned and no delete is
+/// performed.
///
-/// Instead of a @FA{collection-identifier}, a collection name can be given.
-///
-/// @REST{DELETE /collection/@FA{collection-identifier}/@FA{document-identifier}?policy=@FA{policy}}
+/// @REST{DELETE /document/@FA{document-handle}?policy=@FA{policy}}
///
/// As before, if @FA{policy} is @LIT{error}. If @FA{policy} is @LIT{last}, then
/// the last write will win.
///
-/// @REST{DELETE /collection/@FA{collection-identifier}/@FA{document-identifier}? _rev=@FA{etag}}
+/// @REST{DELETE /document/@FA{document-handle}?rev=@FA{etag}}
///
-/// You can also supply the etag using the parameter "_rev" instead of an "ETag"
-/// header.
+/// You can also supply the etag using the parameter @LIT{rev} instead of an "ETag"
+/// header. You must never supply both the "ETag" header and the @LIT{rev}
+/// parameter.
///
/// @EXAMPLES
///
@@ -656,7 +676,7 @@ bool RestCollectionHandler::updateDocument () {
/// @verbinclude rest12
////////////////////////////////////////////////////////////////////////////////
-bool RestCollectionHandler::deleteDocument () {
+bool RestDocumentHandler::deleteDocument () {
vector suffix = request->suffix();
// find and load collection given by name oder identifier
diff --git a/RestHandler/RestCollectionHandler.h b/RestHandler/RestDocumentHandler.h
similarity index 96%
rename from RestHandler/RestCollectionHandler.h
rename to RestHandler/RestDocumentHandler.h
index 63f0290557..6699406711 100644
--- a/RestHandler/RestCollectionHandler.h
+++ b/RestHandler/RestDocumentHandler.h
@@ -31,7 +31,7 @@
#include "RestHandler/RestVocbaseBaseHandler.h"
// -----------------------------------------------------------------------------
-// --SECTION-- RestCollectionHandler
+// --SECTION-- RestDocumentHandler
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
@@ -46,7 +46,7 @@ namespace triagens {
/// @brief collection request handler
////////////////////////////////////////////////////////////////////////////////
- class RestCollectionHandler : public RestVocbaseBaseHandler {
+ class RestDocumentHandler : public RestVocbaseBaseHandler {
////////////////////////////////////////////////////////////////////////////////
/// @}
@@ -67,7 +67,7 @@ namespace triagens {
/// @brief constructor
////////////////////////////////////////////////////////////////////////////////
- RestCollectionHandler (rest::HttpRequest* request, struct TRI_vocbase_s* vocbase);
+ RestDocumentHandler (rest::HttpRequest* request, struct TRI_vocbase_s* vocbase);
////////////////////////////////////////////////////////////////////////////////
/// @}
diff --git a/RestHandler/RestVocbaseBaseHandler.cpp b/RestHandler/RestVocbaseBaseHandler.cpp
index 167fa233da..7de63f3e04 100644
--- a/RestHandler/RestVocbaseBaseHandler.cpp
+++ b/RestHandler/RestVocbaseBaseHandler.cpp
@@ -73,7 +73,7 @@ LoggerData::Extra const RestVocbaseBaseHandler::RES_FAIL;
/// @brief document path
////////////////////////////////////////////////////////////////////////////////
-string RestVocbaseBaseHandler::DOCUMENT_PATH = "/collection";
+string RestVocbaseBaseHandler::DOCUMENT_PATH = "/document";
////////////////////////////////////////////////////////////////////////////////
/// @brief collection path
@@ -220,17 +220,20 @@ void RestVocbaseBaseHandler::generateDocument (TRI_doc_mptr_t const* document,
TRI_string_buffer_t buffer;
if (generateDocument) {
- string id = StringUtils::itoa(_documentCollection->base._cid) + ":" + StringUtils::itoa(document->_did);
+ string id = StringUtils::itoa(_documentCollection->base._cid) + TRI_DOCUMENT_HANDLE_SEPARATOR_STR + StringUtils::itoa(document->_did);
TRI_json_t augmented;
TRI_InitArrayJson(&augmented);
TRI_json_t* _id = TRI_CreateStringCopyJson(id.c_str());
- TRI_json_t* _rev = TRI_CreateNumberJson(document->_rid);
+
if (_id) {
TRI_Insert2ArrayJson(&augmented, "_id", _id);
}
+
+ TRI_json_t* _rev = TRI_CreateNumberJson(document->_rid);
+
if (_rev) {
TRI_Insert2ArrayJson(&augmented, "_rev", _rev);
}
@@ -266,7 +269,7 @@ void RestVocbaseBaseHandler::generateDocument (TRI_doc_mptr_t const* document,
////////////////////////////////////////////////////////////////////////////////
bool RestVocbaseBaseHandler::splitDocumentReference (string const& name, string& did) {
- vector doc = StringUtils::split(name, ":");
+ vector doc = StringUtils::split(name, TRI_DOCUMENT_HANDLE_SEPARATOR_STR);
switch (doc.size()) {
case 1:
diff --git a/RestServer/AvocadoServer.cpp b/RestServer/AvocadoServer.cpp
index 8ea1b6c014..8f1b1bd4af 100644
--- a/RestServer/AvocadoServer.cpp
+++ b/RestServer/AvocadoServer.cpp
@@ -47,7 +47,7 @@
#include "Logger/Logger.h"
#include "Rest/Initialise.h"
#include "RestHandler/RestActionHandler.h"
-#include "RestHandler/RestCollectionHandler.h"
+#include "RestHandler/RestDocumentHandler.h"
#include "RestServer/ActionDispatcherThread.h"
#include "RestServer/AvocadoHttpServer.h"
#include "V8/JSLoader.h"
@@ -548,7 +548,7 @@ int AvocadoServer::startupServer () {
_applicationAdminServer->addBasicHandlers(factory);
- factory->addPrefixHandler(RestVocbaseBaseHandler::DOCUMENT_PATH, RestHandlerCreator::createData, _vocbase);
+ factory->addPrefixHandler(RestVocbaseBaseHandler::DOCUMENT_PATH, RestHandlerCreator::createData, _vocbase);
factory->addPrefixHandler("/", RestHandlerCreator::createData, _vocbase);
_httpServer = _applicationHttpServer->buildServer(new AvocadoHttpServer(scheduler, dispatcher), factory, ports);
@@ -567,7 +567,7 @@ int AvocadoServer::startupServer () {
_applicationAdminServer->addBasicHandlers(adminFactory);
_applicationAdminServer->addHandlers(adminFactory, "/admin");
- adminFactory->addPrefixHandler(RestVocbaseBaseHandler::DOCUMENT_PATH, RestHandlerCreator::createData, _vocbase);
+ adminFactory->addPrefixHandler(RestVocbaseBaseHandler::DOCUMENT_PATH, RestHandlerCreator::createData, _vocbase);
adminFactory->addPrefixHandler("/", RestHandlerCreator::createData, _vocbase);
_adminHttpServer = _applicationHttpServer->buildServer(adminFactory, adminPorts);
diff --git a/RestServer/examples-setup.dox b/RestServer/examples-setup.dox
new file mode 100644
index 0000000000..1ca7ff1dbe
--- /dev/null
+++ b/RestServer/examples-setup.dox
@@ -0,0 +1,87 @@
+////////////////////////////////////////////////////////////////////////////////
+/// @brief over the wire protocol
+///
+/// @file
+///
+/// DISCLAIMER
+///
+/// Copyright 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 Dr. Frank Celler
+/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+/// @page ExamplesSetup Preparing the Examples
+///
+/// All examples in the manuals assume that you have created the following
+/// collections:
+///
+/// - demo
+/// - five
+/// - geo
+///
+/// Some of the examples may destroy the collection. In that case you can
+/// use one of the following script to restore the collection.
+///
+/// @LIT{examples.js}: A JavaScript script usable within the AvocadoDB shell to
+/// regenerate the above collections.
+///
+/// @LIT{examples.sh}: A shell script using curl to setup the collections. The
+/// script works without any additional client, but will not be able to detect
+/// any errors.
+///
+/// @section ExamplesSetupDemo Collection "Demo"
+////////////////////////////////////////////////
+///
+/// @verbinclude demo1
+///
+/// was generated by
+///
+/// @verbinclude demo.js
+///
+/// @section ExamplesSetupFive Collection "five"
+////////////////////////////////////////////////
+///
+/// The collection "five" has a unique constraint on the attribute @LIT{a},
+/// and a second unique constraint on the attribute @LIT{b}.
+///
+/// @verbinclude five1
+///
+/// was generated by
+///
+/// @verbinclude five.js
+///
+/// @section ExamplesSetupGeo Collection "geo"
+//////////////////////////////////////////////
+///
+/// The collection "geo" has two geo fields, one @LIT{home} being a list with
+/// two elements, one @LIT{work} being an hash array with latitude @LIT{b} and
+/// longitude @LIT{l}.
+///
+/// @verbinclude geojs1
+///
+/// was generated by
+///
+/// @verbinclude geo.js
+////////////////////////////////////////////////////////////////////////////////
+
+// Local Variables:
+// mode: c++
+// mode: outline-minor
+// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @\\}\\)"
+// End:
diff --git a/RestServer/glossary.dox b/RestServer/glossary.dox
index e6ee417678..3e1deb3993 100644
--- a/RestServer/glossary.dox
+++ b/RestServer/glossary.dox
@@ -29,8 +29,13 @@
/// @page Glossary
///
/// @copydoc GlossaryCollectionIdentifier
+///
+/// @copydoc GlossaryDocument
+///
/// @copydoc GlossaryDocumentHandle
-/// @cooydoc GlossaryDocumentIdentifier
+///
+/// @copydoc GlossaryDocumentIdentifier
+///
/// @copydoc GlossaryDocumentRevision
///
/// @page GlossaryCollectionIdentifier
@@ -38,6 +43,11 @@
/// @GE{Collection Identifier}: A collection identifier identifies a collection
/// in a database. It is an integer and is unique within the database.
///
+/// @page GlossaryDocument
+///
+/// @GE{Document}: Documents in AvocadoDB are JSON objects. These objects can be
+/// nested (to any depth) and may contains lists.
+///
/// @page GlossaryDocumentHandle
///
/// @GE{Document Handle}: A document handle uniquely identifies a document in
@@ -47,7 +57,7 @@
/// @page GlossaryDocumentIdentifier
///
/// @GE{Document Identifier}: A document identifier identifies a document in a
-/// database. It is an integer and is unique within the collection of the
+/// given collection. It is an integer and is unique within the collection of the
/// document.
///
/// @page GlossaryDocumentRevision
diff --git a/RestServer/key-value.dox b/RestServer/key-value.dox
new file mode 100644
index 0000000000..9c55397dd8
--- /dev/null
+++ b/RestServer/key-value.dox
@@ -0,0 +1,208 @@
+////////////////////////////////////////////////////////////////////////////////
+/// @brief statements and cursors
+///
+/// @file
+///
+/// DISCLAIMER
+///
+/// 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.
+/// 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 Achim Brandt
+/// @author Copyright 2012, triagens GmbH, Cologne, Germany
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+/// @page Key-Value REST Interface for storing key-value pairs
+///
+/// @section Key-ValueCreate Create a new key-value pair in the data store.
+///
+/// Creates a new key-value pair with the given key, the data passed in content
+/// and optional attributes passed in the header.
+/// If a key-value pair with the same key exists in the data store, the request
+/// returns an error.
+///
+/// @anchor Key-ValuePost
+/// @REST{POST /_api/key/@FA{collection-name}/@FA{key}}
+///
+/// Optional Attributes:
+/// - @LIT{x-voc-expires} Expiry-date for this key-value pair.
+/// - @LIT{x-voc-extended} A JSON-object of one or more attributes to be attached
+/// to the key-value pair.
+/// - TODO @LIT{binary data}
+///
+/// If the document was created successfully, then a @LIT{HTTP 201} is returned.
+///
+/// If the @FA{collection-name} is unknown, then a @LIT{HTTP 404} is
+/// returned.
+///
+/// If the @FA{key} is used, then a @LIT{HTTP 404} is returned.
+///
+/// @EXAMPLES
+///
+/// Create a key-value pair
+///
+/// @verbinclude key-value_post-key-request
+///
+/// Response (Success)
+///
+/// @verbinclude key-value_post-key-ok
+///
+/// Response (Failure)
+///
+/// @verbinclude key-value_post-key-bad
+///
+///
+///
+/// @section Key-ValueChange Creates or changes the value for a given key.
+///
+/// Sets the value associated with key to the new data passed in content.
+///
+/// @anchor Key-ValuePut
+/// @REST{PUT /_api/key/@FA{collection-name}/@FA{key}}
+///
+/// Optional parameter:
+/// - @LIT{?create=1} When set to 1 database will create keys if they do not
+/// exist. When set to 0 (default) it will return an error if a key does not
+/// exist.
+///
+/// If the document was updated successfully, then a @LIT{HTTP 202} is returned.
+///
+/// If the @FA{collection-name} is unknown, then a @LIT{HTTP 404} is
+/// returned.
+///
+/// If the @FA{key} is not found and @LIT{?create=0}, then a @LIT{HTTP 404} is
+/// returned.
+///
+/// @EXAMPLES
+///
+/// Update a key-value pair
+///
+/// @verbinclude key-value_put-key-request
+///
+/// Response (Success)
+///
+/// @verbinclude key-value_put-key-ok
+///
+/// Response (Failure)
+///
+/// @verbinclude key-value_put-key-bad
+///
+///
+///
+/// @section Key-ValueReturn Returns the value associated with a given key.
+///
+/// Returns the value associated with the key in content. The Attributes of
+/// the key-value pair are returned in the header.
+///
+/// @anchor Key-ValueGet
+/// @REST{GET /_api/key/@FA{collection-name}/@FA{key}}
+///
+/// If the document was found, then a @LIT{HTTP 200} is returned.
+///
+/// If the @FA{collection-name} is unknown, then a @LIT{HTTP 404} is
+/// returned.
+///
+/// If the @FA{key} is not found, then a @LIT{HTTP 404} is returned.
+///
+/// @EXAMPLES
+///
+/// Get a key-value pair
+///
+/// @verbinclude key-value_get-key-request
+///
+/// Response (Success) with attributes
+///
+/// @verbinclude key-value_get-key-ok
+///
+/// Response (Failure)
+///
+/// @verbinclude key-value_get-key-bad
+///
+///
+///
+/// @section Key-ValueRemove This function deletes a key-value pair from the data store.
+///
+/// Deletes the key-value pair with key from the store.
+/// Deletions cannot be undone!
+///
+/// @anchor Key-ValueDelete
+/// @REST{DELETE /_api/key/@FA{collection-name}/@FA{key}}
+///
+/// This function does not support any header parameters.
+///
+/// If the document was found and deleted, then a @LIT{HTTP 200} is returned.
+///
+/// If the @FA{collection-name} is unknown, then a @LIT{HTTP 404} is
+/// returned.
+///
+/// If the @FA{key} is not found, then a @LIT{HTTP 404} is returned.
+///
+/// @EXAMPLES
+///
+/// Delete a key-value pair
+///
+/// @verbinclude key-value_delete-key-request
+///
+/// Response (Success)
+///
+/// @verbinclude key-value_delete-key-ok
+///
+/// Response (Failure)
+///
+/// @verbinclude key-value_delete-key-bad
+///
+///
+///
+/// @section Key-ValueLookup This function returns all keys matching a given prefix.
+///
+/// Retrieves all values that begin with key and returns them as a JSON-array in
+/// content.
+///
+/// @anchor Key-ValueSearch
+/// @REST{GET /_api/keys/@FA{collection-name}/@FA{prefix}}
+///
+/// @FA{prefix} (=beginning of word) to search for. Note that any /-characters
+/// contained in key are considered part of the key and have no special meaning.
+///
+/// TODO Optional parameter:
+/// - @LIT{?filter=Filter Expression} Return only those keys that match the given
+/// filter expression (have certain attributes). Please note that the filter
+/// expression has to be URL-encoded
+///
+/// If the @FA{collection-name} is unknown, then a @LIT{HTTP 404} is
+/// returned.
+///
+/// @EXAMPLES
+///
+/// Find keys by prefix
+///
+/// @verbinclude key-value_get-keys-request
+///
+/// Response (Success)
+///
+/// @verbinclude key-value_get-keys-ok
+///
+/// Response (Failure)
+///
+/// @verbinclude key-value_get-keys-bad
+///
+////////////////////////////////////////////////////////////////////////////////
+
+// Local Variables:
+// mode: outline-minor
+// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)"
+// End:
diff --git a/RestServer/otwp.dox b/RestServer/otwp.dox
index 7fd9eccf95..9ca77e9953 100644
--- a/RestServer/otwp.dox
+++ b/RestServer/otwp.dox
@@ -33,12 +33,12 @@
///
/// - Documents
///
-/// - @ref RestCollectionCreate "POST /collection/@FA{collection-identifier}"
-/// - @ref RestCollectionRead "GET /collection/@FA{collection-identifier}/@FA{document-identifier}"
-/// - @ref RestCollectionReadAll "GET /collection/@FA{collection-identifier}"
-/// - @ref RestCollectionUpdate "PUT /collection/@FA{collection-identifier}/@FA{document-identifier}"
-/// - @ref RestCollectionDelete "DELETE /collection/@FA{collection-identifier}/@FA{document-identifier}"
-/// - @ref RestCollectionHead "HEAD /collection/@FA{collection-identifier}/@FA{document-identifier}"
+/// - @ref RestDocumentRead "GET /document/@FA{document-handle}"
+/// - @ref RestDocumentCreate "POST /document/collection=@FA{collection-identifier}"
+/// - @ref RestDocumentUpdate "PUT /document/@FA{document-handle}"
+/// - @ref RestDocumentDelete "DELETE /document/@FA{document-handle}"
+/// - @ref RestDocumentHead "HEAD /document/@FA{document-handle}"
+/// - @ref RestDocumentReadAll "GET /document/collection=@FA{collection-identifier}"
///
///
/// - @ref OTWPSimpleQueries
@@ -57,6 +57,15 @@
///
- @ref RestQueryPost "POST /_api/query"
///
///
+/// @ref Key-Value
+///
+/// - @ref Key-ValuePost "POST /_api/key/@FA{collection-name}/@FA{key}"
+/// - @ref Key-ValuePut "PUT /_api/key/@FA{collection-name}/@FA{key}"
+/// - @ref Key-ValueGet "GET /_api/key/@FA{collection-name}/@FA{key}"
+/// - @ref Key-ValueDelete "DELETE /_api/key/@FA{collection-name}/@FA{key}"
+/// - @ref Key-ValueSearch "GET /_api/keys/@FA{collection-name}/@FA{prefix}"
+///
+///
///
///
/// @ref OTWPDatabase
diff --git a/RestServer/rest-document.dox b/RestServer/rest-document.dox
index dcfa7fce6c..48d02ff4ce 100644
--- a/RestServer/rest-document.dox
+++ b/RestServer/rest-document.dox
@@ -29,25 +29,44 @@
/// @page RestDocumentTOC
///
///
-/// - @ref RestCollectionCreate "POST /collection/@FA{collection-identifier}"
-/// - @ref RestCollectionRead "GET /collection/@FA{collection-identifier}/@FA{document-identifier}"
-/// - @ref RestCollectionReadAll "GET /collection/@FA{collection-identifier}"
-/// - @ref RestCollectionUpdate "PUT /collection/@FA{collection-identifier}/@FA{document-identifier}"
-/// - @ref RestCollectionDelete "DELETE /collection/@FA{collection-identifier}/@FA{document-identifier}"
-/// - @ref RestCollectionHead "HEAD /collection/@FA{collection-identifier}/@FA{document-identifier}"
+/// - @ref RestDocumentIntro
+/// - @ref RestDocumentResource
+/// - @ref RestDocumentHttp
+///
+/// - @ref RestDocumentRead "GET /document/@FA{document-handle}"
+/// - @ref RestDocumentCreate "POST /document/collection=@FA{collection-identifier}"
+/// - @ref RestDocumentUpdate "PUT /document/@FA{document-handle}"
+/// - @ref RestDocumentDelete "DELETE /document/@FA{document-handle}"
+/// - @ref RestDocumentHead "HEAD /document/@FA{document-handle}"
+/// - @ref RestDocumentReadAll "GET /document/collection=@FA{collection-identifier}"
+///
+///
///
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @page RestDocument REST Interface for Documents
///
-/// Documents in AvocadoDB are JSON objects. The objects can be nested to any
-/// depth and can contains lists, for example:
+/// This is an introduction to AvocadoDB's REST interface to documents.
+///
+///
+/// @copydoc RestDocumentTOC
+///
+///
+/// @section RestDocumentIntro Documents, Identifiers, Handles
+//////////////////////////////////////////////////////////////
+///
+/// @copydoc GlossaryDocument
+///
+/// For example:
///
/// @verbinclude document1
///
/// All documents contain two special fields, the document handle in @LIT{_id}
-/// and the document revision in @LIT{_rev}.
+/// and the etag aka document revision in @LIT{_rev}.
+///
+/// All examples in the document assume that you have created some example
+/// collections, see @ref ExamplesSetup.
///
/// @copydoc GlossaryDocumentHandle
///
@@ -59,36 +78,56 @@
///
/// The basic operations (create, read, update, delete) for documents are mapped
/// to the standard HTTP methods (POST, GET, PUT, DELETE). An identifier for the
-/// document revision is returned in the "ETag" field. If you modify a document,
-/// you can use the "ETag" field to detect conflicts. The revision of a document
-/// can be checking using the HTTP method HEAD.
+/// document revision is returned in the "ETag" header field. If you modify a
+/// document, you can use the "If-Match" field to detect conflicts. The revision
+/// of a document can be checking using the HTTP method HEAD.
///
-///
-/// @copydoc RestDocumentTOC
+/// @section RestDocumentResource Address and ETag of an Document
+/////////////////////////////////////////////////////////////////
+///
+/// All documents in AvocadoDB have a document handle. This handle uniquely
+/// defines a document and is managed by AvocadoDB. Assume that the document
+/// handle, which is stored in the @LIT{_id} field of the document, is
+/// @LIT{7254820/362549736}, then the HTTP URI of that document is:
+///
+/// @LIT{http://localhost:8529/document/7254820/362549736}
+///
+/// Each document also has a document revision or etag with is returned
+/// in the "ETag" header field when requesting a document.
+///
+/// If you obtain a document using @LIT{GET} and you want to check if a
+/// newer revision is available, then you can use the "If-None-Match"
+/// header. If the document is unchanged, a @LIT{HTTP 412} is returned.
+///
+/// If you want to update or delete a document, then you can use the
+/// "If-Match" header. If the document has changed, then the
+/// operation is aborted and a @LIT{HTTP 409} is returned.
+///
+/// @section RestDocumentHttp Working with Documents using REST
+///////////////////////////////////////////////////////////////
+///
+/// @anchor RestDocumentRead
+/// @copydetails triagens::avocado::RestDocumentHandler::readSingleDocument
///
///
-/// @anchor RestCollectionCreate
-/// @copydetails triagens::avocado::RestCollectionHandler::createDocument
+/// @anchor RestDocumentCreate
+/// @copydetails triagens::avocado::RestDocumentHandler::createDocument
///
///
-/// @anchor RestCollectionRead
-/// @copydetails triagens::avocado::RestCollectionHandler::readSingleDocument
+/// @anchor RestDocumentUpdate
+/// @copydetails triagens::avocado::RestDocumentHandler::updateDocument
///
///
-/// @anchor RestCollectionReadAll
-/// @copydetails triagens::avocado::RestCollectionHandler::readAllDocuments
+/// @anchor RestDocumentDelete
+/// @copydetails triagens::avocado::RestDocumentHandler::deleteDocument
///
///
-/// @anchor RestCollectionUpdate
-/// @copydetails triagens::avocado::RestCollectionHandler::updateDocument
+/// @anchor RestDocumentHead
+/// @copydetails triagens::avocado::RestDocumentHandler::checkDocument
///
///
-/// @anchor RestCollectionDelete
-/// @copydetails triagens::avocado::RestCollectionHandler::deleteDocument
-///
-///
-/// @anchor RestCollectionHead
-/// @copydetails triagens::avocado::RestCollectionHandler::checkDocument
+/// @anchor RestDocumentReadAll
+/// @copydetails triagens::avocado::RestDocumentHandler::readAllDocuments
////////////////////////////////////////////////////////////////////////////////
// Local Variables:
diff --git a/SimpleHttpClient/SimpleHttpConnection.cpp b/SimpleHttpClient/SimpleHttpConnection.cpp
index e456594136..13ad6f3a4c 100644
--- a/SimpleHttpClient/SimpleHttpConnection.cpp
+++ b/SimpleHttpClient/SimpleHttpConnection.cpp
@@ -194,10 +194,10 @@ namespace triagens {
return contentLength;
}
+ toRead -= _readBufferSize;
+
stream.write(_readBuffer, _readBufferSize);
_readBufferSize = 0;
-
- toRead -= _readBufferSize;
}
size_t len = 0;
@@ -216,14 +216,11 @@ namespace triagens {
len += len_read;
runtime = now() - start;
}
-
- //buffer[len] = '\0';
-
stream.write(buffer, len);
free(buffer);
- return len;
+ return (contentLength - toRead + len);
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/SkipLists/skiplist.c b/SkipLists/skiplist.c
index 3eb981088b..c2ec8834fd 100755
--- a/SkipLists/skiplist.c
+++ b/SkipLists/skiplist.c
@@ -714,8 +714,6 @@ bool TRI_InsertKeySkipList (TRI_skiplist_t* skiplist, void* key, void* element,
////////////////////////////////////////////////////////////////////////////////
void* TRI_LeftLookupByKeySkipList (TRI_skiplist_t* skiplist, void* key) {
-
- int32_t level;
int32_t currentLevel;
TRI_skiplist_node_t* currentNode;
TRI_skiplist_node_t* nextNode;
@@ -839,7 +837,7 @@ void* TRI_LeftLookupByKeySkipList (TRI_skiplist_t* skiplist, void* key) {
- END:
+// END:
assert(false); // there is no way we can be here
return NULL;
@@ -862,8 +860,6 @@ void* TRI_LookupByElementSkipList (TRI_skiplist_t* skiplist, void* element) {
////////////////////////////////////////////////////////////////////////////////
void* TRI_LookupByKeySkipList (TRI_skiplist_t* skiplist, void* key) {
-
- int32_t level;
int32_t currentLevel;
TRI_skiplist_node_t* currentNode;
TRI_skiplist_node_t* nextNode;
@@ -979,7 +975,7 @@ void* TRI_LookupByKeySkipList (TRI_skiplist_t* skiplist, void* key) {
- END:
+// END:
assert(false); // there is no way we can be here
return NULL;
@@ -1184,8 +1180,6 @@ bool TRI_RemoveKeySkipList (TRI_skiplist_t* skiplist, void* key, void* old) {
////////////////////////////////////////////////////////////////////////////////
void* TRI_RightLookupByKeySkipList (TRI_skiplist_t* skiplist, void* key) {
-
- int32_t level;
int32_t currentLevel;
TRI_skiplist_node_t* currentNode;
TRI_skiplist_node_t* prevNode;
@@ -1312,7 +1306,7 @@ void* TRI_RightLookupByKeySkipList (TRI_skiplist_t* skiplist, void* key) {
- END:
+// END:
assert(false); // there is no way we can be here
return NULL;
@@ -1526,8 +1520,6 @@ void* TRI_EndNodeSkipListMulti(TRI_skiplist_multi_t* skiplist) {
////////////////////////////////////////////////////////////////////////////////
void* TRI_LeftLookupByKeySkipListMulti(TRI_skiplist_multi_t* skiplist, void* key) {
-
- int32_t level;
int32_t currentLevel;
TRI_skiplist_node_t* currentNode;
TRI_skiplist_node_t* nextNode;
@@ -1647,7 +1639,7 @@ void* TRI_LeftLookupByKeySkipListMulti(TRI_skiplist_multi_t* skiplist, void* key
- END:
+// END:
assert(false); // there is no way we can be here
return NULL;
@@ -2115,8 +2107,6 @@ bool TRI_RemoveKeySkipListMulti(TRI_skiplist_multi_t* skiplist, void* key, void*
////////////////////////////////////////////////////////////////////////////////
void* TRI_RightLookupByKeySkipListMulti(TRI_skiplist_multi_t* skiplist, void* key) {
-
- int32_t level;
int32_t currentLevel;
TRI_skiplist_node_t* currentNode;
TRI_skiplist_node_t* prevNode;
@@ -2234,7 +2224,7 @@ void* TRI_RightLookupByKeySkipListMulti(TRI_skiplist_multi_t* skiplist, void* ke
- END:
+// END:
assert(false); // there is no way we can be here
return NULL;
diff --git a/V8/v8-conv.cpp b/V8/v8-conv.cpp
index 3a7fa21d14..1f4cc37e46 100644
--- a/V8/v8-conv.cpp
+++ b/V8/v8-conv.cpp
@@ -33,6 +33,7 @@
#include "BasicsC/string-buffer.h"
#include "BasicsC/strings.h"
#include "ShapedJson/shaped-json.h"
+#include "VocBase/vocbase.h"
#include "V8/v8-json.h"
#include "V8/v8-utils.h"
@@ -1171,7 +1172,7 @@ v8::Handle TRI_ObjectReference (TRI_voc_cid_t cid, TRI_voc_did_t did)
TRI_InitStringBuffer(&buffer);
TRI_AppendUInt64StringBuffer(&buffer, cid);
- TRI_AppendStringStringBuffer(&buffer, ":");
+ TRI_AppendCharStringBuffer(&buffer, TRI_DOCUMENT_HANDLE_SEPARATOR_CHR);
TRI_AppendUInt64StringBuffer(&buffer, did);
v8::Handle ref = v8::String::New(buffer._buffer);
@@ -1198,7 +1199,7 @@ bool TRI_IdentifiersObjectReference (v8::Handle value, TRI_voc_cid_t&
string v = TRI_ObjectToString(value);
- vector doc = StringUtils::split(v, ":");
+ vector doc = StringUtils::split(v, TRI_DOCUMENT_HANDLE_SEPARATOR_STR);
switch (doc.size()) {
case 1:
@@ -1380,6 +1381,40 @@ char TRI_ObjectToCharacter (v8::Handle value, bool& error) {
return (*sep)[0];
}
+////////////////////////////////////////////////////////////////////////////////
+/// @brief converts an V8 object to an int64_t
+////////////////////////////////////////////////////////////////////////////////
+
+int64_t TRI_ObjectToInt64 (v8::Handle value) {
+ if (value->IsNumber()) {
+ return (int64_t) value->ToNumber()->Value();
+ }
+
+ if (value->IsNumberObject()) {
+ v8::Handle no = v8::Handle::Cast(value);
+ return (int64_t) no->NumberValue();
+ }
+
+ return 0;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief converts an V8 object to a uint64_t
+////////////////////////////////////////////////////////////////////////////////
+
+uint64_t TRI_ObjectToUInt64 (v8::Handle value) {
+ if (value->IsNumber()) {
+ return (uint64_t) value->ToNumber()->Value();
+ }
+
+ if (value->IsNumberObject()) {
+ v8::Handle no = v8::Handle::Cast(value);
+ return (uint64_t) no->NumberValue();
+ }
+
+ return 0;
+}
+
////////////////////////////////////////////////////////////////////////////////
/// @brief converts an V8 object to a double
////////////////////////////////////////////////////////////////////////////////
diff --git a/V8/v8-conv.h b/V8/v8-conv.h
index 03cda939d2..4951b2c1d9 100644
--- a/V8/v8-conv.h
+++ b/V8/v8-conv.h
@@ -83,6 +83,18 @@ std::string TRI_ObjectToString (v8::Handle);
char TRI_ObjectToCharacter (v8::Handle, bool& error);
+////////////////////////////////////////////////////////////////////////////////
+/// @brief converts an V8 object to an int64_t
+////////////////////////////////////////////////////////////////////////////////
+
+int64_t TRI_ObjectToInt64 (v8::Handle);
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief converts an V8 object to a uint64_t
+////////////////////////////////////////////////////////////////////////////////
+
+uint64_t TRI_ObjectToUInt64 (v8::Handle);
+
////////////////////////////////////////////////////////////////////////////////
/// @brief converts an V8 object to a double
////////////////////////////////////////////////////////////////////////////////
diff --git a/V8/v8-globals.h b/V8/v8-globals.h
index 18dd81b419..9b582fe196 100644
--- a/V8/v8-globals.h
+++ b/V8/v8-globals.h
@@ -63,7 +63,6 @@ typedef struct TRI_v8_global_s {
TRI_v8_global_s ()
: JSFluentQueries(),
- JSQueryTemplates(),
JSQueryCursors(),
JSQueries(), // DEPRECATED
JSCursors(), // DEPRECATED
@@ -75,7 +74,6 @@ typedef struct TRI_v8_global_s {
EdgesTempl(),
EdgesColTempl(),
FluentQueryTempl(),
- QueryTemplateTempl(),
QueryCursorTempl(),
QueryErrorTempl(),
QueryTempl(), // DEPRECATED
@@ -105,12 +103,6 @@ typedef struct TRI_v8_global_s {
std::map< void*, v8::Persistent > JSFluentQueries;
-////////////////////////////////////////////////////////////////////////////////
-/// @brief template mapping for weak pointers
-////////////////////////////////////////////////////////////////////////////////
-
- std::map< void*, v8::Persistent > JSQueryTemplates;
-
////////////////////////////////////////////////////////////////////////////////
/// @brief cursor mapping for weak pointers
////////////////////////////////////////////////////////////////////////////////
@@ -202,12 +194,6 @@ typedef struct TRI_v8_global_s {
v8::Persistent FluentQueryTempl;
-////////////////////////////////////////////////////////////////////////////////
-/// @brief query template template
-////////////////////////////////////////////////////////////////////////////////
-
- v8::Persistent QueryTemplateTempl;
-
////////////////////////////////////////////////////////////////////////////////
/// @brief cursor template
////////////////////////////////////////////////////////////////////////////////
@@ -443,10 +429,6 @@ typedef struct TRI_v8_global_s {
// --SECTION-- REGULAR EXPRESSIONS
// -----------------------------------------------------------------------------
-// -----------------------------------------------------------------------------
-// --SECTION-- private variables
-// -----------------------------------------------------------------------------
-
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup V8Globals
/// @{
diff --git a/V8/v8-vocbase.cpp b/V8/v8-vocbase.cpp
index cd35a9a5c4..9ef2bd321e 100644
--- a/V8/v8-vocbase.cpp
+++ b/V8/v8-vocbase.cpp
@@ -232,6 +232,21 @@ static T* UnwrapClass (v8::Handle obj, int32_t type) {
return static_cast(v8::Handle::Cast(obj->GetInternalField(SLOT_CLASS))->Value());
}
+////////////////////////////////////////////////////////////////////////////////
+/// @brief Get the vocbase pointer from the current V8 context
+////////////////////////////////////////////////////////////////////////////////
+
+static TRI_vocbase_t* GetContextVocBase () {
+ v8::Handle currentContext = v8::Context::GetCurrent();
+ v8::Handle db = currentContext->Global()->Get(v8::String::New("db"))->ToObject();
+ TRI_vocbase_t* vocbase = UnwrapClass(db, WRP_VOCBASE_TYPE);
+ if (!vocbase) {
+ return 0;
+ }
+
+ return vocbase;
+}
+
////////////////////////////////////////////////////////////////////////////////
/// @brief checks if argument is a document identifier
////////////////////////////////////////////////////////////////////////////////
@@ -610,67 +625,6 @@ static v8::Handle WrapQuery (TRI_query_t* query) {
return queryObject;
}
-////////////////////////////////////////////////////////////////////////////////
-/// @brief weak reference callback for query instances
-////////////////////////////////////////////////////////////////////////////////
-/*
-static void WeakQueryInstanceCallback (v8::Persistent object, void* parameter) {
- TRI_query_instance_t* instance;
- TRI_v8_global_t* v8g;
-
- v8g = (TRI_v8_global_t*) v8::Isolate::GetCurrent()->GetData();
- instance = (TRI_query_instance_t*) parameter;
-
- LOG_TRACE("weak-callback for query instance called");
-
- TRI_query_template_t* template_ = (TRI_query_template_t*) instance->_template;
- assert(template_);
-
- TRI_DecreaseRefCountQueryTemplate(template_);
-
- // find the persistent handle
- v8::Persistent persistent = v8g->JSQueryInstances[instance];
- v8g->JSQueryInstances.erase(instance);
-
- // dispose and clear the persistent handle
- persistent.Dispose();
- persistent.Clear();
-
- TRI_FreeQueryInstance(instance);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-/// @brief stores a query instance in a javascript object
-////////////////////////////////////////////////////////////////////////////////
-
-static v8::Handle WrapQueryInstance (TRI_query_instance_t* instance) {
- TRI_v8_global_t* v8g;
- v8::HandleScope scope;
-
- v8g = (TRI_v8_global_t*) v8::Isolate::GetCurrent()->GetData();
-
- v8::Handle queryInstance = v8g->QueryInstanceTempl->NewInstance();
- map< void*, v8::Persistent >::iterator i = v8g->JSQueryInstances.find(instance);
-
- if (i == v8g->JSQueryInstances.end()) {
- v8::Persistent persistent = v8::Persistent::New(v8::External::New(instance));
-
- queryInstance->SetInternalField(SLOT_CLASS_TYPE, v8::Integer::New(WRP_QUERY_INSTANCE_TYPE));
- queryInstance->SetInternalField(SLOT_CLASS, persistent);
-
- v8g->JSQueryInstances[instance] = persistent;
-
- LOG_TRACE("creating new query instance");
- persistent.MakeWeak(instance, WeakQueryInstanceCallback);
- }
- else {
- queryInstance->SetInternalField(SLOT_CLASS_TYPE, v8::Integer::New(WRP_QUERY_INSTANCE_TYPE));
- queryInstance->SetInternalField(SLOT_CLASS, i->second);
- }
-
- return scope.Close(queryInstance);
-}
-*/
////////////////////////////////////////////////////////////////////////////////
/// @brief Create a query error in a javascript object
////////////////////////////////////////////////////////////////////////////////
@@ -744,154 +698,32 @@ static TRI_rc_cursor_t* ExecuteQuery (v8::Handle queryObject,
return cursor;
}
-////////////////////////////////////////////////////////////////////////////////
-/// @brief executes a query instance or uses existing result set
-////////////////////////////////////////////////////////////////////////////////
-
-/*
-static TRI_query_cursor_t* ExecuteQueryInstance (v8::Handle queryObject,
- bool doCount,
- uint32_t max,
- v8::Handle* err) {
- v8::TryCatch tryCatch;
-
- TRI_query_instance_t* instance = UnwrapClass(queryObject, WRP_QUERY_INSTANCE_TYPE);
-
- if (!instance) {
- *err = v8::String::New("corrupted query instance");
- return 0;
- }
-
- LOG_TRACE("executing query");
-
- TRI_query_cursor_t* cursor = TRI_ExecuteQueryInstance(instance, doCount, max);
- if (!cursor) {
- if (tryCatch.HasCaught()) {
- *err = tryCatch.Exception();
- }
- else {
- *err = CreateQueryErrorObject(&instance->_error);
- }
-
- return NULL;
- }
-
- return cursor;
-}
-*/
-
-////////////////////////////////////////////////////////////////////////////////
-/// @brief weak reference callback for templates
-////////////////////////////////////////////////////////////////////////////////
-/*
-static void WeakQueryTemplateCallback (v8::Persistent object, void* parameter) {
- LOG_TRACE("weak-callback for query template called");
-
- TRI_query_template_t* template_ = (TRI_query_template_t*) parameter;
-
- // mutex lock
- TRI_LockQueryTemplate(template_);
-
- try {
- // find the persistent handle
- TRI_v8_global_t* v8g;
- v8g = (TRI_v8_global_t*) v8::Isolate::GetCurrent()->GetData();
- v8::Persistent persistent = v8g->JSQueryTemplates[template_];
- v8g->JSQueryTemplates.erase(template_);
-
- // dispose and clear the persistent handle
- persistent.Dispose();
- persistent.Clear();
- }
- catch (...) {
- }
-
- assert(template_->_shadow);
- if (!TRI_ReleaseShadowData(template_->_vocbase->_templates, template_->_shadow)) {
- // unlock mutex only if template was not disposed
- TRI_UnlockQueryTemplate(template_);
- }
-}
-*/
-
-////////////////////////////////////////////////////////////////////////////////
-/// @brief stores a template in a javascript object
-////////////////////////////////////////////////////////////////////////////////
-/*
-static v8::Handle WrapQueryTemplate (TRI_query_template_t* template_) {
- TRI_v8_global_t* v8g;
- v8::HandleScope scope;
-
- v8g = (TRI_v8_global_t*) v8::Isolate::GetCurrent()->GetData();
-
- v8::Handle templateObject = v8g->QueryTemplateTempl->NewInstance();
- map< void*, v8::Persistent >::iterator i = v8g->JSQueryTemplates.find(template_);
-
- if (i == v8g->JSQueryTemplates.end()) {
- v8::Persistent persistent = v8::Persistent::New(v8::External::New(template_));
-
- templateObject->SetInternalField(SLOT_CLASS_TYPE, v8::Integer::New(WRP_QUERY_TEMPLATE_TYPE));
- templateObject->SetInternalField(SLOT_CLASS, persistent);
-
- v8g->JSQueryTemplates[template_] = persistent;
-
- persistent.MakeWeak(template_, WeakQueryTemplateCallback);
- }
- else {
- templateObject->SetInternalField(SLOT_CLASS_TYPE, v8::Integer::New(WRP_QUERY_TEMPLATE_TYPE));
- templateObject->SetInternalField(SLOT_CLASS, i->second);
- }
-
- return scope.Close(templateObject);
-}
-*/
-
-////////////////////////////////////////////////////////////////////////////////
-/// @brief extracts a template from a javascript object
-////////////////////////////////////////////////////////////////////////////////
-
-static TRI_query_template_t* UnwrapQueryTemplate (v8::Handle templateObject) {
- return UnwrapClass(templateObject, WRP_QUERY_TEMPLATE_TYPE);
-}
-
////////////////////////////////////////////////////////////////////////////////
/// @brief weak reference callback for cursors
////////////////////////////////////////////////////////////////////////////////
static void WeakQueryCursorCallback (v8::Persistent object, void* parameter) {
+ v8::HandleScope scope;
+
LOG_TRACE("weak-callback for query cursor called");
+
+ TRI_vocbase_t* vocbase = GetContextVocBase();
+ if (!vocbase) {
+ return;
+ }
TRI_query_cursor_t* cursor = (TRI_query_cursor_t*) parameter;
+ TRI_EndUsageDataShadowData(vocbase->_cursors, cursor);
- // mutex lock
- TRI_LockQueryCursor(cursor);
+ // find the persistent handle
+ TRI_v8_global_t* v8g;
+ v8g = (TRI_v8_global_t*) v8::Isolate::GetCurrent()->GetData();
+ v8::Persistent persistent = v8g->JSQueryCursors[cursor];
+ v8g->JSQueryCursors.erase(cursor);
- try {
- // find the persistent handle
- TRI_v8_global_t* v8g;
- v8g = (TRI_v8_global_t*) v8::Isolate::GetCurrent()->GetData();
- v8::Persistent persistent = v8g->JSQueryCursors[cursor];
- v8g->JSQueryCursors.erase(cursor);
-
- // dispose and clear the persistent handle
- persistent.Dispose();
- persistent.Clear();
- }
- catch (...) {
- }
-
- bool mustFree = false;
- if (cursor->_shadow) {
- TRI_DecreaseRefcountShadowData(cursor->_vocbase->_cursors, cursor->_shadow);
- } else {
- mustFree = true;
- }
- // unlock mutex
- TRI_UnlockQueryCursor(cursor);
-
- if (mustFree) {
- cursor->free(cursor);
- }
+ // dispose and clear the persistent handle
+ persistent.Dispose();
+ persistent.Clear();
}
////////////////////////////////////////////////////////////////////////////////
@@ -1318,7 +1150,6 @@ static v8::Handle JS_InEdgesQuery (v8::Arguments const& argv) {
return EdgesQuery(TRI_EDGE_IN, argv);
}
-
////////////////////////////////////////////////////////////////////////////////
/// @brief finds points near a given coordinate
////////////////////////////////////////////////////////////////////////////////
@@ -1497,53 +1328,10 @@ static v8::Handle JS_WithinQuery (v8::Arguments const& argv) {
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
-/// @brief get a (persistent) template by its id
+/// @addtogroup VocBase
+/// @{
////////////////////////////////////////////////////////////////////////////////
-/*
-static v8::Handle JS_Template (v8::Arguments const& argv) {
- v8::HandleScope scope;
-
- if (argv.Length() != 2) {
- return scope.Close(v8::ThrowException(v8::String::New("usage: AQL_TEMPLATE(, )")));
- }
-
- v8::Handle dbArg = argv[0]->ToObject();
- TRI_vocbase_t* vocbase = UnwrapClass(dbArg, WRP_VOCBASE_TYPE);
-
- if (!vocbase) {
- return scope.Close(v8::ThrowException(v8::String::New("corrupted vocbase")));
- }
-
- // get the id
- v8::Handle idArg = argv[1]->ToNumber();
- if (!idArg->IsNumber()) {
- return scope.Close(v8::ThrowException(v8::String::New("expecting number for ")));
- }
-
- double id = TRI_ObjectToDouble(idArg);
-
- TRI_shadow_t* shadow = TRI_FindShadowData(vocbase->_templates, (TRI_shadow_id) id);
- if (!shadow) {
- return scope.Close(v8::ThrowException(v8::String::New("no template found for id")));
- }
-
- TRI_query_template_t* template_ = (TRI_query_template_t*) shadow->_data;
- if (!template_) {
- return scope.Close(v8::ThrowException(v8::String::New("corrupted or already freed template")));
- }
-
- TRI_LockQueryTemplate(template_);
- if (template_->_deleted) {
- TRI_UnlockQueryTemplate(template_);
- return scope.Close(v8::ThrowException(v8::String::New("template has already been deleted")));
- }
- TRI_UnlockQueryTemplate(template_);
-
- return scope.Close(WrapQueryTemplate(template_));
-}
-*/
-
////////////////////////////////////////////////////////////////////////////////
/// @brief get a (persistent) cursor by its id
////////////////////////////////////////////////////////////////////////////////
@@ -1551,42 +1339,29 @@ static v8::Handle JS_Template (v8::Arguments const& argv) {
static v8::Handle JS_Cursor (v8::Arguments const& argv) {
v8::HandleScope scope;
- if (argv.Length() != 2) {
- return scope.Close(v8::ThrowException(v8::String::New("usage: AQL_CURSOR(, )")));
+ if (argv.Length() != 1) {
+ return scope.Close(v8::ThrowException(v8::String::New("usage: AQL_CURSOR()")));
}
- v8::Handle dbArg = argv[0]->ToObject();
- TRI_vocbase_t* vocbase = UnwrapClass(dbArg, WRP_VOCBASE_TYPE);
-
+ TRI_vocbase_t* vocbase = GetContextVocBase();
if (!vocbase) {
return scope.Close(v8::ThrowException(v8::String::New("corrupted vocbase")));
}
// get the id
- v8::Handle idArg = argv[1]->ToNumber();
- if (!idArg->IsNumber()) {
- return scope.Close(v8::ThrowException(v8::String::New("expecting number for ")));
+ v8::Handle idArg = argv[0]->ToString();
+ if (!idArg->IsString()) {
+ return scope.Close(v8::ThrowException(v8::String::New("expecting string for ")));
}
+ string idString = TRI_ObjectToString(idArg);
+ uint64_t id = TRI_UInt64String(idString.c_str());
- double id = TRI_ObjectToDouble(idArg);
-
- TRI_shadow_t* shadow = TRI_FindShadowData(vocbase->_cursors, (TRI_shadow_id) id);
- if (!shadow) {
- return scope.Close(v8::ThrowException(v8::String::New("no cursor found for id")));
- }
-
- TRI_query_cursor_t* cursor = (TRI_query_cursor_t*) shadow->_data;
+ TRI_query_cursor_t* cursor = (TRI_query_cursor_t*)
+ TRI_BeginUsageIdShadowData(vocbase->_cursors, id);
if (!cursor) {
return scope.Close(v8::ThrowException(v8::String::New("corrupted or already freed cursor")));
}
- TRI_LockQueryCursor(cursor);
- if (cursor->_deleted) {
- TRI_UnlockQueryCursor(cursor);
- return scope.Close(v8::ThrowException(v8::String::New("cursor has already been deleted")));
- }
- TRI_UnlockQueryCursor(cursor);
-
return scope.Close(WrapQueryCursor(cursor));
}
@@ -1608,8 +1383,6 @@ static v8::Handle JS_Cursor (v8::Arguments const& argv) {
////////////////////////////////////////////////////////////////////////////////
static TRI_json_t* ConvertHelper(v8::Handle parameter) {
-
-
if (parameter->IsBoolean()) {
v8::Handle booleanParameter = parameter->ToBoolean();
return TRI_CreateBooleanJson(booleanParameter->Value());
@@ -1664,181 +1437,22 @@ static TRI_json_t* ConvertHelper(v8::Handle parameter) {
return NULL;
}
-////////////////////////////////////////////////////////////////////////////////
-/// @brief constructs a new query template from a string
-////////////////////////////////////////////////////////////////////////////////
-/*
-static v8::Handle JS_CreateTemplateAql (v8::Arguments const& argv) {
- v8::HandleScope scope;
-
- if (argv.Length() < 3) {
- return scope.Close(v8::ThrowException(v8::String::New("usage: AQL_CREATE_TEMPLATE(, , )")));
- }
-
- v8::Handle dbArg = argv[0]->ToObject();
- TRI_vocbase_t* vocbase = UnwrapClass(dbArg, WRP_VOCBASE_TYPE);
- if (!vocbase) {
- return scope.Close(v8::ThrowException(v8::String::New("corrupted vocbase")));
- }
-
- // get the query string
- v8::Handle queryArg = argv[1];
- if (!queryArg->IsString()) {
- return scope.Close(v8::ThrowException(v8::String::New("expecting string for ")));
- }
- string queryString = TRI_ObjectToString(queryArg);
-
- // get the persistent/non-persistent flag
- v8::Handle persistentArg = argv[2];
- if (!persistentArg->IsBoolean()) {
- return scope.Close(v8::ThrowException(v8::String::New("expecting bool for ")));
- }
-
- bool persistent = TRI_ObjectToBoolean(persistentArg);
- TRI_query_template_type_e persistMode;
- if (persistent) {
- persistMode = QUERY_TEMPLATE_PERSISTENT;
- }
- else {
- persistMode = QUERY_TEMPLATE_TRANSIENT;
- }
-
- // create a template object
- TRI_query_template_t* template_ = TRI_CreateQueryTemplate(queryString.c_str(),
- vocbase,
- persistMode);
-
- if (template_) {
- bool ok = TRI_ParseQueryTemplate(template_);
- if (ok) {
- return scope.Close(WrapQueryTemplate(template_));
- }
-
- v8::Handle errorObject = CreateQueryErrorObject(&template_->_error);
- TRI_FreeQueryTemplate(template_);
- return scope.Close(errorObject);
- }
-
- return scope.Close(v8::ThrowException(v8::String::New("out of memory")));
-}
-*/
-
-////////////////////////////////////////////////////////////////////////////////
-/// @brief execute a stored statement
-////////////////////////////////////////////////////////////////////////////////
-/*
-static v8::Handle JS_StoredStatementAql (v8::Arguments const& argv) {
- v8::HandleScope scope;
-
- if (argv.Length() < 2 || argv.Length() > 5) {
- return scope.Close(v8::ThrowException(v8::String::New("usage: AQL_STORED_STATEMENT(, , , , )")));
- }
-
- v8::Handle dbArg = argv[0]->ToObject();
- TRI_vocbase_t* vocbase = UnwrapClass(dbArg, WRP_VOCBASE_TYPE);
- if (!vocbase) {
- return scope.Close(v8::ThrowException(v8::String::New("corrupted vocbase")));
- }
-
- // get the statement id
- v8::Handle idArg = argv[1];
- TRI_voc_cid_t cid;
- TRI_voc_did_t did;
-
- if (! IsDocumentId(idArg, cid, did)) {
- return scope.Close(v8::ThrowException(v8::String::New(" must be a document identifier")));
- }
-
- LOG_INFO("looking up shadow");
- TRI_shadow_document_t* shadow = TRI_FindShadowDocument(vocbase->_statements, vocbase, cid, did);
- LOG_INFO("looked up shadow %p", shadow);
-
- //TRI_StoreShadowData((TRI_shadow_store_t*) vocbase->_templates,
- // (const void* const) template_);
-
- // return number of total records in cursor?
- bool doCount = false;
- if (argv.Length() > 0) {
- doCount = TRI_ObjectToBoolean(argv[3]);
- }
-
- // maximum number of results to return at once
- uint32_t max = 1000;
- if (argv.Length() > 1) {
- double maxValue = TRI_ObjectToDouble(argv[4]);
- if (maxValue >= 1.0) {
- max = (uint32_t) maxValue;
- }
- }
-
- TRI_query_template_t* template_ = NULL;
- TRI_query_instance_t* instance = NULL;
- TRI_query_cursor_t* cursor = NULL;
- TRI_json_t* parameters = NULL;
-// template_ = TRI_CreateQueryTemplate(queryString.c_str(),
-// vocbase,
-// QUERY_TEMPLATE_TRANSIENT);
- if (!template_) {
- return scope.Close(v8::ThrowException(v8::String::New("out of memory")));
- }
-
- bool ok = TRI_ParseQueryTemplate(template_);
- if (!ok) {
- v8::Handle errorObject = CreateQueryErrorObject(&template_->_error);
- TRI_FreeQueryTemplate(template_);
- return scope.Close(errorObject);
- }
-
- if (argv.Length() > 2) {
- parameters = ConvertHelper(argv[2]);
- }
-
- instance = TRI_CreateQueryInstance(template_, parameters);
- if (!instance) {
- if (parameters) {
- TRI_FreeJson(parameters);
- }
- return scope.Close(v8::ThrowException(v8::String::New("out of memory")));
- }
-
- if (!instance->_doAbort) {
- cursor = TRI_ExecuteQueryInstance(instance, doCount, max);
- }
-
- if (parameters) {
- TRI_FreeJson(parameters);
- }
-
- if (!cursor) {
- v8::Handle errorObject = CreateQueryErrorObject(&instance->_error);
-
- TRI_FreeQueryInstance(instance);
- return scope.Close(errorObject);
- }
-
- TRI_FreeQueryInstance(instance);
-
- return scope.Close(WrapQueryCursor(cursor));
-}
-*/
-
////////////////////////////////////////////////////////////////////////////////
/// @brief parses a query and returns the parse result
////////////////////////////////////////////////////////////////////////////////
static v8::Handle JS_ParseAql (v8::Arguments const& argv) {
v8::HandleScope scope;
-
- if (argv.Length() < 2 || argv.Length() > 5) {
- return scope.Close(v8::ThrowException(v8::String::New("usage: AQL_PARSE(, )")));
+
+ if (argv.Length() != 1) {
+ return scope.Close(v8::ThrowException(v8::String::New("usage: AQL_PARSE()")));
}
- v8::Handle dbArg = argv[0]->ToObject();
- TRI_vocbase_t* vocbase = UnwrapClass(dbArg, WRP_VOCBASE_TYPE);
+ TRI_vocbase_t* vocbase = GetContextVocBase();
if (!vocbase) {
return scope.Close(v8::ThrowException(v8::String::New("corrupted vocbase")));
}
-
+
// get the query string
v8::Handle queryArg = argv[1];
if (!queryArg->IsString()) {
@@ -1848,10 +1462,7 @@ static v8::Handle JS_ParseAql (v8::Arguments const& argv) {
TRI_query_template_t* template_ = NULL;
- template_ = TRI_CreateQueryTemplate(queryString.c_str(),
- vocbase,
- QUERY_TEMPLATE_TRANSIENT);
-
+ template_ = TRI_CreateQueryTemplate(queryString.c_str(), vocbase);
if (!template_) {
return scope.Close(v8::ThrowException(v8::String::New("out of memory")));
}
@@ -1893,18 +1504,17 @@ static v8::Handle JS_ParseAql (v8::Arguments const& argv) {
static v8::Handle JS_StatementAql (v8::Arguments const& argv) {
v8::HandleScope scope;
- if (argv.Length() < 2 || argv.Length() > 5) {
- return scope.Close(v8::ThrowException(v8::String::New("usage: AQL_STATEMENT(, , , , )")));
+ if (argv.Length() < 1 || argv.Length() > 4) {
+ return scope.Close(v8::ThrowException(v8::String::New("usage: AQL_STATEMENT(, , , )")));
}
-
- v8::Handle dbArg = argv[0]->ToObject();
- TRI_vocbase_t* vocbase = UnwrapClass(dbArg, WRP_VOCBASE_TYPE);
+
+ TRI_vocbase_t* vocbase = GetContextVocBase();
if (!vocbase) {
return scope.Close(v8::ThrowException(v8::String::New("corrupted vocbase")));
}
// get the query string
- v8::Handle queryArg = argv[1];
+ v8::Handle queryArg = argv[0];
if (!queryArg->IsString()) {
return scope.Close(v8::ThrowException(v8::String::New("expecting string for ")));
}
@@ -1913,13 +1523,13 @@ static v8::Handle JS_StatementAql (v8::Arguments const& argv) {
// return number of total records in cursor?
bool doCount = false;
if (argv.Length() > 0) {
- doCount = TRI_ObjectToBoolean(argv[3]);
+ doCount = TRI_ObjectToBoolean(argv[2]);
}
// maximum number of results to return at once
uint32_t max = 1000;
if (argv.Length() > 1) {
- double maxValue = TRI_ObjectToDouble(argv[4]);
+ double maxValue = TRI_ObjectToDouble(argv[3]);
if (maxValue >= 1.0) {
max = (uint32_t) maxValue;
}
@@ -1930,10 +1540,7 @@ static v8::Handle JS_StatementAql (v8::Arguments const& argv) {
TRI_query_cursor_t* cursor = NULL;
TRI_json_t* parameters = NULL;
- template_ = TRI_CreateQueryTemplate(queryString.c_str(),
- vocbase,
- QUERY_TEMPLATE_TRANSIENT);
-
+ template_ = TRI_CreateQueryTemplate(queryString.c_str(), vocbase);
if (!template_) {
return scope.Close(v8::ThrowException(v8::String::New("out of memory")));
}
@@ -1945,8 +1552,8 @@ static v8::Handle JS_StatementAql (v8::Arguments const& argv) {
return scope.Close(errorObject);
}
- if (argv.Length() > 2) {
- parameters = ConvertHelper(argv[2]);
+ if (argv.Length() > 1) {
+ parameters = ConvertHelper(argv[1]);
}
// TODO: properly free parameters
@@ -1978,6 +1585,8 @@ static v8::Handle JS_StatementAql (v8::Arguments const& argv) {
TRI_FreeQueryInstance(instance);
TRI_FreeQueryTemplate(template_);
+ TRI_StoreShadowData(vocbase->_cursors, (const void* const) cursor);
+
return scope.Close(WrapQueryCursor(cursor));
}
@@ -2910,110 +2519,6 @@ static v8::Handle JS_ExecuteAql (v8::Arguments const& argv) {
return scope.Close(WrapCursor(cursor));
}
-////////////////////////////////////////////////////////////////////////////////
-/// @brief destroy a template
-////////////////////////////////////////////////////////////////////////////////
-
-static v8::Handle JS_DisposeQueryTemplate (v8::Arguments const& argv) {
- v8::HandleScope scope;
- v8::TryCatch tryCatch;
-
- if (argv.Length() != 0) {
- return scope.Close(v8::ThrowException(v8::String::New("usage: dispose()")));
- }
-
- v8::Handle self = argv.Holder();
- TRI_query_template_t* template_ = UnwrapQueryTemplate(self);
- if (!template_) {
- return scope.Close(v8::ThrowException(v8::String::New("corrupted template")));
- }
-
- // set the deleted flag so the gc can catch this instance
- TRI_LockQueryTemplate(template_);
- if (template_->_deleted) {
- TRI_UnlockQueryTemplate(template_);
- return scope.Close(v8::ThrowException(v8::String::New("corrupted or already disposed template")));
- }
- template_->_deleted = true;
- TRI_UnlockQueryTemplate(template_);
-
- return scope.Close(v8::BooleanObject::New(true));
-}
-
-////////////////////////////////////////////////////////////////////////////////
-/// @brief returns the id of the template
-////////////////////////////////////////////////////////////////////////////////
-
-/*
-static v8::Handle JS_IdQueryTemplate (v8::Arguments const& argv) {
- v8::HandleScope scope;
- v8::TryCatch tryCatch;
-
- if (argv.Length() != 0) {
- return scope.Close(v8::ThrowException(v8::String::New("usage: id()")));
- }
-
- v8::Handle self = argv.Holder();
- TRI_query_template_t* template_ = UnwrapQueryTemplate(self);
- if (!template_) {
- return scope.Close(v8::ThrowException(v8::String::New("corrupted template")));
- }
-
- TRI_LockQueryTemplate(template_);
- if (template_->_deleted) {
- TRI_UnlockQueryTemplate(template_);
- return scope.Close(v8::ThrowException(v8::String::New("corrupted template")));
- }
-
- if (template_->_type == QUERY_TEMPLATE_PERSISTENT) {
- TRI_shadow_id id = template_->_shadow->_id;
- TRI_UnlockQueryTemplate(template_);
- return scope.Close(v8::Number::New(id));
- }
- else {
- TRI_UnlockQueryTemplate(template_);
- return scope.Close(v8::ThrowException(v8::String::New("template is non-persistent")));
- }
-}
-*/
-
-////////////////////////////////////////////////////////////////////////////////
-/// @brief executes a query, returns a cursor
-////////////////////////////////////////////////////////////////////////////////
-/*
-static v8::Handle JS_ExecuteQueryInstance (v8::Arguments const& argv) {
- v8::HandleScope scope;
-
- // return number of total records in cursor?
- bool doCount = false;
- if (argv.Length() > 0) {
- doCount = TRI_ObjectToBoolean(argv[3]);
- }
-
- // maximum number of results to return at once
- uint32_t max = 1000;
- if (argv.Length() > 1) {
- double maxValue = TRI_ObjectToDouble(argv[1]);
- if (maxValue >= 1.0) {
- max = (uint32_t) maxValue;
- }
- }
-
- v8::Handle err;
- TRI_query_cursor_t* cursor = ExecuteQueryInstance(argv.Holder(), doCount, max, &err);
-
- if (!cursor) {
- return v8::ThrowException(err);
- }
-
- // we must do this to increase the refcount of the shadow
- TRI_shadow_t* shadow = TRI_FindShadowData(cursor->_vocbase->_cursors, cursor->_shadow->_id);
- assert(shadow);
-
- return scope.Close(WrapQueryCursor(cursor));
-}
-*/
-
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
@@ -3033,28 +2538,21 @@ static v8::Handle JS_ExecuteQueryInstance (v8::Arguments const& argv)
static v8::Handle JS_DisposeQueryCursor (v8::Arguments const& argv) {
v8::HandleScope scope;
- v8::TryCatch tryCatch;
if (argv.Length() != 0) {
return scope.Close(v8::ThrowException(v8::String::New("usage: dispose()")));
}
-
- v8::Handle self = argv.Holder();
- TRI_query_cursor_t* cursor = UnwrapQueryCursor(self);
- if (!cursor) {
- return scope.Close(v8::ThrowException(v8::String::New("corrupted cursor")));
+
+ TRI_vocbase_t* vocbase = GetContextVocBase();
+ if (!vocbase) {
+ return scope.Close(v8::ThrowException(v8::String::New("corrupted vocbase")));
}
- // set the deleted flag so the gc can catch this instance
- TRI_LockQueryCursor(cursor);
- if (cursor->_deleted) {
- TRI_UnlockQueryCursor(cursor);
- return scope.Close(v8::ThrowException(v8::String::New("corrupted or already disposed cursor")));
+ if (TRI_DeleteDataShadowData(vocbase->_cursors, UnwrapQueryCursor(argv.Holder()))) {
+ return scope.Close(v8::True());
}
- cursor->_deleted = true;
- TRI_UnlockQueryCursor(cursor);
- return scope.Close(v8::True());
+ return scope.Close(v8::ThrowException(v8::String::New("corrupted or already disposed cursor")));
}
////////////////////////////////////////////////////////////////////////////////
@@ -3063,34 +2561,22 @@ static v8::Handle JS_DisposeQueryCursor (v8::Arguments const& argv) {
static v8::Handle JS_IdQueryCursor (v8::Arguments const& argv) {
v8::HandleScope scope;
- v8::TryCatch tryCatch;
if (argv.Length() != 0) {
return scope.Close(v8::ThrowException(v8::String::New("usage: id()")));
}
-
- v8::Handle self = argv.Holder();
- TRI_query_cursor_t* cursor = UnwrapQueryCursor(self);
-
- if (!cursor) {
- return scope.Close(v8::ThrowException(v8::String::New("corrupted cursor")));
+
+ TRI_vocbase_t* vocbase = GetContextVocBase();
+ if (!vocbase) {
+ return scope.Close(v8::ThrowException(v8::String::New("corrupted vocbase")));
}
-
- TRI_LockQueryCursor(cursor);
- if (cursor->_deleted) {
- TRI_UnlockQueryCursor(cursor);
- return scope.Close(v8::ThrowException(v8::String::New("corrupted cursor")));
- }
-
- if (cursor->_shadow) {
- TRI_shadow_id id = cursor->_shadow->_id;
- TRI_UnlockQueryCursor(cursor);
-
+
+ TRI_shadow_id id = TRI_GetIdDataShadowData(vocbase->_cursors, UnwrapQueryCursor(argv.Holder()));
+ if (id) {
return scope.Close(v8::Number::New(id));
}
- TRI_UnlockQueryCursor(cursor);
- return scope.Close(v8::ThrowException(v8::String::New("unknown cursor")));
+ return scope.Close(v8::ThrowException(v8::String::New("corrupted or already disposed cursor")));
}
////////////////////////////////////////////////////////////////////////////////
@@ -3099,28 +2585,27 @@ static v8::Handle JS_IdQueryCursor (v8::Arguments const& argv) {
static v8::Handle JS_CountQueryCursor (v8::Arguments const& argv) {
v8::HandleScope scope;
- v8::TryCatch tryCatch;
if (argv.Length() != 0) {
return scope.Close(v8::ThrowException(v8::String::New("usage: count()")));
}
-
- v8::Handle self = argv.Holder();
- TRI_query_cursor_t* cursor = UnwrapQueryCursor(self);
-
- if (!cursor) {
- return scope.Close(v8::ThrowException(v8::String::New("corrupted or already freed cursor")));
- }
-
- TRI_LockQueryCursor(cursor);
- if (cursor->_deleted) {
- TRI_UnlockQueryCursor(cursor);
- return scope.Close(v8::ThrowException(v8::String::New("corrupted or already freed cursor")));
- }
- TRI_select_size_t length = cursor->_length;
- TRI_UnlockQueryCursor(cursor);
- return scope.Close(v8::Number::New(length));
+ TRI_vocbase_t* vocbase = GetContextVocBase();
+ if (!vocbase) {
+ return scope.Close(v8::ThrowException(v8::String::New("corrupted vocbase")));
+ }
+
+ TRI_select_size_t length = 0;
+ TRI_query_cursor_t* cursor = (TRI_query_cursor_t*)
+ TRI_BeginUsageDataShadowData(vocbase->_cursors, UnwrapQueryCursor(argv.Holder()));
+
+ if (cursor) {
+ length = cursor->_length;
+ TRI_EndUsageDataShadowData(vocbase->_cursors, cursor);
+ return scope.Close(v8::Number::New(length));
+ }
+
+ return scope.Close(v8::ThrowException(v8::String::New("corrupted or already freed cursor")));
}
////////////////////////////////////////////////////////////////////////////////
@@ -3129,64 +2614,58 @@ static v8::Handle JS_CountQueryCursor (v8::Arguments const& argv) {
static v8::Handle JS_NextQueryCursor (v8::Arguments const& argv) {
v8::HandleScope scope;
- v8::TryCatch tryCatch;
if (argv.Length() != 0) {
return scope.Close(v8::ThrowException(v8::String::New("usage: next()")));
}
-
- v8::Handle self = argv.Holder();
- TRI_query_cursor_t* cursor = UnwrapQueryCursor(self);
-
- if (!cursor) {
- return scope.Close(v8::ThrowException(v8::String::New("corrupted or already freed cursor")));
- }
-
- v8::Handle value;
-
- TRI_LockQueryCursor(cursor);
- if (cursor->_deleted) {
- TRI_UnlockQueryCursor(cursor);
- return scope.Close(v8::ThrowException(v8::String::New("corrupted or already freed cursor")));
- }
-
- bool ok = true;
- TRI_js_exec_context_t context = NULL;
- // exceptions must be caught in the following part because we hold an exclusive
- // lock that might otherwise not be freed
- try {
- TRI_rc_result_t* next = cursor->next(cursor);
- if (!next) {
- value = v8::Undefined();
- }
- else {
- context = TRI_CreateExecutionContext(cursor->_functionCode);
- if (context) {
- TRI_DefineSelectExecutionContext(context, next);
- ok = TRI_ExecuteExecutionContext(context, (void*) &value);
+ TRI_vocbase_t* vocbase = GetContextVocBase();
+ if (!vocbase) {
+ return scope.Close(v8::ThrowException(v8::String::New("corrupted vocbase")));
+ }
+
+ bool result = false;
+ TRI_js_exec_context_t context = NULL;
+ v8::Handle value;
+ TRI_query_cursor_t* cursor = (TRI_query_cursor_t*)
+ TRI_BeginUsageDataShadowData(vocbase->_cursors, UnwrapQueryCursor(argv.Holder()));
+
+ if (cursor) {
+ TRI_LockQueryCursor(cursor);
+
+ // exceptions must be caught in the following part because we hold an exclusive
+ // lock that might otherwise not be freed
+ try {
+ TRI_rc_result_t* next = cursor->next(cursor);
+ if (!next) {
+ value = v8::Undefined();
+ }
+ else {
+ context = TRI_CreateExecutionContext(cursor->_functionCode);
+ if (context) {
+ TRI_DefineSelectExecutionContext(context, next);
+ if (TRI_ExecuteExecutionContext(context, (void*) &value)) {
+ result = true;
+ }
+ }
}
}
- }
- catch (...) {
- }
-
- if (context) {
- TRI_FreeExecutionContext(context);
- }
- // always free lock
- TRI_UnlockQueryCursor(cursor);
-
- if (!ok) {
- if (tryCatch.HasCaught()) {
- return scope.Close(v8::ThrowException(tryCatch.Exception()));
+ catch (...) {
}
- else {
- return scope.Close(v8::ThrowException(v8::String::New("cannot convert to JavaScript")));
+
+ TRI_UnlockQueryCursor(cursor);
+
+ TRI_EndUsageDataShadowData(vocbase->_cursors, cursor);
+ if (context) {
+ TRI_FreeExecutionContext(context);
+ }
+
+ if (result) {
+ return scope.Close(value);
}
}
- return scope.Close(value);
+ return scope.Close(v8::ThrowException(v8::String::New("corrupted or already freed cursor")));
}
////////////////////////////////////////////////////////////////////////////////
@@ -3199,27 +2678,18 @@ static v8::Handle JS_PersistQueryCursor (v8::Arguments const& argv) {
if (argv.Length() != 0) {
return scope.Close(v8::ThrowException(v8::String::New("usage: persist()")));
}
-
- v8::Handle self = argv.Holder();
- TRI_query_cursor_t* cursor = UnwrapQueryCursor(self);
-
- if (!cursor) {
- return scope.Close(v8::ThrowException(v8::String::New("corrupted or already freed cursor")));
- }
- TRI_LockQueryCursor(cursor);
- if (cursor->_deleted) {
- TRI_UnlockQueryCursor(cursor);
- return scope.Close(v8::ThrowException(v8::String::New("corrupted or already freed cursor")));
+ TRI_vocbase_t* vocbase = GetContextVocBase();
+ if (!vocbase) {
+ return scope.Close(v8::ThrowException(v8::String::New("corrupted vocbase")));
}
- if (!cursor->_shadow) {
- cursor->_shadow = TRI_StoreShadowData((TRI_shadow_store_t*) cursor->_vocbase->_cursors,
- (const void* const) cursor);
+ bool result = TRI_PersistDataShadowData(vocbase->_cursors, UnwrapQueryCursor(argv.Holder()));
+ if (result) {
+ return scope.Close(v8::True());
}
- TRI_UnlockQueryCursor(cursor);
- return scope.Close(v8::True());
+ return scope.Close(v8::ThrowException(v8::String::New("corrupted or already freed cursor")));
}
////////////////////////////////////////////////////////////////////////////////
@@ -3231,101 +2701,93 @@ static v8::Handle JS_PersistQueryCursor (v8::Arguments const& argv) {
static v8::Handle JS_GetRowsQueryCursor (v8::Arguments const& argv) {
v8::HandleScope scope;
- v8::TryCatch tryCatch;
if (argv.Length() != 0) {
return scope.Close(v8::ThrowException(v8::String::New("usage: getRows()")));
}
-
- v8::Handle self = argv.Holder();
- TRI_query_cursor_t* cursor = UnwrapQueryCursor(self);
-
- if (!cursor) {
- return scope.Close(v8::ThrowException(v8::String::New("corrupted or already freed cursor")));
- }
- v8::Handle result = v8::Array::New();
-
- TRI_LockQueryCursor(cursor);
- if (cursor->_deleted) {
- TRI_UnlockQueryCursor(cursor);
- return scope.Close(v8::ThrowException(v8::String::New("corrupted or already freed cursor")));
+ TRI_vocbase_t* vocbase = GetContextVocBase();
+ if (!vocbase) {
+ return scope.Close(v8::ThrowException(v8::String::New("corrupted vocbase")));
}
-
+
+ bool result = false;
TRI_js_exec_context_t context = NULL;
- bool ok = true;
-
- // exceptions must be caught in the following part because we hold an exclusive
- // lock that might otherwise not be freed
- try {
- uint32_t max = cursor->getMax(cursor);
- context = TRI_CreateExecutionContext(cursor->_functionCode);
+ v8::Handle rows = v8::Array::New();
+ TRI_query_cursor_t* cursor = (TRI_query_cursor_t*)
+ TRI_BeginUsageDataShadowData(vocbase->_cursors, UnwrapQueryCursor(argv.Holder()));
- if (context) {
- for (uint32_t i = 0; i < max; i++) {
- TRI_rc_result_t* next = cursor->next(cursor);
- if (!next) {
- break;
- }
+ if (cursor) {
+ TRI_LockQueryCursor(cursor);
+
+ // exceptions must be caught in the following part because we hold an exclusive
+ // lock that might otherwise not be freed
+ try {
+ uint32_t max = cursor->getBatchSize(cursor);
+ context = TRI_CreateExecutionContext(cursor->_functionCode);
+
+ if (context) {
+ for (uint32_t i = 0; i < max; ++i) {
+ TRI_rc_result_t* next = cursor->next(cursor);
+ if (!next) {
+ break;
+ }
- TRI_DefineSelectExecutionContext(context, next);
- v8::Handle value;
- ok = TRI_ExecuteExecutionContext(context, (void*) &value);
- if (ok) {
- result->Set(i, value);
+ TRI_DefineSelectExecutionContext(context, next);
+ v8::Handle value;
+ if (TRI_ExecuteExecutionContext(context, (void*) &value)) {
+ rows->Set(i, value);
+ }
}
+ result = true;
}
}
- }
- catch (...) {
- }
-
- if (context) {
- TRI_FreeExecutionContext(context);
- }
- // always free lock
- TRI_UnlockQueryCursor(cursor);
+ catch (...) {
+ }
+
+ TRI_UnlockQueryCursor(cursor);
+
+ TRI_EndUsageDataShadowData(vocbase->_cursors, cursor);
- if (!ok) {
- if (tryCatch.HasCaught()) {
- return scope.Close(v8::ThrowException(tryCatch.Exception()));
+ if (context) {
+ TRI_FreeExecutionContext(context);
}
- else {
- return scope.Close(v8::ThrowException(v8::String::New("cannot convert to JavaScript")));
+
+ if (result) {
+ return scope.Close(rows);
}
}
- return scope.Close(result);
+ return scope.Close(v8::ThrowException(v8::String::New("corrupted or already freed cursor")));
}
////////////////////////////////////////////////////////////////////////////////
/// @brief return max number of results per transfer for cursor
////////////////////////////////////////////////////////////////////////////////
-static v8::Handle JS_GetMaxQueryCursor (v8::Arguments const& argv) {
+static v8::Handle JS_GetBatchSizeQueryCursor (v8::Arguments const& argv) {
v8::HandleScope scope;
if (argv.Length() != 0) {
- return scope.Close(v8::ThrowException(v8::String::New("usage: getMax()")));
+ return scope.Close(v8::ThrowException(v8::String::New("usage: getBatchSize()")));
}
-
- v8::Handle self = argv.Holder();
- TRI_query_cursor_t* cursor = UnwrapQueryCursor(self);
-
- if (!cursor) {
- return scope.Close(v8::ThrowException(v8::String::New("corrupted or already freed cursor")));
- }
-
- TRI_LockQueryCursor(cursor);
- if (cursor->_deleted) {
- TRI_UnlockQueryCursor(cursor);
- return scope.Close(v8::ThrowException(v8::String::New("corrupted or already freed cursor")));
- }
-
- uint32_t max = cursor->getMax(cursor);
- TRI_UnlockQueryCursor(cursor);
- return scope.Close(v8::Number::New(max));
+ TRI_vocbase_t* vocbase = GetContextVocBase();
+ if (!vocbase) {
+ return scope.Close(v8::ThrowException(v8::String::New("corrupted vocbase")));
+ }
+
+ TRI_query_cursor_t* cursor = (TRI_query_cursor_t*)
+ TRI_BeginUsageDataShadowData(vocbase->_cursors, UnwrapQueryCursor(argv.Holder()));
+
+ if (cursor) {
+ uint32_t max = cursor->getBatchSize(cursor);
+
+ TRI_EndUsageDataShadowData(vocbase->_cursors, cursor);
+ return scope.Close(v8::Number::New(max));
+ }
+
+ return scope.Close(v8::ThrowException(v8::String::New("corrupted or already freed cursor")));
}
////////////////////////////////////////////////////////////////////////////////
@@ -3338,24 +2800,23 @@ static v8::Handle JS_HasCountQueryCursor (v8::Arguments const& argv)
if (argv.Length() != 0) {
return scope.Close(v8::ThrowException(v8::String::New("usage: hasCount()")));
}
-
- v8::Handle self = argv.Holder();
- TRI_query_cursor_t* cursor = UnwrapQueryCursor(self);
-
- if (!cursor) {
- return scope.Close(v8::ThrowException(v8::String::New("corrupted or already freed cursor")));
- }
-
- TRI_LockQueryCursor(cursor);
- if (cursor->_deleted) {
- TRI_UnlockQueryCursor(cursor);
- return scope.Close(v8::ThrowException(v8::String::New("corrupted or already freed cursor")));
- }
-
- bool hasCount = cursor->hasCount(cursor);
- TRI_UnlockQueryCursor(cursor);
- return scope.Close(hasCount ? v8::True() : v8::False());
+ TRI_vocbase_t* vocbase = GetContextVocBase();
+ if (!vocbase) {
+ return scope.Close(v8::ThrowException(v8::String::New("corrupted vocbase")));
+ }
+
+ TRI_query_cursor_t* cursor = (TRI_query_cursor_t*)
+ TRI_BeginUsageDataShadowData(vocbase->_cursors, UnwrapQueryCursor(argv.Holder()));
+
+ if (cursor) {
+ bool hasCount = cursor->hasCount(cursor);
+
+ TRI_EndUsageDataShadowData(vocbase->_cursors, cursor);
+ return scope.Close(hasCount ? v8::True() : v8::False());
+ }
+
+ return scope.Close(v8::ThrowException(v8::String::New("corrupted or already freed cursor")));
}
////////////////////////////////////////////////////////////////////////////////
@@ -3368,24 +2829,25 @@ static v8::Handle JS_HasNextQueryCursor (v8::Arguments const& argv) {
if (argv.Length() != 0) {
return scope.Close(v8::ThrowException(v8::String::New("usage: hasNext()")));
}
-
- v8::Handle self = argv.Holder();
- TRI_query_cursor_t* cursor = UnwrapQueryCursor(self);
-
- if (!cursor) {
- return scope.Close(v8::ThrowException(v8::String::New("corrupted or already freed cursor")));
- }
-
- TRI_LockQueryCursor(cursor);
- if (cursor->_deleted) {
- TRI_UnlockQueryCursor(cursor);
- return scope.Close(v8::ThrowException(v8::String::New("corrupted or already freed cursor")));
- }
-
- bool hasNext = cursor->hasNext(cursor);
- TRI_UnlockQueryCursor(cursor);
- return scope.Close(hasNext ? v8::True() : v8::False());
+ TRI_vocbase_t* vocbase = GetContextVocBase();
+ if (!vocbase) {
+ return scope.Close(v8::ThrowException(v8::String::New("corrupted vocbase")));
+ }
+
+ TRI_query_cursor_t* cursor = (TRI_query_cursor_t*)
+ TRI_BeginUsageDataShadowData(vocbase->_cursors, UnwrapQueryCursor(argv.Holder()));
+
+ if (cursor) {
+ TRI_LockQueryCursor(cursor);
+ bool hasNext = cursor->hasNext(cursor);
+ TRI_UnlockQueryCursor(cursor);
+
+ TRI_EndUsageDataShadowData(vocbase->_cursors, cursor);
+ return scope.Close(hasNext ? v8::True() : v8::False());
+ }
+
+ return scope.Close(v8::ThrowException(v8::String::New("corrupted or already freed cursor")));
}
////////////////////////////////////////////////////////////////////////////////
@@ -3488,7 +2950,7 @@ static v8::Handle JS_NextRefCursor (v8::Arguments const& argv) {
// always use the primary collection
TRI_voc_cid_t cid = cursor->_context->_primary->base._cid;
TRI_voc_did_t did = next->_primary->_did;
- string ref = StringUtils::itoa(cid) + ":" + StringUtils::itoa(did);
+ string ref = StringUtils::itoa(cid) + TRI_DOCUMENT_HANDLE_SEPARATOR_STR + StringUtils::itoa(did);
return scope.Close(v8::String::New(ref.c_str()));
}
@@ -4732,7 +4194,7 @@ static v8::Handle JS_ReplaceVocbaseCol (v8::Arguments const& argv) {
char* cidStr = TRI_StringUInt64(collection->base._cid);
char* didStr = TRI_StringUInt64(did);
- string name = cidStr + string(":") + didStr;
+ string name = cidStr + string(TRI_DOCUMENT_HANDLE_SEPARATOR_STR) + didStr;
TRI_FreeString(didStr);
TRI_FreeString(cidStr);
@@ -4823,7 +4285,7 @@ static v8::Handle JS_SaveVocbaseCol (v8::Arguments const& argv) {
char* cidStr = TRI_StringUInt64(collection->base._cid);
char* didStr = TRI_StringUInt64(did);
- string name = cidStr + string(":") + didStr;
+ string name = cidStr + string(TRI_DOCUMENT_HANDLE_SEPARATOR_STR) + didStr;
TRI_FreeString(didStr);
TRI_FreeString(cidStr);
@@ -4984,7 +4446,7 @@ static v8::Handle JS_SaveEdgesCol (v8::Arguments const& argv) {
char* cidStr = TRI_StringUInt64(collection->base._cid);
char* didStr = TRI_StringUInt64(did);
- string name = cidStr + string(":") + didStr;
+ string name = cidStr + string(TRI_DOCUMENT_HANDLE_SEPARATOR_STR) + didStr;
TRI_FreeString(didStr);
TRI_FreeString(cidStr);
@@ -5670,7 +5132,9 @@ void TRI_InitV8VocBridge (v8::Handle context, TRI_vocbase_t* vocbas
}
// create the regular expressions
- if (regcomp(&v8g->DocumentIdRegex, "([0-9][0-9]*):([0-9][0-9]*)", REG_ICASE | REG_EXTENDED) != 0) {
+ string expr = "([0-9][0-9]*)" + string(TRI_DOCUMENT_HANDLE_SEPARATOR_STR) + "([0-9][0-9]*)";
+
+ if (regcomp(&v8g->DocumentIdRegex, expr.c_str(), REG_ICASE | REG_EXTENDED) != 0) {
LOG_FATAL("cannot compile regular expression");
exit(EXIT_FAILURE);
}
@@ -5707,8 +5171,8 @@ void TRI_InitV8VocBridge (v8::Handle context, TRI_vocbase_t* vocbas
v8::Handle EnsureUniqueConstraintFuncName = v8::Persistent::New(v8::String::New("ensureUniqueConstraint"));
v8::Handle ExecuteFuncName = v8::Persistent::New(v8::String::New("execute"));
v8::Handle FiguresFuncName = v8::Persistent::New(v8::String::New("figures"));
+ v8::Handle GetBatchSizeFuncName = v8::Persistent::New(v8::String::New("getBatchSize"));
v8::Handle GetIndexesFuncName = v8::Persistent::New(v8::String::New("getIndexes"));
- v8::Handle GetMaxFuncName = v8::Persistent::New(v8::String::New("getMax"));
v8::Handle GetRowsFuncName = v8::Persistent::New(v8::String::New("getRows"));
v8::Handle HasCountFuncName = v8::Persistent::New(v8::String::New("hasCount"));
v8::Handle HasNextFuncName = v8::Persistent::New(v8::String::New("hasNext"));
@@ -5936,43 +5400,6 @@ void TRI_InitV8VocBridge (v8::Handle context, TRI_vocbase_t* vocbas
ft->GetFunction());
/* DEPRECATED END */
- // .............................................................................
- // generate the query template template
- // .............................................................................
-
- ft = v8::FunctionTemplate::New();
- ft->SetClassName(v8::String::New("AvocadoQueryTemplate"));
-
- rt = ft->InstanceTemplate();
- rt->SetInternalFieldCount(2);
-
- rt->Set(DisposeFuncName, v8::FunctionTemplate::New(JS_DisposeQueryTemplate));
-// rt->Set(IdFuncName, v8::FunctionTemplate::New(JS_IdQueryTemplate));
-
- v8g->QueryTemplateTempl = v8::Persistent::New(rt);
-
- // must come after SetInternalFieldCount
- context->Global()->Set(v8::String::New("AvocadoQueryTemplate"),
- ft->GetFunction());
-
- // .............................................................................
- // generate the query instance template
- // .............................................................................
-
-// ft = v8::FunctionTemplate::New();
-// ft->SetClassName(v8::String::New("AvocadoQueryInstance"));
-
-// rt = ft->InstanceTemplate();
-// rt->SetInternalFieldCount(2);
-
-// rt->Set(ExecuteFuncName, v8::FunctionTemplate::New(JS_ExecuteQueryInstance));
-
-// v8g->QueryInstanceTempl = v8::Persistent::New(rt);
-
- // must come after SetInternalFieldCount
-// context->Global()->Set(v8::String::New("AvocadoQueryInstance"),
-// ft->GetFunction());
-
// .............................................................................
// generate the query error template
// .............................................................................
@@ -6001,7 +5428,7 @@ void TRI_InitV8VocBridge (v8::Handle context, TRI_vocbase_t* vocbas
rt->Set(CountFuncName, v8::FunctionTemplate::New(JS_CountQueryCursor));
rt->Set(DisposeFuncName, v8::FunctionTemplate::New(JS_DisposeQueryCursor));
- rt->Set(GetMaxFuncName, v8::FunctionTemplate::New(JS_GetMaxQueryCursor));
+ rt->Set(GetBatchSizeFuncName, v8::FunctionTemplate::New(JS_GetBatchSizeQueryCursor));
rt->Set(GetRowsFuncName, v8::FunctionTemplate::New(JS_GetRowsQueryCursor));
rt->Set(HasCountFuncName, v8::FunctionTemplate::New(JS_HasCountQueryCursor));
rt->Set(HasNextFuncName, v8::FunctionTemplate::New(JS_HasNextQueryCursor));
@@ -6037,9 +5464,6 @@ void TRI_InitV8VocBridge (v8::Handle context, TRI_vocbase_t* vocbas
context->Global()->Set(v8::String::New("AvocadoCursor"),
ft->GetFunction());
-
-
-
// .............................................................................
// generate the skip list operator template
// .............................................................................
@@ -6124,9 +5548,6 @@ void TRI_InitV8VocBridge (v8::Handle context, TRI_vocbase_t* vocbas
v8::ReadOnly);
/* DEPRECATED END */
-// context->Global()->Set(v8::String::New("AQL_STORED_STATEMENT"),
-// v8::FunctionTemplate::New(JS_StoredStatementAql)->GetFunction(),
-// v8::ReadOnly);
context->Global()->Set(v8::String::New("AQL_PARSE"),
v8::FunctionTemplate::New(JS_ParseAql)->GetFunction(),
v8::ReadOnly);
diff --git a/VocBase/compactor.c b/VocBase/compactor.c
index 1b013bbb98..c0fdb4141f 100644
--- a/VocBase/compactor.c
+++ b/VocBase/compactor.c
@@ -471,10 +471,7 @@ static void CleanupShadows (TRI_vocbase_t* const vocbase) {
LOG_TRACE("cleaning shadows");
// clean unused cursors
- TRI_CleanupShadowData(vocbase->_cursors, SHADOW_CURSOR_MAX_AGE);
-
- // clean unused statements
-// TRI_CleanupShadowDocuments(vocbase->_statements, SHADOW_STATEMENT_MAX_AGE);
+ TRI_CleanupShadowData(vocbase->_cursors, SHADOW_CURSOR_MAX_AGE, false);
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/VocBase/query-base.c b/VocBase/query-base.c
index 103f15255d..1763585778 100644
--- a/VocBase/query-base.c
+++ b/VocBase/query-base.c
@@ -365,122 +365,7 @@ TRI_bind_parameter_t* TRI_CreateBindParameter (const char* name,
// -----------------------------------------------------------------------------
// --SECTION-- query template
// -----------------------------------------------------------------------------
-/*
-////////////////////////////////////////////////////////////////////////////////
-/// @brief decrease the refcount of a template
-////////////////////////////////////////////////////////////////////////////////
-void TRI_DecreaseRefCountQueryTemplate (TRI_query_template_t* const template_) {
- assert(template_);
-// assert(template_->_shadow);
-
- TRI_LockQueryTemplate(template_);
-// TRI_DecreaseRefCountShadowData(template_->_vocbase->_templates,
-// template_->_shadow->_id);
-
- TRI_UnlockQueryTemplate(template_);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-/// @brief increase the refcount of a template
-////////////////////////////////////////////////////////////////////////////////
-
-void TRI_IncreaseRefCountQueryTemplate (TRI_query_template_t* const template_) {
- assert(template_);
-// assert(template_->_shadow);
-
- TRI_LockQueryTemplate(template_);
-// TRI_IncreaseRefCountShadowData(template_->_vocbase->_templates,
-// template_->_shadow->_id);
-
- TRI_UnlockQueryTemplate(template_);
-}
-*/
-////////////////////////////////////////////////////////////////////////////////
-/// @brief exclusively lock a query template
-////////////////////////////////////////////////////////////////////////////////
-
-void TRI_LockQueryTemplate (TRI_query_template_t* const template_) {
- assert(template_);
-
- TRI_LockMutex(&template_->_lock);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-/// @brief unlock a query template
-////////////////////////////////////////////////////////////////////////////////
-
-void TRI_UnlockQueryTemplate (TRI_query_template_t* const template_) {
- assert(template_);
-
- TRI_UnlockMutex(&template_->_lock);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-/// @brief Free a template based on its shadow
-////////////////////////////////////////////////////////////////////////////////
-/*
-void TRI_FreeShadowQueryTemplate (TRI_shadow_document_store_t* store,
- TRI_shadow_document_t* shadow) {
- TRI_query_template_t* template_ = (TRI_query_template_t*) shadow->_base->_data;
-
- if (!template_) {
- return;
- }
-
- TRI_FreeQueryTemplate(template_);
-}
-*/
-/*
-// TODO: move to own file
-void* TRI_CreateShadowQueryTemplate (TRI_shadow_document_store_t* store, TRI_doc_collection_t* collection, TRI_doc_mptr_t const* document) {
- TRI_json_t* json;
- TRI_json_t* query;
- char* queryString;
-
- LOG_DEBUG("creating shadow for %lu", (unsigned long) document->_did);
-
- json = TRI_JsonShapedJson(collection->_shaper, &document->_document);
- if (!json) {
- return NULL;
- }
-
- query = TRI_LookupArrayJson(json, "query");
- if (!query) {
-// TODO: fix this
-// TRI_FreeJson(json);
- return NULL;
- }
-
- if (query->_type != TRI_JSON_STRING || !query->_value._string.data) {
-// TODO: fix this
-// TRI_FreeJson(json);
- return NULL;
- }
-
- queryString = query->_value._string.data;
- assert(queryString);
-
-
-
-// TODO: fix this
-// TRI_FreeJson(json);
-
- // TODO: fix
- return NULL;
-}
-bool TRI_VerifyShadowQueryTemplate (TRI_shadow_document_store_t* store, TRI_doc_collection_t* collection, TRI_doc_mptr_t const* document, void* shadow) {
- return true;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-/// @brief create shadow data store for templates
-////////////////////////////////////////////////////////////////////////////////
-
-TRI_shadow_document_store_t* TRI_CreateShadowsQueryTemplate (void) {
- return TRI_CreateShadowDocumentStore(&TRI_CreateShadowQueryTemplate, &TRI_VerifyShadowQueryTemplate, &TRI_FreeShadowQueryTemplate);
-}
-*/
////////////////////////////////////////////////////////////////////////////////
/// @brief Initialize the structs contained in a query template and perform
/// some basic optimizations and type detections
@@ -528,8 +413,7 @@ bool TRI_AddBindParameterQueryTemplate (TRI_query_template_t* const template_,
////////////////////////////////////////////////////////////////////////////////
TRI_query_template_t* TRI_CreateQueryTemplate (const char* queryString,
- const TRI_vocbase_t* const vocbase,
- const TRI_query_template_type_e type) {
+ const TRI_vocbase_t* const vocbase) {
TRI_query_template_t* template_;
assert(queryString);
@@ -553,9 +437,6 @@ TRI_query_template_t* TRI_CreateQueryTemplate (const char* queryString,
return NULL;
}
- template_->_type = type;;
- template_->_shadow = NULL;
-
template_->_vocbase = (TRI_vocbase_t*) vocbase;
TRI_InitQueryError(&template_->_error);
diff --git a/VocBase/query-base.h b/VocBase/query-base.h
index aa44faac9e..bd09f0fbdd 100644
--- a/VocBase/query-base.h
+++ b/VocBase/query-base.h
@@ -36,7 +36,6 @@
#include
#include "VocBase/vocbase.h"
-#include "VocBase/shadow-data.h"
#include "VocBase/query-node.h"
#include "VocBase/query-error.h"
@@ -120,24 +119,6 @@ TRI_bind_parameter_t* TRI_CreateBindParameter (const char*, const TRI_json_t*);
// --SECTION-- query template
// -----------------------------------------------------------------------------
-////////////////////////////////////////////////////////////////////////////////
-/// @brief query template types
-///
-/// There are two types of templates:
-/// - QUERY_TEMPLATE_TRANSIENT: these templates only exist for one query and are
-/// disposed automatically when the query execution is finished
-/// - QUERY_TEMPLATE_PERSISTENT: these templates are created on the server and
-/// can be shared for multiple executions. they are disposed automatically
-/// if they are not referenced anymore and have not been used for a certain
-/// period of time (garbage collection)
-////////////////////////////////////////////////////////////////////////////////
-
-typedef enum {
- QUERY_TEMPLATE_TRANSIENT,
- QUERY_TEMPLATE_PERSISTENT
-}
-TRI_query_template_type_e;
-
////////////////////////////////////////////////////////////////////////////////
/// @brief lexer state
///
@@ -173,8 +154,6 @@ TRI_query_parser_t;
////////////////////////////////////////////////////////////////////////////////
typedef struct TRI_query_template_s {
- TRI_query_template_type_e _type;
- TRI_shadow_document_t* _shadow;
TRI_vocbase_t* _vocbase;
char* _queryString;
QL_ast_query_t* _query;
@@ -192,47 +171,6 @@ typedef struct TRI_query_template_s {
}
TRI_query_template_t;
-////////////////////////////////////////////////////////////////////////////////
-/// @brief Free a template based on its shadow
-////////////////////////////////////////////////////////////////////////////////
-
-void TRI_FreeShadowQueryTemplate (TRI_shadow_document_store_t*,
- TRI_shadow_document_t*);
-
-////////////////////////////////////////////////////////////////////////////////
-/// @brief decrease the refcount of a template
-////////////////////////////////////////////////////////////////////////////////
-
-void TRI_DecreaseRefCountQueryTemplate (TRI_query_template_t* const);
-
-////////////////////////////////////////////////////////////////////////////////
-/// @brief increase the refcount of a template
-////////////////////////////////////////////////////////////////////////////////
-
-void TRI_IncreaseRefCountQueryTemplate (TRI_query_template_t* const);
-
-////////////////////////////////////////////////////////////////////////////////
-/// @brief exclusively lock a query template
-////////////////////////////////////////////////////////////////////////////////
-
-void TRI_LockQueryTemplate (TRI_query_template_t* const);
-
-////////////////////////////////////////////////////////////////////////////////
-/// @brief unlock a query template
-////////////////////////////////////////////////////////////////////////////////
-
-void TRI_UnlockQueryTemplate (TRI_query_template_t* const);
-
-// TODO: move to own file
-void* TRI_CreateShadowQueryTemplate (TRI_shadow_document_store_t*, TRI_doc_collection_t*, TRI_doc_mptr_t const*);
-bool TRI_VerifyShadowQueryTemplate (TRI_shadow_document_store_t*, TRI_doc_collection_t*, TRI_doc_mptr_t const*, void*);
-
-////////////////////////////////////////////////////////////////////////////////
-/// @brief create shadow data store for templates
-////////////////////////////////////////////////////////////////////////////////
-
-TRI_shadow_document_store_t* TRI_CreateShadowsQueryTemplate (void);
-
////////////////////////////////////////////////////////////////////////////////
/// @brief Initialize the structs contained in a query template and perform
/// some basic optimizations and type detections
@@ -252,8 +190,7 @@ bool TRI_AddBindParameterQueryTemplate (TRI_query_template_t* const,
////////////////////////////////////////////////////////////////////////////////
TRI_query_template_t* TRI_CreateQueryTemplate (const char*,
- const TRI_vocbase_t* const,
- const TRI_query_template_type_e);
+ const TRI_vocbase_t* const);
////////////////////////////////////////////////////////////////////////////////
/// @brief Free a query template
diff --git a/VocBase/query-cursor.c b/VocBase/query-cursor.c
index b11bc2e5c4..e3c504c760 100644
--- a/VocBase/query-cursor.c
+++ b/VocBase/query-cursor.c
@@ -27,7 +27,6 @@
#include "VocBase/query-cursor.h"
#include "VocBase/query-context.h"
-#include "VocBase/shadow-data.h"
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup VocBase
@@ -85,7 +84,7 @@ static bool HasCountQueryCursor (const TRI_query_cursor_t* const cursor) {
/// @brief returns the maximum number of results per transfer
////////////////////////////////////////////////////////////////////////////////
-static uint32_t GetMaxQueryCursor (const TRI_query_cursor_t* const cursor) {
+static uint32_t GetBatchSizeQueryCursor (const TRI_query_cursor_t* const cursor) {
return cursor->_batchSize;
}
@@ -93,7 +92,7 @@ static uint32_t GetMaxQueryCursor (const TRI_query_cursor_t* const cursor) {
/// @brief frees a cursor
////////////////////////////////////////////////////////////////////////////////
-static void FreeQueryCursor (TRI_query_cursor_t* cursor) {
+void TRI_FreeQueryCursor (TRI_query_cursor_t* cursor) {
assert(cursor->_functionCode);
TRI_Free(cursor->_functionCode);
@@ -136,7 +135,6 @@ TRI_query_cursor_t* TRI_CreateQueryCursor (TRI_query_instance_t* const instance,
return NULL;
}
- cursor->_shadow = NULL;
cursor->_hasCount = doCount;
cursor->_batchSize = batchSize;
cursor->_deleted = false;
@@ -148,8 +146,8 @@ TRI_query_cursor_t* TRI_CreateQueryCursor (TRI_query_instance_t* const instance,
cursor->next = NextQueryCursor;
cursor->hasNext = HasNextQueryCursor;
cursor->hasCount = HasCountQueryCursor;
- cursor->getMax = GetMaxQueryCursor;
- cursor->free = FreeQueryCursor;
+ cursor->getBatchSize = GetBatchSizeQueryCursor;
+ cursor->free = TRI_FreeQueryCursor;
TRI_InitMutex(&cursor->_lock);
TRI_InitVectorPointer(&cursor->_containers);
@@ -157,27 +155,11 @@ TRI_query_cursor_t* TRI_CreateQueryCursor (TRI_query_instance_t* const instance,
return cursor;
}
-////////////////////////////////////////////////////////////////////////////////
-/// @brief Free a cursor based on its shadow
-////////////////////////////////////////////////////////////////////////////////
-
-void TRI_FreeShadowQueryCursor (TRI_shadow_store_t* store, TRI_shadow_t* shadow) {
- TRI_query_cursor_t* cursor = (TRI_query_cursor_t*) shadow->_data;
-
- if (!cursor) {
- return;
- }
-
- FreeQueryCursor(cursor);
-}
-
////////////////////////////////////////////////////////////////////////////////
/// @brief exclusively lock a query cursor
////////////////////////////////////////////////////////////////////////////////
void TRI_LockQueryCursor (TRI_query_cursor_t* const cursor) {
- assert(cursor);
-
TRI_LockMutex(&cursor->_lock);
}
@@ -191,6 +173,16 @@ void TRI_UnlockQueryCursor (TRI_query_cursor_t* const cursor) {
TRI_UnlockMutex(&cursor->_lock);
}
+////////////////////////////////////////////////////////////////////////////////
+/// @brief Free a cursor based on its shadow data pointer
+////////////////////////////////////////////////////////////////////////////////
+
+void TRI_FreeShadowQueryCursor (void* data) {
+ TRI_query_cursor_t* cursor = (TRI_query_cursor_t*) data;
+
+ TRI_FreeQueryCursor(cursor);
+}
+
////////////////////////////////////////////////////////////////////////////////
/// @brief create shadow data store for cursors
////////////////////////////////////////////////////////////////////////////////
diff --git a/VocBase/query-cursor.h b/VocBase/query-cursor.h
index 0c26429198..2da20a985e 100644
--- a/VocBase/query-cursor.h
+++ b/VocBase/query-cursor.h
@@ -48,7 +48,6 @@ extern "C" {
typedef struct TRI_query_cursor_s {
TRI_vocbase_t* _vocbase;
- TRI_shadow_t* _shadow;
char* _functionCode;
bool _hasCount;
uint32_t _batchSize;
@@ -64,11 +63,17 @@ typedef struct TRI_query_cursor_s {
TRI_rc_result_t* (*next)(struct TRI_query_cursor_s* const);
bool (*hasNext)(const struct TRI_query_cursor_s* const);
bool (*hasCount)(const struct TRI_query_cursor_s* const);
- uint32_t (*getMax)(const struct TRI_query_cursor_s* const);
+ uint32_t (*getBatchSize)(const struct TRI_query_cursor_s* const);
}
TRI_query_cursor_t;
+////////////////////////////////////////////////////////////////////////////////
+/// @brief frees a cursor
+////////////////////////////////////////////////////////////////////////////////
+
+void TRI_FreeQueryCursor (TRI_query_cursor_t*);
+
////////////////////////////////////////////////////////////////////////////////
/// @brief create a cursor
////////////////////////////////////////////////////////////////////////////////
@@ -78,12 +83,6 @@ TRI_query_cursor_t* TRI_CreateQueryCursor (TRI_query_instance_t* const,
const bool,
const uint32_t);
-////////////////////////////////////////////////////////////////////////////////
-/// @brief Free a cursor based on its shadow
-////////////////////////////////////////////////////////////////////////////////
-
-void TRI_FreeShadowQueryCursor (TRI_shadow_store_t*, TRI_shadow_t*);
-
////////////////////////////////////////////////////////////////////////////////
/// @brief exclusively lock a query cursor
////////////////////////////////////////////////////////////////////////////////
@@ -96,6 +95,12 @@ void TRI_LockQueryCursor (TRI_query_cursor_t* const);
void TRI_UnlockQueryCursor (TRI_query_cursor_t* const);
+////////////////////////////////////////////////////////////////////////////////
+/// @brief Free a cursor based on its data pointer
+////////////////////////////////////////////////////////////////////////////////
+
+void TRI_FreeShadowQueryCursor (void*);
+
////////////////////////////////////////////////////////////////////////////////
/// @brief create shadow data store for cursors
////////////////////////////////////////////////////////////////////////////////
diff --git a/VocBase/shadow-data.c b/VocBase/shadow-data.c
index c925a63a8c..dbad841a65 100644
--- a/VocBase/shadow-data.c
+++ b/VocBase/shadow-data.c
@@ -54,7 +54,7 @@ static inline void UpdateTimestampShadow (TRI_shadow_t* const shadow) {
/// @brief init a shadow data structure
////////////////////////////////////////////////////////////////////////////////
-static TRI_shadow_t* CreateShadow (const void* const element) {
+static TRI_shadow_t* CreateShadow (const void* const data) {
TRI_shadow_t* shadow = (TRI_shadow_t*) TRI_Allocate(sizeof(TRI_shadow_t));
if (!shadow) {
@@ -62,33 +62,81 @@ static TRI_shadow_t* CreateShadow (const void* const element) {
}
shadow->_rc = 1;
- shadow->_data = (void*) element;
+ shadow->_data = (void*) data;
shadow->_id = TRI_NewTickVocBase();
+ shadow->_deleted = false;
+ shadow->_type = SHADOW_TRANSIENT;
UpdateTimestampShadow(shadow);
+
+ LOG_TRACE("created shadow %p with data ptr %p and id %lu",
+ shadow,
+ data,
+ (unsigned long) shadow->_id);
return shadow;
}
////////////////////////////////////////////////////////////////////////////////
-/// @brief hashes an element
+/// @brief hashes an element in the ids index
////////////////////////////////////////////////////////////////////////////////
-static uint64_t HashShadowElement (TRI_associative_pointer_t* array, void const* e) {
+static uint64_t HashKeyId (TRI_associative_pointer_t* array, void const* k) {
+ TRI_shadow_id key = *((TRI_shadow_id*) k);
+
+ return (uint64_t) key;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief hashes an element in the ids index
+////////////////////////////////////////////////////////////////////////////////
+
+static uint64_t HashElementId (TRI_associative_pointer_t* array, void const* e) {
TRI_shadow_t const* element = e;
- return element->_id;
+ return (uint64_t) element->_id;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief tests if two elements are equal
////////////////////////////////////////////////////////////////////////////////
-static bool EqualShadowElement (TRI_associative_pointer_t* array, void const* l, void const* r) {
- TRI_shadow_t const* left = l;
- TRI_shadow_t const* right = r;
+static bool EqualKeyId (TRI_associative_pointer_t* array, void const* k, void const* e) {
+ TRI_shadow_t const* element = e;
+ TRI_shadow_id key = *((TRI_shadow_id*) k);
- return left->_id == right->_id;
+ return (key == element->_id);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief hashes an element in the pointers index
+////////////////////////////////////////////////////////////////////////////////
+
+static uint64_t HashKeyData (TRI_associative_pointer_t* array, void const* k) {
+ uint64_t key = 0;
+
+ key = (uint64_t) k;
+ return key;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief hashes an element in the pointers index
+////////////////////////////////////////////////////////////////////////////////
+
+static uint64_t HashElementData (TRI_associative_pointer_t* array, void const* e) {
+ TRI_shadow_t const* element = e;
+
+ return (uint64_t) element->_data;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief tests if two elements are equal
+////////////////////////////////////////////////////////////////////////////////
+
+static bool EqualKeyData (TRI_associative_pointer_t* array, void const* k, void const* e) {
+ TRI_shadow_t const* element = e;
+
+ return ((uint64_t) k == (uint64_t) element->_data);
}
////////////////////////////////////////////////////////////////////////////////
@@ -108,16 +156,22 @@ static bool EqualShadowElement (TRI_associative_pointer_t* array, void const* l,
/// @brief creates a shadow data storage
////////////////////////////////////////////////////////////////////////////////
-TRI_shadow_store_t* TRI_CreateShadowStore (void (*destroy) (TRI_shadow_store_t*, TRI_shadow_t*)) {
+TRI_shadow_store_t* TRI_CreateShadowStore (void (*destroy) (void*)) {
TRI_shadow_store_t* store =
(TRI_shadow_store_t*) TRI_Allocate(sizeof(TRI_shadow_store_t));
if (store) {
- TRI_InitAssociativePointer(&store->_index,
- NULL,
- HashShadowElement,
- NULL,
- EqualShadowElement);
+ TRI_InitAssociativePointer(&store->_ids,
+ HashKeyId,
+ HashElementId,
+ EqualKeyId,
+ NULL);
+
+ TRI_InitAssociativePointer(&store->_pointers,
+ HashKeyData,
+ HashElementData,
+ EqualKeyData,
+ NULL);
store->destroyShadow = destroy;
@@ -129,50 +183,22 @@ TRI_shadow_store_t* TRI_CreateShadowStore (void (*destroy) (TRI_shadow_store_t*,
////////////////////////////////////////////////////////////////////////////////
/// @brief destroys a shadow data storage
+///
+/// Note: all remaining shadows will be destroyed
////////////////////////////////////////////////////////////////////////////////
void TRI_FreeShadowStore (TRI_shadow_store_t* const store) {
assert(store);
+ // force deletion of all remaining shadows
+ TRI_CleanupShadowData(store, 0, true);
+
TRI_DestroyMutex(&store->_lock);
- TRI_DestroyAssociativePointer(&store->_index);
+ TRI_DestroyAssociativePointer(&store->_ids);
+ TRI_DestroyAssociativePointer(&store->_pointers);
TRI_Free(store);
}
-////////////////////////////////////////////////////////////////////////////////
-/// @brief Update the refcount of a shadow data element (increase or decrease)
-////////////////////////////////////////////////////////////////////////////////
-
-static bool UpdateRefCountShadowData (TRI_shadow_store_t* const store,
- const TRI_shadow_id id,
- const bool increase) {
- TRI_shadow_t* shadow;
- TRI_shadow_t search;
- union { TRI_shadow_t* s; TRI_shadow_t const* c; } cnv;
-
- assert(store);
-
- TRI_LockMutex(&store->_lock);
-
- search._id = id;
- cnv.c = (TRI_shadow_t*) TRI_LookupByElementAssociativePointer(&store->_index,
- &search);
- shadow = cnv.s;
-
- if (shadow) {
- if (increase) {
- ++shadow->_rc;
- }
- else {
- --shadow->_rc;
- }
- }
-
- TRI_UnlockMutex(&store->_lock);
-
- return (shadow != NULL);
-}
-
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
@@ -187,10 +213,304 @@ static bool UpdateRefCountShadowData (TRI_shadow_store_t* const store,
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
-/// @brief enumerate all shadows and remove them if expired
+/// @brief look up a shadow in the index using its data pointer and return
+/// its id
+////////////////////////////////////////////////////////////////////////////////
+
+TRI_shadow_id TRI_GetIdDataShadowData (TRI_shadow_store_t* const store,
+ const void* const data) {
+ TRI_shadow_t* shadow;
+ TRI_shadow_id id = 0;
+
+ assert(store);
+
+ if (data) {
+ TRI_LockMutex(&store->_lock);
+ shadow = (TRI_shadow_t*) TRI_LookupByKeyAssociativePointer(&store->_pointers, data);
+
+ if (shadow && !shadow->_deleted) {
+ id = shadow->_id;
+ UpdateTimestampShadow(shadow);
+ }
+
+ TRI_UnlockMutex(&store->_lock);
+ }
+
+ return id;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief look up a shadow in the index using its data pointer
+///
+/// If the shadow is found, this will return the data pointer, NULL otherwise.
+/// When the shadow is found, its refcount will also be increased by one
+////////////////////////////////////////////////////////////////////////////////
+
+void* TRI_BeginUsageDataShadowData (TRI_shadow_store_t* const store,
+ const void* const data) {
+ TRI_shadow_t* shadow;
+
+ assert(store);
+
+ if (!data) {
+ return NULL;
+ }
+
+ TRI_LockMutex(&store->_lock);
+ shadow = (TRI_shadow_t*) TRI_LookupByKeyAssociativePointer(&store->_pointers, data);
+
+ if (shadow && !shadow->_deleted) {
+ LOG_TRACE("increasing refcount for shadow %p with data ptr %p and id %lu",
+ shadow,
+ shadow->_data,
+ (unsigned long) shadow->_id);
+
+ ++shadow->_rc;
+ UpdateTimestampShadow(shadow);
+ TRI_UnlockMutex(&store->_lock);
+ return shadow->_data;
+ }
+
+ TRI_UnlockMutex(&store->_lock);
+ return NULL;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief look up a shadow in the index using its id
+///
+/// If the shadow is found, this will return the data pointer, NULL otherwise.
+/// When the shadow is found, its refcount will also be increased by one
+////////////////////////////////////////////////////////////////////////////////
+
+void* TRI_BeginUsageIdShadowData (TRI_shadow_store_t* const store,
+ const TRI_shadow_id id) {
+ TRI_shadow_t* shadow;
+
+ assert(store);
+
+ TRI_LockMutex(&store->_lock);
+ shadow = (TRI_shadow_t*) TRI_LookupByKeyAssociativePointer(&store->_ids, (void const*) &id);
+
+ if (shadow && !shadow->_deleted) {
+ LOG_TRACE("increasing refcount for shadow %p with data ptr %p and id %lu",
+ shadow,
+ shadow->_data,
+ (unsigned long) shadow->_id);
+
+ ++shadow->_rc;
+ UpdateTimestampShadow(shadow);
+ TRI_UnlockMutex(&store->_lock);
+ return shadow->_data;
+ }
+
+ TRI_UnlockMutex(&store->_lock);
+ return NULL;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief look up a shadow in the index using its data pointer
+///
+/// If the shadow is found, its refcount will be decreased by one.
+/// If the refcount is 0 and the shadow is of type SHADOW_TRANSIENT, the shadow
+/// object will be destroyed.
+////////////////////////////////////////////////////////////////////////////////
+
+void TRI_EndUsageDataShadowData (TRI_shadow_store_t* const store,
+ const void* const data) {
+ TRI_shadow_t* shadow;
+
+ assert(store);
+
+ TRI_LockMutex(&store->_lock);
+ shadow = (TRI_shadow_t*) TRI_LookupByKeyAssociativePointer(&store->_pointers, data);
+
+ if (shadow && !shadow->_deleted) {
+ LOG_TRACE("decreasing refcount for shadow %p with data ptr %p and id %lu",
+ shadow,
+ shadow->_data,
+ (unsigned long) shadow->_id);
+
+ if (--shadow->_rc <= 0 && shadow->_type == SHADOW_TRANSIENT) {
+ LOG_TRACE("deleting shadow %p", shadow);
+
+ TRI_RemoveKeyAssociativePointer(&store->_ids, &shadow->_id);
+ TRI_RemoveKeyAssociativePointer(&store->_pointers, data);
+ store->destroyShadow(shadow->_data);
+ TRI_Free(shadow);
+ }
+ }
+
+ TRI_UnlockMutex(&store->_lock);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief look up a shadow in the index using its id
+///
+/// If the shadow is found, its refcount will be decreased by one.
+/// If the refcount is 0 and the shadow is of type SHADOW_TRANSIENT, the shadow
+/// object will be destroyed.
+////////////////////////////////////////////////////////////////////////////////
+
+void TRI_EndUsageIdShadowData (TRI_shadow_store_t* const store,
+ const TRI_shadow_id id) {
+ TRI_shadow_t* shadow;
+
+ assert(store);
+
+ TRI_LockMutex(&store->_lock);
+ shadow = (TRI_shadow_t*) TRI_LookupByKeyAssociativePointer(&store->_ids, &id);
+
+ if (shadow && !shadow->_deleted) {
+ LOG_TRACE("decreasing refcount for shadow %p with data ptr %p and id %lu",
+ shadow,
+ shadow->_data,
+ (unsigned long) shadow->_id);
+
+ if (--shadow->_rc <= 0 && shadow->_type == SHADOW_TRANSIENT) {
+ LOG_TRACE("deleting shadow %p", shadow);
+
+ TRI_RemoveKeyAssociativePointer(&store->_ids, &id);
+ TRI_RemoveKeyAssociativePointer(&store->_pointers, shadow->_data);
+ store->destroyShadow(shadow->_data);
+ TRI_Free(shadow);
+ }
+ }
+
+ TRI_UnlockMutex(&store->_lock);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief set the persistence flag for a shadow using its data pointer
+////////////////////////////////////////////////////////////////////////////////
+
+bool TRI_PersistDataShadowData (TRI_shadow_store_t* const store,
+ const void* const data) {
+ TRI_shadow_t* shadow;
+ bool result = false;
+
+ assert(store);
+
+ TRI_LockMutex(&store->_lock);
+ shadow = (TRI_shadow_t*) TRI_LookupByKeyAssociativePointer(&store->_pointers, data);
+
+ if (shadow && !shadow->_deleted) {
+ LOG_TRACE("persisting shadow %p with data ptr %p and id %lu",
+ shadow,
+ shadow->_data,
+ (unsigned long) shadow->_id);
+
+ shadow->_type = SHADOW_PERSISTENT;
+ UpdateTimestampShadow(shadow);
+ result = true;
+ }
+
+ TRI_UnlockMutex(&store->_lock);
+
+ return result;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief set the persistence flag for a shadow using its id
+////////////////////////////////////////////////////////////////////////////////
+
+bool TRI_PersistIdShadowData (TRI_shadow_store_t* const store,
+ const TRI_shadow_id id) {
+ TRI_shadow_t* shadow;
+ bool result = false;
+
+ assert(store);
+
+ TRI_LockMutex(&store->_lock);
+ shadow = (TRI_shadow_t*) TRI_LookupByKeyAssociativePointer(&store->_ids, &id);
+
+ if (shadow && !shadow->_deleted) {
+ LOG_TRACE("persisting shadow %p with data ptr %p and id %lu",
+ shadow,
+ shadow->_data,
+ (unsigned long) shadow->_id);
+
+ shadow->_type = SHADOW_PERSISTENT;
+ UpdateTimestampShadow(shadow);
+ result = true;
+ }
+
+ TRI_UnlockMutex(&store->_lock);
+
+ return result;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief set the deleted flag for a shadow using its data pointer
+////////////////////////////////////////////////////////////////////////////////
+
+bool TRI_DeleteDataShadowData (TRI_shadow_store_t* const store,
+ const void* const data) {
+ TRI_shadow_t* shadow;
+ bool found = false;
+
+ assert(store);
+
+ if (data) {
+ TRI_LockMutex(&store->_lock);
+ shadow = (TRI_shadow_t*) TRI_LookupByKeyAssociativePointer(&store->_pointers, data);
+
+ if (shadow && !shadow->_deleted) {
+ LOG_TRACE("setting deleted flag for shadow %p with data ptr %p and id %lu",
+ shadow,
+ shadow->_data,
+ (unsigned long) shadow->_id);
+
+ shadow->_deleted = true;
+ found = true;
+ }
+
+ TRI_UnlockMutex(&store->_lock);
+ }
+
+ return found;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief set the deleted flag for a shadow using its id
+////////////////////////////////////////////////////////////////////////////////
+
+bool TRI_DeleteIdShadowData (TRI_shadow_store_t* const store,
+ const TRI_shadow_id id) {
+ TRI_shadow_t* shadow;
+ bool found = false;
+
+ assert(store);
+
+ TRI_LockMutex(&store->_lock);
+ shadow = (TRI_shadow_t*) TRI_LookupByKeyAssociativePointer(&store->_ids, &id);
+
+ if (shadow && !shadow->_deleted) {
+ LOG_TRACE("setting deleted flag for shadow %p with data ptr %p and id %lu",
+ shadow,
+ shadow->_data,
+ (unsigned long) shadow->_id);
+
+ shadow->_deleted = true;
+ found = true;
+ }
+
+ TRI_UnlockMutex(&store->_lock);
+ return found;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief enumerate all shadows and remove them if
+/// - their refcount is 0 and they are transient
+/// - their refcount is 0 and they are expired
+/// - the force flag is set
+///
+/// The max age must be specified in seconds. The max age is ignored if the
+/// force flag is set. In this case all remaining shadows will be deleted
////////////////////////////////////////////////////////////////////////////////
-void TRI_CleanupShadowData (TRI_shadow_store_t* const store, const double maxAge) {
+void TRI_CleanupShadowData (TRI_shadow_store_t* const store,
+ const double maxAge,
+ const bool force) {
double compareStamp = TRI_microtime() - maxAge; // age must be specified in secs
size_t deleteCount = 0;
@@ -199,28 +519,34 @@ void TRI_CleanupShadowData (TRI_shadow_store_t* const store, const double maxAge
// loop until there's nothing to delete or
// we have deleted SHADOW_MAX_DELETE elements
- while (deleteCount++ < SHADOW_MAX_DELETE) {
+ while (deleteCount++ < SHADOW_MAX_DELETE || force) {
bool deleted = false;
size_t i;
- for (i = 0; i < store->_index._nrAlloc; i++) {
+ for (i = 0; i < store->_ids._nrAlloc; i++) {
// enum all shadows
- TRI_shadow_t* shadow = (TRI_shadow_t*) store->_index._table[i];
+ TRI_shadow_t* shadow = (TRI_shadow_t*) store->_ids._table[i];
if (!shadow) {
continue;
}
// check if shadow is unused and expired
- if (shadow->_rc <= 1 && shadow->_timestamp < compareStamp) {
- LOG_DEBUG("cleaning expired shadow %p", shadow);
- TRI_RemoveElementAssociativePointer(&store->_index, shadow);
- store->destroyShadow(store, shadow);
- TRI_Free(shadow);
+ if (shadow->_rc < 1 || force) {
+ if (shadow->_type == SHADOW_TRANSIENT ||
+ shadow->_timestamp < compareStamp ||
+ force) {
+ LOG_TRACE("cleaning expired shadow %p", shadow);
- deleted = true;
- // the remove might reposition elements in the container.
- // therefore break here and start iteration anew
- break;
+ TRI_RemoveKeyAssociativePointer(&store->_ids, &shadow->_id);
+ TRI_RemoveKeyAssociativePointer(&store->_pointers, shadow->_data);
+ store->destroyShadow(shadow->_data);
+ TRI_Free(shadow);
+
+ deleted = true;
+ // the remove might reposition elements in the container.
+ // therefore break here and start iteration anew
+ break;
+ }
}
}
@@ -234,70 +560,33 @@ void TRI_CleanupShadowData (TRI_shadow_store_t* const store, const double maxAge
TRI_UnlockMutex(&store->_lock);
}
-////////////////////////////////////////////////////////////////////////////////
-/// @brief looks up a shadow by id and decreases its refcount if it exists
-////////////////////////////////////////////////////////////////////////////////
-
-bool TRI_DecreaseRefCountShadowData (TRI_shadow_store_t* const store,
- const TRI_shadow_id id) {
- return UpdateRefCountShadowData(store, id, false);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-/// @brief looks up a shadow by id and increases its refcount if it exists
-////////////////////////////////////////////////////////////////////////////////
-
-bool TRI_IncreaseRefCountShadowData (TRI_shadow_store_t* const store,
- const TRI_shadow_id id) {
- return UpdateRefCountShadowData(store, id, true);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-/// @brief looks up a shadow by id
-////////////////////////////////////////////////////////////////////////////////
-
-TRI_shadow_t* TRI_FindShadowData (TRI_shadow_store_t* const store,
- const TRI_shadow_id id) {
- TRI_shadow_t* shadow;
- TRI_shadow_t search;
- union { TRI_shadow_t* s; TRI_shadow_t const* c; } cnv;
-
- LOG_INFO("trying to find shadow %lu", (unsigned long) id);
- assert(store);
-
- TRI_LockMutex(&store->_lock);
-
- search._id = id;
- cnv.c = (TRI_shadow_t*) TRI_LookupByElementAssociativePointer(&store->_index,
- &search);
- shadow = cnv.s;
-
- if (shadow) {
- ++shadow->_rc;
- UpdateTimestampShadow(shadow);
- }
-
- TRI_UnlockMutex(&store->_lock);
-
- // might be NULL if shadow not found
- return shadow;
-}
-
////////////////////////////////////////////////////////////////////////////////
/// @brief store a new shadow in the store
////////////////////////////////////////////////////////////////////////////////
TRI_shadow_t* TRI_StoreShadowData (TRI_shadow_store_t* const store,
- const void* const element) {
+ const void* const data) {
TRI_shadow_t* shadow;
assert(store);
- shadow = CreateShadow(element);
- LOG_INFO("inserting shadow %lu", (unsigned long) shadow->_id);
+ shadow = CreateShadow(data);
if (shadow) {
+ LOG_TRACE("storing shadow %p with data ptr %p and id %lu",
+ shadow,
+ shadow->_data,
+ (unsigned long) shadow->_id);
+
TRI_LockMutex(&store->_lock);
- TRI_InsertElementAssociativePointer(&store->_index, shadow, true);
+ if (TRI_InsertKeyAssociativePointer(&store->_ids, &shadow->_id, shadow, false)) {
+ // duplicate entry
+ LOG_INFO("storing shadow failed");
+ TRI_UnlockMutex(&store->_lock);
+ TRI_Free(shadow);
+ return NULL;
+ }
+ TRI_InsertKeyAssociativePointer(&store->_pointers, data, shadow, false);
+
TRI_UnlockMutex(&store->_lock);
}
@@ -305,61 +594,15 @@ TRI_shadow_t* TRI_StoreShadowData (TRI_shadow_store_t* const store,
return shadow;
}
-////////////////////////////////////////////////////////////////////////////////
-/// @brief decrease the refcount of a shadow without deleting it
-////////////////////////////////////////////////////////////////////////////////
-
-int64_t TRI_DecreaseRefcountShadowData (TRI_shadow_store_t* const store,
- TRI_shadow_t* const shadow) {
- int64_t result;
-
- assert(shadow);
-
- TRI_LockMutex(&store->_lock);
-
- // release the element
- result = --shadow->_rc;
-
- TRI_UnlockMutex(&store->_lock);
-
- return result;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-/// @brief releases shadow data
-////////////////////////////////////////////////////////////////////////////////
-
-bool TRI_ReleaseShadowData (TRI_shadow_store_t* const store, TRI_shadow_t* shadow) {
- bool result;
-
- assert(shadow);
-
- TRI_LockMutex(&store->_lock);
-
- // release the element
- --shadow->_rc;
-
- // need to destroy the element
- if (shadow->_rc < 1) {
- LOG_INFO("releasing shadow %lu", (unsigned long) shadow->_id);
- TRI_RemoveElementAssociativePointer(&store->_index, shadow);
- store->destroyShadow(store, shadow);
- TRI_Free(shadow);
- result = true; // object was destroyed
- }
- else {
- result = false; // object was not destroyed
- }
-
- TRI_UnlockMutex(&store->_lock);
-
- return result;
-}
-
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
+/*
+// -----------------------------------------------------------------------------
+// --SECTION-- UNUSED AND UNTESTED CODE FOLLOWS
+// -----------------------------------------------------------------------------
+
// -----------------------------------------------------------------------------
// --SECTION-- SHADOW DOCUMENTS
// -----------------------------------------------------------------------------
@@ -675,10 +918,10 @@ void TRI_CleanupShadowDocuments (TRI_shadow_document_store_t* const store, const
// release lock
TRI_UnlockMutex(&store->_base->_lock);
}
-
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
+*/
// Local Variables:
// mode: outline-minor
diff --git a/VocBase/shadow-data.h b/VocBase/shadow-data.h
index 3846eb9831..d028a6beff 100644
--- a/VocBase/shadow-data.h
+++ b/VocBase/shadow-data.h
@@ -71,6 +71,21 @@ extern "C" {
/// @{
////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+/// @brief typedef for shadow types
+///
+/// Shadows are first created with the SHADOW_TRANSIENT type. This means that
+/// the shadow will exist only temporarily and will be destroyed when the
+/// refcount gets back to 0. Shadows of type SHADOW_PERSISTENT will remain in
+/// the shadow store even with a refcount of 0 until their ttl is over.
+////////////////////////////////////////////////////////////////////////////////
+
+typedef enum {
+ SHADOW_TRANSIENT = 1,
+ SHADOW_PERSISTENT = 2
+}
+TRI_shadow_type_e;
+
////////////////////////////////////////////////////////////////////////////////
/// @brief typedef for shadow ids
////////////////////////////////////////////////////////////////////////////////
@@ -82,10 +97,12 @@ typedef TRI_voc_tick_t TRI_shadow_id;
////////////////////////////////////////////////////////////////////////////////
typedef struct TRI_shadow_s {
- TRI_shadow_id _id;
- int64_t _rc; // refcount
- double _timestamp; // creation timestamp
- void* _data;
+ TRI_shadow_id _id;
+ int64_t _rc; // refcount
+ double _timestamp; // creation timestamp
+ void* _data; // pointer to data
+ bool _deleted; // deleted flag
+ TRI_shadow_type_e _type; // transient or persistent
}
TRI_shadow_t;
@@ -95,9 +112,10 @@ TRI_shadow_t;
typedef struct TRI_shadow_store_s {
TRI_mutex_t _lock;
- TRI_associative_pointer_t _index;
+ TRI_associative_pointer_t _ids; // ids
+ TRI_associative_pointer_t _pointers; // data pointers
- void (*destroyShadow) (struct TRI_shadow_store_s*, TRI_shadow_t*);
+ void (*destroyShadow) (void*);
}
TRI_shadow_store_t;
@@ -118,10 +136,12 @@ TRI_shadow_store_t;
/// @brief creates a shadow data storage
////////////////////////////////////////////////////////////////////////////////
-TRI_shadow_store_t* TRI_CreateShadowStore (void (*destroy) (TRI_shadow_store_t*, TRI_shadow_t*));
+TRI_shadow_store_t* TRI_CreateShadowStore (void (*destroy) (void*));
////////////////////////////////////////////////////////////////////////////////
/// @brief destroys a shadow data storage
+///
+/// Note: all remaining shadows will be destroyed
////////////////////////////////////////////////////////////////////////////////
void TRI_FreeShadowStore (TRI_shadow_store_t* const store);
@@ -140,54 +160,103 @@ void TRI_FreeShadowStore (TRI_shadow_store_t* const store);
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
-/// @brief enumerate all shadows and remove them if expired
+/// @brief look up a shadow in the index using its data pointer and return
+/// its id
+////////////////////////////////////////////////////////////////////////////////
+
+TRI_shadow_id TRI_GetIdDataShadowData (TRI_shadow_store_t* const,
+ const void* const);
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief look up a shadow in the index using its data pointer
+///
+/// If the shadow is found, this will return the data pointer, NULL otherwise.
+/// When the shadow is found, its refcount will also be increased by one
+////////////////////////////////////////////////////////////////////////////////
+
+void* TRI_BeginUsageDataShadowData (TRI_shadow_store_t* const, const void* const);
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief look up a shadow in the index using its id
+///
+/// If the shadow is found, this will return the data pointer, NULL otherwise.
+/// When the shadow is found, its refcount will also be increased by one
+////////////////////////////////////////////////////////////////////////////////
+
+void* TRI_BeginUsageIdShadowData (TRI_shadow_store_t* const, const TRI_shadow_id);
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief look up a shadow in the index using its data pointer
+///
+/// If the shadow is found, its refcount will be decreased by one.
+/// If the refcount is 0 and the shadow is of type SHADOW_TRANSIENT, the shadow
+/// object will be destroyed.
+////////////////////////////////////////////////////////////////////////////////
+
+void TRI_EndUsageDataShadowData (TRI_shadow_store_t* const, const void* const);
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief look up a shadow in the index using its id
+///
+/// If the shadow is found, its refcount will be decreased by one.
+/// If the refcount is 0 and the shadow is of type SHADOW_TRANSIENT, the shadow
+/// object will be destroyed.
+////////////////////////////////////////////////////////////////////////////////
+
+void TRI_EndUsageIdShadowData (TRI_shadow_store_t* const, const TRI_shadow_id);
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief set the persistence flag for a shadow using its data pointer
+////////////////////////////////////////////////////////////////////////////////
+
+bool TRI_PersistDataShadowData (TRI_shadow_store_t* const, const void* const);
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief set the persistence flag for a shadow using its id
+////////////////////////////////////////////////////////////////////////////////
+
+bool TRI_PersistIdShadowData (TRI_shadow_store_t* const, const TRI_shadow_id);
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief set the deleted flag for a shadow using its data pointer
+////////////////////////////////////////////////////////////////////////////////
+
+bool TRI_DeleteDataShadowData (TRI_shadow_store_t* const, const void* const);
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief set the deleted flag for a shadow using its id
+////////////////////////////////////////////////////////////////////////////////
+
+bool TRI_DeleteIdShadowData (TRI_shadow_store_t* const, const TRI_shadow_id);
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief enumerate all shadows and remove them if
+/// - their refcount is 0 and they are transient
+/// - their refcount is 0 and they are expired
+/// - the force flag is set
///
-/// The max age must be specified in seconds
+/// The max age must be specified in seconds. The max age is ignored if the
+/// force flag is set. In this case all remaining shadows will be deleted
////////////////////////////////////////////////////////////////////////////////
-void TRI_CleanupShadowData (TRI_shadow_store_t* const, const double);
+void TRI_CleanupShadowData (TRI_shadow_store_t* const, const double, const bool);
////////////////////////////////////////////////////////////////////////////////
-/// @brief looks up a shadow by id and decreases its refcount if it exists
-////////////////////////////////////////////////////////////////////////////////
-
-bool TRI_DecreaseRefCountShadowData (TRI_shadow_store_t* const, const TRI_shadow_id);
-
-////////////////////////////////////////////////////////////////////////////////
-/// @brief looks up a shadow by id and increases its refcount if it exists
-////////////////////////////////////////////////////////////////////////////////
-
-bool TRI_IncreaseRefCountShadowData (TRI_shadow_store_t* const, const TRI_shadow_id);
-
-////////////////////////////////////////////////////////////////////////////////
-/// @brief looks up shadow data
-////////////////////////////////////////////////////////////////////////////////
-
-TRI_shadow_t* TRI_FindShadowData (TRI_shadow_store_t* const, const TRI_shadow_id);
-
-////////////////////////////////////////////////////////////////////////////////
-/// @brief stores shadow data
+/// @brief store a new shadow in the store
////////////////////////////////////////////////////////////////////////////////
TRI_shadow_t* TRI_StoreShadowData (TRI_shadow_store_t* const,
const void* const);
-////////////////////////////////////////////////////////////////////////////////
-/// @brief decrease the refcount of a shadow without deleting it
-////////////////////////////////////////////////////////////////////////////////
-
-int64_t TRI_DecreaseRefcountShadowData (TRI_shadow_store_t* const, TRI_shadow_t* const);
-
-////////////////////////////////////////////////////////////////////////////////
-/// @brief releases shadow data
-////////////////////////////////////////////////////////////////////////////////
-
-bool TRI_ReleaseShadowData (TRI_shadow_store_t* const, TRI_shadow_t*);
-
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
+/*
+// -----------------------------------------------------------------------------
+// --SECTION-- UNUSED AND UNTESTED CODE FOLLOWS
+// -----------------------------------------------------------------------------
+
// -----------------------------------------------------------------------------
// --SECTION-- SHADOW DOCUMENTS
// -----------------------------------------------------------------------------
@@ -282,7 +351,7 @@ void TRI_CleanupShadowDocuments (TRI_shadow_document_store_t* const, const doubl
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
-
+*/
#ifdef __cplusplus
}
#endif
diff --git a/VocBase/simple-collection.c b/VocBase/simple-collection.c
index 7a676582bd..6c8c2e8daa 100644
--- a/VocBase/simple-collection.c
+++ b/VocBase/simple-collection.c
@@ -1244,7 +1244,6 @@ static bool OpenIndexIterator (char const* filename, void* data) {
lat = TRI_LookupArrayJson(json, "latitude");
lon = TRI_LookupArrayJson(json, "longitude");
gjs = TRI_LookupArrayJson(json, "geoJson");
- iid = 0;
geoJson = false;
if (gjs != NULL && gjs->_type == TRI_JSON_BOOLEAN) {
diff --git a/VocBase/vocbase.c b/VocBase/vocbase.c
index 1980e6561c..c3165dc031 100644
--- a/VocBase/vocbase.c
+++ b/VocBase/vocbase.c
@@ -450,14 +450,6 @@ TRI_vocbase_t* TRI_OpenVocBase (char const* path) {
return NULL;
}
- // set up shadow data stores for queries
-/* vocbase->_statements = TRI_CreateShadowsQueryTemplate();
- if (!vocbase->_statements) {
- TRI_Free(vocbase);
- LOG_ERROR("out of memory when opening vocbase");
- return NULL;
- }
-*/
vocbase->_cursors = TRI_CreateShadowsQueryCursor();
if (!vocbase->_cursors) {
TRI_FreeShadowStore(vocbase->_cursors);
@@ -470,7 +462,6 @@ TRI_vocbase_t* TRI_OpenVocBase (char const* path) {
vocbase->_path = TRI_DuplicateString(path);
if (!vocbase->_path) {
-// TRI_FreeShadowDocumentStore(vocbase->_statements);
TRI_FreeShadowStore(vocbase->_cursors);
TRI_Free(vocbase);
LOG_ERROR("out of memory when opening vocbase");
@@ -528,12 +519,7 @@ void TRI_CloseVocBase (TRI_vocbase_t* vocbase) {
// cursors
TRI_FreeShadowStore(vocbase->_cursors);
}
-/*
- if (vocbase->_statements) {
- // statements
- TRI_FreeShadowDocumentStore(vocbase->_statements);
- }
-*/
+
TRI_DestroyLockFile(vocbase->_lockFile);
TRI_FreeString(vocbase->_lockFile);
}
diff --git a/VocBase/vocbase.h b/VocBase/vocbase.h
index 3277e3a069..2b339d8df9 100644
--- a/VocBase/vocbase.h
+++ b/VocBase/vocbase.h
@@ -72,6 +72,18 @@ extern size_t PageSize;
#define DEFAULT_MAXIMAL_SIZE (1024 * 1024 * 128)
+////////////////////////////////////////////////////////////////////////////////
+/// @brief document handle separator as character
+////////////////////////////////////////////////////////////////////////////////
+
+#define TRI_DOCUMENT_HANDLE_SEPARATOR_CHR '/'
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief document handle separator as string
+////////////////////////////////////////////////////////////////////////////////
+
+#define TRI_DOCUMENT_HANDLE_SEPARATOR_STR "/"
+
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
diff --git a/js/actions/system/aql-cursor.js b/js/actions/system/aql-cursor.js
index c5f529a589..29ca99c706 100644
--- a/js/actions/system/aql-cursor.js
+++ b/js/actions/system/aql-cursor.js
@@ -89,7 +89,6 @@ function postCursor(req, res) {
}
try {
- var cursor;
var json = JSON.parse(req.requestBody);
if (!json || !(json instanceof Object)) {
@@ -97,18 +96,9 @@ function postCursor(req, res) {
return;
}
- if (json._id != undefined) {
- /*
- cursor = AQL_STORED_STATEMENT(db,
- json._id,
- json.bindVars,
- (json.count != undefined ? json.count : false),
- (json.batchSize != undefined ? json.batchSize : 1000));
- */
- }
- else if (json.query != undefined) {
- cursor = AQL_STATEMENT(db,
- json.query,
+ var cursor;
+ if (json.query != undefined) {
+ cursor = AQL_STATEMENT(json.query,
json.bindVars,
(json.count != undefined ? json.count : false),
(json.batchSize != undefined ? json.batchSize : 1000));
@@ -145,7 +135,7 @@ function putCursor(req, res) {
try {
var cursorId = decodeURIComponent(req.suffix[0]);
- var cursor = AQL_CURSOR(db, cursorId);
+ var cursor = AQL_CURSOR(cursorId);
if (!(cursor instanceof AvocadoQueryCursor)) {
throw "cursor not found";
}
@@ -170,7 +160,7 @@ function deleteCursor(req, res) {
try {
var cursorId = decodeURIComponent(req.suffix[0]);
- var cursor = AQL_CURSOR(db, cursorId);
+ var cursor = AQL_CURSOR(cursorId);
if (!(cursor instanceof AvocadoQueryCursor)) {
throw "cursor not found";
}
diff --git a/js/actions/system/aql-query.js b/js/actions/system/aql-query.js
index 8767f42966..402e8f6726 100644
--- a/js/actions/system/aql-query.js
+++ b/js/actions/system/aql-query.js
@@ -54,7 +54,7 @@ function postQuery(req, res) {
return;
}
- var result = AQL_PARSE(db, json.query);
+ var result = AQL_PARSE(json.query);
if (result instanceof AvocadoQueryError) {
actions.actionResultError (req, res, 404, result.code, result.message);
return;
diff --git a/js/actions/system/key-value.js b/js/actions/system/key-value.js
index 4d0915bed8..8698252cdd 100644
--- a/js/actions/system/key-value.js
+++ b/js/actions/system/key-value.js
@@ -42,11 +42,32 @@ var simple = require("simple-query");
// --SECTION-- private functions
// -----------------------------------------------------------------------------
+function formatTimeStamp (timestamp) {
+ var d = new Date(timestamp * 1000);
+
+ var year = d.getUTCFullYear();
+ var month = d.getUTCMonth() + 1;
+ var date = d.getUTCDate();
+
+ if (month < 10) month = "0" + month;
+ if (date < 10) hour = "0" + date;
+
+ var hour = d.getUTCHours();
+ var minutes = d.getUTCMinutes();
+ var seconds = d.getUTCSeconds();
+
+ if (hour < 10) hour = "0" + hour;
+ if (minutes < 10) minutes = "0" + minutes;
+ if (seconds < 10) seconds = "0" + seconds;
+
+ return year + "-" + month + "-" + date + "T" + hour + ":" + minutes + ":" + seconds + "Z";
+}
+
function buildDocumentFromReq(req) {
// Example requests:
// Header:
- // POST /_api/key/example_collection/example_key1
+ // POST /_api/key/example_collection/example_key1 HTTP/1.1
// Host: localhost:9000
// x-voc-expires: 2011-09-29T08:00:00Z
// x-voc-extended: {"option1":35,"option2":"x"}
@@ -67,8 +88,9 @@ function buildDocumentFromReq(req) {
}
if (req.headers["x-voc-expires"] != undefined) {
- // TODO check value
- doc["x-voc-expires"] = req.headers["x-voc-expires"];
+ var d = new Date(req.headers["x-voc-expires"]);
+ // store time stamp as double
+ doc["x-voc-expires"] = d.getTime() / 1000;
}
if (req.headers["x-voc-extended"] != undefined) {
@@ -78,6 +100,7 @@ function buildDocumentFromReq(req) {
}
}
+ // store time stamp as double
doc["x-voc-created"] = internal.time();
return doc;
@@ -97,9 +120,14 @@ function postKeyValue(req, res) {
try {
var collection = req.suffix[0];
+ if (db._collection(collection) == null) {
+ actions.actionResultError (req, res, 404, actions.keyValueNotModified, "Collection not found.");
+ return;
+ }
+
var doc = buildDocumentFromReq(req);
- var s = db[collection].select({ "key" : doc.key });
+ var s = db[collection].byExample({"key" : doc.key});
s.execute();
if (s._countTotal != 0) {
@@ -115,7 +143,7 @@ function postKeyValue(req, res) {
}
}
catch (e) {
- actions.actionResultError (req, res, 404, actions.keyValueNotModified, "Key value pair not created.");
+ actions.actionResultError (req, res, 404, actions.keyValueNotModified, "Key value pair not created. " + e.message);
}
}
@@ -125,36 +153,59 @@ function postKeyValue(req, res) {
function putKeyValue(req, res) {
if (req.suffix.length < 2) {
- actions.actionResultError (req, res, 404, actions.keyValueNotFound, "Key value pair not found");
+ actions.actionResultError (req, res, 404, actions.keyValueNotModified, "Key value pair not found");
return;
}
try {
var collection = req.suffix[0];
+ if (db._collection(collection) == null) {
+ actions.actionResultError (req, res, 404, actions.keyValueNotModified, "Collection not found.");
+ return;
+ }
+
var doc = buildDocumentFromReq(req);
- var s = db[collection].select({ "key" : doc.key });
+ var s = db[collection].byExample({"key" : doc.key});
s.execute();
if (s._countTotal < 1) {
- actions.actionResultError (req, res, 404, actions.keyValueNotFound, "Key value pair not found");
+ if (req.parameters["create"] == 1) {
+ var id = db[collection].save(doc);
+ var result = {
+ "saved" : true,
+ "_id" : id
+ }
+ actions.actionResultOK(req, res, 201, result);
+ return;
+ }
+ actions.actionResultError (req, res, 404, actions.keyValueNotModified, "Key value pair not found");
}
else if (s._countTotal > 1) {
- actions.actionResultError (req, res, 404, actions.keyValueNotFound, "Key value pair not found. Wrong key?");
+ actions.actionResultError (req, res, 404, actions.keyValueNotModified, "Key value pair not found. Wrong key?");
}
else {
+ // get _id
var id = s._execution._documents[0]._id;
+
+ // save x-voc-created
+ var created = s._execution._documents[0]["x-voc-created"];
+ if (created != undefined) {
+ doc["x-voc-created"] = created;
+ }
+
+ // replace the document
if (db[collection].replace(id, doc)) {
- actions.actionResultOK(req, res, 202, { "changed" : true });
+ actions.actionResultOK(req, res, 202, {"changed" : true});
}
else {
- actions.actionResultError(req, res, 404, actions.keyValueNotFound, "Value not changed");
+ actions.actionResultError(req, res, 404, actions.keyValueNotModified, "Value not changed");
}
}
}
catch (e) {
- actions.actionResultError (req, res, 404, actions.keyValueNotFound, "Key value pair not found");
+ actions.actionResultError (req, res, 404, actions.keyValueNotModified, "Key value pair not found. " + e.message);
}
}
@@ -164,40 +215,45 @@ function putKeyValue(req, res) {
function deleteKeyValue(req, res) {
if (req.suffix.length < 2) {
- actions.actionResultError (req, res, 404, actions.keyValueNotFound, "Key value pair not found");
+ actions.actionResultError (req, res, 404, actions.keyValueNotModified, "Key value pair not found");
return;
}
try {
var collection = req.suffix[0];
+ if (db._collection(collection) == null) {
+ actions.actionResultError (req, res, 404, actions.keyValueNotModified, "Collection not found.");
+ return;
+ }
+
var key = req.suffix[1];
for (var i = 2; i < req.suffix.length; ++i) {
key += "/" + req.suffix[i];
}
- var s = db[collection].select({ "key" : key });
+ var s = db[collection].byExample({"key" : key});
s.execute();
if (s._countTotal < 1) {
- actions.actionResultError (req, res, 404, actions.keyValueNotFound, "Key value pair not found");
+ actions.actionResultError (req, res, 404, actions.keyValueNotModified, "Key value pair not found");
}
else if (s._countTotal > 1) {
- actions.actionResultError (req, res, 404, actions.keyValueNotFound, "Key value pair not found. Wrong key?");
+ actions.actionResultError (req, res, 404, actions.keyValueNotModified, "Key value pair not found. Wrong key?");
}
else {
var id = s._execution._documents[0]._id;
if (db[collection].delete(id)) {
- actions.actionResultOK(req, res, 202, { "removed" : true });
+ actions.actionResultOK(req, res, 202, {"removed" : true});
}
else {
- actions.actionResultError(req, res, 404, actions.keyValueNotFound, "Value not removed");
+ actions.actionResultError(req, res, 404, actions.keyValueNotModified, "Value not removed");
}
}
}
catch (e) {
- actions.actionResultError (req, res, 404, actions.keyValueNotFound, "Key value pair not found");
+ actions.actionResultError (req, res, 404, actions.keyValueNotModified, "Key value pair not found. " + e.message);
}
}
@@ -214,13 +270,18 @@ function getKeyValue(req, res) {
try {
var collection = req.suffix[0];
+ if (db._collection(collection) == null) {
+ actions.actionResultError (req, res, 404, actions.keyValueNotFound, "Collection not found.");
+ return;
+ }
+
var key = req.suffix[1];
for (var i = 2; i < req.suffix.length; ++i) {
key += "/" + req.suffix[i];
}
- var s = db[collection].select({ "key" : key });
+ var s = db[collection].byExample({"key" : key});
s.execute();
if (s._countTotal < 1) {
@@ -233,20 +294,23 @@ function getKeyValue(req, res) {
var headers = {};
if (s._execution._documents[0]["x-voc-expires"] != undefined) {
- headers["x-voc-expires"] = s._execution._documents[0]["x-voc-expires"];
+ // format timestamp
+ headers["x-voc-expires"] = formatTimeStamp(s._execution._documents[0]["x-voc-expires"]);
}
if (s._execution._documents[0]["x-voc-extended"] != undefined) {
+ // serialize header value
headers["x-voc-extended"] = JSON.stringify(s._execution._documents[0]["x-voc-extended"]);
}
if (s._execution._documents[0]["x-voc-created"] != undefined) {
- headers["x-voc-created"] = s._execution._documents[0]["x-voc-created"];
+ // format timestamp
+ headers["x-voc-created"] = formatTimeStamp(s._execution._documents[0]["x-voc-created"]);
}
actions.actionResultOK(req, res, 200, s._execution._documents[0].value, headers);
}
}
catch (e) {
- actions.actionResultError (req, res, 404, actions.keyValueNotFound, "Key value pair not found");
+ actions.actionResultError (req, res, 404, actions.keyValueNotFound, "Key value pair not found. " + e.message);
}
}
@@ -255,7 +319,7 @@ function getKeyValue(req, res) {
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
-/// @brief cursor actions gateway
+/// @brief key value pair actions gateway
////////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
@@ -264,19 +328,19 @@ actions.defineHttp({
callback : function (req, res) {
switch (req.requestType) {
- case ("POST") :
+ case ("POST") :
postKeyValue(req, res);
break;
- case ("GET") :
+ case ("GET") :
getKeyValue(req, res);
break;
- case ("PUT") :
+ case ("PUT") :
putKeyValue(req, res);
break;
- case ("DELETE") :
+ case ("DELETE") :
deleteKeyValue(req, res);
break;
@@ -286,6 +350,94 @@ actions.defineHttp({
}
});
+
+////////////////////////////////////////////////////////////////////////////////
+/// @}
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+/// @addtogroup AvocadoAPI
+/// @{
+////////////////////////////////////////////////////////////////////////////////
+
+// -----------------------------------------------------------------------------
+// --SECTION-- private functions
+// -----------------------------------------------------------------------------
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief key value pair search
+////////////////////////////////////////////////////////////////////////////////
+
+function searchKeyValue(req, res) {
+ if (req.suffix.length < 2) {
+ actions.actionResultError (req, res, 404, actions.keyValueNotFound, "Key value pairs not found.");
+ return;
+ }
+
+ try {
+ var collection = req.suffix[0];
+
+ if (db._collection(collection) == null) {
+ actions.actionResultError (req, res, 404, actions.keyValueNotFound, "Collection not found.");
+ return;
+ }
+
+ var prefix = req.suffix[1];
+
+ for (var i = 2; i < req.suffix.length; ++i) {
+ prefix += "/" + req.suffix[i];
+ }
+
+ //
+ // TODO: build a query which selects the keys
+ //
+
+ var query = "select f from " + collection + " f ";
+ var bindVars = {};
+ var cursor = AQL_STATEMENT(db,
+ query,
+ bindVars,
+ false,
+ 1000);
+ result = [];
+ while (cursor.hasNext() ) {
+ var doc = cursor.next();
+ if (doc["key"] != undefined && doc["key"].indexOf(prefix) === 0) {
+ result.push(doc["key"]);
+ }
+ }
+
+ actions.actionResult (req, res, 200, result);
+ }
+ catch (e) {
+ actions.actionResultError (req, res, 404, actions.keyValueNotFound, "Key value pairs not found. " + e.message);
+ }
+}
+
+// -----------------------------------------------------------------------------
+// --SECTION-- initialiser
+// -----------------------------------------------------------------------------
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief key value pair actions gateway
+////////////////////////////////////////////////////////////////////////////////
+
+actions.defineHttp({
+ url : "_api/keys",
+ context : "api",
+
+ callback : function (req, res) {
+ switch (req.requestType) {
+ case ("GET") :
+ searchKeyValue(req, res);
+ break;
+
+ default:
+ actions.actionResultUnsupported(req, res);
+ }
+ }
+});
+
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
diff --git a/js/server/js-server.h b/js/server/js-server.h
index 222c2e676a..6ecdaf7cda 100644
--- a/js/server/js-server.h
+++ b/js/server/js-server.h
@@ -26,27 +26,6 @@ static string JS_server_server =
"/// @author Copyright 2011-2012, triAGENS GmbH, Cologne, Germany\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
- "////////////////////////////////////////////////////////////////////////////////\n"
- "/// @page JSModuleAvocadoTOC\n"
- "///\n"
- "/// \n"
- "/// - @ref JSModuleAvocadoDefineHttpSystemAction \"avocado.defineHttpSystemAction\"
\n"
- "///
\n"
- "////////////////////////////////////////////////////////////////////////////////\n"
- "\n"
- "////////////////////////////////////////////////////////////////////////////////\n"
- "/// @page JSModuleAvocado Module \"avocado\"\n"
- "///\n"
- "/// The following functions are used avocadoly.\n"
- "///\n"
- "///
\n"
- "/// @copydoc JSModuleAvocadoTOC\n"
- "///
\n"
- "///\n"
- "/// @anchor JSModuleAvocadoDefineHttpSystemAction\n"
- "/// @copydetails JS_DefineSystemAction\n"
- "////////////////////////////////////////////////////////////////////////////////\n"
- "\n"
"// -----------------------------------------------------------------------------\n"
"// --SECTION-- Module \"internal\"\n"
"// -----------------------------------------------------------------------------\n"
@@ -79,31 +58,6 @@ static string JS_server_server =
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
"// -----------------------------------------------------------------------------\n"
- "// --SECTION-- Module \"avocado\"\n"
- "// -----------------------------------------------------------------------------\n"
- "\n"
- "////////////////////////////////////////////////////////////////////////////////\n"
- "/// @addtogroup V8ModuleAvocado\n"
- "/// @{\n"
- "////////////////////////////////////////////////////////////////////////////////\n"
- "\n"
- "////////////////////////////////////////////////////////////////////////////////\n"
- "/// @brief avocado module\n"
- "////////////////////////////////////////////////////////////////////////////////\n"
- "\n"
- "ModuleCache[\"/avocado\"] = new Module(\"/avocado\");\n"
- "\n"
- "if (typeof defineSystemAction == \"function\") {\n"
- " ModuleCache[\"/avocado\"].exports.defineHttpSystemAction = defineSystemAction;\n"
- "}\n"
- "\n"
- "avocado = ModuleCache[\"/avocado\"].exports;\n"
- "\n"
- "////////////////////////////////////////////////////////////////////////////////\n"
- "/// @}\n"
- "////////////////////////////////////////////////////////////////////////////////\n"
- "\n"
- "// -----------------------------------------------------------------------------\n"
"// --SECTION-- Module \"simple-query\"\n"
"// -----------------------------------------------------------------------------\n"
"\n"
@@ -124,7 +78,7 @@ static string JS_server_server =
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
"// -----------------------------------------------------------------------------\n"
- "// --SECTION-- PRINT\n"
+ "// --SECTION-- ShapedJson\n"
"// -----------------------------------------------------------------------------\n"
"\n"
"////////////////////////////////////////////////////////////////////////////////\n"
@@ -149,6 +103,75 @@ static string JS_server_server =
"/// @}\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
+ "// -----------------------------------------------------------------------------\n"
+ "// --SECTION-- AvocadoDatabase\n"
+ "// -----------------------------------------------------------------------------\n"
+ "\n"
+ "////////////////////////////////////////////////////////////////////////////////\n"
+ "/// @addtogroup V8Shell\n"
+ "/// @{\n"
+ "////////////////////////////////////////////////////////////////////////////////\n"
+ "\n"
+ "////////////////////////////////////////////////////////////////////////////////\n"
+ "/// @brief drops a collection\n"
+ "////////////////////////////////////////////////////////////////////////////////\n"
+ "\n"
+ "AvocadoDatabase.prototype._drop = function(name) {\n"
+ " var collection = name;\n"
+ "\n"
+ " if (typeof name === \"string\") {\n"
+ " collection = db[name];\n"
+ " }\n"
+ "\n"
+ " // new born collection\n"
+ " if (collection.status() == 1) {\n"
+ " return;\n"
+ " }\n"
+ "\n"
+ " // drop all indexes\n"
+ " var idx = collection.getIndexes();\n"
+ "\n"
+ " for (var i = 0; i < idx.length; ++i) {\n"
+ " collection.dropIndex(idx[i].iid);\n"
+ " }\n"
+ "\n"
+ " // delete all documents\n"
+ " var all = collection.all();\n"
+ "\n"
+ " while (all.hasNext()) {\n"
+ " var ref = all.nextRef();\n"
+ "\n"
+ " collection.delete(ref);\n"
+ " }\n"
+ "}\n"
+ "\n"
+ "AvocadoEdges.prototype._drop = AvocadoDatabase._drop;\n"
+ "\n"
+ "////////////////////////////////////////////////////////////////////////////////\n"
+ "/// @}\n"
+ "////////////////////////////////////////////////////////////////////////////////\n"
+ "\n"
+ "// -----------------------------------------------------------------------------\n"
+ "// --SECTION-- AvocadoCollection\n"
+ "// -----------------------------------------------------------------------------\n"
+ "\n"
+ "////////////////////////////////////////////////////////////////////////////////\n"
+ "/// @addtogroup V8Shell\n"
+ "/// @{\n"
+ "////////////////////////////////////////////////////////////////////////////////\n"
+ "\n"
+ "////////////////////////////////////////////////////////////////////////////////\n"
+ "/// @brief drops a collection\n"
+ "////////////////////////////////////////////////////////////////////////////////\n"
+ "\n"
+ "AvocadoCollection.prototype.drop = function() {\n"
+ " db._drop(this);\n"
+ "}\n"
+ "\n"
+ "////////////////////////////////////////////////////////////////////////////////\n"
+ "/// @}\n"
+ "////////////////////////////////////////////////////////////////////////////////\n"
+ "\n"
"// Local Variables:\n"
"// mode: outline-minor\n"
"// outline-regexp: \"^\\\\(/// @brief\\\\|/// @addtogroup\\\\|// --SECTION--\\\\|/// @page\\\\|/// @}\\\\)\"\n"
diff --git a/js/server/modules/simple-query.js b/js/server/modules/simple-query.js
index 1cf26dce6d..f772469c52 100644
--- a/js/server/modules/simple-query.js
+++ b/js/server/modules/simple-query.js
@@ -786,7 +786,7 @@ SimpleQueryByExample.prototype.execute = function () {
}
}
- var cursor = AQL_STATEMENT(db, queryString, undefined);
+ var cursor = AQL_STATEMENT(queryString, undefined);
if (cursor instanceof AvocadoQueryError) {
throw cursor.message;
}
diff --git a/js/server/server.js b/js/server/server.js
index 5aff8d45e4..9d5d176bf1 100644
--- a/js/server/server.js
+++ b/js/server/server.js
@@ -25,27 +25,6 @@
/// @author Copyright 2011-2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////
-/// @page JSModuleAvocadoTOC
-///
-///
-/// - @ref JSModuleAvocadoDefineHttpSystemAction "avocado.defineHttpSystemAction"
-///
-////////////////////////////////////////////////////////////////////////////////
-
-////////////////////////////////////////////////////////////////////////////////
-/// @page JSModuleAvocado Module "avocado"
-///
-/// The following functions are used avocadoly.
-///
-///
-/// @copydoc JSModuleAvocadoTOC
-///
-///
-/// @anchor JSModuleAvocadoDefineHttpSystemAction
-/// @copydetails JS_DefineSystemAction
-////////////////////////////////////////////////////////////////////////////////
-
// -----------------------------------------------------------------------------
// --SECTION-- Module "internal"
// -----------------------------------------------------------------------------
@@ -77,31 +56,6 @@ else {
/// @}
////////////////////////////////////////////////////////////////////////////////
-// -----------------------------------------------------------------------------
-// --SECTION-- Module "avocado"
-// -----------------------------------------------------------------------------
-
-////////////////////////////////////////////////////////////////////////////////
-/// @addtogroup V8ModuleAvocado
-/// @{
-////////////////////////////////////////////////////////////////////////////////
-
-////////////////////////////////////////////////////////////////////////////////
-/// @brief avocado module
-////////////////////////////////////////////////////////////////////////////////
-
-ModuleCache["/avocado"] = new Module("/avocado");
-
-if (typeof defineSystemAction == "function") {
- ModuleCache["/avocado"].exports.defineHttpSystemAction = defineSystemAction;
-}
-
-avocado = ModuleCache["/avocado"].exports;
-
-////////////////////////////////////////////////////////////////////////////////
-/// @}
-////////////////////////////////////////////////////////////////////////////////
-
// -----------------------------------------------------------------------------
// --SECTION-- Module "simple-query"
// -----------------------------------------------------------------------------
@@ -123,7 +77,7 @@ catch (err) {
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
-// --SECTION-- PRINT
+// --SECTION-- ShapedJson
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
@@ -148,6 +102,75 @@ ShapedJson.prototype._PRINT = function(seen, path, names) {
/// @}
////////////////////////////////////////////////////////////////////////////////
+// -----------------------------------------------------------------------------
+// --SECTION-- AvocadoDatabase
+// -----------------------------------------------------------------------------
+
+////////////////////////////////////////////////////////////////////////////////
+/// @addtogroup V8Shell
+/// @{
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief drops a collection
+////////////////////////////////////////////////////////////////////////////////
+
+AvocadoDatabase.prototype._drop = function(name) {
+ var collection = name;
+
+ if (typeof name === "string") {
+ collection = db[name];
+ }
+
+ // new born collection
+ if (collection.status() == 1) {
+ return;
+ }
+
+ // drop all indexes
+ var idx = collection.getIndexes();
+
+ for (var i = 0; i < idx.length; ++i) {
+ collection.dropIndex(idx[i].iid);
+ }
+
+ // delete all documents
+ var all = collection.all();
+
+ while (all.hasNext()) {
+ var ref = all.nextRef();
+
+ collection.delete(ref);
+ }
+}
+
+AvocadoEdges.prototype._drop = AvocadoDatabase._drop;
+
+////////////////////////////////////////////////////////////////////////////////
+/// @}
+////////////////////////////////////////////////////////////////////////////////
+
+// -----------------------------------------------------------------------------
+// --SECTION-- AvocadoCollection
+// -----------------------------------------------------------------------------
+
+////////////////////////////////////////////////////////////////////////////////
+/// @addtogroup V8Shell
+/// @{
+////////////////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////////////////
+/// @brief drops a collection
+////////////////////////////////////////////////////////////////////////////////
+
+AvocadoCollection.prototype.drop = function() {
+ db._drop(this);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+/// @}
+////////////////////////////////////////////////////////////////////////////////
+
// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"
diff --git a/js/server/tests/aql-bind.js b/js/server/tests/aql-bind.js
index af135ffb46..a5c241b23b 100644
--- a/js/server/tests/aql-bind.js
+++ b/js/server/tests/aql-bind.js
@@ -60,7 +60,7 @@ function aqlBindParametersTestSuite () {
////////////////////////////////////////////////////////////////////////////////
function executeQuery (query, bindParameters) {
- var cursor = AQL_STATEMENT(db, query, bindParameters);
+ var cursor = AQL_STATEMENT(query, bindParameters);
assertFalse(cursor instanceof AvocadoQueryError);
return cursor;
}
diff --git a/js/server/tests/aql-joins.js b/js/server/tests/aql-joins.js
index 0e9f8b65cf..6e736b4e5e 100644
--- a/js/server/tests/aql-joins.js
+++ b/js/server/tests/aql-joins.js
@@ -111,7 +111,7 @@ function aqlJoinsTestSuite () {
////////////////////////////////////////////////////////////////////////////////
function executeQuery (query) {
- var cursor = AQL_STATEMENT(db, query, undefined);
+ var cursor = AQL_STATEMENT(query, undefined);
assertFalse(cursor instanceof AvocadoQueryError);
return cursor;
}
diff --git a/js/server/tests/aql-keywords.js b/js/server/tests/aql-keywords.js
index aed2932278..b10cd7aad3 100644
--- a/js/server/tests/aql-keywords.js
+++ b/js/server/tests/aql-keywords.js
@@ -76,7 +76,7 @@ function aqlKeywordsTestSuite () {
////////////////////////////////////////////////////////////////////////////////
function executeQuery (query, expectError) {
- var cursor = AQL_STATEMENT(db, query, undefined);
+ var cursor = AQL_STATEMENT(query, undefined);
if (expectError) {
assertTrue(cursor instanceof AvocadoQueryError);
return null;
diff --git a/js/server/tests/aql-simple.js b/js/server/tests/aql-simple.js
index 5dc142b029..0a4fe54e79 100644
--- a/js/server/tests/aql-simple.js
+++ b/js/server/tests/aql-simple.js
@@ -60,7 +60,7 @@ function aqlSimpleTestSuite () {
////////////////////////////////////////////////////////////////////////////////
function executeQuery (query) {
- var cursor = AQL_STATEMENT(db, query, undefined);
+ var cursor = AQL_STATEMENT(query, undefined);
if (cursor instanceof AvocadoQueryError) {
print(query, cursor.message);
}