Cancel wikidiff2 when it takes too long.
This commit is contained in:
parent
1cd3b13aea
commit
5c1ebe9639
@ -1 +1 @@
|
|||||||
Subproject commit e487d37c58bd2147eef3bdd2e65544f1465f839a
|
Subproject commit d8f34d2e7281bcbfa66d28939c3d03f25352ef0a
|
||||||
@ -1,6 +1,9 @@
|
|||||||
#define PY_SSIZE_T_CLEAN
|
#define PY_SSIZE_T_CLEAN
|
||||||
#include <Python.h>
|
#include <Python.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <thread>
|
||||||
|
#include <chrono>
|
||||||
|
#include <atomic>
|
||||||
#include "structmember.h"
|
#include "structmember.h"
|
||||||
#undef HAVE_CONFIG_H // this disables the php allocator
|
#undef HAVE_CONFIG_H // this disables the php allocator
|
||||||
#include "../mediawiki-php-wikidiff2/src/lib/Wikidiff2.h"
|
#include "../mediawiki-php-wikidiff2/src/lib/Wikidiff2.h"
|
||||||
@ -18,6 +21,7 @@ using wikidiff2::InlineJSONFormatter;
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
PyObject_HEAD
|
PyObject_HEAD
|
||||||
Wikidiff2::Config config;
|
Wikidiff2::Config config;
|
||||||
|
bool timed_out;
|
||||||
} pywikidiff2Obj;
|
} pywikidiff2Obj;
|
||||||
|
|
||||||
// here's where we set default configuration values
|
// here's where we set default configuration values
|
||||||
@ -37,6 +41,8 @@ pywikidiff2_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|||||||
self->config.wordsCacheCapacity = 10000;
|
self->config.wordsCacheCapacity = 10000;
|
||||||
self->config.diffCacheCapacity = 10000;
|
self->config.diffCacheCapacity = 10000;
|
||||||
self->config.statsCacheCapacity = 100000;
|
self->config.statsCacheCapacity = 100000;
|
||||||
|
self->config.cancelFlag = nullptr;
|
||||||
|
self->timed_out = false;
|
||||||
return (PyObject *) self;
|
return (PyObject *) self;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,23 +103,49 @@ static PyObject *pywikidiff2_finalSplitThreshold(pywikidiff2Obj *self, PyObject
|
|||||||
return PyFloat_FromDouble(self->config.finalSplitThreshold);
|
return PyFloat_FromDouble(self->config.finalSplitThreshold);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PyObject *pywikidiff2_timed_out(pywikidiff2Obj *self, PyObject *Py_UNUSED(ignored)){
|
||||||
|
return PyBool_FromLong(self->timed_out);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static Wikidiff2::String char_to_string(char* cstr){
|
static Wikidiff2::String char_to_string(char* cstr){
|
||||||
Wikidiff2::String str(cstr, strlen(cstr));
|
Wikidiff2::String str(cstr, strlen(cstr));
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Wikidiff2::String wikidiff2_inline_json_diff(pywikidiff2Obj *self, char* text1, char* text2){
|
static Wikidiff2::String wikidiff2_inline_json_diff(pywikidiff2Obj *self, char* text1, char* text2, long timeout_ms){
|
||||||
|
std::atomic<bool> cancelFlag(false);
|
||||||
|
self->config.cancelFlag = &cancelFlag;
|
||||||
|
self->timed_out = false;
|
||||||
|
|
||||||
|
std::thread timerThread;
|
||||||
|
if (timeout_ms > 0) {
|
||||||
|
timerThread = std::thread([&cancelFlag, timeout_ms]() {
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(timeout_ms));
|
||||||
|
cancelFlag.store(true, std::memory_order_relaxed);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Wikidiff2::String ret;
|
Wikidiff2::String ret;
|
||||||
Py_BEGIN_ALLOW_THREADS
|
Py_BEGIN_ALLOW_THREADS
|
||||||
Wikidiff2::String str1(text1, strlen(text1));
|
Wikidiff2::String str1(text1, strlen(text1));
|
||||||
Wikidiff2::String str2(text2, strlen(text2));
|
Wikidiff2::String str2(text2, strlen(text2));
|
||||||
Wikidiff2 wikidiff2( *(&self->config));
|
Wikidiff2 wikidiff2(self->config);
|
||||||
InlineJSONFormatter formatter;
|
InlineJSONFormatter formatter;
|
||||||
wikidiff2.addFormatter(formatter);
|
wikidiff2.addFormatter(formatter);
|
||||||
wikidiff2.execute(str1, str2);
|
wikidiff2.execute(str1, str2);
|
||||||
ret = formatter.getResult().str();
|
ret = formatter.getResult().str();
|
||||||
Py_END_ALLOW_THREADS
|
Py_END_ALLOW_THREADS
|
||||||
|
|
||||||
|
// Check if we timed out before stopping the timer thread
|
||||||
|
self->timed_out = cancelFlag.load(std::memory_order_relaxed);
|
||||||
|
|
||||||
|
if (timerThread.joinable()) {
|
||||||
|
cancelFlag.store(true, std::memory_order_relaxed); // Stop timer if still waiting
|
||||||
|
timerThread.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
self->config.cancelFlag = nullptr;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,7 +218,7 @@ static PyObject *pywikidiff2_inline_json_diff_sequence(pywikidiff2Obj *self, PyO
|
|||||||
text = new char[text_len];
|
text = new char[text_len];
|
||||||
strcpy(text, input_texts_str[i]);
|
strcpy(text, input_texts_str[i]);
|
||||||
}
|
}
|
||||||
Wikidiff2::String diff_str = wikidiff2_inline_json_diff(self, last_text, text);
|
Wikidiff2::String diff_str = wikidiff2_inline_json_diff(self, last_text, text, 0);
|
||||||
PyObject* py_diff = PyUnicode_FromFormat("%s",diff_str.c_str());
|
PyObject* py_diff = PyUnicode_FromFormat("%s",diff_str.c_str());
|
||||||
PyList_SetItem(result_list, i-1, py_diff);
|
PyList_SetItem(result_list, i-1, py_diff);
|
||||||
}
|
}
|
||||||
@ -196,30 +228,33 @@ static PyObject *pywikidiff2_inline_json_diff_sequence(pywikidiff2Obj *self, PyO
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static PyObject *pywikidiff2_inline_json_diff(pywikidiff2Obj *self, PyObject *args, PyObject *kwargs){
|
static PyObject *pywikidiff2_inline_json_diff(pywikidiff2Obj *self, PyObject *args, PyObject *kwargs){
|
||||||
static char* kwdlist[] = {"text1", "text2", "numContextLines", NULL};
|
static char* kwdlist[] = {"text1", "text2", "numContextLines", "timeout_ms", NULL};
|
||||||
char* text1;
|
char* text1;
|
||||||
char* text2;
|
char* text2;
|
||||||
long numContextLines = NULL;
|
int numContextLines = 0;
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ss|$i",
|
long timeout_ms = 0;
|
||||||
|
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ss|il",
|
||||||
kwdlist,
|
kwdlist,
|
||||||
&text1,
|
&text1,
|
||||||
&text2,
|
&text2,
|
||||||
&numContextLines
|
&numContextLines,
|
||||||
|
&timeout_ms
|
||||||
)){
|
)){
|
||||||
PyErr_SetString(PyExc_ValueError, "Error in arguments to inline_json_diff");
|
PyErr_SetString(PyExc_ValueError, "Error in arguments to inline_json_diff");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if(numContextLines != NULL){
|
if(numContextLines != 0){
|
||||||
self->config.numContextLines = numContextLines;
|
self->config.numContextLines = numContextLines;
|
||||||
}
|
}
|
||||||
Wikidiff2::String ret = wikidiff2_inline_json_diff(self, text1, text2);
|
Wikidiff2::String ret = wikidiff2_inline_json_diff(self, text1, text2, timeout_ms);
|
||||||
return PyUnicode_FromFormat("%s",ret.c_str());
|
return PyUnicode_FromFormat("%s",ret.c_str());
|
||||||
};
|
};
|
||||||
|
|
||||||
static PyMethodDef pywikidiff2_methods[] = {
|
static PyMethodDef pywikidiff2_methods[] = {
|
||||||
{"inline_json_diff", (PyCFunction) pywikidiff2_inline_json_diff, METH_VARARGS | METH_KEYWORDS, "run wikidiff 2 on text1 and text2"},
|
{"inline_json_diff", (PyCFunction) pywikidiff2_inline_json_diff, METH_VARARGS | METH_KEYWORDS, "run wikidiff 2 on text1 and text2"},
|
||||||
{"inline_json_diff_sequence", (PyCFunction) pywikidiff2_inline_json_diff_sequence, METH_VARARGS | METH_KEYWORDS, "run wikidiff 2 on a series of texts"},
|
{"inline_json_diff_sequence", (PyCFunction) pywikidiff2_inline_json_diff_sequence, METH_VARARGS | METH_KEYWORDS, "run wikidiff 2 on a series of texts"},
|
||||||
|
{"timed_out", (PyCFunction) pywikidiff2_timed_out, METH_NOARGS, "Whether the last diff timed out"},
|
||||||
{"num_context_lines", (PyCFunction) pywikidiff2_numContextLines, METH_NOARGS, "number of equal lines to output in the context of a diff"},
|
{"num_context_lines", (PyCFunction) pywikidiff2_numContextLines, METH_NOARGS, "number of equal lines to output in the context of a diff"},
|
||||||
{"moved_line_threshold", (PyCFunction) pywikidiff2_movedLineThreshold, METH_NOARGS, "The minimum similarity a pair of lines must have to be detected as a moved line. If present, this overrides php.ini wikidiff2.moved_line_threshold"},
|
{"moved_line_threshold", (PyCFunction) pywikidiff2_movedLineThreshold, METH_NOARGS, "The minimum similarity a pair of lines must have to be detected as a moved line. If present, this overrides php.ini wikidiff2.moved_line_threshold"},
|
||||||
{"change_threshold", (PyCFunction) pywikidiff2_changeThreshold, METH_NOARGS, "Changed lines with a similarity value below this threshold will be split into a deleted line and added line. This helps matching up moved lines in some cases."},
|
{"change_threshold", (PyCFunction) pywikidiff2_changeThreshold, METH_NOARGS, "Changed lines with a similarity value below this threshold will be split into a deleted line and added line. This helps matching up moved lines in some cases."},
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user