1
0
Fork 0

Merge branch 'devel' of https://github.com/triAGENS/ArangoDB into devel

This commit is contained in:
scottashton 2014-03-03 18:18:27 +01:00
commit 90e18f40d2
11 changed files with 396 additions and 326 deletions

View File

@ -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.

View File

@ -20,6 +20,7 @@ WIKI = \
CommandLine \
Communication \
Compiling \
CookbookCluster \
DbaManual \
DbaManualAuthentication \
DbaManualBasics \

View File

@ -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}
=============================================

View File

@ -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 \

View File

@ -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>

View File

@ -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();
}
});
}());

View File

@ -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() {

View File

@ -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() {

View File

@ -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
// -----------------------------------------------------------------------------

View File

@ -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
// -----------------------------------------------------------------------------

View File

@ -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
////////////////////////////////////////////////////////////////////////////////