1
0
Fork 0

added a panic interrupt of memory gets low

This commit is contained in:
Frank Celler 2016-07-31 12:22:20 +02:00
parent 792f42d5af
commit 51683dbda0
12 changed files with 409 additions and 210 deletions

View File

@ -1,6 +1,10 @@
devel
-----
* added a memory expection of V8 memory gets to low
* fixed epoch computation in hybrid logical clock
* fixed thread affinity
* replaced require("internal").db by require("@arangodb").db

View File

@ -41,17 +41,17 @@ using namespace arangodb::aql;
uint64_t AqlValue::hash(arangodb::AqlTransaction* trx, uint64_t seed) const {
switch (type()) {
case VPACK_SLICE_POINTER:
case VPACK_INLINE:
case VPACK_INLINE:
case VPACK_MANAGED: {
// we must use the slow hash function here, because a value may have
// we must use the slow hash function here, because a value may have
// different representations in case its an array/object/number
return slice().normalizedHash(seed);
}
case DOCVEC:
case RANGE: {
case RANGE: {
VPackBuilder builder;
toVelocyPack(trx, builder, false);
// we must use the slow hash function here, because a value may have
// we must use the slow hash function here, because a value may have
// different representations in case its an array/object/number
return builder.slice().normalizedHash(seed);
}
@ -66,7 +66,7 @@ bool AqlValue::isNone() const {
if (t == DOCVEC || t == RANGE) {
return false;
}
return slice().isNone();
}
@ -76,7 +76,7 @@ bool AqlValue::isNull(bool emptyIsNull) const {
if (t == DOCVEC || t == RANGE) {
return false;
}
VPackSlice s(slice());
return (s.isNull() || (emptyIsNull && s.isNone()));
}
@ -126,7 +126,7 @@ bool AqlValue::isArray() const {
}
return slice().isArray();
}
/// @brief get the (array) length (note: this treats ranges as arrays, too!)
size_t AqlValue::length() const {
switch (type()) {
@ -139,23 +139,22 @@ size_t AqlValue::length() const {
return docvecSize();
}
case RANGE: {
return range()->size();
return range()->size();
}
}
TRI_ASSERT(false);
return 0;
}
/// @brief get the (array) element at position
AqlValue AqlValue::at(arangodb::AqlTransaction* trx,
int64_t position, bool& mustDestroy,
bool doCopy) const {
/// @brief get the (array) element at position
AqlValue AqlValue::at(arangodb::AqlTransaction* trx, int64_t position,
bool& mustDestroy, bool doCopy) const {
mustDestroy = false;
switch (type()) {
case VPACK_SLICE_POINTER:
doCopy = false;
doCopy = false;
case VPACK_INLINE:
// fall-through intentional
// fall-through intentional
case VPACK_MANAGED: {
VPackSlice s(slice());
if (s.isArray()) {
@ -190,7 +189,9 @@ AqlValue AqlValue::at(arangodb::AqlTransaction* trx,
// found the correct vector
if (doCopy) {
mustDestroy = true;
return it->getValueReference(static_cast<size_t>(position - total), 0).clone();
return it
->getValueReference(static_cast<size_t>(position - total), 0)
.clone();
}
return it->getValue(static_cast<size_t>(position - total), 0);
}
@ -210,7 +211,8 @@ AqlValue AqlValue::at(arangodb::AqlTransaction* trx,
if (position >= 0 && position < static_cast<int64_t>(n)) {
// only look up the value if it is within array bounds
TransactionBuilderLeaser builder(trx);
builder->add(VPackValue(_data.range->at(static_cast<size_t>(position))));
builder->add(
VPackValue(_data.range->at(static_cast<size_t>(position))));
mustDestroy = true;
return AqlValue(builder->slice());
}
@ -229,9 +231,9 @@ AqlValue AqlValue::getKeyAttribute(arangodb::AqlTransaction* trx,
mustDestroy = false;
switch (type()) {
case VPACK_SLICE_POINTER:
doCopy = false;
doCopy = false;
case VPACK_INLINE:
// fall-through intentional
// fall-through intentional
case VPACK_MANAGED: {
VPackSlice s(slice());
if (s.isObject()) {
@ -248,7 +250,7 @@ AqlValue AqlValue::getKeyAttribute(arangodb::AqlTransaction* trx,
// fall-through intentional
break;
}
case DOCVEC:
case DOCVEC:
case RANGE: {
// will return null
break;
@ -265,14 +267,14 @@ AqlValue AqlValue::getIdAttribute(arangodb::AqlTransaction* trx,
mustDestroy = false;
switch (type()) {
case VPACK_SLICE_POINTER:
doCopy = false;
doCopy = false;
case VPACK_INLINE:
// fall-through intentional
// fall-through intentional
case VPACK_MANAGED: {
VPackSlice s(slice());
if (s.isObject()) {
VPackSlice found = Transaction::extractIdFromDocument(s);
if (found.isCustom()) {
if (found.isCustom()) {
// _id as a custom type needs special treatment
mustDestroy = true;
return AqlValue(trx->extractIdString(trx->resolver(), found, s));
@ -289,7 +291,7 @@ AqlValue AqlValue::getIdAttribute(arangodb::AqlTransaction* trx,
// fall-through intentional
break;
}
case DOCVEC:
case DOCVEC:
case RANGE: {
// will return null
break;
@ -306,9 +308,9 @@ AqlValue AqlValue::getFromAttribute(arangodb::AqlTransaction* trx,
mustDestroy = false;
switch (type()) {
case VPACK_SLICE_POINTER:
doCopy = false;
doCopy = false;
case VPACK_INLINE:
// fall-through intentional
// fall-through intentional
case VPACK_MANAGED: {
VPackSlice s(slice());
if (s.isObject()) {
@ -325,7 +327,7 @@ AqlValue AqlValue::getFromAttribute(arangodb::AqlTransaction* trx,
// fall-through intentional
break;
}
case DOCVEC:
case DOCVEC:
case RANGE: {
// will return null
break;
@ -342,9 +344,9 @@ AqlValue AqlValue::getToAttribute(arangodb::AqlTransaction* trx,
mustDestroy = false;
switch (type()) {
case VPACK_SLICE_POINTER:
doCopy = false;
doCopy = false;
case VPACK_INLINE:
// fall-through intentional
// fall-through intentional
case VPACK_MANAGED: {
VPackSlice s(slice());
if (s.isObject()) {
@ -361,7 +363,7 @@ AqlValue AqlValue::getToAttribute(arangodb::AqlTransaction* trx,
// fall-through intentional
break;
}
case DOCVEC:
case DOCVEC:
case RANGE: {
// will return null
break;
@ -371,22 +373,21 @@ AqlValue AqlValue::getToAttribute(arangodb::AqlTransaction* trx,
// default is to return null
return AqlValue(arangodb::basics::VelocyPackHelper::NullValue());
}
/// @brief get the (object) element by name
AqlValue AqlValue::get(arangodb::AqlTransaction* trx,
std::string const& name, bool& mustDestroy,
bool doCopy) const {
AqlValue AqlValue::get(arangodb::AqlTransaction* trx, std::string const& name,
bool& mustDestroy, bool doCopy) const {
mustDestroy = false;
switch (type()) {
case VPACK_SLICE_POINTER:
doCopy = false;
case VPACK_INLINE:
// fall-through intentional
// fall-through intentional
case VPACK_MANAGED: {
VPackSlice s(slice());
if (s.isObject()) {
VPackSlice found(s.get(name));
if (found.isCustom()) {
if (found.isCustom()) {
// _id needs special treatment
mustDestroy = true;
return AqlValue(trx->extractIdString(s));
@ -403,7 +404,7 @@ AqlValue AqlValue::get(arangodb::AqlTransaction* trx,
// fall-through intentional
break;
}
case DOCVEC:
case DOCVEC:
case RANGE: {
// will return null
break;
@ -416,8 +417,8 @@ AqlValue AqlValue::get(arangodb::AqlTransaction* trx,
/// @brief get the (object) element(s) by name
AqlValue AqlValue::get(arangodb::AqlTransaction* trx,
std::vector<std::string> const& names,
bool& mustDestroy, bool doCopy) const {
std::vector<std::string> const& names, bool& mustDestroy,
bool doCopy) const {
mustDestroy = false;
if (names.empty()) {
return AqlValue(arangodb::basics::VelocyPackHelper::NullValue());
@ -425,10 +426,10 @@ AqlValue AqlValue::get(arangodb::AqlTransaction* trx,
switch (type()) {
case VPACK_SLICE_POINTER:
doCopy = false;
// fall-through intentional
doCopy = false;
// fall-through intentional
case VPACK_INLINE:
// fall-through intentional
// fall-through intentional
case VPACK_MANAGED: {
VPackSlice s(slice());
if (s.isObject()) {
@ -444,7 +445,7 @@ AqlValue AqlValue::get(arangodb::AqlTransaction* trx,
if (s.isExternal()) {
s = s.resolveExternal();
}
if (s.isNone()) {
// not found
return AqlValue(arangodb::basics::VelocyPackHelper::NullValue());
@ -474,7 +475,7 @@ AqlValue AqlValue::get(arangodb::AqlTransaction* trx,
// fall-through intentional
break;
}
case DOCVEC:
case DOCVEC:
case RANGE: {
// will return null
break;
@ -495,7 +496,7 @@ bool AqlValue::hasKey(arangodb::AqlTransaction* trx,
VPackSlice s(slice());
return (s.isObject() && s.hasKey(name));
}
case DOCVEC:
case DOCVEC:
case RANGE: {
break;
}
@ -507,7 +508,7 @@ bool AqlValue::hasKey(arangodb::AqlTransaction* trx,
/// @brief get the numeric value of an AqlValue
double AqlValue::toDouble(arangodb::AqlTransaction* trx) const {
bool failed; // will be ignored
bool failed; // will be ignored
return toDouble(trx, failed);
}
@ -549,14 +550,13 @@ double AqlValue::toDouble(arangodb::AqlTransaction* trx, bool& failed) const {
// conversion failed
break;
}
}
else if (s.isArray()) {
} else if (s.isArray()) {
auto length = s.length();
if (length == 0) {
return 0.0;
}
if (length == 1) {
bool mustDestroy; // we can ignore destruction here
bool mustDestroy; // we can ignore destruction here
return at(trx, 0, mustDestroy, false).toDouble(trx, failed);
}
}
@ -566,7 +566,7 @@ double AqlValue::toDouble(arangodb::AqlTransaction* trx, bool& failed) const {
case DOCVEC:
case RANGE: {
if (length() == 1) {
bool mustDestroy; // we can ignore destruction here
bool mustDestroy; // we can ignore destruction here
return at(trx, 0, mustDestroy, false).toDouble(trx, failed);
}
// will return 0
@ -601,8 +601,7 @@ int64_t AqlValue::toInt64(arangodb::AqlTransaction* trx) const {
}
// conversion failed
}
}
else if (s.isArray()) {
} else if (s.isArray()) {
auto length = s.length();
if (length == 0) {
return 0;
@ -639,13 +638,13 @@ bool AqlValue::toBoolean() const {
VPackSlice s(slice());
if (s.isBoolean()) {
return s.getBoolean();
}
}
if (s.isNumber()) {
return (s.getNumber<double>() != 0.0);
}
}
if (s.isString()) {
return (s.getStringLength() > 0);
}
}
if (s.isArray() || s.isObject() || s.isCustom()) {
// custom _id type is also true
return true;
@ -653,7 +652,7 @@ bool AqlValue::toBoolean() const {
// all other cases, including Null and None
return false;
}
case DOCVEC:
case DOCVEC:
case RANGE: {
return true;
}
@ -723,9 +722,8 @@ v8::Handle<v8::Value> AqlValue::toV8Partial(
}
/// @brief construct a V8 value as input for the expression execution in V8
v8::Handle<v8::Value> AqlValue::toV8(
v8::Isolate* isolate, arangodb::AqlTransaction* trx) const {
v8::Handle<v8::Value> AqlValue::toV8(v8::Isolate* isolate,
arangodb::AqlTransaction* trx) const {
switch (type()) {
case VPACK_SLICE_POINTER:
case VPACK_INLINE:
@ -744,6 +742,10 @@ v8::Handle<v8::Value> AqlValue::toV8(
size_t const n = it->size();
for (size_t i = 0; i < n; ++i) {
result->Set(j++, it->getValueReference(i, 0).toV8(isolate, trx));
if (V8PlatformFeature::isOutOfMemory(isolate)) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
}
}
}
return result;
@ -755,8 +757,15 @@ v8::Handle<v8::Value> AqlValue::toV8(
for (uint32_t i = 0; i < n; ++i) {
// is it safe to use a double here (precision loss)?
result->Set(i, v8::Number::New(isolate,
static_cast<double>(_data.range->at(static_cast<size_t>(i)))));
result->Set(
i, v8::Number::New(isolate, static_cast<double>(_data.range->at(
static_cast<size_t>(i)))));
if (i % 1000 == 0) {
if (V8PlatformFeature::isOutOfMemory(isolate)) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
}
}
}
return result;
}
@ -767,7 +776,7 @@ v8::Handle<v8::Value> AqlValue::toV8(
}
/// @brief materializes a value into the builder
void AqlValue::toVelocyPack(AqlTransaction* trx,
void AqlValue::toVelocyPack(AqlTransaction* trx,
arangodb::velocypack::Builder& builder,
bool resolveExternals) const {
switch (type()) {
@ -775,8 +784,8 @@ void AqlValue::toVelocyPack(AqlTransaction* trx,
if (!resolveExternals && isMasterPointer()) {
builder.addExternal(_data.pointer);
break;
} // fallthrough intentional
case VPACK_INLINE:
} // fallthrough intentional
case VPACK_INLINE:
case VPACK_MANAGED: {
if (resolveExternals) {
arangodb::basics::VelocyPackHelper::SanitizeExternals(slice(), builder);
@ -790,7 +799,8 @@ void AqlValue::toVelocyPack(AqlTransaction* trx,
for (auto const& it : *_data.docvec) {
size_t const n = it->size();
for (size_t i = 0; i < n; ++i) {
it->getValueReference(i, 0).toVelocyPack(trx, builder, resolveExternals);
it->getValueReference(i, 0).toVelocyPack(trx, builder,
resolveExternals);
}
}
builder.close();
@ -809,19 +819,21 @@ void AqlValue::toVelocyPack(AqlTransaction* trx,
}
/// @brief materializes a value into the builder
AqlValue AqlValue::materialize(AqlTransaction* trx, bool& hasCopied, bool resolveExternals) const {
AqlValue AqlValue::materialize(AqlTransaction* trx, bool& hasCopied,
bool resolveExternals) const {
switch (type()) {
case VPACK_SLICE_POINTER:
case VPACK_INLINE:
case VPACK_INLINE:
case VPACK_MANAGED: {
hasCopied = false;
return *this;
}
case DOCVEC:
case DOCVEC:
case RANGE: {
bool shouldDelete = true;
ConditionalDeleter<VPackBuffer<uint8_t>> deleter(shouldDelete);
std::shared_ptr<VPackBuffer<uint8_t>> buffer(new VPackBuffer<uint8_t>, deleter);
std::shared_ptr<VPackBuffer<uint8_t>> buffer(new VPackBuffer<uint8_t>,
deleter);
VPackBuilder builder(buffer);
toVelocyPack(trx, builder, resolveExternals);
hasCopied = true;
@ -853,7 +865,8 @@ AqlValue AqlValue::clone() const {
// copy buffer
VPackValueLength length = _data.buffer->size();
auto buffer = new VPackBuffer<uint8_t>(length);
buffer->append(reinterpret_cast<char const*>(_data.buffer->data()), length);
buffer->append(reinterpret_cast<char const*>(_data.buffer->data()),
length);
return AqlValue(buffer);
}
case DOCVEC: {
@ -883,8 +896,8 @@ AqlValue AqlValue::clone() const {
/// @brief destroy the value's internals
void AqlValue::destroy() {
switch (type()) {
case VPACK_SLICE_POINTER:
switch (type()) {
case VPACK_SLICE_POINTER:
case VPACK_INLINE: {
// nothing to do
return;
@ -905,8 +918,8 @@ void AqlValue::destroy() {
break;
}
}
erase(); // to prevent duplicate deletion
erase(); // to prevent duplicate deletion
}
/// @brief return the slice from the value
@ -941,10 +954,10 @@ VPackSlice AqlValue::slice() const {
AqlValue AqlValue::CreateFromBlocks(
arangodb::AqlTransaction* trx, std::vector<AqlItemBlock*> const& src,
std::vector<std::string> const& variableNames) {
bool shouldDelete = true;
ConditionalDeleter<VPackBuffer<uint8_t>> deleter(shouldDelete);
std::shared_ptr<VPackBuffer<uint8_t>> buffer(new VPackBuffer<uint8_t>, deleter);
std::shared_ptr<VPackBuffer<uint8_t>> buffer(new VPackBuffer<uint8_t>,
deleter);
VPackBuilder builder(buffer);
builder.openArray();
@ -980,17 +993,18 @@ AqlValue AqlValue::CreateFromBlocks(
AqlValue AqlValue::CreateFromBlocks(
arangodb::AqlTransaction* trx, std::vector<AqlItemBlock*> const& src,
arangodb::aql::RegisterId expressionRegister) {
bool shouldDelete = true;
ConditionalDeleter<VPackBuffer<uint8_t>> deleter(shouldDelete);
std::shared_ptr<VPackBuffer<uint8_t>> buffer(new VPackBuffer<uint8_t>, deleter);
std::shared_ptr<VPackBuffer<uint8_t>> buffer(new VPackBuffer<uint8_t>,
deleter);
VPackBuilder builder(buffer);
builder.openArray();
for (auto const& current : src) {
for (size_t i = 0; i < current->size(); ++i) {
current->getValueReference(i, expressionRegister).toVelocyPack(trx, builder, false);
current->getValueReference(i, expressionRegister)
.toVelocyPack(trx, builder, false);
}
}
@ -1000,23 +1014,24 @@ AqlValue AqlValue::CreateFromBlocks(
/// @brief 3-way comparison for AqlValue objects
int AqlValue::Compare(arangodb::AqlTransaction* trx, AqlValue const& left,
AqlValue const& right,
bool compareUtf8) {
AqlValue const& right, bool compareUtf8) {
VPackOptions* options = trx->transactionContext()->getVPackOptions();
AqlValue::AqlValueType const leftType = left.type();
AqlValue::AqlValueType const rightType = right.type();
if (leftType != rightType) {
if (leftType == RANGE || rightType == RANGE || leftType == DOCVEC || rightType == DOCVEC) {
if (leftType == RANGE || rightType == RANGE || leftType == DOCVEC ||
rightType == DOCVEC) {
// range|docvec against x
VPackBuilder leftBuilder;
left.toVelocyPack(trx, leftBuilder, false);
VPackBuilder rightBuilder;
right.toVelocyPack(trx, rightBuilder, false);
return arangodb::basics::VelocyPackHelper::compare(leftBuilder.slice(), rightBuilder.slice(), compareUtf8, options);
return arangodb::basics::VelocyPackHelper::compare(
leftBuilder.slice(), rightBuilder.slice(), compareUtf8, options);
}
// fall-through to other types intentional
}
@ -1027,7 +1042,8 @@ int AqlValue::Compare(arangodb::AqlTransaction* trx, AqlValue const& left,
case VPACK_SLICE_POINTER:
case VPACK_INLINE:
case VPACK_MANAGED: {
return arangodb::basics::VelocyPackHelper::compare(left.slice(), right.slice(), compareUtf8, options);
return arangodb::basics::VelocyPackHelper::compare(
left.slice(), right.slice(), compareUtf8, options);
}
case DOCVEC: {
// use lexicographic ordering of AqlValues regardless of block,
@ -1051,8 +1067,10 @@ int AqlValue::Compare(arangodb::AqlTransaction* trx, AqlValue const& left,
size_t rrows = right._data.docvec->at(0)->size();
while (lblock < lsize && rblock < rsize) {
AqlValue const& lval = left._data.docvec->at(lblock)->getValueReference(litem, 0);
AqlValue const& rval = right._data.docvec->at(rblock)->getValueReference(ritem, 0);
AqlValue const& lval =
left._data.docvec->at(lblock)->getValueReference(litem, 0);
AqlValue const& rval =
right._data.docvec->at(rblock)->getValueReference(ritem, 0);
int cmp = Compare(trx, lval, rval, compareUtf8);
@ -1101,4 +1119,3 @@ int AqlValue::Compare(arangodb::AqlTransaction* trx, AqlValue const& left,
return 0;
}

View File

@ -721,8 +721,7 @@ QueryResult Query::execute(QueryRegistry* registry) {
}
}
/// @brief execute an AQL query
/// may only be called with an active V8 handle scope
// execute an AQL query: may only be called with an active V8 handle scope
QueryResultV8 Query::executeV8(v8::Isolate* isolate, QueryRegistry* registry) {
LOG_TOPIC(DEBUG, Logger::QUERIES) << TRI_microtime() - _startTime << " "
<< "Query::executeV8" << " this: " << (uintptr_t) this;
@ -829,6 +828,10 @@ QueryResultV8 Query::executeV8(v8::Isolate* isolate, QueryRegistry* registry) {
if (!val.isEmpty()) {
result.result->Set(j++, val.toV8(isolate, _trx));
}
if (V8PlatformFeature::isOutOfMemory(isolate)) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
}
}
}
delete value;

View File

@ -23,8 +23,8 @@
#include "ConsoleThread.h"
#include <iostream>
#include <v8.h>
#include <iostream>
#include "ApplicationFeatures/ApplicationServer.h"
#include "Basics/MutexLocker.h"
@ -157,14 +157,20 @@ start_pretty_print();
}
while (!isStopping() && !_userAborted.load()) {
if (nrCommands >= gcInterval) {
if (nrCommands >= gcInterval ||
V8PlatformFeature::isOutOfMemory(isolate)) {
TRI_RunGarbageCollectionV8(isolate, 0.5);
nrCommands = 0;
// needs to be reset after the garbage collection
V8PlatformFeature::resetOutOfMemory(isolate);
}
std::string input;
bool eof;
isolate->CancelTerminateExecution();
{
MUTEX_LOCKER(mutexLocker, serverConsoleMutex);
input = console.prompt("arangod> ", "arangod", eof);

View File

@ -25,8 +25,8 @@
#include "Utils/CollectionNameResolver.h"
#include "VocBase/transaction.h"
#include "V8/v8-globals.h"
#include <v8.h>
#include "V8/v8-globals.h"
using namespace arangodb;
@ -34,28 +34,31 @@ using namespace arangodb;
/// @brief create the context
////////////////////////////////////////////////////////////////////////////////
V8TransactionContext::V8TransactionContext(TRI_vocbase_t* vocbase, bool embeddable)
V8TransactionContext::V8TransactionContext(TRI_vocbase_t* vocbase,
bool embeddable)
: TransactionContext(vocbase),
_sharedTransactionContext(static_cast<V8TransactionContext*>(
static_cast<TRI_v8_global_t*>(v8::Isolate::GetCurrent()->GetData(
V8DataSlot))->_transactionContext)),
V8PlatformFeature::V8_DATA_SLOT))
->_transactionContext)),
_mainScope(nullptr),
_currentTransaction(nullptr),
_embeddable(embeddable) {
}
_embeddable(embeddable) {}
//////////////////////////////////////////////////////////////////////////////
/// @brief order a custom type handler for the collection
//////////////////////////////////////////////////////////////////////////////
std::shared_ptr<VPackCustomTypeHandler> V8TransactionContext::orderCustomTypeHandler() {
std::shared_ptr<VPackCustomTypeHandler>
V8TransactionContext::orderCustomTypeHandler() {
if (_customTypeHandler == nullptr) {
V8TransactionContext* main = _sharedTransactionContext->_mainScope;
if (main != nullptr && main != this && !main->isGlobal()) {
_customTypeHandler = main->orderCustomTypeHandler();
} else {
_customTypeHandler.reset(TransactionContext::createCustomTypeHandler(_vocbase, getResolver()));
_customTypeHandler.reset(
TransactionContext::createCustomTypeHandler(_vocbase, getResolver()));
}
_options.customTypeHandler = _customTypeHandler.get();
_dumpOptions.customTypeHandler = _customTypeHandler.get();
@ -82,7 +85,7 @@ CollectionNameResolver const* V8TransactionContext::getResolver() {
_resolver = createResolver();
}
}
TRI_ASSERT(_resolver != nullptr);
return _resolver;
}
@ -132,7 +135,7 @@ bool V8TransactionContext::isEmbeddable() const { return _embeddable; }
////////////////////////////////////////////////////////////////////////////////
void V8TransactionContext::makeGlobal() { _sharedTransactionContext = this; }
////////////////////////////////////////////////////////////////////////////////
/// @brief whether or not the transaction context is a global one
////////////////////////////////////////////////////////////////////////////////
@ -147,19 +150,19 @@ bool V8TransactionContext::isGlobal() const {
bool V8TransactionContext::IsEmbedded() {
TRI_v8_global_t* v8g = static_cast<TRI_v8_global_t*>(
v8::Isolate::GetCurrent()->GetData(V8DataSlot));
v8::Isolate::GetCurrent()->GetData(V8PlatformFeature::V8_DATA_SLOT));
if (v8g->_transactionContext == nullptr) {
return false;
}
return static_cast<V8TransactionContext*>(v8g->_transactionContext)
->_currentTransaction != nullptr;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief create a context, returned in a shared ptr
////////////////////////////////////////////////////////////////////////////////
std::shared_ptr<V8TransactionContext> V8TransactionContext::Create(TRI_vocbase_t* vocbase, bool embeddable) {
std::shared_ptr<V8TransactionContext> V8TransactionContext::Create(
TRI_vocbase_t* vocbase, bool embeddable) {
return std::make_shared<V8TransactionContext>(vocbase, embeddable);
}

View File

@ -568,6 +568,27 @@ void V8DealerFeature::exitContext(V8Context* context) {
bool canceled = false;
if (V8PlatformFeature::isOutOfMemory(isolate)) {
static double const availableTime = 300.0;
v8::HandleScope scope(isolate);
{
auto localContext =
v8::Local<v8::Context>::New(isolate, context->_context);
localContext->Enter();
{
v8::Context::Scope contextScope(localContext);
TRI_RunGarbageCollectionV8(isolate, availableTime);
}
// needs to be reset after the garbage collection
V8PlatformFeature::resetOutOfMemory(isolate);
localContext->Exit();
}
}
// update data for later garbage collection
{
TRI_GET_GLOBALS();
@ -858,10 +879,7 @@ void V8DealerFeature::initializeContext(size_t i) {
"V8Platform");
TRI_ASSERT(v8platform != nullptr);
v8::Isolate::CreateParams createParams;
createParams.array_buffer_allocator = v8platform->arrayBufferAllocator();
v8::Isolate* isolate = v8::Isolate::New(createParams);
v8::Isolate* isolate = v8platform->createIsolate();
V8Context* context = _contexts[i] = new V8Context();
TRI_ASSERT(context->_locker == nullptr);

View File

@ -83,7 +83,6 @@ void V8ShellFeature::collectOptions(std::shared_ptr<ProgramOptions> options) {
void V8ShellFeature::validateOptions(
std::shared_ptr<options::ProgramOptions> options) {
if (_startupDirectory.empty()) {
LOG(FATAL) << "'--javascript.startup-directory' is empty, giving up";
FATAL_ERROR_EXIT();
@ -94,12 +93,14 @@ void V8ShellFeature::validateOptions(
}
void V8ShellFeature::start() {
_console = application_features::ApplicationServer::getFeature<ConsoleFeature>("Console");
auto platform = application_features::ApplicationServer::getFeature<V8PlatformFeature>("V8Platform");
_console =
application_features::ApplicationServer::getFeature<ConsoleFeature>(
"Console");
auto platform =
application_features::ApplicationServer::getFeature<V8PlatformFeature>(
"V8Platform");
v8::Isolate::CreateParams createParams;
createParams.array_buffer_allocator = platform->arrayBufferAllocator();
_isolate = v8::Isolate::New(createParams);
_isolate = platform->createIsolate();
v8::Locker locker{_isolate};
@ -141,8 +142,8 @@ void V8ShellFeature::unprepare() {
v8::Local<v8::Context>::New(_isolate, _context);
v8::Context::Scope context_scope{context};
// remove any objects stored in _last global value
// remove any objects stored in _last global value
context->Global()->Delete(TRI_V8_ASCII_STRING2(_isolate, "_last"));
TRI_RunGarbageCollectionV8(_isolate, 2500.0);
@ -152,9 +153,9 @@ void V8ShellFeature::unprepare() {
v8::Locker locker{_isolate};
v8::Isolate::Scope isolate_scope{_isolate};
TRI_v8_global_t* v8g =
static_cast<TRI_v8_global_t*>(_isolate->GetData(V8DataSlot));
_isolate->SetData(V8DataSlot, nullptr);
TRI_v8_global_t* v8g = static_cast<TRI_v8_global_t*>(
_isolate->GetData(arangodb::V8PlatformFeature::V8_DATA_SLOT));
_isolate->SetData(arangodb::V8PlatformFeature::V8_DATA_SLOT, nullptr);
delete v8g;
@ -401,9 +402,13 @@ int V8ShellFeature::runShell(std::vector<std::string> const& positionals) {
_console->flushLog();
// gc
if (++nrCommands >= _gcInterval) {
if (++nrCommands >= _gcInterval ||
V8PlatformFeature::isOutOfMemory(_isolate)) {
nrCommands = 0;
TRI_RunGarbageCollectionV8(_isolate, 500.0);
// needs to be reset after the garbage collection
V8PlatformFeature::resetOutOfMemory(_isolate);
}
}

View File

@ -22,25 +22,27 @@
#include "ApplicationFeatures/V8PlatformFeature.h"
#include "Basics/StringUtils.h"
#include "Logger/Logger.h"
#include "ProgramOptions/ProgramOptions.h"
#include "ProgramOptions/Section.h"
using namespace arangodb;
using namespace arangodb::basics;
using namespace arangodb::options;
namespace {
class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
public:
virtual void* Allocate(size_t length) override {
void* data = AllocateUninitialized(length);
return data == nullptr ? data : memset(data, 0, length);
}
virtual void* AllocateUninitialized(size_t length) override {
return malloc(length);
}
virtual void Free(void* data, size_t) override { free(data); }
};
class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
public:
virtual void* Allocate(size_t length) override {
void* data = AllocateUninitialized(length);
return data == nullptr ? data : memset(data, 0, length);
}
virtual void* AllocateUninitialized(size_t length) override {
return malloc(length);
}
virtual void Free(void* data, size_t) override { free(data); }
};
}
V8PlatformFeature::V8PlatformFeature(
@ -56,16 +58,34 @@ void V8PlatformFeature::collectOptions(
options->addSection("javascript", "Configure the Javascript engine");
options->addHiddenOption("--javascript.v8-options", "options to pass to v8",
new StringParameter(&_v8options));
new VectorParameter<StringParameter>(&_v8Options));
options->addOption("--javascript.v8-max-heap", "maximal heap size",
new UInt64Parameter(&_v8MaxHeap));
}
void V8PlatformFeature::validateOptions(
std::shared_ptr<ProgramOptions> options) {
if (!_v8Options.empty()) {
_v8CombinedOptions = StringUtils::join(_v8Options, " ");
if (_v8CombinedOptions == "help") {
std::string help = "--help";
v8::V8::SetFlagsFromString(help.c_str(), (int)help.size());
exit(EXIT_SUCCESS);
}
}
}
void V8PlatformFeature::start() {
v8::V8::InitializeICU();
// explicit option --javascript.v8-options used
if (!_v8options.empty()) {
LOG(INFO) << "using V8 options '" << _v8options << "'";
v8::V8::SetFlagsFromString(_v8options.c_str(), (int)_v8options.size());
if (!_v8CombinedOptions.empty()) {
LOG_TOPIC(INFO, Logger::V8) << "using V8 options '" << _v8CombinedOptions
<< "'";
v8::V8::SetFlagsFromString(_v8CombinedOptions.c_str(),
(int)_v8CombinedOptions.size());
}
#ifdef TRI_FORCE_ARMV6
@ -86,3 +106,69 @@ void V8PlatformFeature::unprepare() {
_platform.reset();
_allocator.reset();
}
void gcPrologueCallback(v8::Isolate* isolate, v8::GCType type,
v8::GCCallbackFlags flags) {
// if (type != v8::kGCTypeMarkSweepCompact) {
// return;
// }
v8::HeapStatistics h;
isolate->GetHeapStatistics(&h);
V8PlatformFeature::getIsolateData(isolate)->_heapSizeAtStart =
h.used_heap_size();
}
void gcEpilogueCallback(v8::Isolate* isolate, v8::GCType type,
v8::GCCallbackFlags flags) {
static size_t const LIMIT_ABS = 200 * 1024 * 1024;
size_t minFreed = LIMIT_ABS / 10;
if (type != v8::kGCTypeMarkSweepCompact) {
minFreed = 0;
}
v8::HeapStatistics h;
isolate->GetHeapStatistics(&h);
size_t freed = 0;
size_t heapSizeAtStop = h.used_heap_size();
size_t heapSizeAtStart =
V8PlatformFeature::getIsolateData(isolate)->_heapSizeAtStart;
if (heapSizeAtStop < heapSizeAtStart) {
freed = heapSizeAtStart - heapSizeAtStop;
}
size_t heapSizeLimit = h.heap_size_limit();
size_t usedHeadSize = h.used_heap_size();
size_t stillFree = heapSizeLimit - usedHeadSize;
if (stillFree <= LIMIT_ABS && freed <= minFreed) {
LOG(WARN) << "reached heap-size limit, interrupting V8 execution ("
<< "heap size limit " << heapSizeLimit << ", used "
<< usedHeadSize << ")";
isolate->TerminateExecution();
V8PlatformFeature::setOutOfMemory(isolate);
}
}
v8::Isolate* V8PlatformFeature::createIsolate() {
v8::Isolate::CreateParams createParams;
createParams.array_buffer_allocator = _allocator.get();
if (0 < _v8MaxHeap) {
createParams.constraints.set_max_old_space_size(_v8MaxHeap);
}
auto isolate = v8::Isolate::New(createParams);
isolate->AddGCPrologueCallback(gcPrologueCallback);
isolate->AddGCEpilogueCallback(gcEpilogueCallback);
_isolateData.emplace_back(new IsolateData());
isolate->SetData(V8_INFO, _isolateData.back().get());
return isolate;
}

View File

@ -25,30 +25,60 @@
#include "ApplicationFeatures/ApplicationFeature.h"
#include <v8.h>
#include <libplatform/libplatform.h>
#include <v8.h>
namespace arangodb {
class V8PlatformFeature final
: public application_features::ApplicationFeature {
private:
struct IsolateData {
bool _outOfMemory = false;
size_t _heapSizeAtStart = 0;
};
public:
static IsolateData* getIsolateData(v8::Isolate* isolate) {
return reinterpret_cast<IsolateData*>(isolate->GetData(V8_INFO));
}
static bool isOutOfMemory(v8::Isolate* isolate) {
return getIsolateData(isolate)->_outOfMemory;
}
static void setOutOfMemory(v8::Isolate* isolate) {
getIsolateData(isolate)->_outOfMemory = true;
}
static void resetOutOfMemory(v8::Isolate* isolate) {
getIsolateData(isolate)->_outOfMemory = false;
}
public:
static const uint32_t V8_INFO = 0;
static const uint32_t V8_DATA_SLOT = 1;
public:
explicit V8PlatformFeature(application_features::ApplicationServer* server);
public:
void collectOptions(std::shared_ptr<options::ProgramOptions>) override final;
void validateOptions(std::shared_ptr<options::ProgramOptions>) override final;
void start() override final;
void unprepare() override final;
v8::ArrayBuffer::Allocator* arrayBufferAllocator() const {
return _allocator.get();
}
private:
std::string _v8options;
std::vector<std::string> _v8Options;
uint64_t _v8MaxHeap = 3 * 1024;
public:
v8::Isolate* createIsolate();
private:
std::unique_ptr<v8::Platform> _platform;
std::unique_ptr<v8::ArrayBuffer::Allocator> _allocator;
std::string _v8CombinedOptions;
std::vector<std::unique_ptr<IsolateData>> _isolateData;
};
}

View File

@ -218,7 +218,7 @@ TRI_v8_global_t* TRI_CreateV8Globals(v8::Isolate* isolate) {
TRI_ASSERT(v8g == nullptr);
v8g = new TRI_v8_global_t(isolate);
isolate->SetData(V8DataSlot, v8g);
isolate->SetData(arangodb::V8PlatformFeature::V8_DATA_SLOT, v8g);
return v8g;
}

View File

@ -26,12 +26,10 @@
#include "Basics/Common.h"
#include <v8.h>
#include "ApplicationFeatures/V8PlatformFeature.h"
struct TRI_vocbase_t;
static const uint32_t V8DataSlot = 0;
////////////////////////////////////////////////////////////////////////////////
/// @brief shortcut for fetching the isolate from the thread context
////////////////////////////////////////////////////////////////////////////////
@ -45,7 +43,6 @@ static const uint32_t V8DataSlot = 0;
#define TRI_V8_TRY_CATCH_BEGIN(isolateVar) \
auto isolateVar = args.GetIsolate(); \
try {
////////////////////////////////////////////////////////////////////////////////
/// @brief macro to terminate a try-catch sequence for V8 callbacks
////////////////////////////////////////////////////////////////////////////////
@ -76,7 +73,7 @@ static const uint32_t V8DataSlot = 0;
v8::String::NewFromOneByte(isolate, (uint8_t const*)(name), \
v8::String::kNormalString, (int)strlen(name))
#define TRI_V8_ASCII_STD_STRING(isolate, name) \
#define TRI_V8_ASCII_STD_STRING(isolate, name) \
v8::String::NewFromOneByte(isolate, (uint8_t const*)(name.c_str()), \
v8::String::kNormalString, (int)name.size())
@ -135,11 +132,11 @@ static const uint32_t V8DataSlot = 0;
/// @brief shortcut for current v8 globals and scope
////////////////////////////////////////////////////////////////////////////////
#define TRI_V8_CURRENT_GLOBALS_AND_SCOPE \
TRI_v8_global_t* v8g = \
static_cast<TRI_v8_global_t*>(isolate->GetData(V8DataSlot)); \
v8::HandleScope scope(isolate); \
do { \
#define TRI_V8_CURRENT_GLOBALS_AND_SCOPE \
TRI_v8_global_t* v8g = static_cast<TRI_v8_global_t*>( \
isolate->GetData(arangodb::V8PlatformFeature::V8_DATA_SLOT)); \
v8::HandleScope scope(isolate); \
do { \
} while (0)
////////////////////////////////////////////////////////////////////////////////
@ -403,13 +400,13 @@ static const uint32_t V8DataSlot = 0;
/// implicitly requires 'isolate' to be available
////////////////////////////////////////////////////////////////////////////////
#define TRI_GET_GLOBALS() \
TRI_v8_global_t* v8g = \
static_cast<TRI_v8_global_t*>(isolate->GetData(V8DataSlot))
#define TRI_GET_GLOBALS() \
TRI_v8_global_t* v8g = static_cast<TRI_v8_global_t*>( \
isolate->GetData(arangodb::V8PlatformFeature::V8_DATA_SLOT))
#define TRI_GET_GLOBALS2(isolate) \
TRI_v8_global_t* v8g = \
static_cast<TRI_v8_global_t*>(isolate->GetData(V8DataSlot))
#define TRI_GET_GLOBALS2(isolate) \
TRI_v8_global_t* v8g = static_cast<TRI_v8_global_t*>( \
isolate->GetData(arangodb::V8PlatformFeature::V8_DATA_SLOT))
////////////////////////////////////////////////////////////////////////////////
/// @brief fetch a string-member from the global into the local scope of the

View File

@ -22,14 +22,16 @@
////////////////////////////////////////////////////////////////////////////////
#include "v8-vpack.h"
#include <velocypack/Iterator.h>
#include <velocypack/velocypack-aliases.h>
#include "ApplicationFeatures/V8PlatformFeature.h"
#include "Basics/Exceptions.h"
#include "Basics/StringRef.h"
#include "Basics/VelocyPackHelper.h"
#include "V8/v8-utils.h"
#include <velocypack/Iterator.h>
#include <velocypack/velocypack-aliases.h>
using VelocyPackHelper = arangodb::basics::VelocyPackHelper;
/// @brief maximum object nesting depth
@ -63,7 +65,7 @@ static v8::Handle<v8::Value> ObjectVPackObject(v8::Isolate* isolate,
if (object.IsEmpty()) {
return v8::Undefined(isolate);
}
TRI_GET_GLOBALS();
VPackObjectIterator it(slice, true);
@ -74,7 +76,8 @@ static v8::Handle<v8::Value> ObjectVPackObject(v8::Isolate* isolate,
if (k.isString()) {
// regular attribute
char const* p = k.getString(l);
object->ForceSet(TRI_V8_PAIR_STRING(p, l), TRI_VPackToV8(isolate, it.value(), options, &slice));
object->ForceSet(TRI_V8_PAIR_STRING(p, l),
TRI_VPackToV8(isolate, it.value(), options, &slice));
} else {
// optimized code path for translated system attributes
VPackSlice v = VPackSlice(k.begin() + 1);
@ -86,31 +89,41 @@ static v8::Handle<v8::Value> ObjectVPackObject(v8::Isolate* isolate,
sub = TRI_VPackToV8(isolate, v, options, &slice);
}
uint8_t which = static_cast<uint8_t>(k.getUInt()) + VelocyPackHelper::AttributeBase;
uint8_t which =
static_cast<uint8_t>(k.getUInt()) + VelocyPackHelper::AttributeBase;
switch (which) {
case VelocyPackHelper::KeyAttribute: {
object->ForceSet(v8::Local<v8::String>::New(isolate, v8g->_KeyKey), sub);
case VelocyPackHelper::KeyAttribute: {
object->ForceSet(v8::Local<v8::String>::New(isolate, v8g->_KeyKey),
sub);
break;
}
case VelocyPackHelper::RevAttribute: {
object->ForceSet(v8::Local<v8::String>::New(isolate, v8g->_RevKey), sub);
case VelocyPackHelper::RevAttribute: {
object->ForceSet(v8::Local<v8::String>::New(isolate, v8g->_RevKey),
sub);
break;
}
case VelocyPackHelper::IdAttribute: {
object->ForceSet(v8::Local<v8::String>::New(isolate, v8g->_IdKey), sub);
object->ForceSet(v8::Local<v8::String>::New(isolate, v8g->_IdKey),
sub);
break;
}
case VelocyPackHelper::FromAttribute: {
object->ForceSet(v8::Local<v8::String>::New(isolate, v8g->_FromKey), sub);
object->ForceSet(v8::Local<v8::String>::New(isolate, v8g->_FromKey),
sub);
break;
}
case VelocyPackHelper::ToAttribute: {
object->ForceSet(v8::Local<v8::String>::New(isolate, v8g->_ToKey), sub);
object->ForceSet(v8::Local<v8::String>::New(isolate, v8g->_ToKey),
sub);
break;
}
}
}
if (arangodb::V8PlatformFeature::isOutOfMemory(isolate)) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
}
it.next();
}
@ -142,6 +155,9 @@ static v8::Handle<v8::Value> ObjectVPackArray(v8::Isolate* isolate,
if (!val.IsEmpty()) {
object->Set(j++, val);
}
if (arangodb::V8PlatformFeature::isOutOfMemory(isolate)) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_OUT_OF_MEMORY);
}
it.next();
}
@ -166,7 +182,8 @@ v8::Handle<v8::Value> TRI_VPackToV8(v8::Isolate* isolate,
case VPackValueType::Double: {
// convert NaN, +inf & -inf to null
double value = slice.getDouble();
if (std::isnan(value) || !std::isfinite(value) || value == HUGE_VAL || value == -HUGE_VAL) {
if (std::isnan(value) || !std::isfinite(value) || value == HUGE_VAL ||
value == -HUGE_VAL) {
return v8::Null(isolate);
}
return v8::Number::New(isolate, slice.getDouble());
@ -179,7 +196,8 @@ v8::Handle<v8::Value> TRI_VPackToV8(v8::Isolate* isolate,
}
if (value >= 0 && value <= 4294967295LL) {
// value is within bounds of a uint32_t
return v8::Integer::NewFromUnsigned(isolate, static_cast<uint32_t>(value));
return v8::Integer::NewFromUnsigned(isolate,
static_cast<uint32_t>(value));
}
// must use double to avoid truncation
return v8::Number::New(isolate, static_cast<double>(slice.getInt()));
@ -188,7 +206,8 @@ v8::Handle<v8::Value> TRI_VPackToV8(v8::Isolate* isolate,
uint64_t value = slice.getUInt();
if (value <= 4294967295ULL) {
// value is within bounds of a uint32_t
return v8::Integer::NewFromUnsigned(isolate, static_cast<uint32_t>(value));
return v8::Integer::NewFromUnsigned(isolate,
static_cast<uint32_t>(value));
}
// must use double to avoid truncation
return v8::Number::New(isolate, static_cast<double>(slice.getUInt()));
@ -207,10 +226,12 @@ v8::Handle<v8::Value> TRI_VPackToV8(v8::Isolate* isolate,
}
case VPackValueType::External: {
// resolve external
return TRI_VPackToV8(isolate, VPackSlice(slice.getExternal()), options, base);
return TRI_VPackToV8(isolate, VPackSlice(slice.getExternal()), options,
base);
}
case VPackValueType::Custom: {
if (options == nullptr || options->customTypeHandler == nullptr || base == nullptr) {
if (options == nullptr || options->customTypeHandler == nullptr ||
base == nullptr) {
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL,
"Could not extract custom attribute.");
}
@ -219,9 +240,7 @@ v8::Handle<v8::Value> TRI_VPackToV8(v8::Isolate* isolate,
return TRI_V8_STD_STRING(id);
}
case VPackValueType::None:
default: {
return v8::Undefined(isolate);
}
default: { return v8::Undefined(isolate); }
}
}
@ -244,8 +263,9 @@ struct BuilderContext {
/// @brief adds a VPackValue to either an array or an object
////////////////////////////////////////////////////////////////////////////////
template<typename T, bool inObject>
static inline void AddValue(BuilderContext& context, arangodb::StringRef const& attributeName,
template <typename T, bool inObject>
static inline void AddValue(BuilderContext& context,
arangodb::StringRef const& attributeName,
T const& value) {
if (inObject) {
context.builder.add(attributeName.begin(), attributeName.size(), value);
@ -262,34 +282,33 @@ template <bool performAllChecks, bool inObject>
static int V8ToVPack(BuilderContext& context,
v8::Handle<v8::Value> const parameter,
arangodb::StringRef const& attributeName) {
if (parameter->IsNull() || parameter->IsUndefined()) {
AddValue<VPackValue, inObject>(context, attributeName,
VPackValue(VPackValueType::Null));
VPackValue(VPackValueType::Null));
return TRI_ERROR_NO_ERROR;
}
if (parameter->IsBoolean()) {
AddValue<VPackValue, inObject>(context, attributeName,
VPackValue(parameter->ToBoolean()->Value()));
VPackValue(parameter->ToBoolean()->Value()));
return TRI_ERROR_NO_ERROR;
}
if (parameter->IsNumber()) {
if (parameter->IsInt32()) {
AddValue<VPackValue, inObject>(context, attributeName,
VPackValue(parameter->ToInt32()->Value()));
VPackValue(parameter->ToInt32()->Value()));
return TRI_ERROR_NO_ERROR;
}
if (parameter->IsUint32()) {
AddValue<VPackValue, inObject>(context, attributeName,
VPackValue(parameter->ToUint32()->Value()));
AddValue<VPackValue, inObject>(
context, attributeName, VPackValue(parameter->ToUint32()->Value()));
return TRI_ERROR_NO_ERROR;
}
AddValue<VPackValue, inObject>(context, attributeName,
VPackValue(parameter->ToNumber()->Value()));
VPackValue(parameter->ToNumber()->Value()));
return TRI_ERROR_NO_ERROR;
}
@ -300,7 +319,9 @@ static int V8ToVPack(BuilderContext& context,
return TRI_ERROR_OUT_OF_MEMORY;
}
AddValue<VPackValuePair, inObject>(context, attributeName, VPackValuePair(*str, str.length(), VPackValueType::String));
AddValue<VPackValuePair, inObject>(
context, attributeName,
VPackValuePair(*str, str.length(), VPackValueType::String));
return TRI_ERROR_NO_ERROR;
}
@ -308,7 +329,7 @@ static int V8ToVPack(BuilderContext& context,
v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(parameter);
AddValue<VPackValue, inObject>(context, attributeName,
VPackValue(VPackValueType::Array));
VPackValue(VPackValueType::Array));
uint32_t const n = array->Length();
for (uint32_t i = 0; i < n; ++i) {
@ -323,8 +344,9 @@ static int V8ToVPack(BuilderContext& context,
return TRI_ERROR_BAD_PARAMETER;
}
int res = V8ToVPack<performAllChecks, false>(context, value, arangodb::StringRef());
int res = V8ToVPack<performAllChecks, false>(context, value,
arangodb::StringRef());
--context.level;
if (res != TRI_ERROR_NO_ERROR) {
@ -341,16 +363,18 @@ static int V8ToVPack(BuilderContext& context,
if (parameter->IsObject()) {
if (performAllChecks) {
if (parameter->IsBooleanObject()) {
AddValue<VPackValue, inObject>(context, attributeName,
VPackValue(v8::Handle<v8::BooleanObject>::Cast(parameter)
->BooleanValue()));
AddValue<VPackValue, inObject>(
context, attributeName,
VPackValue(v8::Handle<v8::BooleanObject>::Cast(parameter)
->BooleanValue()));
return TRI_ERROR_NO_ERROR;
}
if (parameter->IsNumberObject()) {
AddValue<VPackValue, inObject>(context, attributeName,
VPackValue(v8::Handle<v8::NumberObject>::Cast(parameter)
->NumberValue()));
AddValue<VPackValue, inObject>(
context, attributeName,
VPackValue(
v8::Handle<v8::NumberObject>::Cast(parameter)->NumberValue()));
return TRI_ERROR_NO_ERROR;
}
@ -361,7 +385,9 @@ static int V8ToVPack(BuilderContext& context,
return TRI_ERROR_OUT_OF_MEMORY;
}
AddValue<VPackValuePair, inObject>(context, attributeName, VPackValuePair(*str, str.length(), VPackValueType::String));
AddValue<VPackValuePair, inObject>(
context, attributeName,
VPackValuePair(*str, str.length(), VPackValueType::String));
return TRI_ERROR_NO_ERROR;
}
@ -379,7 +405,8 @@ static int V8ToVPack(BuilderContext& context,
// call it if yes
v8::Handle<v8::Value> func = o->Get(context.toJsonKey);
if (func->IsFunction()) {
v8::Handle<v8::Function> toJson = v8::Handle<v8::Function>::Cast(func);
v8::Handle<v8::Function> toJson =
v8::Handle<v8::Function>::Cast(func);
v8::Handle<v8::Value> args;
v8::Handle<v8::Value> converted = toJson->Call(o, 0, &args);
@ -393,7 +420,9 @@ static int V8ToVPack(BuilderContext& context,
}
// this passes ownership for the utf8 string to the JSON object
AddValue<VPackValuePair, inObject>(context, attributeName, VPackValuePair(*str, str.length(), VPackValueType::String));
AddValue<VPackValuePair, inObject>(
context, attributeName,
VPackValuePair(*str, str.length(), VPackValueType::String));
return TRI_ERROR_NO_ERROR;
}
}
@ -406,7 +435,7 @@ static int V8ToVPack(BuilderContext& context,
uint32_t const n = names->Length();
AddValue<VPackValue, inObject>(context, attributeName,
VPackValue(VPackValueType::Object));
VPackValue(VPackValueType::Object));
for (uint32_t i = 0; i < n; ++i) {
// process attribute name
@ -428,8 +457,9 @@ static int V8ToVPack(BuilderContext& context,
return TRI_ERROR_BAD_PARAMETER;
}
int res = V8ToVPack<performAllChecks, true>(context, value, arangodb::StringRef(*str, str.length()));
int res = V8ToVPack<performAllChecks, true>(
context, value, arangodb::StringRef(*str, str.length()));
--context.level;
if (res != TRI_ERROR_NO_ERROR) {
@ -466,10 +496,10 @@ int TRI_V8ToVPack(v8::Isolate* isolate, VPackBuilder& builder,
/// does not contain types such as Function, Date or RegExp
////////////////////////////////////////////////////////////////////////////////
int TRI_V8ToVPackSimple(v8::Isolate* isolate, arangodb::velocypack::Builder& builder,
int TRI_V8ToVPackSimple(v8::Isolate* isolate,
arangodb::velocypack::Builder& builder,
v8::Handle<v8::Value> const value) {
// a HandleScope must have been created by the caller already
BuilderContext context(isolate, builder, false);
return V8ToVPack<false, false>(context, value, arangodb::StringRef());
}