1
0
Fork 0

changed reference counting for cursors

This commit is contained in:
Jan Steemann 2013-09-16 13:51:33 +02:00
parent 9c95582703
commit 0bdae05b96
24 changed files with 664 additions and 1150 deletions

View File

@ -411,6 +411,8 @@ void ApplicationMR::stop () {
for (size_t i = 0; i < _nrInstances; ++i) {
shutdownMRInstance(i);
}
delete[] _contexts;
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -106,7 +106,6 @@ bin_arangod_SOURCES = \
arangod/VocBase/replication-logger.c \
arangod/VocBase/replication-master.c \
arangod/VocBase/server.c \
arangod/VocBase/shadow-data.c \
arangod/VocBase/shape-collection.c \
arangod/VocBase/synchroniser.c \
arangod/VocBase/transaction.c \

View File

@ -184,7 +184,9 @@ Handler::status_e RestBatchHandler::execute() {
}
// inject the request context from the framing (batch) request
this->_server->setRequestContext(request, false);
// the "false" means the context is not responsible for resource handling
request->setRequestContext(_request->getRequestContext(), false);
request->setDatabaseName(_request->databaseName());
if (bodyLength > 0) {
LOGGER_TRACE("part body is " << string(bodyStart, bodyLength));

View File

@ -153,7 +153,9 @@ static void DefineAdminHandlers (HttpHandlerFactory* factory,
}
////////////////////////////////////////////////////////////////////////////////
/// @brief determine the requested database
/// @brief determine the requested database from the request URL
/// when the database is present in the request and is still "alive", its
/// reference-counter is increased by one
////////////////////////////////////////////////////////////////////////////////
static TRI_vocbase_t* LookupDatabaseFromRequest (triagens::rest::HttpRequest* request,
@ -218,8 +220,7 @@ static TRI_vocbase_t* LookupDatabaseFromRequest (triagens::rest::HttpRequest* re
////////////////////////////////////////////////////////////////////////////////
static bool SetRequestContext (triagens::rest::HttpRequest* request,
void* data,
bool manageResources) {
void* data) {
TRI_server_t* server = (TRI_server_t*) data;
TRI_vocbase_t* vocbase = LookupDatabaseFromRequest(request, server);
@ -228,8 +229,16 @@ static bool SetRequestContext (triagens::rest::HttpRequest* request,
// invalid database name specified, database not found etc.
return false;
}
VocbaseContext* ctx = new triagens::arango::VocbaseContext(request, server, vocbase);
if (ctx == 0) {
// out of memory
return false;
}
request->setRequestContext(new triagens::arango::VocbaseContext(request, server, vocbase, manageResources));
// the "true" means the request is the owner of the context
request->setRequestContext(ctx, true);
return true;
}

View File

@ -59,12 +59,10 @@ using namespace triagens::rest;
VocbaseContext::VocbaseContext (HttpRequest* request,
TRI_server_t* server,
TRI_vocbase_t* vocbase,
bool releaseDatabase) :
TRI_vocbase_t* vocbase) :
RequestContext(request),
_server(server),
_vocbase(vocbase),
_releaseDatabase(releaseDatabase) {
_vocbase(vocbase) {
assert(_server != 0);
assert(_vocbase != 0);
@ -75,9 +73,7 @@ VocbaseContext::VocbaseContext (HttpRequest* request,
////////////////////////////////////////////////////////////////////////////////
VocbaseContext::~VocbaseContext () {
if (_releaseDatabase) {
TRI_ReleaseVocBase(_vocbase);
}
TRI_ReleaseVocBase(_vocbase);
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -80,8 +80,7 @@ namespace triagens {
VocbaseContext (rest::HttpRequest*,
struct TRI_server_s*,
struct TRI_vocbase_s*,
bool);
struct TRI_vocbase_s*);
////////////////////////////////////////////////////////////////////////////////
/// @brief destructor
@ -145,12 +144,6 @@ namespace triagens {
struct TRI_vocbase_s* _vocbase;
////////////////////////////////////////////////////////////////////////////////
/// @brief whether or not to release the database at end
////////////////////////////////////////////////////////////////////////////////
bool _releaseDatabase;
};
}
}

View File

@ -329,26 +329,29 @@ void ApplicationV8::exitContext (V8Context* context) {
context->handleGlobalContextMethods();
// TODO: setting vocbase to 0 will make the server crash because GC
// might refer to it. But it would be better to reset the vocbase
// pointer after each request so there are no unintended side-effects
// TRI_v8_global_t* v8g = (TRI_v8_global_t*) context->_isolate->GetData();
// set vocbase to 0
// v8g->_vocbase = 0;
++context->_dirt;
// exit the context
context->_context->Exit();
context->_isolate->Exit();
delete context->_locker;
++context->_dirt;
bool performGarbageCollection;
if (context->_lastGcStamp + _gcFrequency < lastGc) {
LOGGER_TRACE("V8 context has reached GC timeout threshold and will be scheduled for GC");
_dirtyContexts.push_back(context);
_busyContexts.erase(context);
performGarbageCollection = true;
}
else if (context->_dirt >= _gcInterval) {
LOGGER_TRACE("V8 context has reached maximum number of requests and will be scheduled for GC");
performGarbageCollection = true;
}
else {
performGarbageCollection = false;
}
if (performGarbageCollection) {
_dirtyContexts.push_back(context);
_busyContexts.erase(context);
}
@ -682,7 +685,6 @@ void ApplicationV8::close () {
////////////////////////////////////////////////////////////////////////////////
void ApplicationV8::stop () {
// stop GC
_gcThread->shutdown();

View File

@ -73,7 +73,6 @@
#include "VocBase/replication-applier.h"
#include "VocBase/replication-logger.h"
#include "VocBase/server.h"
#include "VocBase/shadow-data.h"
#include "VocBase/voc-shaper.h"
#include "v8.h"
#include "V8/JSLoader.h"
@ -463,16 +462,21 @@ static bool IsIndexHandle (v8::Handle<v8::Value> arg,
static void WeakCollectionCallback (v8::Isolate* isolate,
v8::Persistent<v8::Value> object,
void* parameter) {
v8::HandleScope scope; // do not remove, will fail otherwise!!
TRI_v8_global_t* v8g = (TRI_v8_global_t*) v8::Isolate::GetCurrent()->GetData();
TRI_vocbase_col_t* collection = (TRI_vocbase_col_t*) parameter;
// decrease the reference-counter for the collection
v8::HandleScope scope; // do not remove, will fail otherwise!!
// decrease the reference-counter for the database
TRI_ReleaseVocBase(collection->_vocbase);
// find the persistent handle
v8::Persistent<v8::Value> persistent = v8g->JSCollections[collection];
v8g->JSCollections.erase(collection);
// dispose and clear the persistent handle
object.Dispose(isolate);
object.Clear();
persistent.Dispose(isolate);
persistent.Clear();
}
////////////////////////////////////////////////////////////////////////////////
@ -2018,7 +2022,7 @@ static v8::Handle<v8::Value> ExecuteQueryCursorAhuacatl (TRI_vocbase_t* const vo
extra = TRI_ObjectToJson(resultObject->Get(TRI_V8_SYMBOL("extra")));
}
TRI_general_cursor_t* cursor = TRI_CreateGeneralCursor(cursorResult, doCount, batchSize, extra);
TRI_general_cursor_t* cursor = TRI_CreateGeneralCursor(vocbase, cursorResult, doCount, batchSize, extra);
if (cursor == 0) {
TRI_Free(TRI_UNKNOWN_MEM_ZONE, cursorResult);
@ -2030,7 +2034,6 @@ static v8::Handle<v8::Value> ExecuteQueryCursorAhuacatl (TRI_vocbase_t* const vo
}
assert(cursor != 0);
TRI_StoreShadowData(vocbase->_cursors, (const void* const) cursor);
v8::Handle<v8::Value> cursorObject = WrapGeneralCursor(cursor);
@ -2067,15 +2070,12 @@ static void WeakGeneralCursorCallback (v8::Isolate* isolate,
void* parameter) {
v8::HandleScope scope; // do not remove, will fail otherwise!!
LOG_TRACE("weak-callback for general cursor called");
TRI_vocbase_t* vocbase = GetContextVocBase();
if (vocbase == 0) {
return;
}
TRI_EndUsageDataShadowData(vocbase->_cursors, parameter);
TRI_general_cursor_t* cursor = (TRI_general_cursor_t*) parameter;
TRI_ReleaseGeneralCursor(cursor);
// decrease the reference-counter for the database
TRI_ReleaseVocBase(cursor->_vocbase);
// dispose and clear the persistent handle
object.Dispose(isolate);
@ -2093,33 +2093,35 @@ static v8::Handle<v8::Value> WrapGeneralCursor (void* cursor) {
v8::Isolate* isolate = v8::Isolate::GetCurrent();
TRI_v8_global_t* v8g = (TRI_v8_global_t*) isolate->GetData();
v8::Handle<v8::Object> cursorObject = v8g->GeneralCursorTempl->NewInstance();
v8::Handle<v8::Object> result = v8g->GeneralCursorTempl->NewInstance();
if (cursorObject.IsEmpty()) {
// error
return scope.Close(cursorObject);
if (! result.IsEmpty()) {
TRI_general_cursor_t* c = (TRI_general_cursor_t*) cursor;
TRI_UseGeneralCursor(c);
// increase the reference-counter for the database
TRI_UseVocBase(c->_vocbase);
v8::Persistent<v8::Value> persistent = v8::Persistent<v8::Value>::New(isolate, v8::External::New(cursor));
if (tryCatch.HasCaught()) {
return scope.Close(v8::Undefined());
}
result->SetInternalField(SLOT_CLASS_TYPE, v8::Integer::New(WRP_GENERAL_CURSOR_TYPE));
result->SetInternalField(SLOT_CLASS, persistent);
persistent.MakeWeak(isolate, cursor, WeakGeneralCursorCallback);
}
v8::Persistent<v8::Value> persistent = v8::Persistent<v8::Value>::New(isolate, v8::External::New(cursor));
if (tryCatch.HasCaught()) {
return scope.Close(v8::Undefined());
}
cursorObject->SetInternalField(SLOT_CLASS_TYPE, v8::Integer::New(WRP_GENERAL_CURSOR_TYPE));
cursorObject->SetInternalField(SLOT_CLASS, persistent);
persistent.MakeWeak(isolate, cursor, WeakGeneralCursorCallback);
return scope.Close(cursorObject);
return scope.Close(result);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief extracts a cursor from a V8 object
////////////////////////////////////////////////////////////////////////////////
static void* UnwrapGeneralCursor (v8::Handle<v8::Object> cursorObject) {
return TRI_UnwrapClass<void>(cursorObject, WRP_GENERAL_CURSOR_TYPE);
static TRI_general_cursor_t* UnwrapGeneralCursor (v8::Handle<v8::Object> cursorObject) {
return TRI_UnwrapClass<TRI_general_cursor_t>(cursorObject, WRP_GENERAL_CURSOR_TYPE);
}
////////////////////////////////////////////////////////////////////////////////
@ -2636,7 +2638,7 @@ static v8::Handle<v8::Value> JS_CreateCursor (v8::Arguments const& argv) {
TRI_general_cursor_result_t* cursorResult = TRI_CreateResultAql(json);
if (cursorResult != 0) {
cursor = TRI_CreateGeneralCursor(cursorResult, doCount, batchSize, 0);
cursor = TRI_CreateGeneralCursor(vocbase, cursorResult, doCount, batchSize, 0);
if (cursor == 0) {
TRI_Free(TRI_UNKNOWN_MEM_ZONE, cursorResult);
@ -2644,7 +2646,6 @@ static v8::Handle<v8::Value> JS_CreateCursor (v8::Arguments const& argv) {
}
}
else {
TRI_Free(TRI_UNKNOWN_MEM_ZONE, cursorResult);
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
}
@ -2652,9 +2653,8 @@ static v8::Handle<v8::Value> JS_CreateCursor (v8::Arguments const& argv) {
TRI_V8_EXCEPTION_INTERNAL(scope, "cannot create cursor");
}
TRI_StoreShadowData(vocbase->_cursors, (const void* const) cursor);
v8::Handle<v8::Value> cursorObject = WrapGeneralCursor(cursor);
if (cursorObject.IsEmpty()) {
TRI_V8_EXCEPTION_MEMORY(scope);
}
@ -2673,15 +2673,9 @@ static v8::Handle<v8::Value> JS_DisposeGeneralCursor (v8::Arguments const& argv)
TRI_V8_EXCEPTION_USAGE(scope, "dispose()");
}
TRI_vocbase_t* vocbase = GetContextVocBase();
if (vocbase == 0) {
TRI_V8_EXCEPTION(scope, TRI_ERROR_ARANGO_DATABASE_NOT_FOUND);
}
bool found = TRI_DropGeneralCursor(UnwrapGeneralCursor(argv.Holder()));
bool found = TRI_DeleteDataShadowData(vocbase->_cursors, UnwrapGeneralCursor(argv.Holder()));
return scope.Close(found ? v8::True() : v8::False());
return scope.Close(v8::Boolean::New(found));
}
////////////////////////////////////////////////////////////////////////////////
@ -2695,13 +2689,7 @@ static v8::Handle<v8::Value> JS_IdGeneralCursor (v8::Arguments const& argv) {
TRI_V8_EXCEPTION_USAGE(scope, "id()");
}
TRI_vocbase_t* vocbase = GetContextVocBase();
if (vocbase == 0) {
TRI_V8_EXCEPTION(scope, TRI_ERROR_ARANGO_DATABASE_NOT_FOUND);
}
TRI_shadow_id id = TRI_GetIdDataShadowData(vocbase->_cursors, UnwrapGeneralCursor(argv.Holder()));
TRI_voc_tick_t id = TRI_IdGeneralCursor(UnwrapGeneralCursor(argv.Holder()));
if (id != 0) {
return scope.Close(V8TickId(id));
@ -2721,24 +2709,9 @@ static v8::Handle<v8::Value> JS_CountGeneralCursor (v8::Arguments const& argv) {
TRI_V8_EXCEPTION_USAGE(scope, "count()");
}
TRI_vocbase_t* vocbase = GetContextVocBase();
if (vocbase == 0) {
TRI_V8_EXCEPTION(scope, TRI_ERROR_ARANGO_DATABASE_NOT_FOUND);
}
size_t length = TRI_CountGeneralCursor(UnwrapGeneralCursor(argv.Holder()));
TRI_general_cursor_t* cursor;
cursor = (TRI_general_cursor_t*) TRI_BeginUsageDataShadowData(vocbase->_cursors, UnwrapGeneralCursor(argv.Holder()));
if (cursor) {
size_t length = (size_t) cursor->_length;
TRI_EndUsageDataShadowData(vocbase->_cursors, cursor);
return scope.Close(v8::Number::New(length));
}
TRI_V8_EXCEPTION(scope, TRI_ERROR_CURSOR_NOT_FOUND);
return scope.Close(v8::Number::New((double) length));
}
////////////////////////////////////////////////////////////////////////////////
@ -2752,26 +2725,20 @@ static v8::Handle<v8::Value> JS_NextGeneralCursor (v8::Arguments const& argv) {
TRI_V8_EXCEPTION_USAGE(scope, "next()");
}
TRI_vocbase_t* vocbase = GetContextVocBase();
if (vocbase == 0) {
TRI_V8_EXCEPTION(scope, TRI_ERROR_ARANGO_DATABASE_NOT_FOUND);
}
v8::Handle<v8::Value> value;
TRI_general_cursor_t* cursor;
cursor = (TRI_general_cursor_t*) TRI_BeginUsageDataShadowData(vocbase->_cursors, UnwrapGeneralCursor(argv.Holder()));
cursor = (TRI_general_cursor_t*) TRI_UseGeneralCursor(UnwrapGeneralCursor(argv.Holder()));
if (cursor) {
if (cursor != 0) {
bool result = false;
TRI_LockGeneralCursor(cursor);
if (cursor->_length == 0) {
TRI_UnlockGeneralCursor(cursor);
TRI_EndUsageDataShadowData(vocbase->_cursors, cursor);
TRI_ReleaseGeneralCursor(cursor);
return scope.Close(v8::Undefined());
}
@ -2795,8 +2762,7 @@ static v8::Handle<v8::Value> JS_NextGeneralCursor (v8::Arguments const& argv) {
}
TRI_UnlockGeneralCursor(cursor);
TRI_EndUsageDataShadowData(vocbase->_cursors, cursor);
TRI_ReleaseGeneralCursor(cursor);
if (result && ! tryCatch.HasCaught()) {
return scope.Close(value);
@ -2821,19 +2787,8 @@ static v8::Handle<v8::Value> JS_PersistGeneralCursor (v8::Arguments const& argv)
TRI_V8_EXCEPTION_USAGE(scope, "persist()");
}
TRI_vocbase_t* vocbase = GetContextVocBase();
if (vocbase == 0) {
TRI_V8_EXCEPTION(scope, TRI_ERROR_ARANGO_DATABASE_NOT_FOUND);
}
bool result = TRI_PersistDataShadowData(vocbase->_cursors, UnwrapGeneralCursor(argv.Holder()));
if (result) {
return scope.Close(v8::True());
}
TRI_V8_EXCEPTION(scope, TRI_ERROR_CURSOR_NOT_FOUND);
TRI_PersistGeneralCursor(UnwrapGeneralCursor(argv.Holder()), 30.0);
return scope.Close(v8::True());
}
////////////////////////////////////////////////////////////////////////////////
@ -2850,19 +2805,10 @@ static v8::Handle<v8::Value> JS_ToArrayGeneralCursor (v8::Arguments const& argv)
TRI_V8_EXCEPTION_USAGE(scope, "toArray()");
}
TRI_vocbase_t* vocbase = GetContextVocBase();
if (vocbase == 0) {
TRI_V8_EXCEPTION(scope, TRI_ERROR_ARANGO_DATABASE_NOT_FOUND);
}
v8::Handle<v8::Array> rows = v8::Array::New();
TRI_general_cursor_t* cursor;
TRI_general_cursor_t* cursor = TRI_UseGeneralCursor(UnwrapGeneralCursor(argv.Holder()));
cursor = (TRI_general_cursor_t*) TRI_BeginUsageDataShadowData(vocbase->_cursors, UnwrapGeneralCursor(argv.Holder()));
if (cursor) {
if (cursor != 0) {
bool result = false;
TRI_LockGeneralCursor(cursor);
@ -2888,8 +2834,7 @@ static v8::Handle<v8::Value> JS_ToArrayGeneralCursor (v8::Arguments const& argv)
}
TRI_UnlockGeneralCursor(cursor);
TRI_EndUsageDataShadowData(vocbase->_cursors, cursor);
TRI_ReleaseGeneralCursor(cursor);
if (result && ! tryCatch.HasCaught()) {
return scope.Close(rows);
@ -2923,22 +2868,15 @@ static v8::Handle<v8::Value> JS_GetBatchSizeGeneralCursor (v8::Arguments const&
TRI_V8_EXCEPTION_USAGE(scope, "getBatchSize()");
}
TRI_vocbase_t* vocbase = GetContextVocBase();
if (vocbase == 0) {
TRI_V8_EXCEPTION(scope, TRI_ERROR_ARANGO_DATABASE_NOT_FOUND);
}
TRI_general_cursor_t* cursor = TRI_UseGeneralCursor(UnwrapGeneralCursor(argv.Holder()));
TRI_general_cursor_t* cursor;
cursor = (TRI_general_cursor_t*) TRI_BeginUsageDataShadowData(vocbase->_cursors, UnwrapGeneralCursor(argv.Holder()));
if (cursor) {
if (cursor != 0) {
TRI_LockGeneralCursor(cursor);
uint32_t max = cursor->getBatchSize(cursor);
TRI_UnlockGeneralCursor(cursor);
TRI_ReleaseGeneralCursor(cursor);
TRI_EndUsageDataShadowData(vocbase->_cursors, cursor);
return scope.Close(v8::Number::New(max));
return scope.Close(v8::Number::New((size_t) max));
}
TRI_V8_EXCEPTION(scope, TRI_ERROR_CURSOR_NOT_FOUND);
@ -2955,25 +2893,22 @@ static v8::Handle<v8::Value> JS_GetExtraGeneralCursor (v8::Arguments const& argv
TRI_V8_EXCEPTION_USAGE(scope, "getExtra()");
}
TRI_vocbase_t* vocbase = GetContextVocBase();
if (vocbase == 0) {
TRI_V8_EXCEPTION(scope, TRI_ERROR_ARANGO_DATABASE_NOT_FOUND);
}
TRI_general_cursor_t* cursor = TRI_UseGeneralCursor(UnwrapGeneralCursor(argv.Holder()));
TRI_general_cursor_t* cursor;
cursor = (TRI_general_cursor_t*) TRI_BeginUsageDataShadowData(vocbase->_cursors, UnwrapGeneralCursor(argv.Holder()));
if (cursor) {
if (cursor != 0) {
TRI_LockGeneralCursor(cursor);
TRI_json_t* extra = cursor->getExtra(cursor);
TRI_EndUsageDataShadowData(vocbase->_cursors, cursor);
if (extra != 0 && extra->_type == TRI_JSON_ARRAY) {
TRI_UnlockGeneralCursor(cursor);
TRI_ReleaseGeneralCursor(cursor);
return scope.Close(TRI_ObjectJson(extra));
}
TRI_UnlockGeneralCursor(cursor);
TRI_ReleaseGeneralCursor(cursor);
return scope.Close(v8::Undefined());
}
@ -2991,21 +2926,14 @@ static v8::Handle<v8::Value> JS_HasCountGeneralCursor (v8::Arguments const& argv
TRI_V8_EXCEPTION_USAGE(scope, "hasCount()");
}
TRI_vocbase_t* vocbase = GetContextVocBase();
if (vocbase == 0) {
TRI_V8_EXCEPTION(scope, TRI_ERROR_ARANGO_DATABASE_NOT_FOUND);
}
TRI_general_cursor_t* cursor = TRI_UseGeneralCursor(UnwrapGeneralCursor(argv.Holder()));
TRI_general_cursor_t* cursor;
cursor = (TRI_general_cursor_t*) TRI_BeginUsageDataShadowData(vocbase->_cursors, UnwrapGeneralCursor(argv.Holder()));
if (cursor) {
if (cursor != 0) {
TRI_LockGeneralCursor(cursor);
bool hasCount = cursor->hasCount(cursor);
TRI_UnlockGeneralCursor(cursor);
TRI_ReleaseGeneralCursor(cursor);
TRI_EndUsageDataShadowData(vocbase->_cursors, cursor);
return scope.Close(hasCount ? v8::True() : v8::False());
}
@ -3024,51 +2952,20 @@ static v8::Handle<v8::Value> JS_HasNextGeneralCursor (v8::Arguments const& argv)
TRI_V8_EXCEPTION_USAGE(scope, "hasNext()");
}
TRI_vocbase_t* vocbase = GetContextVocBase();
if (vocbase == 0) {
TRI_V8_EXCEPTION(scope, TRI_ERROR_ARANGO_DATABASE_NOT_FOUND);
}
TRI_general_cursor_t* cursor = TRI_UseGeneralCursor(UnwrapGeneralCursor(argv.Holder()));
TRI_general_cursor_t* cursor;
cursor = (TRI_general_cursor_t*) TRI_BeginUsageDataShadowData(vocbase->_cursors, UnwrapGeneralCursor(argv.Holder()));
if (cursor) {
if (cursor != 0) {
TRI_LockGeneralCursor(cursor);
bool hasNext = cursor->hasNext(cursor);
TRI_UnlockGeneralCursor(cursor);
TRI_ReleaseGeneralCursor(cursor);
TRI_EndUsageDataShadowData(vocbase->_cursors, cursor);
return scope.Close(hasNext ? v8::True() : v8::False());
return scope.Close(v8::Boolean::New(hasNext));
}
TRI_V8_EXCEPTION(scope, TRI_ERROR_CURSOR_NOT_FOUND);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief unuse a general cursor
////////////////////////////////////////////////////////////////////////////////
static v8::Handle<v8::Value> JS_UnuseGeneralCursor (v8::Arguments const& argv) {
v8::HandleScope scope;
if (argv.Length() != 0) {
TRI_V8_EXCEPTION_USAGE(scope, "unuse()");
}
TRI_vocbase_t* vocbase = GetContextVocBase();
if (vocbase == 0) {
TRI_V8_EXCEPTION(scope, TRI_ERROR_ARANGO_DATABASE_NOT_FOUND);
}
TRI_EndUsageDataShadowData(vocbase->_cursors, UnwrapGeneralCursor(argv.Holder()));
return scope.Close(v8::Undefined());
}
////////////////////////////////////////////////////////////////////////////////
/// @brief get a (persistent) cursor by its id
////////////////////////////////////////////////////////////////////////////////
@ -3096,15 +2993,14 @@ static v8::Handle<v8::Value> JS_Cursor (v8::Arguments const& argv) {
const string idString = TRI_ObjectToString(idArg);
uint64_t id = TRI_UInt64String(idString.c_str());
TRI_general_cursor_t* cursor;
cursor = (TRI_general_cursor_t*) TRI_BeginUsageIdShadowData(vocbase->_cursors, id);
TRI_general_cursor_t* cursor = TRI_FindGeneralCursor(vocbase, (TRI_voc_tick_t) id);
if (cursor == 0) {
TRI_V8_EXCEPTION(scope, TRI_ERROR_CURSOR_NOT_FOUND);
}
v8::Handle<v8::Value> cursorObject = WrapGeneralCursor(cursor);
if (cursorObject.IsEmpty()) {
TRI_V8_EXCEPTION_MEMORY(scope);
}
@ -3136,12 +3032,12 @@ static v8::Handle<v8::Value> JS_DeleteCursor (v8::Arguments const& argv) {
TRI_V8_TYPE_ERROR(scope, "expecting a string for <cursor-identifier>)");
}
string idString = TRI_ObjectToString(idArg);
const string idString = TRI_ObjectToString(idArg);
uint64_t id = TRI_UInt64String(idString.c_str());
bool found = TRI_RemoveGeneralCursor(vocbase, id);
bool found = TRI_DeleteIdShadowData(vocbase->_cursors, id);
return scope.Close(found ? v8::True() : v8::False());
return scope.Close(v8::Boolean::New(found));
}
////////////////////////////////////////////////////////////////////////////////
@ -7206,27 +7102,22 @@ static v8::Handle<v8::Value> JS_CompletionsVocbase (v8::Arguments const& argv) {
}
TRI_vector_pointer_t colls = TRI_CollectionsVocBase(vocbase);
TRI_vector_string_t names = TRI_CollectionNamesVocBase(vocbase);
uint32_t n = (uint32_t) colls._length;
size_t n = names._length;
uint32_t j = 0;
v8::Handle<v8::Array> result = v8::Array::New();
// add collection names
for (uint32_t i = 0; i < n; ++i) {
TRI_vocbase_col_t const* collection = (TRI_vocbase_col_t const*) colls._buffer[i];
for (size_t i = 0; i < n; ++i) {
char const* name = TRI_AtVectorString(&names, i);
// this copies the name into a new place so we can safely access it later
// if we wouldn't do this, we would risk other threads modifying the name while
// we're reading it
char* name = TRI_GetCollectionNameByIdVocBase(collection->_vocbase, collection->_cid);
if (name != 0) {
result->Set(j++, v8::String::New(name));
TRI_Free(TRI_UNKNOWN_MEM_ZONE, name);
}
}
TRI_DestroyVectorPointer(&colls);
TRI_DestroyVectorString(&names);
// add function names. these are hard coded
result->Set(j++, v8::String::New("_collection()"));
@ -8118,8 +8009,21 @@ static void WeakBarrierCallback (v8::Isolate* isolate,
persistent.Dispose(isolate);
persistent.Clear();
TRI_vocbase_t* vocbase;
if (! barrier->_mustFree) {
vocbase = barrier->base._container->_collection->base._vocbase;
}
else {
vocbase = 0;
}
// free the barrier
TRI_FreeBarrier(&barrier->base);
if (vocbase != 0) {
// decrease the reference-counter for the database
TRI_ReleaseVocBase(vocbase);
}
}
////////////////////////////////////////////////////////////////////////////////
@ -8526,16 +8430,27 @@ v8::Handle<v8::Object> TRI_WrapCollection (TRI_vocbase_col_t const* collection)
v8::Handle<v8::Object> result = v8g->VocbaseColTempl->NewInstance();
if (! result.IsEmpty()) {
// increase the reference-counter for the database
TRI_UseVocBase(collection->_vocbase);
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::Persistent<v8::Value> persistent = v8::Persistent<v8::Value>::New(isolate, v8::External::New(const_cast<TRI_vocbase_col_t*>(collection)));
persistent.MakeWeak(isolate, const_cast<TRI_vocbase_col_t*>(collection), WeakCollectionCallback);
TRI_vocbase_col_t* c = const_cast<TRI_vocbase_col_t*>(collection);
result->SetInternalField(SLOT_CLASS_TYPE, v8::Integer::New(WRP_VOCBASE_COL_TYPE));
result->SetInternalField(SLOT_CLASS, v8::External::New(const_cast<TRI_vocbase_col_t*>(collection)));
result->SetInternalField(SLOT_COLLECTION, persistent);
result->SetInternalField(SLOT_CLASS, v8::External::New(c));
map< void*, v8::Persistent<v8::Value> >::iterator i = v8g->JSCollections.find(c);
if (i == v8g->JSCollections.end()) {
// increase the reference-counter for the database
TRI_UseVocBase(collection->_vocbase);
v8::Persistent<v8::Value> persistent = v8::Persistent<v8::Value>::New(isolate, v8::External::New(c));
result->SetInternalField(SLOT_COLLECTION, persistent);
v8g->JSCollections[c] = persistent;
persistent.MakeWeak(isolate, c, WeakCollectionCallback);
}
else {
result->SetInternalField(SLOT_COLLECTION, i->second);
}
const string cidString = StringUtils::itoa(collection->_cid);
@ -8580,9 +8495,9 @@ v8::Handle<v8::Value> TRI_WrapShapedJson (T& trx,
// we'll create our own copy of the data
TRI_df_marker_t const* m = static_cast<TRI_df_marker_t const*>(document->_data);
if (blocker->_data != NULL && blocker->_mustFree) {
if (blocker->_data != 0 && blocker->_mustFree) {
TRI_Free(TRI_UNKNOWN_MEM_ZONE, blocker->_data);
blocker->_data = NULL;
blocker->_data = 0;
blocker->_mustFree = false;
}
@ -8610,6 +8525,11 @@ v8::Handle<v8::Value> TRI_WrapShapedJson (T& trx,
map< void*, v8::Persistent<v8::Value> >::iterator i = v8g->JSBarriers.find(barrier);
if (i == v8g->JSBarriers.end()) {
if (! blocker->_mustFree) {
// increase the reference-counter for the database
TRI_UseVocBase(barrier->_container->_collection->base._vocbase);
}
v8::Persistent<v8::Value> persistent = v8::Persistent<v8::Value>::New(isolate, v8::External::New(barrier));
result->SetInternalField(SLOT_BARRIER, persistent);
@ -8919,7 +8839,6 @@ void TRI_InitV8VocBridge (v8::Handle<v8::Context> context,
TRI_AddMethodVocbase(rt, "next", JS_NextGeneralCursor);
TRI_AddMethodVocbase(rt, "persist", JS_PersistGeneralCursor);
TRI_AddMethodVocbase(rt, "toArray", JS_ToArrayGeneralCursor);
TRI_AddMethodVocbase(rt, "unuse", JS_UnuseGeneralCursor);
v8g->GeneralCursorTempl = v8::Persistent<v8::ObjectTemplate>::New(isolate, rt);
TRI_AddGlobalFunctionVocbase(context, "ArangoCursor", ft->GetFunction());

View File

@ -33,7 +33,7 @@
#include "VocBase/barrier.h"
#include "VocBase/compactor.h"
#include "VocBase/document-collection.h"
#include "VocBase/shadow-data.h"
#include "VocBase/general-cursor.h"
// -----------------------------------------------------------------------------
// --SECTION-- private constants
@ -194,12 +194,13 @@ static void CleanupDocumentCollection (TRI_document_collection_t* document) {
}
////////////////////////////////////////////////////////////////////////////////
/// @brief clean up shadows
/// @brief clean up cursors
////////////////////////////////////////////////////////////////////////////////
static void CleanupShadows (TRI_vocbase_t* const vocbase, bool force) {
static void CleanupCursors (TRI_vocbase_t* const vocbase,
bool force) {
// clean unused cursors
TRI_CleanupShadowData(vocbase->_cursors, (double) SHADOW_CURSOR_MAX_AGE, force);
TRI_CleanupGeneralCursor(vocbase->_cursors, force);
}
////////////////////////////////////////////////////////////////////////////////
@ -242,7 +243,7 @@ void TRI_CleanupVocBase (void* data) {
// shadows must be cleaned before collections are handled
// otherwise the shadows might still hold barriers on collections
// and collections cannot be closed properly
CleanupShadows(vocbase, true);
CleanupCursors(vocbase, true);
}
// check if we can get the compactor lock exclusively
@ -298,7 +299,7 @@ void TRI_CleanupVocBase (void* data) {
if (vocbase->_state >= 1) {
// server is still running, clean up unused shadows
if (iterations % CLEANUP_SHADOW_ITERATIONS == 0) {
CleanupShadows(vocbase, false);
CleanupCursors(vocbase, false);
}
// clean up expired compactor locks

View File

@ -31,7 +31,28 @@
#include "BasicsC/logging.h"
#include "BasicsC/vector.h"
#include "VocBase/shadow-data.h"
// -----------------------------------------------------------------------------
// --SECTION-- cursor store
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// --SECTION-- private defines
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup VocBase
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief delete at most this number of cursors during a gc cycle
////////////////////////////////////////////////////////////////////////////////
#define CURSOR_MAX_DELETE 256
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- cursor result sets
@ -118,6 +139,35 @@ void TRI_FreeCursorResult (TRI_general_cursor_result_t* const result) {
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief hashes an element in the ids index
////////////////////////////////////////////////////////////////////////////////
static uint64_t HashKeyId (TRI_associative_pointer_t* array, void const* k) {
return (uint64_t) *((TRI_voc_tick_t*) k);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief hashes an element in the ids index
////////////////////////////////////////////////////////////////////////////////
static uint64_t HashElementId (TRI_associative_pointer_t* array, void const* e) {
TRI_general_cursor_t const* element = e;
return (uint64_t) element->_id;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief tests if two elements are equal
////////////////////////////////////////////////////////////////////////////////
static bool EqualKeyId (TRI_associative_pointer_t* array, void const* k, void const* e) {
TRI_general_cursor_t const* element = e;
TRI_voc_tick_t key = *((TRI_voc_tick_t*) k);
return (key == element->_id);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief returns the next element
////////////////////////////////////////////////////////////////////////////////
@ -185,20 +235,13 @@ static TRI_json_t* GetExtraGeneralCursor (const TRI_general_cursor_t* const curs
////////////////////////////////////////////////////////////////////////////////
void TRI_FreeGeneralCursor (TRI_general_cursor_t* cursor) {
if (cursor->_deleted) {
// prevent duplicate deletion
return;
}
cursor->_deleted = true;
if (cursor->_extra != NULL) {
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, cursor->_extra);
}
TRI_FreeCursorResult(cursor->_result);
TRI_DestroyMutex(&cursor->_lock);
TRI_DestroySpin(&cursor->_lock);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, cursor);
LOG_TRACE("destroyed general cursor");
@ -208,11 +251,14 @@ void TRI_FreeGeneralCursor (TRI_general_cursor_t* cursor) {
/// @brief create a cursor
////////////////////////////////////////////////////////////////////////////////
TRI_general_cursor_t* TRI_CreateGeneralCursor (TRI_general_cursor_result_t* result,
TRI_general_cursor_t* TRI_CreateGeneralCursor (TRI_vocbase_t* vocbase,
TRI_general_cursor_result_t* result,
const bool doCount,
const TRI_general_cursor_length_t batchSize,
TRI_json_t* extra) {
TRI_general_cursor_t* cursor;
assert(vocbase != NULL);
cursor = (TRI_general_cursor_t*) TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_general_cursor_t), false);
@ -220,15 +266,22 @@ TRI_general_cursor_t* TRI_CreateGeneralCursor (TRI_general_cursor_result_t* resu
return NULL;
}
cursor->_vocbase = vocbase;
cursor->_store = vocbase->_cursors;
cursor->_result = result;
cursor->_extra = extra; // might be NULL
cursor->_expires = TRI_microtime() + 3600; // default lifetime: 1h
cursor->_id = TRI_NewTickServer();
// state
cursor->_currentRow = 0;
cursor->_length = result->getLength(result);
cursor->_hasCount = doCount;
cursor->_batchSize = batchSize;
cursor->_deleted = false;
cursor->_usage._refCount = 0;
cursor->_usage._isDeleted = false;
// assign functions
cursor->next = NextGeneralCursor;
@ -238,7 +291,12 @@ TRI_general_cursor_t* TRI_CreateGeneralCursor (TRI_general_cursor_result_t* resu
cursor->getExtra = GetExtraGeneralCursor;
cursor->free = TRI_FreeGeneralCursor;
TRI_InitMutex(&cursor->_lock);
TRI_InitSpin(&cursor->_lock);
TRI_LockSpin(&vocbase->_cursors->_lock);
// TODO: check for errors here
TRI_InsertKeyAssociativePointer(&vocbase->_cursors->_ids, &cursor->_id, cursor, true);
TRI_UnlockSpin(&vocbase->_cursors->_lock);
LOG_TRACE("created general cursor");
@ -250,7 +308,7 @@ TRI_general_cursor_t* TRI_CreateGeneralCursor (TRI_general_cursor_result_t* resu
////////////////////////////////////////////////////////////////////////////////
void TRI_LockGeneralCursor (TRI_general_cursor_t* const cursor) {
TRI_LockMutex(&cursor->_lock);
TRI_LockSpin(&cursor->_lock);
}
////////////////////////////////////////////////////////////////////////////////
@ -258,27 +316,252 @@ void TRI_LockGeneralCursor (TRI_general_cursor_t* const cursor) {
////////////////////////////////////////////////////////////////////////////////
void TRI_UnlockGeneralCursor (TRI_general_cursor_t* const cursor) {
assert(cursor);
TRI_UnlockMutex(&cursor->_lock);
TRI_UnlockSpin(&cursor->_lock);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief free a cursor based on its shadow data pointer
/// @brief reference-count a general cursor
////////////////////////////////////////////////////////////////////////////////
void TRI_FreeShadowGeneralCursor (void* data) {
TRI_general_cursor_t* cursor = (TRI_general_cursor_t*) data;
TRI_general_cursor_t* TRI_UseGeneralCursor (TRI_general_cursor_t* cursor) {
TRI_general_cursor_store_t* store = cursor->_store;
TRI_FreeGeneralCursor(cursor);
TRI_LockSpin(&store->_lock);
cursor = TRI_LookupByKeyAssociativePointer(&store->_ids, &cursor->_id);
if (cursor != NULL) {
if (cursor->_usage._isDeleted) {
cursor = NULL;
}
else {
++cursor->_usage._refCount;
}
}
TRI_UnlockSpin(&store->_lock);
return cursor;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief create shadow data store for cursors
/// @brief de-reference-count a general cursor
////////////////////////////////////////////////////////////////////////////////
TRI_shadow_store_t* TRI_CreateShadowsGeneralCursor (void) {
return TRI_CreateShadowStore(&TRI_FreeShadowGeneralCursor);
void TRI_ReleaseGeneralCursor (TRI_general_cursor_t* cursor) {
TRI_general_cursor_store_t* store = cursor->_store;
TRI_LockSpin(&store->_lock);
cursor = TRI_LookupByKeyAssociativePointer(&store->_ids, &cursor->_id);
if (cursor != NULL) {
--cursor->_usage._refCount;
}
TRI_UnlockSpin(&store->_lock);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief mark as cursor as deleted
////////////////////////////////////////////////////////////////////////////////
bool TRI_DropGeneralCursor (TRI_general_cursor_t* cursor) {
TRI_general_cursor_store_t* store = cursor->_store;
bool result;
TRI_LockSpin(&store->_lock);
cursor = TRI_LookupByKeyAssociativePointer(&store->_ids, &cursor->_id);
if (cursor != NULL && ! cursor->_usage._isDeleted) {
cursor->_usage._isDeleted = true;
result = true;
}
else {
result = false;
}
TRI_UnlockSpin(&store->_lock);
return result;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief return the cursor id
////////////////////////////////////////////////////////////////////////////////
TRI_voc_tick_t TRI_IdGeneralCursor (TRI_general_cursor_t* cursor) {
return cursor->_id;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief return the cursor length
////////////////////////////////////////////////////////////////////////////////
size_t TRI_CountGeneralCursor (TRI_general_cursor_t* cursor) {
return (size_t) cursor->_length;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief persist the cursor by setting a timeout
////////////////////////////////////////////////////////////////////////////////
void TRI_PersistGeneralCursor (TRI_general_cursor_t* cursor,
double ttl) {
cursor->_expires = TRI_microtime() + ttl;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief lookup a cursor by its id
////////////////////////////////////////////////////////////////////////////////
TRI_general_cursor_t* TRI_FindGeneralCursor (TRI_vocbase_t* vocbase,
TRI_voc_tick_t id) {
TRI_general_cursor_store_t* store = vocbase->_cursors;
TRI_general_cursor_t* cursor;
TRI_LockSpin(&store->_lock);
cursor = TRI_LookupByKeyAssociativePointer(&store->_ids, &id);
if (cursor == NULL || cursor->_usage._isDeleted) {
cursor = NULL;
}
TRI_UnlockSpin(&store->_lock);
return cursor;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief mark as cursor as deleted
////////////////////////////////////////////////////////////////////////////////
bool TRI_RemoveGeneralCursor (TRI_vocbase_t* vocbase,
TRI_voc_tick_t id) {
TRI_general_cursor_store_t* store = vocbase->_cursors;
TRI_general_cursor_t* cursor;
bool result;
TRI_LockSpin(&store->_lock);
cursor = TRI_LookupByKeyAssociativePointer(&store->_ids, &id);
if (cursor == NULL || cursor->_usage._isDeleted) {
result = false;
}
else {
cursor->_usage._isDeleted = true;
result = true;
}
TRI_UnlockSpin(&store->_lock);
return result;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief create data store for cursors
////////////////////////////////////////////////////////////////////////////////
TRI_general_cursor_store_t* TRI_CreateStoreGeneralCursor (void) {
TRI_general_cursor_store_t* store;
int res;
store = TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_general_cursor_t), false);
if (store == NULL) {
return NULL;
}
res = TRI_InitAssociativePointer(&store->_ids,
TRI_UNKNOWN_MEM_ZONE,
HashKeyId,
HashElementId,
EqualKeyId,
NULL);
if (res != TRI_ERROR_NO_ERROR) {
TRI_Free(TRI_UNKNOWN_MEM_ZONE, store);
return NULL;
}
TRI_InitSpin(&store->_lock);
return store;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief free the data store for cursors
////////////////////////////////////////////////////////////////////////////////
void TRI_FreeStoreGeneralCursor (TRI_general_cursor_store_t* store) {
// force deletion of all remaining cursors
TRI_CleanupGeneralCursor(store, true);
TRI_DestroySpin(&store->_lock);
TRI_DestroyAssociativePointer(&store->_ids);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, store);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief enumerate all cursors and remove them if
/// - their refcount is 0 and they are transient
/// - their refcount is 0 and they are expired
/// - the force flag is set
////////////////////////////////////////////////////////////////////////////////
void TRI_CleanupGeneralCursor (TRI_general_cursor_store_t* store,
bool force) {
double compareStamp = TRI_microtime();
size_t deleteCount = 0;
// we need an exclusive lock on the index
TRI_LockSpin(&store->_lock);
if (store->_ids._nrUsed == 0) {
// store is empty, nothing to do!
TRI_UnlockSpin(&store->_lock);
return;
}
LOG_TRACE("cleaning shadows. in store: %ld", (unsigned long) store->_ids._nrUsed);
// loop until there's nothing to delete or
// we have deleted CURSOR_MAX_DELETE elements
while (deleteCount++ < CURSOR_MAX_DELETE || force) {
bool deleted = false;
size_t i;
for (i = 0; i < store->_ids._nrAlloc; i++) {
// enum all cursors
TRI_general_cursor_t* cursor = (TRI_general_cursor_t*) store->_ids._table[i];
if (cursor == NULL) {
continue;
}
TRI_LockSpin(&cursor->_lock);
if (force ||
(cursor->_usage._refCount == 0 &&
(cursor->_usage._isDeleted || cursor->_expires < compareStamp))) {
LOG_TRACE("cleaning cursor %p, id: %llu, rc: %d, expires: %d, deleted: %d",
cursor,
(unsigned long long) cursor->_id,
(int) cursor->_usage._refCount,
(int) cursor->_expires,
(int) cursor->_usage._isDeleted);
TRI_RemoveKeyAssociativePointer(&store->_ids, &cursor->_id);
TRI_UnlockSpin(&cursor->_lock);
TRI_FreeGeneralCursor(cursor);
deleted = true;
// the remove might reposition elements in the container.
// therefore break here and start iteration anew
break;
}
TRI_UnlockSpin(&cursor->_lock);
}
if (! deleted) {
// we did not find anything to delete, so give up
break;
}
}
// release lock
TRI_UnlockSpin(&store->_lock);
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -28,6 +28,8 @@
#ifndef TRIAGENS_VOC_BASE_GENERAL_CURSOR_H
#define TRIAGENS_VOC_BASE_GENERAL_CURSOR_H 1
#include "BasicsC/associative.h"
#include "VocBase/server.h"
#include "VocBase/vocbase.h"
#ifdef __cplusplus
@ -40,6 +42,34 @@ extern "C" {
struct TRI_json_s;
struct TRI_shadow_store_s;
struct TRI_vocbase_s;
// -----------------------------------------------------------------------------
// --SECTION-- cursor store
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// --SECTION-- public types
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup VocBase
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief cursor store
////////////////////////////////////////////////////////////////////////////////
typedef struct TRI_general_cursor_store_s {
TRI_spin_t _lock;
TRI_associative_pointer_t _ids; // ids
}
TRI_general_cursor_store_t;
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- cursor result sets
@ -123,15 +153,25 @@ void TRI_FreeCursorResult (TRI_general_cursor_result_t* const);
////////////////////////////////////////////////////////////////////////////////
typedef struct TRI_general_cursor_s {
struct TRI_vocbase_s* _vocbase;
TRI_general_cursor_store_t* _store;
TRI_general_cursor_result_t* _result;
TRI_general_cursor_length_t _length;
TRI_general_cursor_length_t _currentRow;
uint32_t _batchSize;
TRI_mutex_t _lock;
TRI_spin_t _lock;
TRI_voc_tick_t _id;
struct {
uint32_t _refCount;
bool _isDeleted;
} _usage;
double _expires;
struct TRI_json_s* _extra;
bool _hasCount;
bool _deleted;
void (*free)(struct TRI_general_cursor_s*);
TRI_general_cursor_row_t (*next)(struct TRI_general_cursor_s* const);
@ -165,7 +205,8 @@ void TRI_FreeGeneralCursor (TRI_general_cursor_t*);
/// @brief create a cursor
////////////////////////////////////////////////////////////////////////////////
TRI_general_cursor_t* TRI_CreateGeneralCursor (TRI_general_cursor_result_t*,
TRI_general_cursor_t* TRI_CreateGeneralCursor (struct TRI_vocbase_s*,
TRI_general_cursor_result_t*,
const bool,
const TRI_general_cursor_length_t,
struct TRI_json_s*);
@ -183,16 +224,77 @@ void TRI_LockGeneralCursor (TRI_general_cursor_t* const);
void TRI_UnlockGeneralCursor (TRI_general_cursor_t* const);
////////////////////////////////////////////////////////////////////////////////
/// @brief Free a cursor based on its data pointer
/// @brief reference-count a general cursor
////////////////////////////////////////////////////////////////////////////////
void TRI_FreeShadowGeneralCursor (void*);
TRI_general_cursor_t* TRI_UseGeneralCursor (TRI_general_cursor_t*);
////////////////////////////////////////////////////////////////////////////////
/// @brief de-reference-count a general cursor
////////////////////////////////////////////////////////////////////////////////
void TRI_ReleaseGeneralCursor (TRI_general_cursor_t*);
////////////////////////////////////////////////////////////////////////////////
/// @brief mark as cursor as deleted
////////////////////////////////////////////////////////////////////////////////
bool TRI_DropGeneralCursor (TRI_general_cursor_t*);
////////////////////////////////////////////////////////////////////////////////
/// @brief return the cursor id
////////////////////////////////////////////////////////////////////////////////
TRI_voc_tick_t TRI_IdGeneralCursor (TRI_general_cursor_t*);
////////////////////////////////////////////////////////////////////////////////
/// @brief return the cursor length
////////////////////////////////////////////////////////////////////////////////
size_t TRI_CountGeneralCursor (TRI_general_cursor_t*);
////////////////////////////////////////////////////////////////////////////////
/// @brief persist the cursor by setting a timeout
////////////////////////////////////////////////////////////////////////////////
void TRI_PersistGeneralCursor (TRI_general_cursor_t*,
double);
////////////////////////////////////////////////////////////////////////////////
/// @brief lookup a cursor by its id
////////////////////////////////////////////////////////////////////////////////
TRI_general_cursor_t* TRI_FindGeneralCursor (struct TRI_vocbase_s*,
TRI_voc_tick_t);
////////////////////////////////////////////////////////////////////////////////
/// @brief mark as cursor as deleted
////////////////////////////////////////////////////////////////////////////////
bool TRI_RemoveGeneralCursor (struct TRI_vocbase_s*,
TRI_voc_tick_t);
////////////////////////////////////////////////////////////////////////////////
/// @brief create shadow data store for cursors
////////////////////////////////////////////////////////////////////////////////
struct TRI_shadow_store_s* TRI_CreateShadowsGeneralCursor (void);
TRI_general_cursor_store_t* TRI_CreateStoreGeneralCursor (void);
////////////////////////////////////////////////////////////////////////////////
/// @brief free the data store for cursors
////////////////////////////////////////////////////////////////////////////////
void TRI_FreeStoreGeneralCursor (TRI_general_cursor_store_t*);
////////////////////////////////////////////////////////////////////////////////
/// @brief enumerate all cursors and remove them if
/// - their refcount is 0 and they are transient
/// - their refcount is 0 and they are expired
/// - the force flag is set
////////////////////////////////////////////////////////////////////////////////
void TRI_CleanupGeneralCursor (TRI_general_cursor_store_t*,
bool);
////////////////////////////////////////////////////////////////////////////////
/// @}

View File

@ -1294,6 +1294,10 @@ static void DatabaseManager (void* data) {
// remember the database path
char* path;
LOG_TRACE("physically removing database directory '%s' of database '%s'",
database->_path,
database->_name);
path = TRI_DuplicateStringZ(TRI_CORE_MEM_ZONE, database->_path);
TRI_DestroyVocBase(database);

View File

@ -1,608 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief shadow data storage
///
/// @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 Dr. Frank Celler
/// @author Copyright 2012-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#include "BasicsC/logging.h"
#include "VocBase/server.h"
#include "VocBase/shadow-data.h"
// -----------------------------------------------------------------------------
// --SECTION-- SHADOW DATA
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// --SECTION-- private functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup VocBase
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief set the timestamp of a shadow to the current date & time
////////////////////////////////////////////////////////////////////////////////
static inline void UpdateTimestampShadow (TRI_shadow_t* const shadow) {
shadow->_timestamp = TRI_microtime();
}
////////////////////////////////////////////////////////////////////////////////
/// @brief init a shadow data structure
////////////////////////////////////////////////////////////////////////////////
static TRI_shadow_t* CreateShadow (const void* const data) {
TRI_shadow_t* shadow = (TRI_shadow_t*) TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_shadow_t), false);
if (shadow == NULL) {
return NULL;
}
shadow->_rc = 1;
shadow->_data = (void*) data;
shadow->_id = TRI_NewTickServer();
shadow->_deleted = false;
shadow->_type = SHADOW_TRANSIENT;
UpdateTimestampShadow(shadow);
LOG_TRACE("created shadow %p with data ptr %p and id %llu",
shadow,
data,
(unsigned long long) shadow->_id);
return shadow;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief decrease the refcount for a shadow
////////////////////////////////////////////////////////////////////////////////
static void DecreaseRefCount (TRI_shadow_store_t* const store, TRI_shadow_t* const shadow) {
LOG_TRACE("decreasing refcount for shadow %p with data ptr %p and id %llu to %d",
shadow,
shadow->_data,
(unsigned long long) shadow->_id,
(int) (shadow->_rc - 1));
if (--shadow->_rc <= 0 && shadow->_type == SHADOW_TRANSIENT) {
LOG_TRACE("deleting transient shadow %p", shadow);
TRI_RemoveKeyAssociativePointer(&store->_ids, &shadow->_id);
TRI_RemoveKeyAssociativePointer(&store->_pointers, shadow->_data);
store->destroyShadow(shadow->_data);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, shadow);
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief increase the refcount for a shadow
////////////////////////////////////////////////////////////////////////////////
static void IncreaseRefCount (TRI_shadow_store_t* const store, TRI_shadow_t* const shadow) {
LOG_TRACE("increasing refcount for shadow %p with data ptr %p and id %llu to %d",
shadow,
shadow->_data,
(unsigned long long) shadow->_id,
(int) (shadow->_rc + 1));
if (++shadow->_rc <= 0) {
// should not be less or equal to 0 now
shadow->_rc = 1;
}
UpdateTimestampShadow(shadow);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief set the persistence flag for a shadow
////////////////////////////////////////////////////////////////////////////////
static void PersistShadow (TRI_shadow_t* const shadow) {
LOG_TRACE("persisting shadow %p with data ptr %p and id %llu",
shadow,
shadow->_data,
(unsigned long long) shadow->_id);
shadow->_type = SHADOW_PERSISTENT;
UpdateTimestampShadow(shadow);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief set the deleted flag for a shadow
////////////////////////////////////////////////////////////////////////////////
static void DeleteShadow (TRI_shadow_store_t* const store,
TRI_shadow_t* const shadow,
const bool decreaseRefCount) {
LOG_TRACE("setting deleted flag for shadow %p with data ptr %p and id %llu",
shadow,
shadow->_data,
(unsigned long long) shadow->_id);
shadow->_deleted = true;
if (decreaseRefCount) {
DecreaseRefCount(store, shadow);
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief hashes an element in the ids index
////////////////////////////////////////////////////////////////////////////////
static uint64_t HashKeyId (TRI_associative_pointer_t* array, void const* k) {
TRI_shadow_id key = *((TRI_shadow_id*) k);
return (uint64_t) key;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief hashes an element in the ids index
////////////////////////////////////////////////////////////////////////////////
static uint64_t HashElementId (TRI_associative_pointer_t* array, void const* e) {
TRI_shadow_t const* element = e;
return (uint64_t) element->_id;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief tests if two elements are equal
////////////////////////////////////////////////////////////////////////////////
static bool EqualKeyId (TRI_associative_pointer_t* array, void const* k, void const* e) {
TRI_shadow_t const* element = e;
TRI_shadow_id key = *((TRI_shadow_id*) k);
return (key == element->_id);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief hashes an element in the pointers index
////////////////////////////////////////////////////////////////////////////////
static uint64_t HashKeyData (TRI_associative_pointer_t* array, void const* k) {
uint64_t key;
key = (uint64_t) (uintptr_t) k;
return key;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief hashes an element in the pointers index
////////////////////////////////////////////////////////////////////////////////
static uint64_t HashElementData (TRI_associative_pointer_t* array, void const* e) {
TRI_shadow_t const* element = e;
return (uint64_t) (uintptr_t) element->_data;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief tests if two elements are equal
////////////////////////////////////////////////////////////////////////////////
static bool EqualKeyData (TRI_associative_pointer_t* array, void const* k, void const* e) {
TRI_shadow_t const* element = e;
return ((uint64_t) (uintptr_t) k == (uint64_t) (uintptr_t) element->_data);
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- constructors and destructors
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup VocBase
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief creates a shadow data storage
////////////////////////////////////////////////////////////////////////////////
TRI_shadow_store_t* TRI_CreateShadowStore (void (*destroy) (void*)) {
TRI_shadow_store_t* store;
int res;
store = (TRI_shadow_store_t*) TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_shadow_store_t), false);
if (store == NULL) {
return NULL;
}
res = TRI_InitAssociativePointer(&store->_ids,
TRI_UNKNOWN_MEM_ZONE,
HashKeyId,
HashElementId,
EqualKeyId,
NULL);
if (res != TRI_ERROR_NO_ERROR) {
TRI_Free(TRI_UNKNOWN_MEM_ZONE, store);
return NULL;
}
res = TRI_InitAssociativePointer(&store->_pointers,
TRI_UNKNOWN_MEM_ZONE,
HashKeyData,
HashElementData,
EqualKeyData,
NULL);
if (res != TRI_ERROR_NO_ERROR) {
TRI_DestroyAssociativePointer(&store->_ids);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, store);
return NULL;
}
store->destroyShadow = destroy;
TRI_InitMutex(&store->_lock);
return store;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief destroys a shadow data storage
///
/// Note: all remaining shadows will be destroyed
////////////////////////////////////////////////////////////////////////////////
void TRI_FreeShadowStore (TRI_shadow_store_t* const store) {
assert(store);
// force deletion of all remaining shadows
TRI_CleanupShadowData(store, 0.0, true);
TRI_DestroyMutex(&store->_lock);
TRI_DestroyAssociativePointer(&store->_ids);
TRI_DestroyAssociativePointer(&store->_pointers);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, store);
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- public methods
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup VocBase
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief look up a shadow in the index using its data pointer and return
/// its id
////////////////////////////////////////////////////////////////////////////////
TRI_shadow_id TRI_GetIdDataShadowData (TRI_shadow_store_t* const store,
const void* const data) {
TRI_shadow_t* shadow;
TRI_shadow_id id = 0;
assert(store);
if (data) {
TRI_LockMutex(&store->_lock);
shadow = (TRI_shadow_t*) TRI_LookupByKeyAssociativePointer(&store->_pointers, data);
if (shadow && ! shadow->_deleted) {
id = shadow->_id;
UpdateTimestampShadow(shadow);
}
TRI_UnlockMutex(&store->_lock);
}
return id;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief look up a shadow in the index using its data pointer
///
/// If the shadow is found, this will return the data pointer, NULL otherwise.
/// When the shadow is found, its refcount will also be increased by one
////////////////////////////////////////////////////////////////////////////////
void* TRI_BeginUsageDataShadowData (TRI_shadow_store_t* const store,
const void* const data) {
TRI_shadow_t* shadow;
assert(store);
if (! data) {
return NULL;
}
TRI_LockMutex(&store->_lock);
shadow = (TRI_shadow_t*) TRI_LookupByKeyAssociativePointer(&store->_pointers, data);
if (shadow && ! shadow->_deleted) {
IncreaseRefCount(store, shadow);
TRI_UnlockMutex(&store->_lock);
return shadow->_data;
}
TRI_UnlockMutex(&store->_lock);
return NULL;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief look up a shadow in the index using its id
///
/// If the shadow is found, this will return the data pointer, NULL otherwise.
/// When the shadow is found, its refcount will also be increased by one
////////////////////////////////////////////////////////////////////////////////
void* TRI_BeginUsageIdShadowData (TRI_shadow_store_t* const store,
const TRI_shadow_id id) {
TRI_shadow_t* shadow;
assert(store);
TRI_LockMutex(&store->_lock);
shadow = (TRI_shadow_t*) TRI_LookupByKeyAssociativePointer(&store->_ids, (void const*) &id);
if (shadow && ! shadow->_deleted) {
IncreaseRefCount(store, shadow);
TRI_UnlockMutex(&store->_lock);
return shadow->_data;
}
TRI_UnlockMutex(&store->_lock);
return NULL;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief look up a shadow in the index using its data pointer
///
/// If the shadow is found, its refcount will be decreased by one.
/// If the refcount is 0 and the shadow is of type SHADOW_TRANSIENT, the shadow
/// object will be destroyed.
////////////////////////////////////////////////////////////////////////////////
void TRI_EndUsageDataShadowData (TRI_shadow_store_t* const store,
const void* const data) {
TRI_shadow_t* shadow;
assert(store);
TRI_LockMutex(&store->_lock);
shadow = (TRI_shadow_t*) TRI_LookupByKeyAssociativePointer(&store->_pointers, data);
if (shadow && ! shadow->_deleted) {
DecreaseRefCount(store, shadow); // this might delete the shadow
}
TRI_UnlockMutex(&store->_lock);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief set the persistence flag for a shadow using its data pointer
////////////////////////////////////////////////////////////////////////////////
bool TRI_PersistDataShadowData (TRI_shadow_store_t* const store,
const void* const data) {
TRI_shadow_t* shadow;
bool result = false;
assert(store);
TRI_LockMutex(&store->_lock);
shadow = (TRI_shadow_t*) TRI_LookupByKeyAssociativePointer(&store->_pointers, data);
if (shadow && ! shadow->_deleted) {
PersistShadow(shadow);
result = true;
}
TRI_UnlockMutex(&store->_lock);
return result;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief set the deleted flag for a shadow using its data pointer
////////////////////////////////////////////////////////////////////////////////
bool TRI_DeleteDataShadowData (TRI_shadow_store_t* const store,
const void* const data) {
bool found = false;
assert(store);
if (data) {
TRI_shadow_t* shadow;
TRI_LockMutex(&store->_lock);
shadow = (TRI_shadow_t*) TRI_LookupByKeyAssociativePointer(&store->_pointers, data);
if (shadow && ! shadow->_deleted) {
DeleteShadow(store, shadow, true);
found = true;
}
TRI_UnlockMutex(&store->_lock);
}
return found;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief set the deleted flag for a shadow using its id
////////////////////////////////////////////////////////////////////////////////
bool TRI_DeleteIdShadowData (TRI_shadow_store_t* const store,
const TRI_shadow_id id) {
TRI_shadow_t* shadow;
bool found = false;
assert(store);
TRI_LockMutex(&store->_lock);
shadow = (TRI_shadow_t*) TRI_LookupByKeyAssociativePointer(&store->_ids, &id);
if (shadow && ! shadow->_deleted) {
DeleteShadow(store, shadow, false);
found = true;
}
TRI_UnlockMutex(&store->_lock);
return found;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief enumerate all shadows and remove them if
/// - their refcount is 0 and they are transient
/// - their refcount is 0 and they are expired
/// - the force flag is set
///
/// The max age must be specified in seconds. The max age is ignored if the
/// force flag is set. In this case all remaining shadows will be deleted
////////////////////////////////////////////////////////////////////////////////
void TRI_CleanupShadowData (TRI_shadow_store_t* const store,
const double maxAge,
const bool force) {
double compareStamp = TRI_microtime() - maxAge; // age must be specified in secs
size_t deleteCount = 0;
// we need an exclusive lock on the index
TRI_LockMutex(&store->_lock);
if (store->_ids._nrUsed == 0) {
// store is empty, nothing to do!
TRI_UnlockMutex(&store->_lock);
return;
}
LOG_TRACE("cleaning shadows. in store: %ld", (unsigned long) store->_ids._nrUsed);
// loop until there's nothing to delete or
// we have deleted SHADOW_MAX_DELETE elements
while (deleteCount++ < SHADOW_MAX_DELETE || force) {
bool deleted = false;
size_t i;
for (i = 0; i < store->_ids._nrAlloc; i++) {
// enum all shadows
TRI_shadow_t* shadow = (TRI_shadow_t*) store->_ids._table[i];
if (shadow == NULL) {
continue;
}
// check if shadow is unused and expired
if (shadow->_rc < 1 || force) {
if (shadow->_type == SHADOW_TRANSIENT ||
shadow->_timestamp < compareStamp ||
shadow->_deleted ||
force) {
LOG_TRACE("cleaning shadow %p, id: %llu, rc: %d, expired: %d, deleted: %d",
shadow,
(unsigned long long) shadow->_id,
(int) shadow->_rc,
(int) (shadow->_timestamp < compareStamp),
(int) shadow->_deleted);
TRI_RemoveKeyAssociativePointer(&store->_ids, &shadow->_id);
TRI_RemoveKeyAssociativePointer(&store->_pointers, shadow->_data);
store->destroyShadow(shadow->_data);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, shadow);
deleted = true;
// the remove might reposition elements in the container.
// therefore break here and start iteration anew
break;
}
}
}
if (! deleted) {
// we did not find anything to delete, so give up
break;
}
}
// release lock
TRI_UnlockMutex(&store->_lock);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief store a new shadow in the store
////////////////////////////////////////////////////////////////////////////////
TRI_shadow_t* TRI_StoreShadowData (TRI_shadow_store_t* const store,
const void* const data) {
TRI_shadow_t* shadow;
assert(store);
shadow = CreateShadow(data);
if (shadow) {
LOG_TRACE("storing shadow %p with data ptr %p and id %llu",
shadow,
shadow->_data,
(unsigned long long) shadow->_id);
TRI_LockMutex(&store->_lock);
if (TRI_InsertKeyAssociativePointer(&store->_ids, &shadow->_id, shadow, false)) {
// duplicate entry
LOG_WARNING("storing shadow failed");
TRI_UnlockMutex(&store->_lock);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, shadow);
return NULL;
}
TRI_InsertKeyAssociativePointer(&store->_pointers, data, shadow, false);
TRI_UnlockMutex(&store->_lock);
}
// might be NULL in case of OOM
return shadow;
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:

View File

@ -1,247 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief shadow data storage
///
/// @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 Dr. Frank Celler
/// @author Copyright 2012-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#ifndef TRIAGENS_VOC_BASE_SHADOW_DATA_H
#define TRIAGENS_VOC_BASE_SHADOW_DATA_H 1
#include "BasicsC/common.h"
#include "BasicsC/locks.h"
#include "BasicsC/associative.h"
#include "VocBase/vocbase.h"
#ifdef __cplusplus
extern "C" {
#endif
// -----------------------------------------------------------------------------
// --SECTION-- DEFINES
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup VocBase
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief delete at most this number of shadows during a gc cycle
////////////////////////////////////////////////////////////////////////////////
#define SHADOW_MAX_DELETE 256
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- SHADOW DATA
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// --SECTION-- public types
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup VocBase
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief typedef for shadow types
///
/// Shadows are first created with the SHADOW_TRANSIENT type. This means that
/// the shadow will exist only temporarily and will be destroyed when the
/// refcount gets back to 0. Shadows of type SHADOW_PERSISTENT will remain in
/// the shadow store even with a refcount of 0 until their ttl is over.
////////////////////////////////////////////////////////////////////////////////
typedef enum {
SHADOW_TRANSIENT = 1,
SHADOW_PERSISTENT = 2
}
TRI_shadow_type_e;
////////////////////////////////////////////////////////////////////////////////
/// @brief typedef for shadow ids
////////////////////////////////////////////////////////////////////////////////
typedef TRI_voc_tick_t TRI_shadow_id;
////////////////////////////////////////////////////////////////////////////////
/// @brief shadow data (base struct)
////////////////////////////////////////////////////////////////////////////////
typedef struct TRI_shadow_s {
TRI_shadow_id _id;
int64_t _rc; // refcount
double _timestamp; // creation timestamp
void* _data; // pointer to data
bool _deleted; // deleted flag
TRI_shadow_type_e _type; // transient or persistent
}
TRI_shadow_t;
////////////////////////////////////////////////////////////////////////////////
/// @brief shadow data storage
////////////////////////////////////////////////////////////////////////////////
typedef struct TRI_shadow_store_s {
TRI_mutex_t _lock;
TRI_associative_pointer_t _ids; // ids
TRI_associative_pointer_t _pointers; // data pointers
void (*destroyShadow) (void*);
}
TRI_shadow_store_t;
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- constructors and destructors
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup VocBase
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief creates a shadow data storage
////////////////////////////////////////////////////////////////////////////////
TRI_shadow_store_t* TRI_CreateShadowStore (void (*destroy) (void*));
////////////////////////////////////////////////////////////////////////////////
/// @brief destroys a shadow data storage
///
/// Note: all remaining shadows will be destroyed
////////////////////////////////////////////////////////////////////////////////
void TRI_FreeShadowStore (TRI_shadow_store_t* const store);
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- public methods
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup VocBase
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief look up a shadow in the index using its data pointer and return
/// its id
////////////////////////////////////////////////////////////////////////////////
TRI_shadow_id TRI_GetIdDataShadowData (TRI_shadow_store_t* const,
const void* const);
////////////////////////////////////////////////////////////////////////////////
/// @brief look up a shadow in the index using its data pointer
///
/// If the shadow is found, this will return the data pointer, NULL otherwise.
/// When the shadow is found, its refcount will also be increased by one
////////////////////////////////////////////////////////////////////////////////
void* TRI_BeginUsageDataShadowData (TRI_shadow_store_t* const, const void* const);
////////////////////////////////////////////////////////////////////////////////
/// @brief look up a shadow in the index using its id
///
/// If the shadow is found, this will return the data pointer, NULL otherwise.
/// When the shadow is found, its refcount will also be increased by one
////////////////////////////////////////////////////////////////////////////////
void* TRI_BeginUsageIdShadowData (TRI_shadow_store_t* const, const TRI_shadow_id);
////////////////////////////////////////////////////////////////////////////////
/// @brief look up a shadow in the index using its data pointer
///
/// If the shadow is found, its refcount will be decreased by one.
/// If the refcount is 0 and the shadow is of type SHADOW_TRANSIENT, the shadow
/// object will be destroyed.
////////////////////////////////////////////////////////////////////////////////
void TRI_EndUsageDataShadowData (TRI_shadow_store_t* const, const void* const);
////////////////////////////////////////////////////////////////////////////////
/// @brief set the persistence flag for a shadow using its data pointer
////////////////////////////////////////////////////////////////////////////////
bool TRI_PersistDataShadowData (TRI_shadow_store_t* const, const void* const);
////////////////////////////////////////////////////////////////////////////////
/// @brief set the deleted flag for a shadow using its data pointer
////////////////////////////////////////////////////////////////////////////////
bool TRI_DeleteDataShadowData (TRI_shadow_store_t* const, const void* const);
////////////////////////////////////////////////////////////////////////////////
/// @brief set the deleted flag for a shadow using its id
////////////////////////////////////////////////////////////////////////////////
bool TRI_DeleteIdShadowData (TRI_shadow_store_t* const, const TRI_shadow_id);
////////////////////////////////////////////////////////////////////////////////
/// @brief enumerate all shadows and remove them if
/// - their refcount is 0 and they are transient
/// - their refcount is 0 and they are expired
/// - the force flag is set
///
/// The max age must be specified in seconds. The max age is ignored if the
/// force flag is set. In this case all remaining shadows will be deleted
////////////////////////////////////////////////////////////////////////////////
void TRI_CleanupShadowData (TRI_shadow_store_t* const, const double, const bool);
////////////////////////////////////////////////////////////////////////////////
/// @brief store a new shadow in the store
////////////////////////////////////////////////////////////////////////////////
TRI_shadow_t* TRI_StoreShadowData (TRI_shadow_store_t* const,
const void* const);
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
#ifdef __cplusplus
}
#endif
#endif
// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:

View File

@ -53,7 +53,6 @@
#include "VocBase/replication-applier.h"
#include "VocBase/replication-logger.h"
#include "VocBase/server.h"
#include "VocBase/shadow-data.h"
#include "VocBase/synchroniser.h"
#include "VocBase/transaction.h"
#include "VocBase/vocbase-defaults.h"
@ -1116,7 +1115,7 @@ TRI_vocbase_t* TRI_OpenVocBase (TRI_server_t* server,
}
// init cursors
vocbase->_cursors = TRI_CreateShadowsGeneralCursor();
vocbase->_cursors = TRI_CreateStoreGeneralCursor();
if (vocbase->_cursors == NULL) {
TRI_FreeFunctionsAql(vocbase->_functions);
@ -1189,7 +1188,7 @@ TRI_vocbase_t* TRI_OpenVocBase (TRI_server_t* server,
TRI_DestroyVectorPointer(&vocbase->_deadCollections);
TRI_FreeString(TRI_CORE_MEM_ZONE, vocbase->_path);
TRI_FreeString(TRI_CORE_MEM_ZONE, vocbase->_name);
TRI_FreeShadowStore(vocbase->_cursors);
TRI_FreeStoreGeneralCursor(vocbase->_cursors);
TRI_DestroyReadWriteLock(&vocbase->_authInfoLock);
TRI_DestroyReadWriteLock(&vocbase->_lock);
TRI_DestroySpin(&vocbase->_usage._lock);
@ -1364,7 +1363,7 @@ void TRI_DestroyVocBase (TRI_vocbase_t* vocbase) {
TRI_FreeFunctionsAql(vocbase->_functions);
// free the cursors
TRI_FreeShadowStore(vocbase->_cursors);
TRI_FreeStoreGeneralCursor(vocbase->_cursors);
// destroy locks
TRI_DestroySpin(&vocbase->_usage._lock);
@ -1414,6 +1413,37 @@ TRI_vector_pointer_t TRI_CollectionsVocBase (TRI_vocbase_t* vocbase) {
return result;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief returns names of all known (document) collections
////////////////////////////////////////////////////////////////////////////////
TRI_vector_string_t TRI_CollectionNamesVocBase (TRI_vocbase_t* vocbase) {
TRI_vector_string_t result;
size_t i;
TRI_InitVectorString(&result, TRI_UNKNOWN_MEM_ZONE);
TRI_READ_LOCK_COLLECTIONS_VOCBASE(vocbase);
for (i = 0; i < vocbase->_collectionsById._nrAlloc; ++i) {
TRI_vocbase_col_t* found;
found = vocbase->_collectionsById._table[i];
if (found != NULL) {
char const* name = found->_name;
if (name != NULL) {
TRI_PushBackVectorString(&result, TRI_DuplicateStringZ(TRI_UNKNOWN_MEM_ZONE, name));
}
}
}
TRI_READ_UNLOCK_COLLECTIONS_VOCBASE(vocbase);
return result;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief returns all known (document) collections with their parameters
/// and indexes, up to a specific tick value

View File

@ -47,12 +47,13 @@ extern "C" {
struct TRI_primary_collection_s;
struct TRI_col_info_s;
struct TRI_general_cursor_store_s;
struct TRI_json_s;
struct TRI_replication_applier_s;
struct TRI_replication_logger_s;
struct TRI_server_s;
struct TRI_shadow_store_s;
struct TRI_vector_pointer_s;
struct TRI_vector_string_s;
struct TRI_vocbase_defaults_s;
// -----------------------------------------------------------------------------
@ -363,7 +364,7 @@ typedef struct TRI_vocbase_s {
TRI_thread_t _indexGC;
#endif
struct TRI_shadow_store_s* _cursors;
struct TRI_general_cursor_store_s* _cursors;
TRI_associative_pointer_t* _functions;
struct {
@ -474,6 +475,12 @@ void TRI_LoadAuthInfoVocBase (TRI_vocbase_t*);
TRI_vector_pointer_t TRI_CollectionsVocBase (TRI_vocbase_t*);
////////////////////////////////////////////////////////////////////////////////
/// @brief returns names of all known collections
////////////////////////////////////////////////////////////////////////////////
TRI_vector_string_t TRI_CollectionNamesVocBase (TRI_vocbase_t*);
////////////////////////////////////////////////////////////////////////////////
/// @brief returns all known (document) collections with their parameters
/// and optionally indexes

View File

@ -407,8 +407,7 @@ function put_api_cursor (req, res) {
catch (e) {
}
// unuse the cursor and garbage-collect it
cursor.unuse();
// force garbage-collection
cursor = null;
internal.wait(0.0);
}

View File

@ -1596,7 +1596,6 @@ function resultCursor (req, res, cursor, code, options) {
if (hasNext) {
cursor.persist();
cursorId = cursor.id();
cursor.unuse();
}
else {
cursorId = null;

View File

@ -137,7 +137,7 @@ HttpResponse::HttpResponseCode HttpHandlerFactory::authenticateRequest (HttpRequ
RequestContext* rc = request->getRequestContext();
if (rc == 0) {
if (! setRequestContext(request, true)) {
if (! setRequestContext(request)) {
return HttpResponse::NOT_FOUND;
}
@ -153,9 +153,8 @@ HttpResponse::HttpResponseCode HttpHandlerFactory::authenticateRequest (HttpRequ
/// @brief set request context, wrapper method
////////////////////////////////////////////////////////////////////////////////
bool HttpHandlerFactory::setRequestContext (HttpRequest* request,
bool manageResources) {
return _setContext(request, _setContextData, manageResources);
bool HttpHandlerFactory::setRequestContext (HttpRequest* request) {
return _setContext(request, _setContextData);
}
////////////////////////////////////////////////////////////////////////////////
@ -182,7 +181,9 @@ HttpRequest* HttpHandlerFactory::createRequest (ConnectionInfo const& info,
#endif
HttpRequest* request = new HttpRequest(info, ptr, length);
setRequestContext(request, true);
if (request != 0) {
setRequestContext(request);
}
return request;
}

View File

@ -104,7 +104,7 @@ namespace triagens {
/// @brief context handler
////////////////////////////////////////////////////////////////////////////////
typedef bool (*context_fptr) (HttpRequest*, void*, bool);
typedef bool (*context_fptr) (HttpRequest*, void*);
////////////////////////////////////////////////////////////////////////////////
/// @}
@ -178,8 +178,7 @@ namespace triagens {
/// @brief set request context, wrapper method
////////////////////////////////////////////////////////////////////////////////
virtual bool setRequestContext (HttpRequest*,
bool);
virtual bool setRequestContext (HttpRequest*);
////////////////////////////////////////////////////////////////////////////////
/// @brief returns the authentication realm

View File

@ -130,7 +130,8 @@ HttpRequest::~HttpRequest () {
TRI_FreeString(TRI_UNKNOWN_MEM_ZONE, (*i));
}
if (_requestContext) {
if (_requestContext != 0 && _isRequestContextOwner) {
// only delete if we are the owner of the context
delete _requestContext;
}
}
@ -1206,12 +1207,19 @@ void HttpRequest::addSuffix (char const* part) {
/// @brief set the request context
////////////////////////////////////////////////////////////////////////////////
void HttpRequest::setRequestContext (RequestContext* requestContext) {
void HttpRequest::setRequestContext (RequestContext* requestContext,
bool isRequestContextOwner) {
if (_requestContext) {
// if we have a shared context, we should not have got here
assert(isRequestContextOwner);
// delete any previous context
assert(false);
delete _requestContext;
}
_requestContext = requestContext;
_requestContext = requestContext;
_isRequestContextOwner = isRequestContextOwner;
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -288,7 +288,8 @@ namespace triagens {
/// @brief set the request context
////////////////////////////////////////////////////////////////////////////////
void setRequestContext (RequestContext*);
void setRequestContext (RequestContext*,
bool);
////////////////////////////////////////////////////////////////////////////////
/// @brief add request context
@ -680,6 +681,12 @@ namespace triagens {
////////////////////////////////////////////////////////////////////////////////
RequestContext* _requestContext;
////////////////////////////////////////////////////////////////////////////////
/// @brief whether or not we are the owner of the context
////////////////////////////////////////////////////////////////////////////////
bool _isRequestContextOwner;
};
}
}

View File

@ -37,6 +37,7 @@
TRI_v8_global_s::TRI_v8_global_s (v8::Isolate* isolate)
: JSBarriers(),
JSCollections(),
ErrorTempl(),
GeneralCursorTempl(),

View File

@ -201,6 +201,12 @@ typedef struct TRI_v8_global_s {
std::map< void*, v8::Persistent<v8::Value> > JSBarriers;
////////////////////////////////////////////////////////////////////////////////
/// @brief collection mapping for weak pointers
////////////////////////////////////////////////////////////////////////////////
std::map< void*, v8::Persistent<v8::Value> > JSCollections;
// -----------------------------------------------------------------------------
// --SECTION-- JAVASCRIPT OBJECT TEMPLATES
// -----------------------------------------------------------------------------