1
0
Fork 0

Merge branch 'devel' of github.com:triAGENS/ArangoDB into devel

This commit is contained in:
Michael Hackstein 2013-05-21 09:30:01 +02:00
commit 6bf1d00d18
27 changed files with 1537 additions and 275 deletions

View File

@ -15,6 +15,8 @@ v1.4
v1.3.1 (2013-XX-XX)
-------------------
* issue #530: ReferenceError: ArangoError is not a constructor
* issue #535: Problem with AQL user functions javascript API
* set --javascript.app-path for test execution to prevent startup error

View File

@ -28,7 +28,11 @@ start () {
chown arangodb $PIDDIR
$DAEMON -c $CONF --pid-file "$PIDFILE" --supervisor $@
log_end_msg $?
RETVAL=$?
log_end_msg $RETVAL
return $RETVAL
}
case "$1" in
@ -36,25 +40,30 @@ case "$1" in
log_daemon_msg "Starting $DESC" "$NAME"
start
exit $?
;;
stop)
log_daemon_msg "Stopping $DESC" "$NAME"
start-stop-daemon --stop --quiet --oknodo --exec $DAEMON --startas $DAEMON
log_end_msg $?
RETVAL=$?
log_end_msg $RETVAL
test -f $PIDFILE && rm -f $PIDFILE
exit $RETVAL
;;
restart)
$0 stop
sleep 3
$0 start
exit $?
;;
force-reload)
$0 restart
exit $?
;;
status)
@ -65,6 +74,7 @@ case "$1" in
log_daemon_msg "Upgrading $DESC" "$NAME"
start --upgrade
exit $?
;;
*)

View File

@ -786,6 +786,7 @@ static TRI_aql_node_t* OptimiseLimit (TRI_aql_statement_walker_t* const walker,
TRI_aql_node_t* node) {
TRI_aql_scope_t* scope;
TRI_aql_node_t* limit;
aql_optimiser_t* optimiser = (aql_optimiser_t*) walker->_data;
int64_t limitValue;
assert(node);
@ -794,7 +795,27 @@ static TRI_aql_node_t* OptimiseLimit (TRI_aql_statement_walker_t* const walker,
assert(scope);
limit = TRI_AQL_NODE_MEMBER(node, 1);
limitValue = TRI_AQL_NODE_INT(limit);
if (limit->_type != TRI_AQL_NODE_VALUE) {
return node;
}
if (limit->_value._type == TRI_AQL_TYPE_INT) {
limitValue = TRI_AQL_NODE_INT(limit);
}
else if (limit->_value._type == TRI_AQL_TYPE_DOUBLE) {
limitValue = (int64_t) TRI_AQL_NODE_DOUBLE(limit);
}
else if (limit->_value._type == TRI_AQL_TYPE_NULL) {
limitValue = 0;
}
else if (limit->_value._type == TRI_AQL_TYPE_BOOL) {
limitValue = (int64_t) TRI_AQL_NODE_BOOL(limit);
}
else {
TRI_SetErrorContextAql(optimiser->_context, TRI_ERROR_QUERY_NUMBER_OUT_OF_RANGE, NULL);
return node;
}
// check for the easy case, a limit value of 0, e.g. LIMIT 10, 0
if (limitValue == 0) {

View File

@ -750,17 +750,20 @@ static int RollbackInsert (TRI_document_collection_t* document,
static int RollbackUpdate (TRI_document_collection_t* document,
TRI_doc_mptr_t* newHeader,
TRI_doc_mptr_t* oldHeader) {
TRI_doc_mptr_t* oldHeader,
bool adjustHeader) {
int res;
assert(newHeader != NULL);
assert(oldHeader != NULL);
// ignore any errors we're getting from this
DeleteSecondaryIndexes(document, newHeader, true);
// put back the header into its old position
document->_headers->move(document->_headers, newHeader, oldHeader);
if (adjustHeader) {
// put back the header into its old position
document->_headers->move(document->_headers, newHeader, oldHeader);
}
*newHeader = *oldHeader;
@ -779,7 +782,8 @@ static int RollbackUpdate (TRI_document_collection_t* document,
static int RollbackRemove (TRI_document_collection_t* document,
TRI_doc_mptr_t* newHeader,
TRI_doc_mptr_t* oldHeader) {
TRI_doc_mptr_t* oldHeader,
bool adjustHeader) {
int res;
// there is no new header
@ -794,8 +798,10 @@ static int RollbackRemove (TRI_document_collection_t* document,
LOG_ERROR("error rolling back remove operation");
}
// put back the header into its old position
document->_headers->relink(document->_headers, oldHeader, oldHeader);
if (adjustHeader) {
// put back the header into its old position
document->_headers->relink(document->_headers, oldHeader, oldHeader);
}
return res;
}
@ -851,7 +857,7 @@ static int InsertDocument (TRI_transaction_collection_t* trxCollection,
TRI_doc_mptr_t* mptr,
bool* freeMarker) {
TRI_document_collection_t* document;
bool written;
bool directOperation;
int res;
TRI_ASSERT_MAINTAINER(*freeMarker == true);
@ -893,8 +899,8 @@ static int InsertDocument (TRI_transaction_collection_t* trxCollection,
&marker->base,
totalSize,
forceSync,
&written);
if (! written) {
&directOperation);
if (! directOperation) {
*freeMarker = false;
}
@ -918,11 +924,13 @@ static int InsertDocument (TRI_transaction_collection_t* trxCollection,
idx->postInsert(trxCollection, idx, header);
}
}
return TRI_ERROR_NO_ERROR;
}
else {
// something has failed.... now delete from the indexes again
RollbackInsert(document, header, NULL);
}
// something has failed.... now delete from the indexes again
RollbackInsert(document, header, NULL);
TRI_ASSERT_MAINTAINER(*freeMarker == true);
return res;
}
@ -988,7 +996,7 @@ static int RemoveDocument (TRI_transaction_collection_t* trxCollection,
TRI_primary_collection_t* primary;
TRI_document_collection_t* document;
TRI_doc_mptr_t* header;
bool written;
bool directOperation;
int res;
TRI_ASSERT_MAINTAINER(*freeMarker == true);
@ -1048,22 +1056,24 @@ static int RemoveDocument (TRI_transaction_collection_t* trxCollection,
&marker->base,
totalSize,
forceSync,
&written);
&directOperation);
if (! written) {
if (! directOperation) {
*freeMarker = false;
}
if (res == TRI_ERROR_NO_ERROR) {
if (written) {
if (directOperation) {
// release the header pointer
document->_headers->release(document->_headers, header);
}
return TRI_ERROR_NO_ERROR;
}
else {
// deletion failed. roll back
RollbackRemove(document, NULL, header);
}
// deletion failed. roll back
RollbackRemove(document, NULL, header, ! directOperation);
TRI_ASSERT_MAINTAINER(*freeMarker == true);
return res;
}
@ -1153,7 +1163,7 @@ static int UpdateDocument (TRI_transaction_collection_t* trxCollection,
TRI_doc_mptr_t* newHeader;
TRI_doc_mptr_t oldData;
int res;
bool written;
bool directOperation;
TRI_ASSERT_MAINTAINER(*freeMarker == true);
document = (TRI_document_collection_t*) trxCollection->_collection->_collection;
@ -1215,23 +1225,25 @@ static int UpdateDocument (TRI_transaction_collection_t* trxCollection,
&marker->base,
totalSize,
forceSync,
&written);
&directOperation);
if (! written) {
if (! directOperation) {
*freeMarker = false;
}
if (res == TRI_ERROR_NO_ERROR) {
if (written) {
if (directOperation) {
document->_headers->moveBack(document->_headers, oldHeader);
}
// write new header into result
*mptr = *((TRI_doc_mptr_t*) newHeader);
return TRI_ERROR_NO_ERROR;
}
else {
RollbackUpdate(document, newHeader, &oldData);
}
RollbackUpdate(document, newHeader, &oldData, ! directOperation);
TRI_ASSERT_MAINTAINER(*freeMarker == true);
return res;
}
@ -2988,10 +3000,10 @@ int TRI_RollbackOperationDocumentCollection (TRI_document_collection_t* document
res = RollbackInsert(document, newHeader, NULL);
}
else if (type == TRI_VOC_DOCUMENT_OPERATION_UPDATE) {
res = RollbackUpdate(document, newHeader, oldData);
res = RollbackUpdate(document, newHeader, oldData, true);
}
else if (type == TRI_VOC_DOCUMENT_OPERATION_REMOVE) {
res = RollbackRemove(document, NULL, oldHeader);
res = RollbackRemove(document, NULL, oldHeader, true);
}
else {
res = TRI_ERROR_INTERNAL;
@ -3057,6 +3069,10 @@ int TRI_WriteOperationDocumentCollection (TRI_document_collection_t* document,
bool waitForSync) {
int res;
TRI_DEBUG_INTENTIONAL_FAIL_IF("TRI_WriteOperationDocumentCollection") {
return TRI_ERROR_INTERNAL;
}
if (type == TRI_VOC_DOCUMENT_OPERATION_INSERT) {
res = WriteInsertMarker(document, (TRI_doc_document_key_marker_t*) marker, newHeader, totalSize, waitForSync);
}

View File

@ -234,29 +234,38 @@ static void MoveHeader (TRI_headers_t* h,
if (old->_prev == NULL) {
headers->_begin = header;
}
else if (headers->_begin == header) {
if (header->_next != NULL) {
headers->_begin = header->_next;
}
}
if (old->_next == NULL) {
headers->_end = header;
}
if (header->_prev != NULL && header->_prev == old->_next) {
header->_prev->_next = NULL;
headers->_end = header->_prev;
else if (headers->_end == header) {
if (header->_prev != NULL) {
headers->_end = header->_prev;
}
}
else if (header->_next != NULL && header->_next == old->_prev) {
header->_next->_prev = NULL;
headers->_begin = header->_next;
if (header->_prev != NULL) {
if (header->_prev == old->_next) {
header->_prev->_next = NULL;
}
else {
header->_prev->_next = header->_next;
}
}
/*
if (headers->_begin == old->_next) {
// adjust list start pointer
headers->_begin = header;
if (header->_next != NULL) {
if (header->_next == old->_prev) {
header->_next->_prev = NULL;
}
else {
header->_next->_prev = header->_prev;
}
}
*/
/*
if (old->_next == NULL) {
// adjust list end pointer
headers->_end = header;
}
*/
if (old->_prev != NULL) {
old->_prev->_next = header;
@ -273,11 +282,7 @@ static void MoveHeader (TRI_headers_t* h,
else {
header->_next = NULL;
}
/*
header->_prev = old->_prev;
header->_next = old->_next;
*/
TRI_ASSERT_MAINTAINER(headers->_begin != NULL);
TRI_ASSERT_MAINTAINER(headers->_end != NULL);
TRI_ASSERT_MAINTAINER(header->_prev != header);

View File

@ -491,12 +491,15 @@ static int AddCollectionOperation (TRI_transaction_collection_t* trxCollection,
transaction_operation_t trxOperation;
int res;
TRI_DEBUG_INTENTIONAL_FAIL_IF("AddCollectionOperation-OOM") {
return TRI_ERROR_OUT_OF_MEMORY;
}
if (trxCollection->_operations == NULL) {
res = InitCollectionOperations(trxCollection);
if (res != TRI_ERROR_NO_ERROR) {
return res;
return TRI_ERROR_OUT_OF_MEMORY;
}
}
@ -514,21 +517,23 @@ static int AddCollectionOperation (TRI_transaction_collection_t* trxCollection,
}
res = TRI_PushBackVector(trxCollection->_operations, &trxOperation);
if (res != TRI_ERROR_NO_ERROR) {
return TRI_ERROR_OUT_OF_MEMORY;
}
if (res == TRI_ERROR_NO_ERROR) {
if (type == TRI_VOC_DOCUMENT_OPERATION_UPDATE) {
TRI_document_collection_t* document = (TRI_document_collection_t*) trxCollection->_collection->_collection;
if (type == TRI_VOC_DOCUMENT_OPERATION_UPDATE) {
TRI_document_collection_t* document = (TRI_document_collection_t*) trxCollection->_collection->_collection;
document->_headers->moveBack(document->_headers, oldHeader);
}
else if (type == TRI_VOC_DOCUMENT_OPERATION_REMOVE) {
TRI_document_collection_t* document = (TRI_document_collection_t*) trxCollection->_collection->_collection;
document->_headers->moveBack(document->_headers, oldHeader);
}
else if (type == TRI_VOC_DOCUMENT_OPERATION_REMOVE) {
TRI_document_collection_t* document = (TRI_document_collection_t*) trxCollection->_collection->_collection;
document->_headers->unlink(document->_headers, oldHeader);
}
document->_headers->unlink(document->_headers, oldHeader);
}
return res;
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
@ -1687,7 +1692,7 @@ int TRI_AddOperationCollectionTransaction (TRI_transaction_collection_t* trxColl
TRI_df_marker_t* marker,
size_t totalSize,
bool syncRequested,
bool* written) {
bool* directOperation) {
TRI_transaction_t* trx;
TRI_primary_collection_t* primary;
int res;
@ -1699,13 +1704,8 @@ int TRI_AddOperationCollectionTransaction (TRI_transaction_collection_t* trxColl
trxCollection->_originalRevision = primary->base._info._tick;
}
// the tick value of a marker must always be greater than the tick value of any other
// existing marker in the collection
TRI_SetRevisionDocumentCollection((TRI_document_collection_t*) primary, marker->_tick);
if (trx->_hints & ((TRI_transaction_hint_t) TRI_TRANSACTION_HINT_SINGLE_OPERATION)) {
// just one operation in the transaction. we can write the marker directly
// TODO: error checking
res = TRI_WriteOperationDocumentCollection((TRI_document_collection_t*) primary,
type,
newHeader,
@ -1714,14 +1714,22 @@ int TRI_AddOperationCollectionTransaction (TRI_transaction_collection_t* trxColl
marker,
totalSize,
syncRequested || trxCollection->_waitForSync || trx->_waitForSync);
*written = true;
*directOperation = true;
}
else {
trx->_hasOperations = true;
res = AddCollectionOperation(trxCollection, type, newHeader, oldHeader, oldData, marker, totalSize);
*written = false;
if (res == TRI_ERROR_NO_ERROR) {
// if everything went well, this will ensure we don't double free etc. headers
*directOperation = false;
}
else {
TRI_ASSERT_MAINTAINER(res == TRI_ERROR_OUT_OF_MEMORY);
// if something went wrong, this will ensure that we'll not manipulate headers twice
*directOperation = true;
}
}
if (syncRequested) {
@ -1732,6 +1740,14 @@ int TRI_AddOperationCollectionTransaction (TRI_transaction_collection_t* trxColl
trx->_waitForSync = true;
}
if (res == TRI_ERROR_NO_ERROR) {
// operation succeeded, now update the revision id for the collection
// the tick value of a marker must always be greater than the tick value of any other
// existing marker in the collection
TRI_SetRevisionDocumentCollection((TRI_document_collection_t*) primary, marker->_tick);
}
return res;
}

View File

@ -0,0 +1,12 @@
@font-face {
font-family: 'Droid Sans';
font-style: normal;
font-weight: 400;
src: local('Droid Sans'), local('DroidSans'), url(/_admin/ttf/droidsans.ttf) format('truetype');
}
@font-face {
font-family: 'Droid Sans';
font-style: normal;
font-weight: 700;
src: local('Droid Sans Bold'), local('DroidSans-Bold'), url(/_admin/ttf/droidsans-bold.ttf) format('truetype');
}

0
html/admin/css/jquery.gritter.css Executable file → Normal file
View File

View File

@ -8,7 +8,7 @@
<meta name="description" content="ArangoDB Admin Web Interface">
<meta name="author" content="Heiko Kernbach">
<link href='http://fonts.googleapis.com/css?family=Droid+Sans:400,700' rel='stylesheet' type='text/css'/>
<link href='css/droidsans.css' rel='stylesheet' type='text/css'/>
<link href='css/swagger/hightlight.default.css' media='screen' rel='stylesheet' type='text/css'/>
<link href='css/swagger/screen.css' media='screen' rel='stylesheet' type='text/css'/>
@ -132,8 +132,6 @@
<script src="js/modules/org/arangodb/arango-collection-common.js"></script>
<script src="js/modules/org/arangodb/arango-collection.js"></script>
<script src="js/modules/org/arangodb/arango-database.js"></script>
<script src="js/modules/org/arangodb/arango-error-common.js"></script>
<script src="js/modules/org/arangodb/arango-error.js"></script>
<script src="js/modules/org/arangodb/arango-query-cursor.js"></script>
<script src="js/modules/org/arangodb/arango-statement-common.js"></script>
<script src="js/modules/org/arangodb/arango-statement.js"></script>

View File

@ -1,5 +1,6 @@
/*jslint indent: 2, nomen: true, maxlen: 120, vars: true, white: true, plusplus: true, nonpropdel: true, proto: true, regexp: true */
/*global require, module, Module, ArangoError, SYS_DOWNLOAD,
/*global require, module, Module, ArangoError, SYS_DEBUG_SET_FAILAT, SYS_DEBUG_REMOVE_FAILAT,
SYS_DEBUG_CLEAR_FAILAT, SYS_DOWNLOAD,
SYS_EXECUTE, SYS_LOAD, SYS_LOG_LEVEL, SYS_MD5, SYS_OUTPUT, SYS_PROCESS_STATISTICS,
SYS_RAND, SYS_SERVER_STATISTICS, SYS_SPRINTF, SYS_TIME, SYS_START_PAGER, SYS_STOP_PAGER,
SYS_SHA256, SYS_WAIT, SYS_PARSE, SYS_IMPORT_CSV_FILE, SYS_IMPORT_JSON_FILE, SYS_LOG,
@ -59,15 +60,23 @@
/// @brief ArangoError
////////////////////////////////////////////////////////////////////////////////
try {
// necessary for the web interface
if (ArangoError !== undefined) {
exports.ArangoError = ArangoError;
delete ArangoError;
}
if (typeof ArangoError !== "undefined") {
exports.ArangoError = ArangoError;
delete ArangoError;
}
catch (err) {
exports.ArangoError = require("org/arangodb/arango-error").ArangoError;
else {
exports.ArangoError = function (error) {
if (error !== undefined) {
this.error = error.error;
this.code = error.code;
this.errorNum = error.errorNum;
this.errorMessage = error.errorMessage;
}
this.message = this.toString();
}
exports.ArangoError.prototype = Error.prototype;
}
exports.ArangoError.prototype._PRINT = function (context) {
@ -216,6 +225,42 @@
// --SECTION-- public functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief debugSetFailAt
////////////////////////////////////////////////////////////////////////////////
if (typeof SYS_DEBUG_SET_FAILAT !== "undefined") {
exports.debugSetFailAt = SYS_DEBUG_SET_FAILAT;
delete SYS_DEBUG_SET_FAILAT;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief debugRemoveFailAt
////////////////////////////////////////////////////////////////////////////////
if (typeof SYS_DEBUG_REMOVE_FAILAT !== "undefined") {
exports.debugRemoveFailAt = SYS_DEBUG_REMOVE_FAILAT;
delete SYS_DEBUG_REMOVE_FAILAT;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief debugClearFailAt
////////////////////////////////////////////////////////////////////////////////
if (typeof SYS_DEBUG_CLEAR_FAILAT !== "undefined") {
exports.debugClearFailAt = SYS_DEBUG_CLEAR_FAILAT;
delete SYS_DEBUG_CLEAR_FAILAT;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief debugCanUseFailAt
////////////////////////////////////////////////////////////////////////////////
if (typeof SYS_DEBUG_CAN_USE_FAILAT !== "undefined") {
exports.debugCanUseFailAt = SYS_DEBUG_CAN_USE_FAILAT;
delete SYS_DEBUG_CAN_USE_FAILAT;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief download
////////////////////////////////////////////////////////////////////////////////

View File

@ -247,7 +247,7 @@ var unregisterFunctionsGroup = function (group) {
/// @fn JSF_aqlfunctions_register
/// @brief register an AQL user function
///
/// @FUN{aqlfunctions.register(@FA{name}, @FA{code}, @FA{isDeterministic}, @FA{testValues})}
/// @FUN{aqlfunctions.register(@FA{name}, @FA{code}, @FA{isDeterministic})}
///
/// Registers an AQL user function, identified by a fully qualified function
/// name. The function code in @FA{code} must be specified as a Javascript
@ -280,7 +280,7 @@ var registerFunction = function (name, code, isDeterministic) {
var testCode = "(function() { var callback = " + code + "; return callback; })()";
try {
var res = INTERNAL.executeScript(testCode, undefined, "(user function " + name + ")");
var res = internal.executeScript(testCode, undefined, "(user function " + name + ")");
}
catch (err1) {
var err = new ArangoError();

View File

@ -1,81 +0,0 @@
module.define("org/arangodb/arango-error-common", function(exports, module) {
/*jslint indent: 2, nomen: true, maxlen: 100, sloppy: true, vars: true, white: true, plusplus: true */
/*global require */
////////////////////////////////////////////////////////////////////////////////
/// @brief ArangoError
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2013 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 Dr. Frank Celler
/// @author Copyright 2012-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
var arangodb = require("org/arangodb");
var ArangoError = require("org/arangodb/arango-error").ArangoError;
// -----------------------------------------------------------------------------
// --SECTION-- ArangoError
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// --SECTION-- private methods
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoShell
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief prints the object
////////////////////////////////////////////////////////////////////////////////
ArangoError.prototype._PRINT = function (context) {
context.output += this.toString();
};
////////////////////////////////////////////////////////////////////////////////
/// @brief converts into a string
////////////////////////////////////////////////////////////////////////////////
ArangoError.prototype.toString = function() {
var errorNum = this.errorNum;
var errorMessage = this.errorMessage;
return "[ArangoError " + errorNum + ": " + errorMessage + "]";
};
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @}\\|/\\*jslint"
// End:
});

View File

@ -1,78 +0,0 @@
module.define("org/arangodb/arango-error", function(exports, module) {
/*jslint indent: 2, nomen: true, maxlen: 100, sloppy: true, vars: true, white: true, plusplus: true */
/*global require, exports */
////////////////////////////////////////////////////////////////////////////////
/// @brief ArangoError
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2013 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 Dr. Frank Celler
/// @author Copyright 2012-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
var internal = require("internal");
// -----------------------------------------------------------------------------
// --SECTION-- ArangoError
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// --SECTION-- constructors and destructors
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoShell
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief constructor
////////////////////////////////////////////////////////////////////////////////
function ArangoError (error) {
if (error !== undefined) {
this.error = error.error;
this.code = error.code;
this.errorNum = error.errorNum;
this.errorMessage = error.errorMessage;
}
}
exports.ArangoError = ArangoError;
// must be called after exporting ArangoError
require("org/arangodb/arango-error-common");
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @}\\|/\\*jslint"
// End:
});

View File

@ -1,2 +1,2 @@
<div class="copy"><p>Copyright 2012 triAGENS GmbH | <a href="#about">About</a></p></div>
<div class="copy"><p>Copyright (c) triAGENS GmbH | <a href="#about">About</a></p></div>

View File

@ -60,8 +60,15 @@ var dashboardView = Backbone.View.extend({
$(this.el).html(this.template.text);
//Client calculated charts
self.genCustomCategory("Client calculated charts", "custom", "Customized Charts");
self.genCustomChart();
self.genCustomCategories();
self.genCustomChartDescription(
"userTime + systemTime",
"custom",
"totalTime2",
"Total Time (User+System)",
"accumulated",
"seconds"
);
$.each(this.options.description.models[0].attributes.groups, function () {
$('.thumbnails').append(
@ -98,6 +105,11 @@ var dashboardView = Backbone.View.extend({
}
return this;
},
//generate function for all custom categories
genCustomCategories: function () {
this.genCustomCategory("Client calculated charts", "custom", "Customized Charts");
},
//generate a custom category
genCustomCategory: function(description, group, name) {
this.options.description.models[0].attributes.groups.push({
"description":description,
@ -105,22 +117,26 @@ var dashboardView = Backbone.View.extend({
"name":name
});
},
genCustomChart: function () {
//totalTime
//generate a custom description
genCustomChartDescription: function (description, group, identifier, name, type, units) {
var figure = {
"description" : "userTime + systemTime",
"group" : "custom",
"identifier" : "totalTime2",
"name" : "Total Time (User+System)",
"type" : "accumulated",
"units" : "seconds"
"description" : description,
"group" : group,
"identifier" : identifier,
"name" : name,
"type" : type,
"units" : units
};
this.options.description.models[0].attributes.figures.push(figure);
this.renderFigure(figure);
},
//calculate customized chart value functions here
updateCustomChartValues: function () {
this.totalTime2();
},
updateCustomChart: function () {
//totalTime
//custom chart value calculation for totalTime2
totalTime2: function () {
var val1 = this.collection.models[0].attributes.system.userTime;
var val2 = this.collection.models[0].attributes.system.systemTime;
var totalTime2Value = val1+val2;
@ -283,7 +299,7 @@ var dashboardView = Backbone.View.extend({
calculateSeries: function (flush) {
var self = this;
self.updateCustomChart();
self.updateCustomChartValues();
var timeStamp = Math.round(new Date() * 10);

View File

@ -61,7 +61,7 @@ var shellView = Backbone.View.extend({
var internal = require("internal");
var arangodb = require("org/arangodb");
var client = require("org/arangodb/arangosh");
var header = 'Welcome to arangosh Copyright (c) 2012 triAGENS GmbH.\n';
var header = 'Welcome to arangosh Copyright (c) triAGENS GmbH.\n';
window.jqconsole = $('#replShell').jqconsole(header, 'JSH> ', "...>");
this.executeJs(internal.print(client.HELP));
// Abort prompt on Ctrl+Z.

View File

@ -2,7 +2,7 @@
<html>
<head>
<title>Swagger UI</title>
<link href='http://fonts.googleapis.com/css?family=Droid+Sans:400,700' rel='stylesheet' type='text/css'/>
<link href='css/droidsans.css' rel='stylesheet' type='text/css'/>
<link href='css/swagger/hightlight.default.css' media='screen' rel='stylesheet' type='text/css'/>
<link href='css/swagger/screen.css' media='screen' rel='stylesheet' type='text/css'/>
<script src='js/lib/jquery-1.8.0.min.js' type='text/javascript'></script>

Binary file not shown.

Binary file not shown.

View File

@ -1,5 +1,6 @@
/*jslint indent: 2, nomen: true, maxlen: 120, vars: true, white: true, plusplus: true, nonpropdel: true, proto: true, regexp: true */
/*global require, module, Module, ArangoError, SYS_DOWNLOAD,
/*global require, module, Module, ArangoError, SYS_DEBUG_SET_FAILAT, SYS_DEBUG_REMOVE_FAILAT,
SYS_DEBUG_CLEAR_FAILAT, SYS_DOWNLOAD,
SYS_EXECUTE, SYS_LOAD, SYS_LOG_LEVEL, SYS_MD5, SYS_OUTPUT, SYS_PROCESS_STATISTICS,
SYS_RAND, SYS_SERVER_STATISTICS, SYS_SPRINTF, SYS_TIME, SYS_START_PAGER, SYS_STOP_PAGER,
SYS_SHA256, SYS_WAIT, SYS_PARSE, SYS_IMPORT_CSV_FILE, SYS_IMPORT_JSON_FILE, SYS_LOG,
@ -59,15 +60,23 @@
/// @brief ArangoError
////////////////////////////////////////////////////////////////////////////////
try {
// necessary for the web interface
if (ArangoError !== undefined) {
exports.ArangoError = ArangoError;
delete ArangoError;
}
if (typeof ArangoError !== "undefined") {
exports.ArangoError = ArangoError;
delete ArangoError;
}
catch (err) {
exports.ArangoError = require("org/arangodb/arango-error").ArangoError;
else {
exports.ArangoError = function (error) {
if (error !== undefined) {
this.error = error.error;
this.code = error.code;
this.errorNum = error.errorNum;
this.errorMessage = error.errorMessage;
}
this.message = this.toString();
}
exports.ArangoError.prototype = Error.prototype;
}
exports.ArangoError.prototype._PRINT = function (context) {
@ -216,6 +225,42 @@
// --SECTION-- public functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief debugSetFailAt
////////////////////////////////////////////////////////////////////////////////
if (typeof SYS_DEBUG_SET_FAILAT !== "undefined") {
exports.debugSetFailAt = SYS_DEBUG_SET_FAILAT;
delete SYS_DEBUG_SET_FAILAT;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief debugRemoveFailAt
////////////////////////////////////////////////////////////////////////////////
if (typeof SYS_DEBUG_REMOVE_FAILAT !== "undefined") {
exports.debugRemoveFailAt = SYS_DEBUG_REMOVE_FAILAT;
delete SYS_DEBUG_REMOVE_FAILAT;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief debugClearFailAt
////////////////////////////////////////////////////////////////////////////////
if (typeof SYS_DEBUG_CLEAR_FAILAT !== "undefined") {
exports.debugClearFailAt = SYS_DEBUG_CLEAR_FAILAT;
delete SYS_DEBUG_CLEAR_FAILAT;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief debugCanUseFailAt
////////////////////////////////////////////////////////////////////////////////
if (typeof SYS_DEBUG_CAN_USE_FAILAT !== "undefined") {
exports.debugCanUseFailAt = SYS_DEBUG_CAN_USE_FAILAT;
delete SYS_DEBUG_CAN_USE_FAILAT;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief download
////////////////////////////////////////////////////////////////////////////////

View File

@ -2438,6 +2438,155 @@ function transactionRollbackSuite () {
c1.save({ _key: "test" });
assertEqual(3, c1.count());
assertEqual([ "bar", "baz", "test" ], sortedKeys(c1));
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test: rollback a mixed workload
////////////////////////////////////////////////////////////////////////////////
testRollbackMixed1 : function () {
c1 = db._create(cn1);
var i;
for (i = 0; i < 100; ++i) {
c1.save({ _key: "key" + i, value: i });
}
var obj = {
collections : {
write: [ cn1 ]
},
action : function () {
for (i = 0; i < 50; ++i) {
c1.remove("key" + i);
}
for (i = 50; i < 100; ++i) {
c1.update("key" + i, { value: i - 50 });
}
c1.remove("key50");
throw "doh!";
}
};
try {
TRANSACTION(obj);
fail();
}
catch (err) {
}
assertEqual(100, c1.count());
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test: rollback a mixed workload
////////////////////////////////////////////////////////////////////////////////
testRollbackMixed2 : function () {
c1 = db._create(cn1);
c1.save({ _key: "foo" });
c1.save({ _key: "bar" });
var obj = {
collections : {
write: [ cn1 ]
},
action : function () {
var i;
for (i = 0; i < 10; ++i) {
c1.save({ _key: "key" + i, value: i });
}
for (i = 0; i < 5; ++i) {
c1.remove("key" + i);
}
for (i = 5; i < 10; ++i) {
c1.update("key" + i, { value: i - 5 });
}
c1.remove("key5");
throw "doh!";
}
};
try {
TRANSACTION(obj);
fail();
}
catch (err) {
}
assertEqual(2, c1.count());
assertEqual("foo", c1.document("foo")._key);
assertEqual("bar", c1.document("bar")._key);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test: rollback a mixed workload
////////////////////////////////////////////////////////////////////////////////
testRollbackMixed3 : function () {
c1 = db._create(cn1);
c1.save({ _key: "foo" });
c1.save({ _key: "bar" });
var obj = {
collections : {
write: [ cn1 ]
},
action : function () {
var i;
for (i = 0; i < 10; ++i) {
c1.save({ _key: "key" + i, value: i });
}
for (i = 0; i < 10; ++i) {
c1.remove("key" + i);
}
for (i = 0; i < 10; ++i) {
c1.save({ _key: "key" + i, value: i });
}
for (i = 0; i < 10; ++i) {
c1.update("key" + i, { value: i - 5 });
}
for (i = 0; i < 10; ++i) {
c1.update("key" + i, { value: i + 5 });
}
for (i = 0; i < 10; ++i) {
c1.remove("key" + i);
}
for (i = 0; i < 10; ++i) {
c1.save({ _key: "key" + i, value: i });
}
throw "doh!";
}
};
try {
TRANSACTION(obj);
fail();
}
catch (err) {
}
assertEqual(2, c1.count());
assertEqual("foo", c1.document("foo")._key);
assertEqual("bar", c1.document("bar")._key);
}
};
@ -2898,6 +3047,483 @@ function transactionCrossCollectionSuite () {
};
}
// -----------------------------------------------------------------------------
// --SECTION-- test suite
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief test suite
////////////////////////////////////////////////////////////////////////////////
function transactionServerFailuresSuite () {
var cn = "UnitTestsTransaction";
var c = null;
return {
////////////////////////////////////////////////////////////////////////////////
/// @brief set up
////////////////////////////////////////////////////////////////////////////////
setUp : function () {
internal.debugClearFailAt();
db._drop(cn);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief tear down
////////////////////////////////////////////////////////////////////////////////
tearDown : function () {
internal.debugClearFailAt();
if (c !== null) {
c.drop();
}
c = null;
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test: rollback in case of a server-side fail
////////////////////////////////////////////////////////////////////////////////
testRollbackInsertSingle1 : function () {
c = db._create(cn);
internal.debugSetFailAt("TRI_WriteOperationDocumentCollection");
try {
c.save({ _key: "foo" });
fail();
}
catch (err) {
assertEqual(internal.errors.ERROR_INTERNAL.code, err.errorNum);
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test: rollback in case of a server-side fail
////////////////////////////////////////////////////////////////////////////////
testRollbackInsertSingle2 : function () {
c = db._create(cn);
c.save({ _key: "foo" });
internal.debugSetFailAt("TRI_WriteOperationDocumentCollection");
try {
c.save({ _key: "foo2" });
fail();
}
catch (err) {
assertEqual(internal.errors.ERROR_INTERNAL.code, err.errorNum);
}
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test: rollback in case of a server-side fail
////////////////////////////////////////////////////////////////////////////////
testRollbackInsertMulti1 : function () {
c = db._create(cn);
c.save({ _key: "baz" });
var obj = {
collections : {
write: [ cn ]
},
action : function () {
c.save({ _key: "foo" });
internal.debugSetFailAt("AddCollectionOperation-OOM");
c.save({ _key: "bar" });
fail();
}
};
try {
TRANSACTION(obj);
fail();
}
catch (err) {
assertEqual(internal.errors.ERROR_OUT_OF_MEMORY.code, err.errorNum);
}
assertEqual(1, c.count());
assertEqual("baz", c.document("baz")._key);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test: rollback in case of a server-side fail
////////////////////////////////////////////////////////////////////////////////
testRollbackInsertMulti2 : function () {
c = db._create(cn);
var i;
for (i = 0; i < 100; ++i) {
c.save({ _key: "key" + i });
}
var obj = {
collections : {
write: [ cn ]
},
action : function () {
for (i = 0; i < 100; ++i) {
c.save({ _key: "foo" + i });
}
internal.debugSetFailAt("AddCollectionOperation-OOM");
c.save({ _key: "bar" });
fail();
}
};
try {
TRANSACTION(obj);
fail();
}
catch (err) {
assertEqual(internal.errors.ERROR_OUT_OF_MEMORY.code, err.errorNum);
}
assertEqual(100, c.count());
assertEqual("key0", c.document("key0")._key);
assertEqual("key99", c.document("key99")._key);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test: rollback in case of a server-side fail
////////////////////////////////////////////////////////////////////////////////
testRollbackUpdateSingle1 : function () {
c = db._create(cn);
c.save({ _key: "foo", value: 1 });
internal.debugSetFailAt("TRI_WriteOperationDocumentCollection");
try {
c.update("foo", { value: 2 });
fail();
}
catch (err) {
assertEqual(internal.errors.ERROR_INTERNAL.code, err.errorNum);
}
assertEqual(1, c.count());
assertEqual("foo", c.document("foo")._key);
assertEqual(1, c.document("foo").value);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test: rollback in case of a server-side fail
////////////////////////////////////////////////////////////////////////////////
testRollbackUpdateSingle2 : function () {
c = db._create(cn);
c.save({ _key: "foo", value: 1 });
c.save({ _key: "bar", value: "a" });
c.update("foo", { value: 2 });
internal.debugSetFailAt("TRI_WriteOperationDocumentCollection");
try {
c.update("bar", { value: "b" });
fail();
}
catch (err) {
assertEqual(internal.errors.ERROR_INTERNAL.code, err.errorNum);
}
assertEqual(2, c.count());
assertEqual("foo", c.document("foo")._key);
assertEqual(2, c.document("foo").value);
assertEqual("bar", c.document("bar")._key);
assertEqual("a", c.document("bar").value);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test: rollback in case of a server-side fail
////////////////////////////////////////////////////////////////////////////////
testRollbackUpdateMulti1 : function () {
c = db._create(cn);
c.save({ _key: "foo", value: 1 });
c.save({ _key: "bar", value: "a" });
var obj = {
collections : {
write: [ cn ]
},
action : function () {
c.update("foo", { value: 2 });
internal.debugSetFailAt("AddCollectionOperation-OOM");
c.update("bar", { value: "b" });
fail();
}
};
try {
TRANSACTION(obj);
fail();
}
catch (err) {
assertEqual(internal.errors.ERROR_OUT_OF_MEMORY.code, err.errorNum);
}
assertEqual(2, c.count());
assertEqual("foo", c.document("foo")._key);
assertEqual(1, c.document("foo").value);
assertEqual("bar", c.document("bar")._key);
assertEqual("a", c.document("bar").value);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test: rollback in case of a server-side fail
////////////////////////////////////////////////////////////////////////////////
testRollbackUpdateMulti2 : function () {
c = db._create(cn);
c.save({ _key: "foo", value: 1 });
c.save({ _key: "bar", value: "a" });
var obj = {
collections : {
write: [ cn ]
},
action : function () {
internal.debugSetFailAt("AddCollectionOperation-OOM");
c.update("foo", { value: 2 });
fail();
}
};
try {
TRANSACTION(obj);
fail();
}
catch (err) {
assertEqual(internal.errors.ERROR_OUT_OF_MEMORY.code, err.errorNum);
}
assertEqual(2, c.count());
assertEqual("foo", c.document("foo")._key);
assertEqual(1, c.document("foo").value);
assertEqual("bar", c.document("bar")._key);
assertEqual("a", c.document("bar").value);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test: rollback in case of a server-side fail
////////////////////////////////////////////////////////////////////////////////
testRollbackRemoveSingle1 : function () {
c = db._create(cn);
c.save({ _key: "foo" });
internal.debugSetFailAt("TRI_WriteOperationDocumentCollection");
try {
c.remove("foo");
fail();
}
catch (err) {
assertEqual(internal.errors.ERROR_INTERNAL.code, err.errorNum);
}
assertEqual(1, c.count());
assertEqual("foo", c.document("foo")._key);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test: rollback in case of a server-side fail
////////////////////////////////////////////////////////////////////////////////
testRollbackRemoveSingle2 : function () {
c = db._create(cn);
c.save({ _key: "foo" });
c.save({ _key: "bar" });
internal.debugSetFailAt("TRI_WriteOperationDocumentCollection");
try {
c.remove("foo");
fail();
}
catch (err) {
assertEqual(internal.errors.ERROR_INTERNAL.code, err.errorNum);
}
assertEqual(2, c.count());
assertEqual("foo", c.document("foo")._key);
assertEqual("bar", c.document("bar")._key);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test: rollback in case of a server-side fail
////////////////////////////////////////////////////////////////////////////////
testRollbackRemoveMulti1 : function () {
c = db._create(cn);
c.save({ _key: "foo" });
c.save({ _key: "bar" });
var obj = {
collections : {
write: [ cn ]
},
action : function () {
c.remove("foo");
internal.debugSetFailAt("AddCollectionOperation-OOM");
c.remove("bar");
fail();
}
};
try {
TRANSACTION(obj);
fail();
}
catch (err) {
assertEqual(internal.errors.ERROR_OUT_OF_MEMORY.code, err.errorNum);
}
assertEqual(2, c.count());
assertEqual("foo", c.document("foo")._key);
assertEqual("bar", c.document("bar")._key);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test: rollback in case of a server-side fail
////////////////////////////////////////////////////////////////////////////////
testRollbackRemoveMulti2 : function () {
c = db._create(cn);
c.save({ _key: "foo" });
c.save({ _key: "bar" });
var obj = {
collections : {
write: [ cn ]
},
action : function () {
internal.debugSetFailAt("AddCollectionOperation-OOM");
c.remove("foo");
fail();
}
};
try {
TRANSACTION(obj);
fail();
}
catch (err) {
assertEqual(internal.errors.ERROR_OUT_OF_MEMORY.code, err.errorNum);
}
assertEqual(2, c.count());
assertEqual("foo", c.document("foo")._key);
assertEqual("bar", c.document("bar")._key);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test: rollback in case of a server-side fail
////////////////////////////////////////////////////////////////////////////////
testRollbackRemoveMixed1 : function () {
c = db._create(cn);
var i;
for (i = 0; i < 100; ++i) {
c.save({ _key: "key" + i, value: i });
}
var obj = {
collections : {
write: [ cn ]
},
action : function () {
for (i = 0; i < 50; ++i) {
c.remove("key" + i);
}
for (i = 50; i < 100; ++i) {
c.update("key" + i, { value: i - 50 });
}
internal.debugSetFailAt("AddCollectionOperation-OOM");
c.remove("key50");
fail();
}
};
try {
TRANSACTION(obj);
fail();
}
catch (err) {
assertEqual(internal.errors.ERROR_OUT_OF_MEMORY.code, err.errorNum);
}
assertEqual(100, c.count());
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test: rollback in case of a server-side fail
////////////////////////////////////////////////////////////////////////////////
testRollbackRemoveMixed2 : function () {
c = db._create(cn);
c.save({ _key: "foo" });
c.save({ _key: "bar" });
var obj = {
collections : {
write: [ cn ]
},
action : function () {
var i;
for (i = 0; i < 10; ++i) {
c.save({ _key: "key" + i, value: i });
}
for (i = 0; i < 5; ++i) {
c.remove("key" + i);
}
for (i = 5; i < 10; ++i) {
c.update("key" + i, { value: i - 5 });
}
internal.debugSetFailAt("AddCollectionOperation-OOM");
c.remove("key5");
fail();
}
};
try {
TRANSACTION(obj);
fail();
}
catch (err) {
assertEqual(internal.errors.ERROR_OUT_OF_MEMORY.code, err.errorNum);
}
assertEqual(2, c.count());
assertEqual("foo", c.document("foo")._key);
assertEqual("bar", c.document("bar")._key);
}
};
}
// -----------------------------------------------------------------------------
// --SECTION-- main
// -----------------------------------------------------------------------------
@ -2915,6 +3541,11 @@ jsunity.run(transactionRollbackSuite);
jsunity.run(transactionCountSuite);
jsunity.run(transactionCrossCollectionSuite);
// only run this test suite if server-side failures are enabled
if (internal.debugCanUseFailAt()) {
jsunity.run(transactionServerFailuresSuite);
}
return jsunity.done();
// -----------------------------------------------------------------------------

View File

@ -130,6 +130,7 @@ typedef long suseconds_t;
#define TRI_WITHIN_COMMON 1
#include "BasicsC/voc-errors.h"
#include "BasicsC/error.h"
#include "BasicsC/debugging.h"
#include "BasicsC/memory.h"
#include "BasicsC/mimetypes.h"
#include "BasicsC/structures.h"

371
lib/BasicsC/debugging.c Normal file
View File

@ -0,0 +1,371 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief debugging helpers
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2004-2013 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Jan Steemann
/// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#include "BasicsC/common.h"
#include "BasicsC/debugging.h"
#include "BasicsC/locks.h"
// -----------------------------------------------------------------------------
// --SECTION-- private variables
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup Debugging
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief a global string containing the currently registered failure points
/// the string is a comma-separated list of point names
////////////////////////////////////////////////////////////////////////////////
#ifdef TRI_ENABLE_MAINTAINER_MODE
static char* FailurePoints;
#endif
////////////////////////////////////////////////////////////////////////////////
/// @brief a read-write lock for thread-safe access to the failure-points list
////////////////////////////////////////////////////////////////////////////////
#ifdef TRI_ENABLE_MAINTAINER_MODE
TRI_read_write_lock_t FailurePointsLock;
#endif
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- private functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup Debugging
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief make a delimited value from a string, so we can unambigiously
/// search for it (e.g. searching for just "foo" would find "foo" and "foobar",
/// so we'll be putting the value inside some delimiter: ",foo,")
////////////////////////////////////////////////////////////////////////////////
#ifdef TRI_ENABLE_MAINTAINER_MODE
static char* MakeValue (char const* value) {
char* delimited;
if (value == NULL || strlen(value) == 0) {
return NULL;
}
delimited = TRI_Allocate(TRI_CORE_MEM_ZONE, strlen(value) + 3, false);
if (delimited != NULL) {
memcpy(delimited + 1, value, strlen(value));
delimited[0] = ',';
delimited[strlen(value) + 1] = ',';
delimited[strlen(value) + 2] = '\0';
}
return delimited;
}
#endif
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- public functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup Debugging
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief check whether we should fail at a specific failure point
////////////////////////////////////////////////////////////////////////////////
#ifdef TRI_ENABLE_MAINTAINER_MODE
bool TRI_ShouldFailDebugging (char const* value) {
char* found;
char* checkValue;
checkValue = MakeValue(value);
if (checkValue == NULL) {
return false;
}
TRI_ReadLockReadWriteLock(&FailurePointsLock);
if (FailurePoints == NULL) {
found = NULL;
}
else {
found = strstr(FailurePoints, checkValue);
}
TRI_ReadUnlockReadWriteLock(&FailurePointsLock);
TRI_Free(TRI_CORE_MEM_ZONE, checkValue);
return (found != NULL);
}
#endif
////////////////////////////////////////////////////////////////////////////////
/// @brief add a failure point
////////////////////////////////////////////////////////////////////////////////
void TRI_AddFailurePointDebugging (char const* value) {
#ifdef TRI_ENABLE_MAINTAINER_MODE
char* found;
char* checkValue;
checkValue = MakeValue(value);
if (checkValue == NULL) {
return;
}
TRI_WriteLockReadWriteLock(&FailurePointsLock);
if (FailurePoints == NULL) {
found = NULL;
}
else {
found = strstr(FailurePoints, checkValue);
}
if (found == NULL) {
// not yet found. so add it
char* copy;
size_t n;
n = strlen(checkValue);
if (FailurePoints == NULL) {
copy = TRI_Allocate(TRI_CORE_MEM_ZONE, n + 1, false);
if (copy == NULL) {
TRI_WriteUnlockReadWriteLock(&FailurePointsLock);
TRI_Free(TRI_CORE_MEM_ZONE, checkValue);
return;
}
memcpy(copy, checkValue, n);
copy[n] = '\0';
}
else {
copy = TRI_Allocate(TRI_CORE_MEM_ZONE, n + strlen(FailurePoints), false);
if (copy == NULL) {
TRI_WriteUnlockReadWriteLock(&FailurePointsLock);
TRI_Free(TRI_CORE_MEM_ZONE, checkValue);
return;
}
memcpy(copy, FailurePoints, strlen(FailurePoints));
memcpy(copy + strlen(FailurePoints) - 1, checkValue, n);
copy[strlen(FailurePoints) + n - 1] = '\0';
}
FailurePoints = copy;
}
TRI_WriteUnlockReadWriteLock(&FailurePointsLock);
TRI_Free(TRI_CORE_MEM_ZONE, checkValue);
#else
#endif
}
////////////////////////////////////////////////////////////////////////////////
/// @brief remove a failure points
////////////////////////////////////////////////////////////////////////////////
void TRI_RemoveFailurePointDebugging (char const* value) {
#ifdef TRI_ENABLE_MAINTAINER_MODE
char* checkValue;
TRI_WriteLockReadWriteLock(&FailurePointsLock);
if (FailurePoints == NULL) {
TRI_WriteUnlockReadWriteLock(&FailurePointsLock);
return;
}
checkValue = MakeValue(value);
if (checkValue != NULL) {
char* found;
char* copy;
size_t n;
found = strstr(FailurePoints, checkValue);
if (found == NULL) {
TRI_WriteUnlockReadWriteLock(&FailurePointsLock);
TRI_Free(TRI_CORE_MEM_ZONE, checkValue);
return;
}
if (strlen(FailurePoints) - strlen(checkValue) <= 2) {
TRI_Free(TRI_CORE_MEM_ZONE, FailurePoints);
FailurePoints = NULL;
TRI_WriteUnlockReadWriteLock(&FailurePointsLock);
TRI_Free(TRI_CORE_MEM_ZONE, checkValue);
return;
}
copy = TRI_Allocate(TRI_CORE_MEM_ZONE, strlen(FailurePoints) - strlen(checkValue) + 2, false);
if (copy == NULL) {
TRI_WriteUnlockReadWriteLock(&FailurePointsLock);
TRI_Free(TRI_CORE_MEM_ZONE, checkValue);
return;
}
// copy start of string
n = found - FailurePoints;
memcpy(copy, FailurePoints, n);
// copy remainder of string
memcpy(copy + n, found + strlen(checkValue) - 1, strlen(FailurePoints) - strlen(checkValue) - n + 1);
copy[strlen(FailurePoints) - strlen(checkValue) + 1] = '\0';
TRI_Free(TRI_CORE_MEM_ZONE, FailurePoints);
FailurePoints = copy;
TRI_WriteUnlockReadWriteLock(&FailurePointsLock);
TRI_Free(TRI_CORE_MEM_ZONE, checkValue);
}
#else
#endif
}
////////////////////////////////////////////////////////////////////////////////
/// @brief clear all failure points
////////////////////////////////////////////////////////////////////////////////
void TRI_ClearFailurePointsDebugging () {
#ifdef TRI_ENABLE_MAINTAINER_MODE
TRI_WriteLockReadWriteLock(&FailurePointsLock);
if (FailurePoints != NULL) {
TRI_Free(TRI_CORE_MEM_ZONE, FailurePoints);
}
FailurePoints = NULL;
TRI_WriteUnlockReadWriteLock(&FailurePointsLock);
#else
#endif
}
////////////////////////////////////////////////////////////////////////////////
/// @brief returns whether failure point debugging can be used
////////////////////////////////////////////////////////////////////////////////
bool TRI_CanUseFailurePointsDebugging () {
#ifdef TRI_ENABLE_MAINTAINER_MODE
return true;
#else
return false;
#endif
}
////////////////////////////////////////////////////////////////////////////////
/// @brief initialise the debugging
////////////////////////////////////////////////////////////////////////////////
void TRI_InitialiseDebugging () {
#ifdef TRI_ENABLE_MAINTAINER_MODE
FailurePoints = NULL;
TRI_InitReadWriteLock(&FailurePointsLock);
#endif
}
////////////////////////////////////////////////////////////////////////////////
/// @brief shutdown the debugging
////////////////////////////////////////////////////////////////////////////////
void TRI_ShutdownDebugging () {
#ifdef TRI_ENABLE_MAINTAINER_MODE
if (FailurePoints != NULL) {
TRI_Free(TRI_CORE_MEM_ZONE, FailurePoints);
}
FailurePoints = NULL;
TRI_DestroyReadWriteLock(&FailurePointsLock);
#endif
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:

137
lib/BasicsC/debugging.h Normal file
View File

@ -0,0 +1,137 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief debugging helpers
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2004-2013 triAGENS GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Jan Steemann
/// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#ifndef TRIAGENS_BASICS_C_DEBUGGING_H
#define TRIAGENS_BASICS_C_DEBUGGING_H 1
#ifndef TRI_WITHIN_COMMON
#error use <BasicsC/common.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
// -----------------------------------------------------------------------------
// --SECTION-- public defines
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup Debugging
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief macro TRI_DEBUG_INTENTIONAL_FAIL_IF
/// this macro can be used in maintainer mode to make the server fail at
/// certain locations in the C code. The points at which a failure is actually
/// triggered can be defined at runtime using TRI_AddFailurePointDebugging().
////////////////////////////////////////////////////////////////////////////////
#ifdef TRI_ENABLE_MAINTAINER_MODE
#define TRI_DEBUG_INTENTIONAL_FAIL_IF(what) if (TRI_ShouldFailDebugging(what))
#else
#define TRI_DEBUG_INTENTIONAL_FAIL_IF(what) if (false)
#endif
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- public functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup Debugging
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief check whether we should fail at a failure point
////////////////////////////////////////////////////////////////////////////////
#ifdef TRI_ENABLE_MAINTAINER_MODE
bool TRI_ShouldFailDebugging (char const*);
#endif
////////////////////////////////////////////////////////////////////////////////
/// @brief add a failure point
////////////////////////////////////////////////////////////////////////////////
void TRI_AddFailurePointDebugging (char const*);
////////////////////////////////////////////////////////////////////////////////
/// @brief remove a failure point
////////////////////////////////////////////////////////////////////////////////
void TRI_RemoveFailurePointDebugging (char const*);
////////////////////////////////////////////////////////////////////////////////
/// @brief clear all failure points
////////////////////////////////////////////////////////////////////////////////
void TRI_ClearFailurePointsDebugging (void);
////////////////////////////////////////////////////////////////////////////////
/// @brief returns whether failure point debugging can be used
////////////////////////////////////////////////////////////////////////////////
bool TRI_CanUseFailurePointsDebugging (void);
////////////////////////////////////////////////////////////////////////////////
/// @brief initialise the debugging
////////////////////////////////////////////////////////////////////////////////
void TRI_InitialiseDebugging (void);
////////////////////////////////////////////////////////////////////////////////
/// @brief shutdown the debugging
////////////////////////////////////////////////////////////////////////////////
void TRI_ShutdownDebugging (void);
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
#ifdef __cplusplus
}
#endif
#endif
// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:

View File

@ -52,6 +52,7 @@
void TRI_InitialiseC (int argc, char* argv[]) {
TRI_InitialiseMemory();
TRI_InitialiseDebugging();
TRI_InitialiseMersenneTwister();
TRI_InitialiseError();
TRI_InitialiseFiles();
@ -78,6 +79,7 @@ void TRI_ShutdownC () {
TRI_ShutdownMimetypes();
TRI_ShutdownFiles();
TRI_ShutdownError();
TRI_ShutdownDebugging();
TRI_ShutdownMemory();
}

View File

@ -39,6 +39,7 @@ lib_libarango_a_SOURCES = \
lib/BasicsC/associative.c \
lib/BasicsC/conversions.c \
lib/BasicsC/csv.c \
lib/BasicsC/debugging.c \
lib/BasicsC/error.c \
lib/BasicsC/files.c \
lib/BasicsC/hashes.c \

View File

@ -1959,6 +1959,92 @@ static v8::Handle<v8::Value> JS_Wait (v8::Arguments const& argv) {
return scope.Close(v8::Undefined());
}
////////////////////////////////////////////////////////////////////////////////
/// @brief set a failure point
///
/// @FUN{internal.debugSetFailAt(@FA{point})}
///
/// Set a point for an intentional system failure
////////////////////////////////////////////////////////////////////////////////
static v8::Handle<v8::Value> JS_DebugSetFailAt (v8::Arguments const& argv) {
v8::HandleScope scope;
// extract arguments
if (argv.Length() != 1) {
TRI_V8_EXCEPTION_USAGE(scope, "debugSetFailAt(<point>)");
}
string point = TRI_ObjectToString(argv[0]);
TRI_AddFailurePointDebugging(point.c_str());
return scope.Close(v8::Undefined());
}
////////////////////////////////////////////////////////////////////////////////
/// @brief remove a failure point
///
/// @FUN{internal.debugRemoveFailAt(@FA{point})}
///
/// Remove a point for an intentional system failure
////////////////////////////////////////////////////////////////////////////////
static v8::Handle<v8::Value> JS_DebugRemoveFailAt (v8::Arguments const& argv) {
v8::HandleScope scope;
// extract arguments
if (argv.Length() != 1) {
TRI_V8_EXCEPTION_USAGE(scope, "debugRemoveFailAt(<point>)");
}
string point = TRI_ObjectToString(argv[0]);
TRI_RemoveFailurePointDebugging(point.c_str());
return scope.Close(v8::Undefined());
}
////////////////////////////////////////////////////////////////////////////////
/// @brief clear all failure points
///
/// @FUN{internal.debugClearFailAt()}
///
/// Remove all points for intentional system failures
////////////////////////////////////////////////////////////////////////////////
static v8::Handle<v8::Value> JS_DebugClearFailAt (v8::Arguments const& argv) {
v8::HandleScope scope;
// extract arguments
if (argv.Length() != 0) {
TRI_V8_EXCEPTION_USAGE(scope, "debugClearFailAt()");
}
TRI_ClearFailurePointsDebugging();
return scope.Close(v8::Undefined());
}
////////////////////////////////////////////////////////////////////////////////
/// @brief returns whether failure points can be used
///
/// @FUN{internal.debugCanUseFailAt()}
///
/// Returns whether failure points can be be used
////////////////////////////////////////////////////////////////////////////////
static v8::Handle<v8::Value> JS_DebugCanUseFailAt (v8::Arguments const& argv) {
v8::HandleScope scope;
// extract arguments
if (argv.Length() != 0) {
TRI_V8_EXCEPTION_USAGE(scope, "debugCanUseFailAt()");
}
return scope.Close(TRI_CanUseFailurePointsDebugging() ? v8::True() : v8::False());
}
////////////////////////////////////////////////////////////////////////////////
/// @brief returns the current request and connection statistics
////////////////////////////////////////////////////////////////////////////////
@ -2481,6 +2567,12 @@ void TRI_InitV8Utils (v8::Handle<v8::Context> context,
TRI_AddGlobalFunctionVocbase(context, "SYS_TIME", JS_Time);
TRI_AddGlobalFunctionVocbase(context, "SYS_WAIT", JS_Wait);
// debugging functions
TRI_AddGlobalFunctionVocbase(context, "SYS_DEBUG_SET_FAILAT", JS_DebugSetFailAt);
TRI_AddGlobalFunctionVocbase(context, "SYS_DEBUG_REMOVE_FAILAT", JS_DebugRemoveFailAt);
TRI_AddGlobalFunctionVocbase(context, "SYS_DEBUG_CLEAR_FAILAT", JS_DebugClearFailAt);
TRI_AddGlobalFunctionVocbase(context, "SYS_DEBUG_CAN_USE_FAILAT", JS_DebugCanUseFailAt);
// .............................................................................
// create the global variables
// .............................................................................