提交 99e01c7e 编写于 作者: J Jonathan Pickett

Sentinel working on Windows. Eliminated use of fork, instead relying on async CreateProcess.

上级 4440406b
......@@ -44,7 +44,7 @@ typedef char *sds;
struct sdshdr {
int len;
int free;
char* buf;
char buf[];
};
static inline size_t sdslen(const sds s) {
......
......@@ -217,7 +217,12 @@ typedef struct sentinelScriptJob {
execution at any time. If the script is not
running and it's not 0, it means: do not run
before the specified time. */
#ifdef _WIN32
HANDLE hScriptProcess; /* handle of process executing script */
pid_t processId; /* Script execution pid. (for reporting only) */
#else
pid_t pid; /* Script execution pid. */
#endif
} sentinelScriptJob;
/* ======================= hiredis ae.c adapters =============================
......@@ -595,7 +600,12 @@ void sentinelScheduleScriptExecution(char *path, ...) {
sj->retry_num = 0;
sj->argv = zmalloc(sizeof(char*)*(argc+1));
sj->start_time = 0;
#ifdef _WIN32
sj->hScriptProcess = INVALID_HANDLE_VALUE;
sj->processId = 0;
#else
sj->pid = 0;
#endif
memcpy(sj->argv,argv,sizeof(char*)*(argc+1));
listAddNodeTail(sentinel.scripts_queue,sj);
......@@ -622,6 +632,7 @@ void sentinelScheduleScriptExecution(char *path, ...) {
/* Lookup a script in the scripts queue via pid, and returns the list node
* (so that we can easily remove it from the queue if needed). */
#ifndef _WIN32
listNode *sentinelGetScriptListNodeByPid(pid_t pid) {
listNode *ln;
listIter li;
......@@ -635,6 +646,7 @@ listNode *sentinelGetScriptListNodeByPid(pid_t pid) {
}
return NULL;
}
#endif
/* Run pending scripts if we are not already at max number of running
* scripts. */
......@@ -647,8 +659,7 @@ void sentinelRunPendingScripts(void) {
* tail of the queue, so we run older jobs first. */
listRewind(sentinel.scripts_queue,&li);
while (sentinel.running_scripts < SENTINEL_SCRIPT_MAX_RUNNING &&
(ln = listNext(&li)) != NULL)
{
(ln = listNext(&li)) != NULL) {
sentinelScriptJob *sj = ln->value;
pid_t pid;
......@@ -661,6 +672,38 @@ void sentinelRunPendingScripts(void) {
sj->flags |= SENTINEL_SCRIPT_RUNNING;
sj->start_time = mstime();
sj->retry_num++;
#ifdef _WIN32
{
PROCESS_INFORMATION pi;
char args[1024];
int j = 1;
int pos = 0;
while(sj->argv[j]) {
int arglen = strlen(sj->argv[j]);
memcpy(args+pos, sj->argv[j], arglen);
pos += arglen;
memcpy(args+pos, " ", 1);
pos += 1;
j++;
}
if(TRUE == CreateProcessA(sj->argv[0], args, NULL, NULL, FALSE, 0, NULL, NULL, NULL, &pi)) {
sj->hScriptProcess = pi.hProcess;
sj->processId = pi.dwProcessId;
CloseHandle( pi.hThread );
sentinel.running_scripts++;
sentinelEvent(REDIS_DEBUG,"+script-child",NULL,"%ld",(long)sj->processId);
} else {
sentinelEvent(REDIS_WARNING,"-script-error",NULL,
"%s %d %d", sj->argv[0], 99, 0);
sj->flags &= ~SENTINEL_SCRIPT_RUNNING;
sj->processId = 0;
sj->hScriptProcess = INVALID_HANDLE_VALUE;
}
}
}
#else
pid = fork();
if (pid == -1) {
......@@ -673,11 +716,7 @@ void sentinelRunPendingScripts(void) {
sj->pid = 0;
} else if (pid == 0) {
/* Child */
#ifdef _WIN32
_execv(sj->argv[0],sj->argv);
#else
execve(sj->argv[0],sj->argv,environ);
#endif
/* If we are here an error occurred. */
_exit(2); /* Don't retry execution. */
} else {
......@@ -686,6 +725,7 @@ void sentinelRunPendingScripts(void) {
sentinelEvent(REDIS_DEBUG,"+script-child",NULL,"%ld",(long)pid);
}
}
#endif
}
/* How much to delay the execution of a script that we need to retry after
......@@ -707,6 +747,49 @@ mstime_t sentinelScriptRetryDelay(int retry_num) {
* a signal, or returned exit code "1", it is scheduled to run again if
* the max number of retries did not already elapsed. */
void sentinelCollectTerminatedScripts(void) {
#ifdef _WIN32
listNode *ln;
listIter li;
DWORD exitCode;
listRewind(sentinel.scripts_queue,&li);
while (sentinel.running_scripts < SENTINEL_SCRIPT_MAX_RUNNING &&
(ln = listNext(&li)) != NULL) {
sentinelScriptJob *sj = ln->value;
if(sj->hScriptProcess == INVALID_HANDLE_VALUE)
continue;
if(WaitForSingleObject(sj->hScriptProcess,0) == WAIT_OBJECT_0) {
GetExitCodeProcess(sj->hScriptProcess,&exitCode);
sentinelEvent(REDIS_DEBUG,"-script-child",NULL,"%ld %d %d",
(long)sj->processId, exitCode, 0);
/* at this point the process ID may be recycled by Windows */
CloseHandle(sj->hScriptProcess);
/* If the script returns an exit code of "1" (that means: please retry),
* we reschedule it if the max number of retries is not already reached. */
if (exitCode == 1 && sj->retry_num != SENTINEL_SCRIPT_MAX_RETRY) {
sj->hScriptProcess = INVALID_HANDLE_VALUE;
sj->processId = 0;
sj->flags &= ~SENTINEL_SCRIPT_RUNNING;
sj->start_time = mstime() +
sentinelScriptRetryDelay(sj->retry_num);
} else {
/* Otherwise let's remove the script, but log the event if the
* execution did not terminated in the best of the ways. */
if (exitCode != 0) {
sentinelEvent(REDIS_WARNING,"-script-error",NULL,
"%s %d", sj->argv[0], exitCode);
}
listDelNode(sentinel.scripts_queue,ln);
sentinelReleaseScriptJob(sj);
sentinel.running_scripts--;
}
}
}
#else
int statloc;
pid_t pid;
......@@ -749,6 +832,7 @@ void sentinelCollectTerminatedScripts(void) {
sentinel.running_scripts--;
}
}
#endif
}
/* Kill scripts in timeout, they'll be collected by the
......@@ -765,9 +849,15 @@ void sentinelKillTimedoutScripts(void) {
if (sj->flags & SENTINEL_SCRIPT_RUNNING &&
(now - sj->start_time) > SENTINEL_SCRIPT_MAX_RUNTIME)
{
#ifdef _WIN32
sentinelEvent(REDIS_WARNING,"-script-timeout",NULL,"%s %ld",
sj->argv[0], (long)sj->processId);
TerminateProcess(sj->hScriptProcess,1);
#else
sentinelEvent(REDIS_WARNING,"-script-timeout",NULL,"%s %ld",
sj->argv[0], (long)sj->pid);
kill(sj->pid,SIGKILL);
#endif
}
}
}
......@@ -796,7 +886,11 @@ void sentinelPendingScriptsCommand(redisClient *c) {
(sj->flags & SENTINEL_SCRIPT_RUNNING) ? "running" : "scheduled");
addReplyBulkCString(c,"pid");
#ifdef _WIN32
addReplyBulkLongLong(c,sj->processId);
#else
addReplyBulkLongLong(c,sj->pid);
#endif
if (sj->flags & SENTINEL_SCRIPT_RUNNING) {
addReplyBulkCString(c,"run-time");
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册