mirror of https://gitee.com/bigwinds/arangodb
added optional `ttl` attribute to specify result cursor expiration for HTTP API method `POST /_api/cursor`
The `ttl` attribute can be used to prevent cursor results from timing out too early.
This commit is contained in:
parent
472240948a
commit
712358d069
|
@ -1,11 +1,16 @@
|
|||
v2.2.1 (XXXX-XX-XX)
|
||||
-------------------
|
||||
|
||||
* issue #947 Foxx applicationContext missing some properties
|
||||
* added optional `ttl` attribute to specify result cursor expiration for HTTP API method
|
||||
`POST /_api/cursor`
|
||||
|
||||
The `ttl` attribute can be used to prevent cursor results from timing out too early.
|
||||
|
||||
* issue #947: Foxx applicationContext missing some properties
|
||||
|
||||
* (reported by Christian Neubauer):
|
||||
|
||||
The problem was that in googles V8, signed and unsignet chars are not always declared cleanly.
|
||||
The problem was that in Google's V8, signed and unsigned chars are not always declared cleanly.
|
||||
so we need to force v8 to compile with forced signed chars which is done by the Flag:
|
||||
-fsigned-char
|
||||
at least it is enough to follow the instructions of compiling arango on rasperry
|
||||
|
|
|
@ -288,7 +288,7 @@ describe ArangoDB do
|
|||
doc.parsed_response['id'].should be_nil
|
||||
end
|
||||
|
||||
it "deleting an invalid cursor" do
|
||||
it "deleting an invalid cursor" do
|
||||
cmd = api
|
||||
cmd = api + "/999999" # we assume this cursor id is invalid
|
||||
doc = ArangoDB.log_delete("#{prefix}-delete", cmd)
|
||||
|
@ -300,6 +300,118 @@ describe ArangoDB do
|
|||
doc.parsed_response['code'].should eq(404)
|
||||
doc.parsed_response['id'].should be_nil
|
||||
end
|
||||
|
||||
it "creates a cursor that will expire" do
|
||||
cmd = api
|
||||
body = "{ \"query\" : \"FOR u IN #{@cn} LIMIT 5 RETURN u.n\", \"count\" : true, \"batchSize\" : 1, \"ttl\" : 4 }"
|
||||
doc = ArangoDB.log_post("#{prefix}-create-ttl", cmd, :body => body)
|
||||
|
||||
doc.code.should eq(201)
|
||||
doc.headers['content-type'].should eq("application/json; charset=utf-8")
|
||||
doc.parsed_response['error'].should eq(false)
|
||||
doc.parsed_response['code'].should eq(201)
|
||||
doc.parsed_response['id'].should be_kind_of(String)
|
||||
doc.parsed_response['id'].should match(@reId)
|
||||
doc.parsed_response['hasMore'].should eq(true)
|
||||
doc.parsed_response['count'].should eq(5)
|
||||
doc.parsed_response['result'].length.should eq(1)
|
||||
|
||||
sleep 1
|
||||
id = doc.parsed_response['id']
|
||||
|
||||
cmd = api + "/#{id}"
|
||||
doc = ArangoDB.log_put("#{prefix}-create-ttl", cmd)
|
||||
|
||||
doc.code.should eq(200)
|
||||
doc.headers['content-type'].should eq("application/json; charset=utf-8")
|
||||
doc.parsed_response['error'].should eq(false)
|
||||
doc.parsed_response['code'].should eq(200)
|
||||
doc.parsed_response['id'].should be_kind_of(String)
|
||||
doc.parsed_response['id'].should match(@reId)
|
||||
doc.parsed_response['id'].should eq(id)
|
||||
doc.parsed_response['hasMore'].should eq(true)
|
||||
doc.parsed_response['count'].should eq(5)
|
||||
doc.parsed_response['result'].length.should eq(1)
|
||||
|
||||
sleep 1
|
||||
|
||||
doc = ArangoDB.log_put("#{prefix}-create-ttl", cmd)
|
||||
|
||||
doc.code.should eq(200)
|
||||
doc.headers['content-type'].should eq("application/json; charset=utf-8")
|
||||
doc.parsed_response['error'].should eq(false)
|
||||
doc.parsed_response['code'].should eq(200)
|
||||
doc.parsed_response['id'].should eq(id)
|
||||
doc.parsed_response['hasMore'].should eq(true)
|
||||
doc.parsed_response['count'].should eq(5)
|
||||
doc.parsed_response['result'].length.should eq(1)
|
||||
|
||||
sleep 15 # this should delete the cursor on the server
|
||||
doc = ArangoDB.log_put("#{prefix}-create-ttl", cmd)
|
||||
|
||||
doc.code.should eq(404)
|
||||
doc.headers['content-type'].should eq("application/json; charset=utf-8")
|
||||
doc.parsed_response['error'].should eq(true)
|
||||
doc.parsed_response['errorNum'].should eq(1600)
|
||||
doc.parsed_response['code'].should eq(404)
|
||||
end
|
||||
|
||||
it "creates a cursor that will not expire" do
|
||||
cmd = api
|
||||
body = "{ \"query\" : \"FOR u IN #{@cn} LIMIT 5 RETURN u.n\", \"count\" : true, \"batchSize\" : 1, \"ttl\" : 60 }"
|
||||
doc = ArangoDB.log_post("#{prefix}-create-ttl", cmd, :body => body)
|
||||
|
||||
doc.code.should eq(201)
|
||||
doc.headers['content-type'].should eq("application/json; charset=utf-8")
|
||||
doc.parsed_response['error'].should eq(false)
|
||||
doc.parsed_response['code'].should eq(201)
|
||||
doc.parsed_response['id'].should be_kind_of(String)
|
||||
doc.parsed_response['id'].should match(@reId)
|
||||
doc.parsed_response['hasMore'].should eq(true)
|
||||
doc.parsed_response['count'].should eq(5)
|
||||
doc.parsed_response['result'].length.should eq(1)
|
||||
|
||||
sleep 1
|
||||
id = doc.parsed_response['id']
|
||||
|
||||
cmd = api + "/#{id}"
|
||||
doc = ArangoDB.log_put("#{prefix}-create-ttl", cmd)
|
||||
|
||||
doc.code.should eq(200)
|
||||
doc.headers['content-type'].should eq("application/json; charset=utf-8")
|
||||
doc.parsed_response['error'].should eq(false)
|
||||
doc.parsed_response['code'].should eq(200)
|
||||
doc.parsed_response['id'].should be_kind_of(String)
|
||||
doc.parsed_response['id'].should match(@reId)
|
||||
doc.parsed_response['id'].should eq(id)
|
||||
doc.parsed_response['hasMore'].should eq(true)
|
||||
doc.parsed_response['count'].should eq(5)
|
||||
doc.parsed_response['result'].length.should eq(1)
|
||||
|
||||
sleep 1
|
||||
|
||||
doc = ArangoDB.log_put("#{prefix}-create-ttl", cmd)
|
||||
|
||||
doc.code.should eq(200)
|
||||
doc.headers['content-type'].should eq("application/json; charset=utf-8")
|
||||
doc.parsed_response['error'].should eq(false)
|
||||
doc.parsed_response['code'].should eq(200)
|
||||
doc.parsed_response['id'].should eq(id)
|
||||
doc.parsed_response['hasMore'].should eq(true)
|
||||
doc.parsed_response['count'].should eq(5)
|
||||
doc.parsed_response['result'].length.should eq(1)
|
||||
|
||||
sleep 5 # this should not delete the cursor on the server
|
||||
doc = ArangoDB.log_put("#{prefix}-create-ttl", cmd)
|
||||
|
||||
doc.code.should eq(200)
|
||||
doc.parsed_response['error'].should eq(false)
|
||||
doc.parsed_response['code'].should eq(200)
|
||||
doc.parsed_response['id'].should eq(id)
|
||||
doc.parsed_response['hasMore'].should eq(true)
|
||||
doc.parsed_response['count'].should eq(5)
|
||||
doc.parsed_response['result'].length.should eq(1)
|
||||
end
|
||||
end
|
||||
|
||||
################################################################################
|
||||
|
|
|
@ -3486,9 +3486,10 @@ static v8::Handle<v8::Value> ExecuteQueryNativeAhuacatl (TRI_aql_context_t* cont
|
|||
|
||||
static v8::Handle<v8::Value> ExecuteQueryCursorAhuacatl (TRI_vocbase_t* const vocbase,
|
||||
TRI_aql_context_t* const context,
|
||||
const TRI_json_t* const parameters,
|
||||
const bool doCount,
|
||||
const uint32_t batchSize) {
|
||||
TRI_json_t const* parameters,
|
||||
bool doCount,
|
||||
uint32_t batchSize,
|
||||
double cursorTtl) {
|
||||
v8::HandleScope scope;
|
||||
v8::TryCatch tryCatch;
|
||||
|
||||
|
@ -3499,7 +3500,7 @@ static v8::Handle<v8::Value> ExecuteQueryCursorAhuacatl (TRI_vocbase_t* const vo
|
|||
return scope.Close(v8::ThrowException(tryCatch.Exception()));
|
||||
}
|
||||
else {
|
||||
TRI_v8_global_t* v8g = (TRI_v8_global_t*) v8::Isolate::GetCurrent()->GetData();
|
||||
TRI_v8_global_t* v8g = static_cast<TRI_v8_global_t*>(v8::Isolate::GetCurrent()->GetData());
|
||||
|
||||
v8g->_canceled = true;
|
||||
return scope.Close(result);
|
||||
|
@ -3536,35 +3537,35 @@ static v8::Handle<v8::Value> ExecuteQueryCursorAhuacatl (TRI_vocbase_t* const vo
|
|||
// transform the result into JSON first
|
||||
TRI_json_t* json = TRI_ObjectToJson(docs);
|
||||
|
||||
if (json == 0) {
|
||||
if (json == nullptr) {
|
||||
TRI_V8_EXCEPTION_MEMORY(scope);
|
||||
}
|
||||
|
||||
TRI_general_cursor_result_t* cursorResult = TRI_CreateResultAql(json);
|
||||
|
||||
if (cursorResult == 0) {
|
||||
if (cursorResult == nullptr) {
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
|
||||
TRI_V8_EXCEPTION_MEMORY(scope);
|
||||
}
|
||||
|
||||
// extra return values
|
||||
TRI_json_t* extra = 0;
|
||||
TRI_json_t* extra = nullptr;
|
||||
if (resultObject->Has(TRI_V8_SYMBOL("extra"))) {
|
||||
extra = TRI_ObjectToJson(resultObject->Get(TRI_V8_SYMBOL("extra")));
|
||||
}
|
||||
|
||||
TRI_general_cursor_t* cursor = TRI_CreateGeneralCursor(vocbase, cursorResult, doCount, batchSize, extra);
|
||||
TRI_general_cursor_t* cursor = TRI_CreateGeneralCursor(vocbase, cursorResult, doCount, batchSize, cursorTtl, extra);
|
||||
|
||||
if (cursor == 0) {
|
||||
if (cursor == nullptr) {
|
||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, cursorResult);
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
|
||||
if (extra != 0) {
|
||||
if (extra != nullptr) {
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, extra);
|
||||
}
|
||||
TRI_V8_EXCEPTION_MEMORY(scope);
|
||||
}
|
||||
|
||||
TRI_ASSERT(cursor != 0);
|
||||
TRI_ASSERT(cursor != nullptr);
|
||||
|
||||
v8::Handle<v8::Value> cursorObject = WrapGeneralCursor(cursor);
|
||||
|
||||
|
@ -4317,12 +4318,12 @@ static v8::Handle<v8::Value> JS_CreateCursor (v8::Arguments const& argv) {
|
|||
|
||||
TRI_vocbase_t* vocbase = GetContextVocBase();
|
||||
|
||||
if (vocbase == 0) {
|
||||
if (vocbase == nullptr) {
|
||||
TRI_V8_EXCEPTION(scope, TRI_ERROR_ARANGO_DATABASE_NOT_FOUND);
|
||||
}
|
||||
|
||||
if (argv.Length() < 1) {
|
||||
TRI_V8_EXCEPTION_USAGE(scope, "CREATE_CURSOR(<list>, <doCount>, <batchSize>)");
|
||||
TRI_V8_EXCEPTION_USAGE(scope, "CREATE_CURSOR(<list>, <doCount>, <batchSize>, <ttl>)");
|
||||
}
|
||||
|
||||
if (! argv[0]->IsArray()) {
|
||||
|
@ -4333,7 +4334,7 @@ static v8::Handle<v8::Value> JS_CreateCursor (v8::Arguments const& argv) {
|
|||
v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(argv[0]);
|
||||
TRI_json_t* json = TRI_ObjectToJson(array);
|
||||
|
||||
if (json == 0) {
|
||||
if (json == nullptr) {
|
||||
TRI_V8_TYPE_ERROR(scope, "cannot convert <list> to JSON");
|
||||
}
|
||||
|
||||
|
@ -4355,14 +4356,23 @@ static v8::Handle<v8::Value> JS_CreateCursor (v8::Arguments const& argv) {
|
|||
}
|
||||
}
|
||||
|
||||
double ttl = 0.0;
|
||||
if (argv.Length() >= 4) {
|
||||
ttl = TRI_ObjectToDouble(argv[3]);
|
||||
}
|
||||
|
||||
if (ttl <= 0.0) {
|
||||
ttl = 30.0; // default ttl
|
||||
}
|
||||
|
||||
// create a cursor
|
||||
TRI_general_cursor_t* cursor = 0;
|
||||
TRI_general_cursor_t* cursor = nullptr;
|
||||
TRI_general_cursor_result_t* cursorResult = TRI_CreateResultAql(json);
|
||||
|
||||
if (cursorResult != 0) {
|
||||
cursor = TRI_CreateGeneralCursor(vocbase, cursorResult, doCount, batchSize, 0);
|
||||
if (cursorResult != nullptr) {
|
||||
cursor = TRI_CreateGeneralCursor(vocbase, cursorResult, doCount, batchSize, ttl, 0);
|
||||
|
||||
if (cursor == 0) {
|
||||
if (cursor == nullptr) {
|
||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, cursorResult);
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
|
||||
}
|
||||
|
@ -4371,7 +4381,7 @@ static v8::Handle<v8::Value> JS_CreateCursor (v8::Arguments const& argv) {
|
|||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
|
||||
}
|
||||
|
||||
if (cursor == 0) {
|
||||
if (cursor == nullptr) {
|
||||
TRI_V8_EXCEPTION_INTERNAL(scope, "cannot create cursor");
|
||||
}
|
||||
|
||||
|
@ -4517,7 +4527,7 @@ static v8::Handle<v8::Value> JS_PersistGeneralCursor (v8::Arguments const& argv)
|
|||
TRI_V8_EXCEPTION_USAGE(scope, "persist()");
|
||||
}
|
||||
|
||||
TRI_PersistGeneralCursor(UnwrapGeneralCursor(argv.Holder()), 30.0);
|
||||
TRI_PersistGeneralCursor(UnwrapGeneralCursor(argv.Holder()));
|
||||
return scope.Close(v8::True());
|
||||
}
|
||||
|
||||
|
@ -5370,6 +5380,9 @@ static v8::Handle<v8::Value> JS_RunAhuacatl (v8::Arguments const& argv) {
|
|||
|
||||
// maximum number of results to return at once
|
||||
uint32_t batchSize = UINT32_MAX;
|
||||
|
||||
// ttl for cursor
|
||||
double ttl = 0.0;
|
||||
|
||||
if (argc > 2 && argv[2]->IsObject()) {
|
||||
// treat the argument as an object from now on
|
||||
|
@ -5386,12 +5399,21 @@ static v8::Handle<v8::Value> JS_RunAhuacatl (v8::Arguments const& argv) {
|
|||
batchSize = (uint32_t) maxValue;
|
||||
}
|
||||
}
|
||||
|
||||
if (options->Has(TRI_V8_SYMBOL("ttl"))) {
|
||||
ttl = TRI_ObjectToDouble(options->Get(TRI_V8_SYMBOL("ttl")));
|
||||
}
|
||||
}
|
||||
|
||||
if (ttl <= 0.0) {
|
||||
// default ttl
|
||||
ttl = 30.0;
|
||||
}
|
||||
|
||||
// user options
|
||||
// -------------------------------------------------
|
||||
|
||||
TRI_json_t* userOptions = 0;
|
||||
TRI_json_t* userOptions = nullptr;
|
||||
if (argc > 3 && argv[3]->IsObject()) {
|
||||
// treat the argument as an object from now on
|
||||
v8::Handle<v8::Object> options = v8::Handle<v8::Object>::Cast(argv[3]);
|
||||
|
@ -5413,7 +5435,7 @@ static v8::Handle<v8::Value> JS_RunAhuacatl (v8::Arguments const& argv) {
|
|||
TRI_V8_EXCEPTION_MEMORY(scope);
|
||||
}
|
||||
|
||||
v8::Handle<v8::Value> result = ExecuteQueryCursorAhuacatl(vocbase, context.ptr(), parameters, doCount, batchSize);
|
||||
v8::Handle<v8::Value> result = ExecuteQueryCursorAhuacatl(vocbase, context.ptr(), parameters, doCount, batchSize, ttl);
|
||||
int res = context.ptr()->_error._code;
|
||||
|
||||
if (res == TRI_ERROR_REQUEST_CANCELED) {
|
||||
|
@ -5446,7 +5468,7 @@ static v8::Handle<v8::Value> JS_RunAhuacatl (v8::Arguments const& argv) {
|
|||
return scope.Close(v8::ThrowException(errorObject));
|
||||
}
|
||||
else {
|
||||
TRI_v8_global_t* v8g = (TRI_v8_global_t*) v8::Isolate::GetCurrent()->GetData();
|
||||
TRI_v8_global_t* v8g = static_cast<TRI_v8_global_t*>(v8::Isolate::GetCurrent()->GetData());
|
||||
|
||||
v8g->_canceled = true;
|
||||
return scope.Close(result);
|
||||
|
|
|
@ -64,16 +64,15 @@ TRI_general_cursor_result_t* TRI_CreateCursorResult (void* data,
|
|||
TRI_general_cursor_row_t (*getAt)(TRI_general_cursor_result_t const*, const TRI_general_cursor_length_t),
|
||||
TRI_general_cursor_length_t (*getLength)(TRI_general_cursor_result_t const*)) {
|
||||
|
||||
TRI_general_cursor_result_t* result;
|
||||
|
||||
if (data == NULL) {
|
||||
return NULL;
|
||||
if (data == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
result = (TRI_general_cursor_result_t*) TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_general_cursor_result_t), false);
|
||||
TRI_general_cursor_result_t* result = static_cast<TRI_general_cursor_result_t*>(TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_general_cursor_result_t), false));
|
||||
|
||||
if (result == NULL) {
|
||||
return NULL;
|
||||
if (result == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
result->_data = data;
|
||||
|
@ -104,7 +103,7 @@ void TRI_DestroyCursorResult (TRI_general_cursor_result_t* const result) {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void TRI_FreeCursorResult (TRI_general_cursor_result_t* const result) {
|
||||
if (result != NULL) {
|
||||
if (result != nullptr) {
|
||||
TRI_DestroyCursorResult(result);
|
||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, result);
|
||||
}
|
||||
|
@ -161,7 +160,7 @@ static inline TRI_general_cursor_row_t NextGeneralCursor (TRI_general_cursor_t*
|
|||
cursor->_result->freeData(cursor->_result);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -205,7 +204,7 @@ static TRI_json_t* GetExtraGeneralCursor (const TRI_general_cursor_t* const curs
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void TRI_FreeGeneralCursor (TRI_general_cursor_t* cursor) {
|
||||
if (cursor->_extra != NULL) {
|
||||
if (cursor->_extra != nullptr) {
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, cursor->_extra);
|
||||
}
|
||||
|
||||
|
@ -225,15 +224,21 @@ 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,
|
||||
double ttl,
|
||||
TRI_json_t* extra) {
|
||||
TRI_general_cursor_t* cursor;
|
||||
TRI_ASSERT(vocbase != nullptr);
|
||||
|
||||
TRI_ASSERT(vocbase != NULL);
|
||||
TRI_general_cursor_t* cursor = static_cast<TRI_general_cursor_t*>(TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_general_cursor_t), false));
|
||||
|
||||
cursor = (TRI_general_cursor_t*) TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_general_cursor_t), false);
|
||||
if (cursor == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (cursor == NULL) {
|
||||
return NULL;
|
||||
if (ttl <= 0.0) {
|
||||
ttl = 30.0; // default ttl
|
||||
}
|
||||
else if (ttl >= 3600.0) {
|
||||
ttl = 3600.0; // max ttl
|
||||
}
|
||||
|
||||
cursor->_vocbase = vocbase;
|
||||
|
@ -242,9 +247,10 @@ TRI_general_cursor_t* TRI_CreateGeneralCursor (TRI_vocbase_t* vocbase,
|
|||
cursor->_result = result;
|
||||
cursor->_extra = extra; // might be NULL
|
||||
|
||||
cursor->_expires = TRI_microtime() + 3600; // default lifetime: 1h
|
||||
cursor->_ttl = ttl;
|
||||
cursor->_expires = TRI_microtime() + ttl;
|
||||
cursor->_id = TRI_NewTickServer();
|
||||
|
||||
|
||||
// state
|
||||
cursor->_currentRow = 0;
|
||||
cursor->_length = result->getLength(result);
|
||||
|
@ -299,12 +305,13 @@ TRI_general_cursor_t* TRI_UseGeneralCursor (TRI_general_cursor_t* cursor) {
|
|||
TRI_LockSpin(&store->_lock);
|
||||
cursor = static_cast<TRI_general_cursor_t*>(TRI_LookupByKeyAssociativePointer(&store->_ids, &cursor->_id));
|
||||
|
||||
if (cursor != NULL) {
|
||||
if (cursor != nullptr) {
|
||||
if (cursor->_usage._isDeleted) {
|
||||
cursor = NULL;
|
||||
cursor = nullptr;
|
||||
}
|
||||
else {
|
||||
++cursor->_usage._refCount;
|
||||
cursor->_expires = TRI_microtime() + cursor->_ttl;
|
||||
}
|
||||
}
|
||||
TRI_UnlockSpin(&store->_lock);
|
||||
|
@ -321,7 +328,7 @@ void TRI_ReleaseGeneralCursor (TRI_general_cursor_t* cursor) {
|
|||
|
||||
TRI_LockSpin(&store->_lock);
|
||||
cursor = static_cast<TRI_general_cursor_t*>(TRI_LookupByKeyAssociativePointer(&store->_ids, &cursor->_id));
|
||||
if (cursor != NULL) {
|
||||
if (cursor != nullptr) {
|
||||
--cursor->_usage._refCount;
|
||||
}
|
||||
TRI_UnlockSpin(&store->_lock);
|
||||
|
@ -338,7 +345,7 @@ bool TRI_DropGeneralCursor (TRI_general_cursor_t* cursor) {
|
|||
TRI_LockSpin(&store->_lock);
|
||||
cursor = static_cast<TRI_general_cursor_t*>(TRI_LookupByKeyAssociativePointer(&store->_ids, &cursor->_id));
|
||||
|
||||
if (cursor != NULL && ! cursor->_usage._isDeleted) {
|
||||
if (cursor != nullptr && ! cursor->_usage._isDeleted) {
|
||||
cursor->_usage._isDeleted = true;
|
||||
result = true;
|
||||
}
|
||||
|
@ -370,9 +377,8 @@ size_t TRI_CountGeneralCursor (TRI_general_cursor_t* cursor) {
|
|||
/// @brief persist the cursor by setting a timeout
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void TRI_PersistGeneralCursor (TRI_general_cursor_t* cursor,
|
||||
double ttl) {
|
||||
cursor->_expires = TRI_microtime() + ttl;
|
||||
void TRI_PersistGeneralCursor (TRI_general_cursor_t* cursor) {
|
||||
cursor->_expires = TRI_microtime() + cursor->_ttl;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -385,8 +391,8 @@ TRI_general_cursor_t* TRI_FindGeneralCursor (TRI_vocbase_t* vocbase,
|
|||
|
||||
TRI_LockSpin(&store->_lock);
|
||||
TRI_general_cursor_t* cursor = static_cast<TRI_general_cursor_t*>(TRI_LookupByKeyAssociativePointer(&store->_ids, &id));
|
||||
if (cursor == NULL || cursor->_usage._isDeleted) {
|
||||
cursor = NULL;
|
||||
if (cursor == nullptr || cursor->_usage._isDeleted) {
|
||||
cursor = nullptr;
|
||||
}
|
||||
TRI_UnlockSpin(&store->_lock);
|
||||
|
||||
|
@ -404,7 +410,7 @@ bool TRI_RemoveGeneralCursor (TRI_vocbase_t* vocbase,
|
|||
|
||||
TRI_LockSpin(&store->_lock);
|
||||
TRI_general_cursor_t* cursor = static_cast<TRI_general_cursor_t*>(TRI_LookupByKeyAssociativePointer(&store->_ids, &id));
|
||||
if (cursor == NULL || cursor->_usage._isDeleted) {
|
||||
if (cursor == nullptr || cursor->_usage._isDeleted) {
|
||||
result = false;
|
||||
}
|
||||
else {
|
||||
|
@ -423,8 +429,8 @@ bool TRI_RemoveGeneralCursor (TRI_vocbase_t* vocbase,
|
|||
TRI_general_cursor_store_t* TRI_CreateStoreGeneralCursor (void) {
|
||||
TRI_general_cursor_store_t* store = static_cast<TRI_general_cursor_store_t*>(TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_general_cursor_t), false));
|
||||
|
||||
if (store == NULL) {
|
||||
return NULL;
|
||||
if (store == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int res = TRI_InitAssociativePointer(&store->_ids,
|
||||
|
@ -432,12 +438,12 @@ TRI_general_cursor_store_t* TRI_CreateStoreGeneralCursor (void) {
|
|||
HashKeyId,
|
||||
HashElementId,
|
||||
EqualKeyId,
|
||||
NULL);
|
||||
nullptr);
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
TRI_Free(TRI_UNKNOWN_MEM_ZONE, store);
|
||||
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TRI_InitSpin(&store->_lock);
|
||||
|
@ -485,13 +491,12 @@ void TRI_CleanupGeneralCursor (TRI_general_cursor_store_t* store,
|
|||
// 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++) {
|
||||
for (size_t i = 0; i < store->_ids._nrAlloc; i++) {
|
||||
// enum all cursors
|
||||
TRI_general_cursor_t* cursor = (TRI_general_cursor_t*) store->_ids._table[i];
|
||||
TRI_general_cursor_t* cursor = static_cast<TRI_general_cursor_t*>(store->_ids._table[i]);
|
||||
|
||||
if (cursor == NULL) {
|
||||
if (cursor == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -500,6 +505,7 @@ void TRI_CleanupGeneralCursor (TRI_general_cursor_store_t* store,
|
|||
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,
|
||||
|
|
|
@ -145,6 +145,7 @@ typedef struct TRI_general_cursor_s {
|
|||
uint32_t _refCount;
|
||||
bool _isDeleted;
|
||||
} _usage;
|
||||
double _ttl;
|
||||
double _expires;
|
||||
|
||||
struct TRI_json_s* _extra;
|
||||
|
@ -177,6 +178,7 @@ TRI_general_cursor_t* TRI_CreateGeneralCursor (struct TRI_vocbase_s*,
|
|||
TRI_general_cursor_result_t*,
|
||||
const bool,
|
||||
const TRI_general_cursor_length_t,
|
||||
double,
|
||||
struct TRI_json_s*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -225,8 +227,7 @@ size_t TRI_CountGeneralCursor (TRI_general_cursor_t*);
|
|||
/// @brief persist the cursor by setting a timeout
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void TRI_PersistGeneralCursor (TRI_general_cursor_t*,
|
||||
double);
|
||||
void TRI_PersistGeneralCursor (TRI_general_cursor_t*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief lookup a cursor by its id
|
||||
|
|
|
@ -41,11 +41,6 @@ var internal = require("internal");
|
|||
// --SECTION-- private functions
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @addtogroup ArangoAPI
|
||||
/// @{
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @startDocuBlock JSF_post_api_cursor
|
||||
/// @brief create a cursor and return the first results
|
||||
|
@ -74,6 +69,11 @@ var internal = require("internal");
|
|||
/// the server to the client in one roundtrip (optional). If this attribute is
|
||||
/// not set, a server-controlled default value will be used.
|
||||
///
|
||||
/// - *ttl*: an optional time-to-live for the cursor (in seconds). The cursor will be
|
||||
/// removed on the server automatically after the specified amount of time. This
|
||||
/// is useful to ensure garbage collection of cursors that are not fully fetched
|
||||
/// by clients. If not set, a server-defined value will be used.
|
||||
///
|
||||
/// - *bindVars*: key/value list of bind parameters (optional).
|
||||
///
|
||||
/// - *options*: key/value list of extra options for the query (optional).
|
||||
|
@ -349,7 +349,8 @@ function post_api_cursor(req, res) {
|
|||
json.bindVars,
|
||||
{
|
||||
count : json.count || false,
|
||||
batchSize: json.batchSize || 1000
|
||||
batchSize: json.batchSize || 1000,
|
||||
ttl: json.ttl
|
||||
},
|
||||
json.options);
|
||||
}
|
||||
|
@ -613,10 +614,6 @@ actions.defineHttp({
|
|||
}
|
||||
});
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Local Variables:
|
||||
// mode: outline-minor
|
||||
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"
|
||||
|
|
|
@ -345,7 +345,7 @@ function setupIndexQuery (name, func, isExampleQuery) {
|
|||
result.limit(limit);
|
||||
}
|
||||
|
||||
createCursorResponse(req, res, CREATE_CURSOR(result.toArray(), true, body.batchSize));
|
||||
createCursorResponse(req, res, CREATE_CURSOR(result.toArray(), true, body.batchSize, body.ttl));
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
|
@ -503,7 +503,7 @@ actions.defineHttp({
|
|||
result = result.limit(limit);
|
||||
}
|
||||
|
||||
createCursorResponse(req, res, CREATE_CURSOR(result.toArray(), true, body.batchSize));
|
||||
createCursorResponse(req, res, CREATE_CURSOR(result.toArray(), true, body.batchSize, body.ttl));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -779,7 +779,7 @@ actions.defineHttp({
|
|||
result = result.distance(distance);
|
||||
}
|
||||
|
||||
createCursorResponse(req, res, CREATE_CURSOR(result.toArray(), true, body.batchSize));
|
||||
createCursorResponse(req, res, CREATE_CURSOR(result.toArray(), true, body.batchSize, body.ttl));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -956,7 +956,7 @@ actions.defineHttp({
|
|||
result = result.distance(distance);
|
||||
}
|
||||
|
||||
createCursorResponse(req, res, CREATE_CURSOR(result.toArray(), true, body.batchSize));
|
||||
createCursorResponse(req, res, CREATE_CURSOR(result.toArray(), true, body.batchSize, body.ttl));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1080,7 +1080,7 @@ actions.defineHttp({
|
|||
result = result.limit(limit);
|
||||
}
|
||||
|
||||
createCursorResponse(req, res, CREATE_CURSOR(result.toArray(), true, body.batchSize));
|
||||
createCursorResponse(req, res, CREATE_CURSOR(result.toArray(), true, body.batchSize, body.ttl));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1235,7 +1235,7 @@ actions.defineHttp({
|
|||
result = result.limit(limit);
|
||||
}
|
||||
|
||||
createCursorResponse(req, res, CREATE_CURSOR(result.toArray(), true, body.batchSize));
|
||||
createCursorResponse(req, res, CREATE_CURSOR(result.toArray(), true, body.batchSize, body.ttl));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1730,7 +1730,7 @@ actions.defineHttp({
|
|||
result = result.limit(limit);
|
||||
}
|
||||
|
||||
createCursorResponse(req, res, CREATE_CURSOR(result.toArray(), true, body.batchSize));
|
||||
createCursorResponse(req, res, CREATE_CURSOR(result.toArray(), true, body.batchSize, body.ttl));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue