1
0
Fork 0

started rewrite of rest interface

This commit is contained in:
Frank Celler 2012-03-16 17:58:30 +01:00
parent 360b7f96fd
commit c64f76b701
62 changed files with 1946 additions and 1589 deletions

View File

@ -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);
}

19
Demos/Scripts/demo.js Normal file
View File

@ -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" ]});

16
Demos/Scripts/five.js Normal file
View File

@ -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" });

22
Demos/Scripts/geo.js Normal file
View File

@ -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 }
});
}
}

View File

@ -0,0 +1,4 @@
HTTP/1.1 404 Bad Request
...
{"error":true,"code":404,"errorNum":41404,"errorMessage":"Key value pair not found"}

View File

@ -0,0 +1,4 @@
HTTP/1.1 200 OK
...
{"removed":true,"error":false,"code":202}

View File

@ -0,0 +1,2 @@
DELETE /_api/key/example_collection/example_key1 HTTP/1.1
Host: localhost:9000

View File

@ -0,0 +1,4 @@
HTTP/1.1 404 Bad Request
...
{"error":true,"code":404,"errorNum":41404,"errorMessage":"Key value pair not found"}

View File

@ -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

View File

@ -0,0 +1,2 @@
GET /_api/key/example_collection/example_key1 HTTP/1.1
Host: localhost:9000

View File

@ -0,0 +1,4 @@
HTTP/1.1 404 Bad Request
...
{"error":true,"code":404,"errorNum":41404,"errorMessage":"Collection not found"}

View File

@ -0,0 +1,4 @@
HTTP/1.1 200 OK
...
["example_keyboard","example_keystone"]

View File

@ -0,0 +1,2 @@
GET /_api/keys/example_collection/example_key HTTP/1.1
Host: localhost:9000

View File

@ -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"}

View File

@ -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}

View File

@ -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

View File

@ -0,0 +1,4 @@
HTTP/1.1 404 Bad Request
...
{"error":true,"code":404,"errorNum":41404,"errorMessage":"Key value pair not found"}

View File

@ -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}

View File

@ -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

View File

@ -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"
}
]

View File

@ -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"
}
]

View File

@ -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
]
},
...
]

View File

@ -206,7 +206,7 @@ ALIASES += CMDOPT{1}="<tt><b>\1</b></tt>"
ALIASES += CA{1}="<var>\1</var>"
ALIASES += CO{1}="<tt>\1</tt>"
ALIASES += REST{1}="<tt><b>\1</b></tt>"
ALIASES += GE{1}="<tt><b>\1</b></tt>"
ALIASES += GE{1}="<b>\1</b>"
ALIASES += EXAMPLES="<b>Examples</b><br>"
# 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

View File

@ -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) {

View File

@ -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();

View File

@ -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 \

View File

@ -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@

View File

@ -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<string> 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/<document-handle>");
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<string> 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<string> 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/<document-handle>");
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<string> 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<string> suffix = request->suffix();
// find and load collection given by name oder identifier

View File

@ -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);
////////////////////////////////////////////////////////////////////////////////
/// @}

View File

@ -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<string> doc = StringUtils::split(name, ":");
vector<string> doc = StringUtils::split(name, TRI_DOCUMENT_HANDLE_SEPARATOR_STR);
switch (doc.size()) {
case 1:

View File

@ -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<RestCollectionHandler>::createData<TRI_vocbase_t*>, _vocbase);
factory->addPrefixHandler(RestVocbaseBaseHandler::DOCUMENT_PATH, RestHandlerCreator<RestDocumentHandler>::createData<TRI_vocbase_t*>, _vocbase);
factory->addPrefixHandler("/", RestHandlerCreator<RestActionHandler>::createData<TRI_vocbase_t*>, _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<RestCollectionHandler>::createData<TRI_vocbase_t*>, _vocbase);
adminFactory->addPrefixHandler(RestVocbaseBaseHandler::DOCUMENT_PATH, RestHandlerCreator<RestDocumentHandler>::createData<TRI_vocbase_t*>, _vocbase);
adminFactory->addPrefixHandler("/", RestHandlerCreator<RestActionHandler>::createData<TRI_vocbase_t*>, _vocbase);
_adminHttpServer = _applicationHttpServer->buildServer(adminFactory, adminPorts);

View File

@ -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:

View File

@ -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

208
RestServer/key-value.dox Normal file
View File

@ -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:

View File

@ -33,12 +33,12 @@
/// <ol>
/// <li>Documents
/// <ol>
/// <li>@ref RestCollectionCreate "POST /collection/@FA{collection-identifier}"</li>
/// <li>@ref RestCollectionRead "GET /collection/@FA{collection-identifier}/@FA{document-identifier}"</li>
/// <li>@ref RestCollectionReadAll "GET /collection/@FA{collection-identifier}"</li>
/// <li>@ref RestCollectionUpdate "PUT /collection/@FA{collection-identifier}/@FA{document-identifier}"</li>
/// <li>@ref RestCollectionDelete "DELETE /collection/@FA{collection-identifier}/@FA{document-identifier}"</li>
/// <li>@ref RestCollectionHead "HEAD /collection/@FA{collection-identifier}/@FA{document-identifier}"</li>
/// <li>@ref RestDocumentRead "GET /document/@FA{document-handle}"</li>
/// <li>@ref RestDocumentCreate "POST /document/collection=@FA{collection-identifier}"</li>
/// <li>@ref RestDocumentUpdate "PUT /document/@FA{document-handle}"</li>
/// <li>@ref RestDocumentDelete "DELETE /document/@FA{document-handle}"</li>
/// <li>@ref RestDocumentHead "HEAD /document/@FA{document-handle}"</li>
/// <li>@ref RestDocumentReadAll "GET /document/collection=@FA{collection-identifier}"</li>
/// </ol>
/// </li>
/// <li>@ref OTWPSimpleQueries
@ -57,6 +57,15 @@
/// <li>@ref RestQueryPost "POST /_api/query"</li>
/// </ol>
/// </li>
/// <li>@ref Key-Value
/// <ol>
/// <li>@ref Key-ValuePost "POST /_api/key/@FA{collection-name}/@FA{key}"</li>
/// <li>@ref Key-ValuePut "PUT /_api/key/@FA{collection-name}/@FA{key}"</li>
/// <li>@ref Key-ValueGet "GET /_api/key/@FA{collection-name}/@FA{key}"</li>
/// <li>@ref Key-ValueDelete "DELETE /_api/key/@FA{collection-name}/@FA{key}"</li>
/// <li>@ref Key-ValueSearch "GET /_api/keys/@FA{collection-name}/@FA{prefix}"</li>
/// </ol>
/// </li>
/// </ol>
/// </li>
/// <li>@ref OTWPDatabase

View File

@ -29,25 +29,44 @@
/// @page RestDocumentTOC
///
/// <ol>
/// <li>@ref RestCollectionCreate "POST /collection/@FA{collection-identifier}"</li>
/// <li>@ref RestCollectionRead "GET /collection/@FA{collection-identifier}/@FA{document-identifier}"</li>
/// <li>@ref RestCollectionReadAll "GET /collection/@FA{collection-identifier}"</li>
/// <li>@ref RestCollectionUpdate "PUT /collection/@FA{collection-identifier}/@FA{document-identifier}"</li>
/// <li>@ref RestCollectionDelete "DELETE /collection/@FA{collection-identifier}/@FA{document-identifier}"</li>
/// <li>@ref RestCollectionHead "HEAD /collection/@FA{collection-identifier}/@FA{document-identifier}"</li>
/// <li>@ref RestDocumentIntro</li>
/// <li>@ref RestDocumentResource</li>
/// <li>@ref RestDocumentHttp
/// <ol>
/// <li>@ref RestDocumentRead "GET /document/@FA{document-handle}"</li>
/// <li>@ref RestDocumentCreate "POST /document/collection=@FA{collection-identifier}"</li>
/// <li>@ref RestDocumentUpdate "PUT /document/@FA{document-handle}"</li>
/// <li>@ref RestDocumentDelete "DELETE /document/@FA{document-handle}"</li>
/// <li>@ref RestDocumentHead "HEAD /document/@FA{document-handle}"</li>
/// <li>@ref RestDocumentReadAll "GET /document/collection=@FA{collection-identifier}"</li>
/// </ol>
/// </li>
/// </ol>
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @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.
///
/// <hr>
/// @copydoc RestDocumentTOC
/// <hr>
///
/// @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.
///
/// <hr>
/// @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
/// <hr>
///
/// @anchor RestCollectionCreate
/// @copydetails triagens::avocado::RestCollectionHandler::createDocument
/// @anchor RestDocumentCreate
/// @copydetails triagens::avocado::RestDocumentHandler::createDocument
/// <hr>
///
/// @anchor RestCollectionRead
/// @copydetails triagens::avocado::RestCollectionHandler::readSingleDocument
/// @anchor RestDocumentUpdate
/// @copydetails triagens::avocado::RestDocumentHandler::updateDocument
/// <hr>
///
/// @anchor RestCollectionReadAll
/// @copydetails triagens::avocado::RestCollectionHandler::readAllDocuments
/// @anchor RestDocumentDelete
/// @copydetails triagens::avocado::RestDocumentHandler::deleteDocument
/// <hr>
///
/// @anchor RestCollectionUpdate
/// @copydetails triagens::avocado::RestCollectionHandler::updateDocument
/// @anchor RestDocumentHead
/// @copydetails triagens::avocado::RestDocumentHandler::checkDocument
/// <hr>
///
/// @anchor RestCollectionDelete
/// @copydetails triagens::avocado::RestCollectionHandler::deleteDocument
/// <hr>
///
/// @anchor RestCollectionHead
/// @copydetails triagens::avocado::RestCollectionHandler::checkDocument
/// @anchor RestDocumentReadAll
/// @copydetails triagens::avocado::RestDocumentHandler::readAllDocuments
////////////////////////////////////////////////////////////////////////////////
// Local Variables:

View File

@ -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);
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -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;

View File

@ -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<v8::Value> 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<v8::String> ref = v8::String::New(buffer._buffer);
@ -1198,7 +1199,7 @@ bool TRI_IdentifiersObjectReference (v8::Handle<v8::Value> value, TRI_voc_cid_t&
string v = TRI_ObjectToString(value);
vector<string> doc = StringUtils::split(v, ":");
vector<string> doc = StringUtils::split(v, TRI_DOCUMENT_HANDLE_SEPARATOR_STR);
switch (doc.size()) {
case 1:
@ -1380,6 +1381,40 @@ char TRI_ObjectToCharacter (v8::Handle<v8::Value> value, bool& error) {
return (*sep)[0];
}
////////////////////////////////////////////////////////////////////////////////
/// @brief converts an V8 object to an int64_t
////////////////////////////////////////////////////////////////////////////////
int64_t TRI_ObjectToInt64 (v8::Handle<v8::Value> value) {
if (value->IsNumber()) {
return (int64_t) value->ToNumber()->Value();
}
if (value->IsNumberObject()) {
v8::Handle<v8::NumberObject> no = v8::Handle<v8::NumberObject>::Cast(value);
return (int64_t) no->NumberValue();
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief converts an V8 object to a uint64_t
////////////////////////////////////////////////////////////////////////////////
uint64_t TRI_ObjectToUInt64 (v8::Handle<v8::Value> value) {
if (value->IsNumber()) {
return (uint64_t) value->ToNumber()->Value();
}
if (value->IsNumberObject()) {
v8::Handle<v8::NumberObject> no = v8::Handle<v8::NumberObject>::Cast(value);
return (uint64_t) no->NumberValue();
}
return 0;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief converts an V8 object to a double
////////////////////////////////////////////////////////////////////////////////

View File

@ -83,6 +83,18 @@ std::string TRI_ObjectToString (v8::Handle<v8::Value>);
char TRI_ObjectToCharacter (v8::Handle<v8::Value>, bool& error);
////////////////////////////////////////////////////////////////////////////////
/// @brief converts an V8 object to an int64_t
////////////////////////////////////////////////////////////////////////////////
int64_t TRI_ObjectToInt64 (v8::Handle<v8::Value>);
////////////////////////////////////////////////////////////////////////////////
/// @brief converts an V8 object to a uint64_t
////////////////////////////////////////////////////////////////////////////////
uint64_t TRI_ObjectToUInt64 (v8::Handle<v8::Value>);
////////////////////////////////////////////////////////////////////////////////
/// @brief converts an V8 object to a double
////////////////////////////////////////////////////////////////////////////////

View File

@ -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<v8::Value> > JSFluentQueries;
////////////////////////////////////////////////////////////////////////////////
/// @brief template mapping for weak pointers
////////////////////////////////////////////////////////////////////////////////
std::map< void*, v8::Persistent<v8::Value> > JSQueryTemplates;
////////////////////////////////////////////////////////////////////////////////
/// @brief cursor mapping for weak pointers
////////////////////////////////////////////////////////////////////////////////
@ -202,12 +194,6 @@ typedef struct TRI_v8_global_s {
v8::Persistent<v8::ObjectTemplate> FluentQueryTempl;
////////////////////////////////////////////////////////////////////////////////
/// @brief query template template
////////////////////////////////////////////////////////////////////////////////
v8::Persistent<v8::ObjectTemplate> QueryTemplateTempl;
////////////////////////////////////////////////////////////////////////////////
/// @brief cursor template
////////////////////////////////////////////////////////////////////////////////
@ -443,10 +429,6 @@ typedef struct TRI_v8_global_s {
// --SECTION-- REGULAR EXPRESSIONS
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// --SECTION-- private variables
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup V8Globals
/// @{

File diff suppressed because it is too large Load Diff

View File

@ -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);
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -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);

View File

@ -36,7 +36,6 @@
#include <BasicsC/json.h>
#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

View File

@ -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
////////////////////////////////////////////////////////////////////////////////

View File

@ -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
////////////////////////////////////////////////////////////////////////////////

View File

@ -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

View File

@ -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

View File

@ -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) {

View File

@ -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);
}

View File

@ -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 "/"
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

View File

@ -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";
}

View File

@ -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;

View File

@ -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);
}
}
});
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

View File

@ -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"
"/// <ol>\n"
"/// <li>@ref JSModuleAvocadoDefineHttpSystemAction \"avocado.defineHttpSystemAction\"</li>\n"
"/// </ol>\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"\n"
"////////////////////////////////////////////////////////////////////////////////\n"
"/// @page JSModuleAvocado Module \"avocado\"\n"
"///\n"
"/// The following functions are used avocadoly.\n"
"///\n"
"/// <hr>\n"
"/// @copydoc JSModuleAvocadoTOC\n"
"/// <hr>\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"

View File

@ -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;
}

View File

@ -25,27 +25,6 @@
/// @author Copyright 2011-2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @page JSModuleAvocadoTOC
///
/// <ol>
/// <li>@ref JSModuleAvocadoDefineHttpSystemAction "avocado.defineHttpSystemAction"</li>
/// </ol>
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @page JSModuleAvocado Module "avocado"
///
/// The following functions are used avocadoly.
///
/// <hr>
/// @copydoc JSModuleAvocadoTOC
/// <hr>
///
/// @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\\|/// @}\\)"

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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);
}