mirror of https://gitee.com/bigwinds/arangodb
changed reference counting for cursors
This commit is contained in:
parent
9c95582703
commit
0bdae05b96
|
|
@ -411,6 +411,8 @@ void ApplicationMR::stop () {
|
|||
for (size_t i = 0; i < _nrInstances; ++i) {
|
||||
shutdownMRInstance(i);
|
||||
}
|
||||
|
||||
delete[] _contexts;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
@ -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:
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1596,7 +1596,6 @@ function resultCursor (req, res, cursor, code, options) {
|
|||
if (hasNext) {
|
||||
cursor.persist();
|
||||
cursorId = cursor.id();
|
||||
cursor.unuse();
|
||||
}
|
||||
else {
|
||||
cursorId = null;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
|
||||
TRI_v8_global_s::TRI_v8_global_s (v8::Isolate* isolate)
|
||||
: JSBarriers(),
|
||||
JSCollections(),
|
||||
|
||||
ErrorTempl(),
|
||||
GeneralCursorTempl(),
|
||||
|
|
|
|||
|
|
@ -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
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
|||
Loading…
Reference in New Issue