mirror of https://gitee.com/bigwinds/arangodb
Merge branch 'devel' of https://github.com/triAGENS/ArangoDB into devel
This commit is contained in:
commit
90e18f40d2
|
@ -0,0 +1,92 @@
|
|||
Stir up your ArangoDB Cluster{#CookbookCluster}
|
||||
=============================
|
||||
|
||||
Setting up a cluster can be intimidating task. You have to deal with
|
||||
firewalls, ports, different types of machines, and the like. ArangoDB
|
||||
is prepared to deal with all kinds of different setups and
|
||||
requirements.
|
||||
|
||||
However, in the following sections we concentrate on a standard setup
|
||||
and show you, how to build a ArangoDB cluster within minutes. If you
|
||||
want to dive deeper into the nasty details, you should read LINK.
|
||||
|
||||
Single Machine Cluster
|
||||
----------------------
|
||||
|
||||
While not really relevant for a prodution environment, a common setup
|
||||
for development is to create a cluster on a single maschine.
|
||||
|
||||
###Step 1: Install ArangoDB
|
||||
|
||||
We assume that you are using a Debian 7.0 system to run ArangoDB. For other
|
||||
operation systems, checkout our
|
||||
@S_EXTREF_S{https://www.arangodb.org/download,download page}
|
||||
and follow the instructions given there.
|
||||
|
||||
Run the following as root:
|
||||
|
||||
echo 'deb http://www.arangodb.org/repositories/arangodb2/Debian_7.0/ /' >> /etc/apt/sources.list.d/arangodb.list
|
||||
apt-get update
|
||||
apt-get install arangodb
|
||||
|
||||
You have now installed ArangoDB on your system. By default, ArangoDB
|
||||
runs in standalone mode.
|
||||
|
||||
###Step 2: Enable the Cluster mode
|
||||
|
||||
In order to enable the cluster mode, edit as root the configuration file
|
||||
|
||||
vi /etc/arangodb/arangod.conf
|
||||
|
||||
and change the lines
|
||||
|
||||
[cluster]
|
||||
disable-dispatcher-kickstarter = yes
|
||||
disable-dispatcher-frontend = yes
|
||||
|
||||
to
|
||||
|
||||
[cluster]
|
||||
disable-dispatcher-kickstarter = no
|
||||
disable-dispatcher-frontend = no
|
||||
|
||||
save and restarted
|
||||
|
||||
/etc/init.d/arangodb restart
|
||||
|
||||
###Setp 3: Setup your Cluster
|
||||
|
||||
You can now configure your cluster. A cluster consists of a number of
|
||||
database server and coordinators. A database servers holds you
|
||||
precious data, while a coordinator talks to the outside worlds, takes
|
||||
requests from clients, distributes them to database server and
|
||||
assembles the result.
|
||||
|
||||
For this example, we assume that are creating three database servers
|
||||
and two coordinators.
|
||||
|
||||
Use your favorite web browser and go to
|
||||
|
||||
http://localhost:8529/
|
||||
|
||||
You will see the cluster management frontend.
|
||||
|
||||
Select `Single Machine` scenario. The next page allows you to enter
|
||||
the number of coordinators and database servers. Press `Launch Cluster`
|
||||
to fire up the cluster.
|
||||
|
||||
That's it. Your cluster is up and running.
|
||||
|
||||
###Step 4: Test your Cluster
|
||||
|
||||
Click on one of the coordinators (e. g. "Claus") to access your
|
||||
cluster. In order to create a sharded collection, use `Tools / JS
|
||||
Shell` and execute
|
||||
|
||||
JSH> db._create("users", { numberOfShards: 3 });
|
||||
JSH> db.users.save({ _key: "cmeier", firstName: "Claus", lastName: "Meier" });
|
||||
|
||||
Congratulations! You have created your first sharded collection and
|
||||
stored a document in it.
|
||||
|
||||
|
|
@ -20,6 +20,7 @@ WIKI = \
|
|||
CommandLine \
|
||||
Communication \
|
||||
Compiling \
|
||||
CookbookCluster \
|
||||
DbaManual \
|
||||
DbaManualAuthentication \
|
||||
DbaManualBasics \
|
||||
|
|
|
@ -1,26 +1,25 @@
|
|||
ArangoDB (@VERSION) {#Home}
|
||||
===========================
|
||||
|
||||
@xmlonly
|
||||
Please note: This is the current DEVELOPMENT version of the manual. The stable
|
||||
HTML and PDF versions of the manual can be found
|
||||
<ulink url="http://www.arangodb.org/manuals">here</ulink>.
|
||||
@endxmlonly
|
||||
ArangoDB is a multi-purpose, open-source database with flexible data
|
||||
models for documents, graphs, and key-values. Build high performance
|
||||
applications using a convenient SQL-like query language or
|
||||
JavaScript/Ruby extensions. Use ACID transaction if you require
|
||||
them. Scale horizontally and vertically with a few mouse clicks.
|
||||
|
||||
ArangoDB is a universal open-source database with a flexible data model for
|
||||
documents, graphs, and key-values. You can easily build high performance
|
||||
applications using a convenient AQL-like query language or JavaScript/Ruby
|
||||
extensions. It focuses on durability of the data taking advantage of new
|
||||
technologies like SSD, support for graph and geo algorithms needed in social
|
||||
networks, ease of use for the developer and minimal effort to operate for the
|
||||
administrator. The design goals are described @S_EXTREF{http://www.arangodb.org/,here}.
|
||||
It focuses on durability of the data taking advantage of new
|
||||
technologies like SSD, support for graph and geo algorithms needed in
|
||||
social networks, ease of use for the developer and minimal effort to
|
||||
operate for the administrator. The design goals are described
|
||||
@S_EXTREF{http://www.arangodb.org/,here}.
|
||||
|
||||
The ArangoDB package consists of a server, a separate shell, which allows you to
|
||||
administrate the server, and a set of client APIs (or sometimes called drivers)
|
||||
for various languages including the Big-P (PHP, Python, Perl) and Ruby.
|
||||
The ArangoDB package consists of a server, a separate shell, which
|
||||
allows you to administrate the server, and a set of client APIs (or
|
||||
sometimes called drivers) for various languages including the Big-P
|
||||
(PHP, Python, Perl) and Ruby.
|
||||
|
||||
Please contact @S_EXTREF_S{http://www.arangodb.org/connect,us} if you have any
|
||||
questions.
|
||||
Please contact @S_EXTREF_S{http://www.arangodb.org/community,us} if
|
||||
you have any questions.
|
||||
|
||||
Upgrading to ArangoDB 2.0 {#ArangoDBUpgrading20}
|
||||
================================================
|
||||
|
@ -30,6 +29,16 @@ Upgrading to ArangoDB 2.0 {#ArangoDBUpgrading20}
|
|||
|
||||
See @ref Upgrading from older releases.
|
||||
|
||||
Cookbooks and Tutorials {#ArangoCookbooks}
|
||||
==========================================
|
||||
|
||||
The reference manuals provide you with all the information you will
|
||||
every need. However, this amount of information can sometimes be
|
||||
overwhelming. Therefore, we provide a series of cookbooks and
|
||||
tutorials which give you a brief overview.
|
||||
|
||||
- @BOOK_REF{CookbookCluster}
|
||||
|
||||
ArangoDB's User Manuals {#ArangoDBUserManual}
|
||||
=============================================
|
||||
|
||||
|
|
|
@ -724,7 +724,8 @@ WARN_LOGFILE =
|
|||
# directories like "/usr/src/myproject". Separate the files or directories
|
||||
# with spaces.
|
||||
|
||||
INPUT = @srcdir@/Documentation/DbaManual \
|
||||
INPUT = @srcdir@/Documentation/Cookbooks \
|
||||
@srcdir@/Documentation/DbaManual \
|
||||
@srcdir@/Documentation/ImplementorManual \
|
||||
@srcdir@/Documentation/InstallationManual \
|
||||
@srcdir@/Documentation/Manual \
|
||||
|
|
|
@ -20,4 +20,45 @@
|
|||
Delete Cluster Plan
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div id="editPlanModal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true" style="display:none">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<a class="arangoHeader">Edit Cluster Plan</a>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<table>
|
||||
<tr>
|
||||
<th>An edited plan can not be restored. Really edit?</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-close" data-dismiss="modal" aria-hidden="true">Close</button>
|
||||
<button id="submitEditPlan" class="button-danger pull-right">Edit</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="deletePlanModal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true" style="display:none">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<a class="arangoHeader">Delete Cluster Plan</a>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<table>
|
||||
<tr>
|
||||
<th>A deleted plan can not be restored. Really delete?</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-close" data-dismiss="modal" aria-hidden="true">Close</button>
|
||||
<button id="submitDeletePlan" class="button-danger pull-right">Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</script>
|
||||
|
|
|
@ -14,7 +14,9 @@
|
|||
events: {
|
||||
"click #relaunchCluster" : "relaunchCluster",
|
||||
"click #editPlan" : "editPlan",
|
||||
"click #deletePlan" : "deletePlan"
|
||||
"click #submitEditPlan" : "submitEditPlan",
|
||||
"click #deletePlan" : "deletePlan",
|
||||
"click #submitDeletePlan" : "submitDeletePlan"
|
||||
},
|
||||
|
||||
render: function() {
|
||||
|
@ -38,7 +40,14 @@
|
|||
}
|
||||
});
|
||||
},
|
||||
|
||||
editPlan: function() {
|
||||
$('#deletePlanModal').modal('hide');
|
||||
$('#editPlanModal').modal('show');
|
||||
},
|
||||
|
||||
submitEditPlan : function() {
|
||||
$('#editPlanModal').modal('hide');
|
||||
var plan = window.App.clusterPlan;
|
||||
if (plan.isTestSetup()) {
|
||||
window.App.navigate("planTest", {trigger : true});
|
||||
|
@ -52,11 +61,18 @@
|
|||
},
|
||||
|
||||
deletePlan: function() {
|
||||
$('#editPlanModal').modal('hide');
|
||||
$('#deletePlanModal').modal('show');
|
||||
},
|
||||
|
||||
submitDeletePlan : function() {
|
||||
$('#deletePlanModal').modal('hide');
|
||||
window.App.clusterPlan.destroy();
|
||||
window.App.clusterPlan = new window.ClusterPlan();
|
||||
window.App.planScenario();
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
|
||||
}());
|
||||
|
|
|
@ -18,7 +18,11 @@
|
|||
},
|
||||
|
||||
cancel: function() {
|
||||
window.App.navigate("", {trigger: true});
|
||||
if(window.App.clusterPlan.get("plan")) {
|
||||
window.App.navigate("handleClusterDown", {trigger: true});
|
||||
} else {
|
||||
window.App.navigate("planScenario", {trigger: true});
|
||||
}
|
||||
},
|
||||
|
||||
startPlan: function() {
|
||||
|
|
|
@ -17,7 +17,11 @@
|
|||
},
|
||||
|
||||
cancel: function() {
|
||||
window.App.navigate("", {trigger: true});
|
||||
if(window.App.clusterPlan.get("plan")) {
|
||||
window.App.navigate("handleClusterDown", {trigger: true});
|
||||
} else {
|
||||
window.App.navigate("planScenario", {trigger: true});
|
||||
}
|
||||
},
|
||||
|
||||
startPlan: function() {
|
||||
|
|
|
@ -302,8 +302,8 @@ static void StartExternalProcess (TRI_external_t* external, bool usePipes) {
|
|||
external->_status = TRI_EXT_RUNNING;
|
||||
}
|
||||
#else
|
||||
bool createPipes (HANDLE * hChildStdinRd, HANDLE * hChildStdinWr,
|
||||
HANDLE * hChildStdoutRd, HANDLE * hChildStdoutWr) {
|
||||
static bool createPipes (HANDLE* hChildStdinRd, HANDLE* hChildStdinWr,
|
||||
HANDLE* hChildStdoutRd, HANDLE* hChildStdoutWr) {
|
||||
|
||||
// set the bInheritHandle flag so pipe handles are inherited
|
||||
SECURITY_ATTRIBUTES saAttr;
|
||||
|
@ -457,7 +457,8 @@ static bool startProcess (TRI_external_t * external, HANDLE rd, HANDLE wr) {
|
|||
return false;
|
||||
}
|
||||
else {
|
||||
external->_pid = piProcInfo.hProcess;
|
||||
external->_pid = piProcInfo.dwProcessId;
|
||||
CloseHandle(piProcInfo.hProcess);
|
||||
CloseHandle(piProcInfo.hThread);
|
||||
return true;
|
||||
}
|
||||
|
@ -468,7 +469,8 @@ static void StartExternalProcess (TRI_external_t* external, bool usePipes) {
|
|||
HANDLE hChildStdoutRd = NULL, hChildStdoutWr = NULL;
|
||||
bool fSuccess;
|
||||
if(usePipes) {
|
||||
fSuccess = createPipes(& hChildStdinRd, & hChildStdinWr, & hChildStdoutRd, & hChildStdoutWr);
|
||||
fSuccess = createPipes(&hChildStdinRd, &hChildStdinWr,
|
||||
&hChildStdoutRd, &hChildStdoutWr);
|
||||
|
||||
if (! fSuccess) {
|
||||
external->_status = TRI_EXT_PIPE_FAILED;
|
||||
|
@ -485,7 +487,6 @@ static void StartExternalProcess (TRI_external_t* external, bool usePipes) {
|
|||
CloseHandle(hChildStdoutWr);
|
||||
CloseHandle(hChildStdinRd);
|
||||
CloseHandle(hChildStdinWr);
|
||||
CloseHandle(external->_pid);
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -496,9 +497,9 @@ static void StartExternalProcess (TRI_external_t* external, bool usePipes) {
|
|||
external->_readPipe = hChildStdoutRd;
|
||||
external->_writePipe = hChildStdinWr;
|
||||
external->_status = TRI_EXT_RUNNING;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- public functions
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -784,14 +785,45 @@ void TRI_SetProcessTitle (char const* title) {
|
|||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief frees an external process structure
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void FreeExternal(TRI_external_t* ext) {
|
||||
size_t i;
|
||||
TRI_Free(TRI_CORE_MEM_ZONE, ext->_executable);
|
||||
for (i = 0; i < ext->_numberArguments; i++) {
|
||||
TRI_Free(TRI_CORE_MEM_ZONE, ext->_arguments[i]);
|
||||
}
|
||||
TRI_Free(TRI_CORE_MEM_ZONE, ext->_arguments);
|
||||
|
||||
#ifndef _WIN32
|
||||
if (ext->_readPipe != -1) {
|
||||
close(ext->_readPipe);
|
||||
}
|
||||
if (ext->_writePipe != -1) {
|
||||
close(ext->_writePipe);
|
||||
}
|
||||
#else
|
||||
if (ext->_readPipe != NULL) {
|
||||
CloseHandle(ext->_readPipe);
|
||||
}
|
||||
if (ext->_writePipe != NULL) {
|
||||
CloseHandle(ext->_writePipe);
|
||||
}
|
||||
#endif
|
||||
TRI_Free(TRI_CORE_MEM_ZONE, ext);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief starts an external process
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void TRI_CreateExternalProcess (const char* executable,
|
||||
const char** arguments,
|
||||
size_t n,
|
||||
TRI_external_id_t* pid) {
|
||||
const char** arguments,
|
||||
size_t n,
|
||||
bool usePipes,
|
||||
TRI_external_id_t* pid) {
|
||||
TRI_external_t* external;
|
||||
|
||||
size_t i;
|
||||
|
@ -812,38 +844,29 @@ void TRI_CreateExternalProcess (const char* executable,
|
|||
external->_arguments[n + 1] = NULL;
|
||||
external->_status = TRI_EXT_NOT_STARTED;
|
||||
|
||||
StartExternalProcess(external, false);
|
||||
StartExternalProcess(external, usePipes);
|
||||
if (external->_status != TRI_EXT_RUNNING) {
|
||||
#ifndef _WIN32
|
||||
pid->pid = -1;
|
||||
#else
|
||||
pid->_hProcess = 0;
|
||||
#endif
|
||||
pid->_pid = TRI_INVALID_PROCESS_ID;
|
||||
FreeExternal(external);
|
||||
return;
|
||||
}
|
||||
|
||||
TRI_LockMutex(&ExternalProcessesLock);
|
||||
TRI_PushBackVectorPointer(&ExternalProcesses, external);
|
||||
#ifndef _WIN32
|
||||
pid->pid = external->_pid;
|
||||
pid->readPipe = external->_readPipe;
|
||||
pid->writePipe = external->_writePipe;
|
||||
#else
|
||||
pid->_hProcess = external->_pid;
|
||||
pid->_hChildStdoutRd = external->_readPipe;
|
||||
pid->_hChildStdinWr = external->_writePipe;
|
||||
|
||||
#endif
|
||||
// Note that the following deals with different types under windows,
|
||||
// however, this code here can be written in a platform-independent
|
||||
// way:
|
||||
pid->_pid = external->_pid;
|
||||
pid->_readPipe = external->_readPipe;
|
||||
pid->_writePipe = external->_writePipe;
|
||||
TRI_UnlockMutex(&ExternalProcessesLock);
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns the status of an external process
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _WIN32
|
||||
TRI_external_status_t TRI_CheckExternalProcess (TRI_external_id_t pid,
|
||||
bool wait) {
|
||||
TRI_external_status_t status;
|
||||
|
@ -861,27 +884,26 @@ TRI_external_status_t TRI_CheckExternalProcess (TRI_external_id_t pid,
|
|||
for (i = 0; i < ExternalProcesses._length; ++i) {
|
||||
external = TRI_AtVectorPointer(&ExternalProcesses, i);
|
||||
|
||||
if (external->_pid == pid.pid) {
|
||||
if (external->_pid == pid._pid) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == ExternalProcesses._length) {
|
||||
TRI_UnlockMutex(&ExternalProcessesLock);
|
||||
// Just in case to get rid of zombies:
|
||||
waitpid(pid.pid, &loc, WNOHANG | WUNTRACED);
|
||||
return status;
|
||||
}
|
||||
|
||||
if (external->_status == TRI_EXT_RUNNING || external->_status == TRI_EXT_STOPPED) {
|
||||
if (!wait) {
|
||||
opts = WNOHANG | WUNTRACED;
|
||||
}
|
||||
else {
|
||||
if (external->_status == TRI_EXT_RUNNING ||
|
||||
external->_status == TRI_EXT_STOPPED) {
|
||||
#ifndef _WIN32
|
||||
if (wait) {
|
||||
opts = WUNTRACED;
|
||||
}
|
||||
else {
|
||||
opts = WNOHANG | WUNTRACED;
|
||||
}
|
||||
res = waitpid(external->_pid, &loc, opts);
|
||||
|
||||
if (res == 0) {
|
||||
external->_exitStatus = 0;
|
||||
}
|
||||
|
@ -897,73 +919,100 @@ TRI_external_status_t TRI_CheckExternalProcess (TRI_external_id_t pid,
|
|||
external->_status = TRI_EXT_STOPPED;
|
||||
external->_exitStatus = 0;
|
||||
}
|
||||
}
|
||||
|
||||
status._status = external->_status;
|
||||
status._exitStatus = external->_exitStatus;
|
||||
|
||||
TRI_UnlockMutex(&ExternalProcessesLock);
|
||||
return status;
|
||||
}
|
||||
#else
|
||||
TRI_external_status_t TRI_CheckExternalProcess (HANDLE hProcess,
|
||||
bool wait) {
|
||||
TRI_external_status_t status;
|
||||
TRI_external_t* external;
|
||||
size_t i;
|
||||
|
||||
TRI_LockMutex(&ExternalProcessesLock);
|
||||
|
||||
status._status = TRI_EXT_NOT_FOUND;
|
||||
status._exitStatus = 0;
|
||||
for (i = 0; i < ExternalProcesses._length; ++i) {
|
||||
external = TRI_AtVectorPointer(&ExternalProcesses, i);
|
||||
|
||||
if (external->_pid == hProcess) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == ExternalProcesses._length) {
|
||||
TRI_UnlockMutex(&ExternalProcessesLock);
|
||||
return status;
|
||||
}
|
||||
|
||||
if (external->_status == TRI_EXT_RUNNING || external->_status == TRI_EXT_STOPPED) {
|
||||
if (wait) {
|
||||
DWORD result;
|
||||
result = WaitForSingleObject(hProcess, INFINITE);
|
||||
}
|
||||
DWORD exitCode;
|
||||
if (!GetExitCodeProcess(hProcess , &exitCode)) {
|
||||
LOG_WARNING("exit status could not be called for handle '%p'", hProcess);
|
||||
TRI_UnlockMutex(&ExternalProcessesLock);
|
||||
return status;
|
||||
}
|
||||
|
||||
if (exitCode == STILL_ACTIVE) {
|
||||
external->_exitStatus = 0;
|
||||
HANDLE hProcess = OpenProcess(SYNCHRONIZE |
|
||||
PROCESS_QUERY_LIMITED_INFORMATION,
|
||||
FALSE, external->_pid);
|
||||
if (hProcess == NULL) {
|
||||
LOG_WARNING("could not do OpenProcess for subprocess with PID '%ud'",
|
||||
external->_pid);
|
||||
}
|
||||
else {
|
||||
external->_status = TRI_EXT_TERMINATED;
|
||||
external->_exitStatus = exitCode;
|
||||
if (wait) {
|
||||
DWORD result;
|
||||
result = WaitForSingleObject(hProcess, INFINITE);
|
||||
if (result == WAIT_FAILED) {
|
||||
LOG_WARNING("could not wait for subprocess with PID '%ud'",
|
||||
external->_pid);
|
||||
}
|
||||
}
|
||||
DWORD exitCode = STILL_ACTIVE;
|
||||
if (!GetExitCodeProcess(hProcess , &exitCode)) {
|
||||
LOG_WARNING("exit status could not be determined for PID '%ud'",
|
||||
external->_pid);
|
||||
}
|
||||
else {
|
||||
if (exitCode == STILL_ACTIVE) {
|
||||
external->_exitStatus = 0;
|
||||
}
|
||||
else {
|
||||
external->_status = TRI_EXT_TERMINATED;
|
||||
external->_exitStatus = exitCode;
|
||||
}
|
||||
}
|
||||
CloseHandle(hProcess);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
status._status = external->_status;
|
||||
status._exitStatus = external->_exitStatus;
|
||||
|
||||
// Do we have to free our data?
|
||||
if (external->_status != TRI_EXT_RUNNING &&
|
||||
external->_status != TRI_EXT_STOPPED) {
|
||||
TRI_RemoveVectorPointer(&ExternalProcesses, i);
|
||||
FreeExternal(external);
|
||||
}
|
||||
|
||||
TRI_UnlockMutex(&ExternalProcessesLock);
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
static bool ourKillProcess(TRI_pid_t pid) {
|
||||
return (0 != kill(pid, SIGTERM));
|
||||
}
|
||||
#else
|
||||
static bool ourKillProcess(DWORD pid) {
|
||||
bool ok = true;
|
||||
HANDLE hProcess = OpenProcess(SYNCHRONIZE | PROCESS_TERMINATE,
|
||||
FALSE, pid);
|
||||
if (hProcess == NULL) {
|
||||
LOG_WARNING("could not do OpenProcess for subprocess with PID '%ud'", pid);
|
||||
ok = false;
|
||||
}
|
||||
else {
|
||||
UINT uExitCode = 0;
|
||||
DWORD exitCode;
|
||||
|
||||
// kill worker process
|
||||
if (0 != TerminateProcess(hProcess, uExitCode)) {
|
||||
LOG_TRACE("kill of worker process succeeded");
|
||||
CloseHandle(hProcess);
|
||||
}
|
||||
else {
|
||||
DWORD e1 = GetLastError();
|
||||
BOOL ok = GetExitCodeProcess(hProcess, &exitCode);
|
||||
|
||||
if (ok) {
|
||||
LOG_DEBUG("worker process already dead: %d", exitCode);
|
||||
}
|
||||
else {
|
||||
LOG_WARNING("kill of worker process failed: %d", exitCode);
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief kills an external process
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void TRI_KillExternalProcess (TRI_external_id_t pid) {
|
||||
|
||||
bool TRI_KillExternalProcess (TRI_external_id_t pid) {
|
||||
TRI_external_t* external;
|
||||
size_t i;
|
||||
|
||||
|
@ -972,66 +1021,28 @@ void TRI_KillExternalProcess (TRI_external_id_t pid) {
|
|||
for (i = 0; i < ExternalProcesses._length; ++i) {
|
||||
external = TRI_AtVectorPointer(&ExternalProcesses, i);
|
||||
|
||||
if (external->_pid == pid.pid) {
|
||||
if (external->_pid == pid._pid) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == ExternalProcesses._length) {
|
||||
TRI_UnlockMutex(&ExternalProcessesLock);
|
||||
kill(pid.pid, SIGTERM);
|
||||
return;
|
||||
// Kill just in case:
|
||||
return ourKillProcess(pid._pid);
|
||||
}
|
||||
|
||||
if (external->_status == TRI_EXT_RUNNING || external->_status == TRI_EXT_STOPPED) {
|
||||
int val = kill(external->_pid , SIGTERM);
|
||||
|
||||
if (val) {
|
||||
external->_status = TRI_EXT_KILL_FAILED;
|
||||
}
|
||||
else {
|
||||
TRI_RemoveVectorPointer(&ExternalProcesses, i);
|
||||
}
|
||||
bool ok = true;
|
||||
if (external->_status == TRI_EXT_RUNNING ||
|
||||
external->_status == TRI_EXT_STOPPED) {
|
||||
ok = ourKillProcess(external->_pid);
|
||||
}
|
||||
else {
|
||||
TRI_RemoveVectorPointer(&ExternalProcesses, i);
|
||||
}
|
||||
|
||||
TRI_RemoveVectorPointer(&ExternalProcesses, i);
|
||||
TRI_UnlockMutex(&ExternalProcessesLock);
|
||||
FreeExternal(external);
|
||||
return ok;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void TRI_KillExternalProcess (TRI_external_id_t *pid) {
|
||||
UINT uExitCode = 0;
|
||||
DWORD exitCode;
|
||||
|
||||
// kill worker process
|
||||
if (TerminateProcess(pid->_hProcess, uExitCode)) {
|
||||
LOG_TRACE("kill of worker process succeeded");
|
||||
CloseHandle(pid->_hProcess);
|
||||
}
|
||||
else {
|
||||
DWORD e1 = GetLastError();
|
||||
BOOL ok = GetExitCodeProcess(pid->_hProcess, &exitCode);
|
||||
|
||||
if (ok) {
|
||||
LOG_DEBUG("worker process already dead: %d", exitCode);
|
||||
}
|
||||
else {
|
||||
LOG_WARNING("kill of worker process failed: %d", exitCode);
|
||||
}
|
||||
}
|
||||
|
||||
if(pid->_hChildStdoutRd) {
|
||||
CloseHandle(pid->_hChildStdoutRd);
|
||||
}
|
||||
if(pid->_hChildStdinWr) {
|
||||
CloseHandle(pid->_hChildStdinWr);
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- MODULE
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -41,10 +41,14 @@ extern "C" {
|
|||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief invalid process
|
||||
/// @brief invalid process id
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define INVALID_PROCESS (0)
|
||||
#ifdef _WIN32
|
||||
#define TRI_INVALID_PROCESS_ID (0)
|
||||
#else
|
||||
#define TRI_INVALID_PROCESS_ID (-1)
|
||||
#endif
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- public types
|
||||
|
@ -79,7 +83,6 @@ typedef enum {
|
|||
TRI_EXT_TERMINATED = 5, // process has terminated normally
|
||||
TRI_EXT_ABORTED = 6, // process has terminated abnormally
|
||||
TRI_EXT_STOPPED = 7, // process has been stopped
|
||||
TRI_EXT_KILL_FAILED = 8, // kill failed
|
||||
}
|
||||
TRI_external_status_e;
|
||||
|
||||
|
@ -89,15 +92,15 @@ TRI_external_status_e;
|
|||
|
||||
#ifndef _WIN32
|
||||
typedef struct TRI_external_id_s {
|
||||
TRI_pid_t pid;
|
||||
int readPipe;
|
||||
int writePipe;
|
||||
TRI_pid_t _pid;
|
||||
int _readPipe;
|
||||
int _writePipe;
|
||||
} TRI_external_id_t;
|
||||
#else
|
||||
typedef struct TRI_external_id_s {
|
||||
HANDLE _hProcess;
|
||||
HANDLE _hChildStdoutRd;
|
||||
HANDLE _hChildStdinWr;
|
||||
DWORD _pid;
|
||||
HANDLE _readPipe;
|
||||
HANDLE _writePipe;
|
||||
} TRI_external_id_t;
|
||||
#endif
|
||||
|
||||
|
@ -115,7 +118,7 @@ typedef struct TRI_external_s {
|
|||
int _readPipe;
|
||||
int _writePipe;
|
||||
#else
|
||||
HANDLE _pid;
|
||||
DWORD _pid;
|
||||
HANDLE _readPipe;
|
||||
HANDLE _writePipe;
|
||||
#endif
|
||||
|
@ -181,11 +184,11 @@ void TRI_SetProcessTitle (char const* title);
|
|||
/// @brief starts an external process
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
void TRI_CreateExternalProcess (const char* executable,
|
||||
const char** arguments,
|
||||
size_t n,
|
||||
const char** arguments,
|
||||
size_t n,
|
||||
bool usePipes,
|
||||
TRI_external_id_t * pid);
|
||||
|
||||
#ifndef _WIN32
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns the status of an external process
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -197,22 +200,8 @@ TRI_external_status_t TRI_CheckExternalProcess (TRI_external_id_t pid,
|
|||
/// @brief kills an external process
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void TRI_KillExternalProcess (TRI_external_id_t pid);
|
||||
bool TRI_KillExternalProcess (TRI_external_id_t pid);
|
||||
|
||||
#else
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns the status of an external process
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TRI_external_status_t TRI_CheckExternalProcess (HANDLE hProcess,
|
||||
bool wait);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief kills an external process
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void TRI_KillExternalProcess (TRI_external_id_t *pid);
|
||||
#endif
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- MODULE
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
|
@ -2488,8 +2488,9 @@ static v8::Handle<v8::Value> JS_ExecuteExternal (v8::Arguments const& argv) {
|
|||
v8::HandleScope scope;
|
||||
|
||||
// extract the arguments
|
||||
if (2 < argv.Length() || argv.Length() < 1) {
|
||||
TRI_V8_EXCEPTION_USAGE(scope, "executeExternal(<filename>, [<arguments>])");
|
||||
if (3 < argv.Length() || argv.Length() < 1) {
|
||||
TRI_V8_EXCEPTION_USAGE(scope,
|
||||
"executeExternal(<filename>[, <arguments> [,<usePipes>] ])");
|
||||
}
|
||||
|
||||
TRI_Utf8ValueNFC name(TRI_UNKNOWN_MEM_ZONE, argv[0]);
|
||||
|
@ -2535,9 +2536,14 @@ static v8::Handle<v8::Value> JS_ExecuteExternal (v8::Arguments const& argv) {
|
|||
}
|
||||
}
|
||||
}
|
||||
bool usePipes = false;
|
||||
if (3 <= argv.Length()) {
|
||||
usePipes = TRI_ObjectToBoolean(argv[2]);
|
||||
}
|
||||
|
||||
TRI_external_id_t external;
|
||||
TRI_CreateExternalProcess(*name, (const char**) arguments, n, &external);
|
||||
TRI_CreateExternalProcess(*name, (const char**) arguments, n,
|
||||
usePipes, &external);
|
||||
if (arguments != 0) {
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
TRI_FreeString(TRI_CORE_MEM_ZONE, arguments[i]);
|
||||
|
@ -2545,58 +2551,42 @@ static v8::Handle<v8::Value> JS_ExecuteExternal (v8::Arguments const& argv) {
|
|||
|
||||
TRI_Free(TRI_CORE_MEM_ZONE, arguments);
|
||||
}
|
||||
#ifndef _WIN32
|
||||
if (external.pid < 0) {
|
||||
if (external._pid == TRI_INVALID_PROCESS_ID) {
|
||||
TRI_V8_ERROR(scope, "Process could not be started");
|
||||
}
|
||||
v8::Handle<v8::Object> result = v8::Object::New();
|
||||
result->Set(v8::String::New("pid"), v8::Number::New(external.pid));
|
||||
if (external.readPipe >= 0) {
|
||||
result->Set(v8::String::New("pid"), v8::Number::New(external._pid));
|
||||
// Now report about possible stdin and stdout pipes:
|
||||
#ifndef _WIN32
|
||||
if (external._readPipe >= 0) {
|
||||
result->Set(v8::String::New("readPipe"),
|
||||
v8::Number::New(external.readPipe));
|
||||
v8::Number::New(external._readPipe));
|
||||
}
|
||||
if (external.writePipe >= 0) {
|
||||
if (external._writePipe >= 0) {
|
||||
result->Set(v8::String::New("writePipe"),
|
||||
v8::Number::New(external.writePipe));
|
||||
v8::Number::New(external._writePipe));
|
||||
}
|
||||
return scope.Close(result);
|
||||
#else
|
||||
size_t pid_len, readPipe_len, writePipe_len;
|
||||
char * hProcess = NULL;
|
||||
char * readPipe = NULL;
|
||||
char * writePipe = NULL;
|
||||
|
||||
if (external._hProcess) {
|
||||
hProcess = TRI_EncodeHexString((const char *)&external._hProcess, sizeof(HANDLE), &pid_len);
|
||||
} else {
|
||||
TRI_V8_ERROR(scope, "Internal Error, Process could not be started");
|
||||
}
|
||||
|
||||
|
||||
if (external._hChildStdoutRd) {
|
||||
readPipe = TRI_EncodeHexString((const char *)external._hChildStdoutRd, sizeof(HANDLE), &readPipe_len);
|
||||
}
|
||||
if (external._hChildStdinWr) {
|
||||
writePipe = TRI_EncodeHexString((const char *)external._hChildStdinWr, sizeof(HANDLE), &writePipe_len);
|
||||
}
|
||||
// return the result
|
||||
v8::Handle<v8::Object> result = v8::Object::New();
|
||||
result->Set(v8::String::New("pid"), v8::String::New(hProcess, pid_len));
|
||||
TRI_FreeString(TRI_CORE_MEM_ZONE, hProcess);
|
||||
|
||||
if (readPipe) {
|
||||
result->Set(v8::String::New("readPipe"), v8::String::New(readPipe, readPipe_len));
|
||||
size_t readPipe_len, writePipe_len;
|
||||
char* readPipe = NULL;
|
||||
char* writePipe = NULL;
|
||||
if (0 != external._readPipe) {
|
||||
readPipe = TRI_EncodeHexString((const char *)external._readPipe,
|
||||
sizeof(HANDLE), &readPipe_len);
|
||||
result->Set(v8::String::New("readPipe"),
|
||||
v8::String::New(readPipe, readPipe_len));
|
||||
TRI_FreeString(TRI_CORE_MEM_ZONE, readPipe);
|
||||
}
|
||||
|
||||
if (writePipe) {
|
||||
result->Set(v8::String::New("writePipe"), v8::String::New(writePipe, writePipe_len));
|
||||
if (0 != external._hChildStdinWr) {
|
||||
writePipe = TRI_EncodeHexString((const char *)external._writePipe,
|
||||
sizeof(HANDLE), &writePipe_len);
|
||||
result->Set(v8::String::New("writePipe"),
|
||||
v8::String::New(writePipe, writePipe_len));
|
||||
TRI_FreeString(TRI_CORE_MEM_ZONE, writePipe);
|
||||
}
|
||||
return scope.Close(result);
|
||||
#endif
|
||||
return scope.Close(result);
|
||||
}
|
||||
#ifndef _WIN32
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns the status of an external process
|
||||
|
@ -2609,7 +2599,8 @@ static v8::Handle<v8::Value> JS_StatusExternal (v8::Arguments const& argv) {
|
|||
// extract the arguments
|
||||
if (argv.Length() < 1 || argv.Length() > 2 ||
|
||||
!argv[0]->IsObject()) {
|
||||
TRI_V8_EXCEPTION_USAGE(scope, "statusExternal(<external-identifier>[, <wait>])");
|
||||
TRI_V8_EXCEPTION_USAGE(scope,
|
||||
"statusExternal(<external-identifier>[, <wait>])");
|
||||
}
|
||||
|
||||
v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(argv[0]);
|
||||
|
@ -2618,7 +2609,11 @@ static v8::Handle<v8::Value> JS_StatusExternal (v8::Arguments const& argv) {
|
|||
"statusExternal: pid must be given");
|
||||
}
|
||||
TRI_external_id_t pid;
|
||||
pid.pid = static_cast<TRI_pid_t>(TRI_ObjectToUInt64(obj->Get(pidname), true));
|
||||
#ifndef _WIN32
|
||||
pid._pid = static_cast<TRI_pid_t>(TRI_ObjectToUInt64(obj->Get(pidname),true));
|
||||
#else
|
||||
pid._pid = static_cast<DWORD>(TRI_ObjectToUInt64(obj->Get(pidname), true));
|
||||
#endif
|
||||
bool wait = false;
|
||||
if (argv.Length() == 2) {
|
||||
wait = TRI_ObjectToBoolean(argv[1]);
|
||||
|
@ -2637,7 +2632,6 @@ static v8::Handle<v8::Value> JS_StatusExternal (v8::Arguments const& argv) {
|
|||
case TRI_EXT_TERMINATED: status = "TERMINATED"; break;
|
||||
case TRI_EXT_ABORTED: status = "ABORTED"; break;
|
||||
case TRI_EXT_STOPPED: status = "STOPPED"; break;
|
||||
case TRI_EXT_KILL_FAILED: status = "ZOMBIE"; break;
|
||||
}
|
||||
|
||||
result->Set(v8::String::New("status"), v8::String::New(status));
|
||||
|
@ -2669,108 +2663,16 @@ static v8::Handle<v8::Value> JS_KillExternal (v8::Arguments const& argv) {
|
|||
"statusExternal: pid must be given");
|
||||
}
|
||||
TRI_external_id_t pid;
|
||||
pid.pid = static_cast<TRI_pid_t>(TRI_ObjectToUInt64(obj->Get(pidname), true));
|
||||
|
||||
TRI_KillExternalProcess(pid);
|
||||
|
||||
// return the result
|
||||
return scope.Close(v8::Undefined());
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
pid._pid = static_cast<TRI_pid_t>(TRI_ObjectToUInt64(obj->Get(pidname),true));
|
||||
#else
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief kills an external process
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static v8::Handle<v8::Value> JS_KillExternal (v8::Arguments const& argv) {
|
||||
v8::HandleScope scope;
|
||||
|
||||
// extract the arguments
|
||||
if (argv.Length() != 1 || ! argv[0]->IsObject()) {
|
||||
TRI_V8_EXCEPTION_USAGE(scope, "killExternal(<external-identifier>)");
|
||||
}
|
||||
v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(argv[0]);
|
||||
string pid; //, hChildStdoutRd, hChildStdinWr;
|
||||
if(obj->Has(v8::String::New("pid"))) {
|
||||
pid = TRI_ObjectToString(obj->Get(v8::String::New("pid")));
|
||||
}
|
||||
if (pid.empty()) {
|
||||
TRI_V8_EXCEPTION(scope, TRI_ERROR_BAD_PARAMETER);
|
||||
}
|
||||
size_t pid_len /*, readPipe_len, writePipe_len*/;
|
||||
char * thePid = TRI_DecodeHexString(pid.c_str(), pid.size(), &pid_len);
|
||||
/*
|
||||
char * readPipe = TRI_DecodeHexString(hChildStdoutRd.c_str(), hChildStdoutRd.c_str.size(), &readPipe_len);
|
||||
char * writePipe = TRI_DecodeHexString(hChildStdinWr.c_str(), hChildStdinWr.c_str.size(), &writePipe_len);
|
||||
*/
|
||||
TRI_external_id_t external;
|
||||
external._hProcess = (HANDLE)(*((intptr_t* )thePid));
|
||||
external._hChildStdoutRd = NULL;
|
||||
external._hChildStdinWr = NULL;
|
||||
/*
|
||||
external._hChildStdoutRd = (HANDLE)(*readPipe);
|
||||
external._hChildStdinWr = (HANDLE)(*writePipe);
|
||||
*/
|
||||
TRI_KillExternalProcess(&external);
|
||||
|
||||
TRI_FreeString(TRI_CORE_MEM_ZONE, thePid);
|
||||
/*
|
||||
TRI_FreeString(TRI_CORE_MEM_ZONE, readPipe);
|
||||
TRI_FreeString(TRI_CORE_MEM_ZONE, writePipe);
|
||||
*/
|
||||
// return the result
|
||||
return scope.Close(v8::Undefined());
|
||||
}
|
||||
|
||||
static v8::Handle<v8::Value> JS_StatusExternal (v8::Arguments const& argv) {
|
||||
v8::HandleScope scope;
|
||||
v8::Handle<v8::String> pidname = v8::String::New("pid");
|
||||
|
||||
// extract the arguments
|
||||
if (argv.Length() < 1 || argv.Length() > 2 || !argv[0]->IsObject()) {
|
||||
TRI_V8_EXCEPTION_USAGE(scope, "statusExternal(<external-identifier>[, <wait>])");
|
||||
}
|
||||
v8::Handle<v8::Object> obj = v8::Handle<v8::Object>::Cast(argv[0]);
|
||||
if (!obj->Has(pidname)) {
|
||||
TRI_V8_EXCEPTION_MESSAGE(scope, TRI_ERROR_BAD_PARAMETER,
|
||||
"statusExternal: pid must be given");
|
||||
}
|
||||
bool wait = false;
|
||||
if (argv.Length() == 2) {
|
||||
wait = TRI_ObjectToBoolean(argv[1]);
|
||||
}
|
||||
string hProcessStr = TRI_ObjectToString(obj->Get(pidname));
|
||||
size_t pid_len;
|
||||
char * hProcessCharPtr = TRI_DecodeHexString(hProcessStr.c_str(), hProcessStr.size(), &pid_len);
|
||||
HANDLE hProcess = (HANDLE)(*((intptr_t* )hProcessCharPtr));
|
||||
TRI_external_status_t external = TRI_CheckExternalProcess(hProcess, wait);
|
||||
|
||||
v8::Handle<v8::Object> result = v8::Object::New();
|
||||
const char* status = "UNKNOWN";
|
||||
|
||||
switch (external._status) {
|
||||
case TRI_EXT_NOT_STARTED: status = "NOT-STARTED"; break;
|
||||
case TRI_EXT_PIPE_FAILED: status = "FAILED"; break;
|
||||
case TRI_EXT_FORK_FAILED: status = "FAILED"; break;
|
||||
case TRI_EXT_RUNNING: status = "RUNNING"; break;
|
||||
case TRI_EXT_NOT_FOUND: status = "NOT-FOUND"; break;
|
||||
case TRI_EXT_TERMINATED: status = "TERMINATED"; break;
|
||||
case TRI_EXT_ABORTED: status = "ABORTED"; break;
|
||||
case TRI_EXT_STOPPED: status = "STOPPED"; break;
|
||||
case TRI_EXT_KILL_FAILED: status = "ZOMBIE"; break;
|
||||
}
|
||||
|
||||
result->Set(v8::String::New("status"), v8::String::New(status));
|
||||
|
||||
if (external._status == TRI_EXT_TERMINATED) {
|
||||
result->Set(v8::String::New("exit"), v8::Number::New(external._exitStatus));
|
||||
}
|
||||
|
||||
// return the result
|
||||
return scope.Close(result);
|
||||
}
|
||||
pid._pid = static_cast<DWORD>(TRI_ObjectToUInt64(obj->Get(pidname), true));
|
||||
#endif
|
||||
|
||||
// return the result
|
||||
return scope.Close(v8::Boolean::New(TRI_KillExternalProcess(pid)));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief checks if a port is available
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
Loading…
Reference in New Issue