1
0
Fork 0

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

This commit is contained in:
Jan Steemann 2014-05-09 00:42:32 +02:00
commit 20f1940458
9 changed files with 419 additions and 29 deletions

View File

@ -195,10 +195,6 @@ Handler::status_t RestReplicationHandler::execute() {
goto BAD_CALL;
}
if (isCoordinatorError()) {
return status_t(Handler::HANDLER_DONE);
}
handleCommandRestoreCollection();
}
else if (command == "restore-indexes") {
@ -206,10 +202,6 @@ Handler::status_t RestReplicationHandler::execute() {
goto BAD_CALL;
}
if (isCoordinatorError()) {
return status_t(Handler::HANDLER_DONE);
}
handleCommandRestoreIndexes();
}
else if (command == "restore-data") {
@ -219,7 +211,7 @@ Handler::status_t RestReplicationHandler::execute() {
#ifdef TRI_ENABLE_CLUSTER
if (ServerState::instance()->isCoordinator()) {
handleTrampolineCoordinator();
handleCommandRestoreDataCoordinator();
}
else {
handleCommandRestoreData();
@ -1941,7 +1933,20 @@ void RestReplicationHandler::handleCommandRestoreCollection () {
TRI_server_id_t remoteServerId = 0; // TODO
string errorMsg;
int res = processRestoreCollection(json, overwrite, recycleIds, force, remoteServerId, errorMsg);
#ifdef TRI_ENABLE_CLUSTER
int res;
if (ServerState::instance()->isCoordinator()) {
res = processRestoreCollectionCoordinator(json, overwrite, recycleIds,
force, remoteServerId, errorMsg);
}
else {
res = processRestoreCollection(json, overwrite, recycleIds, force,
remoteServerId, errorMsg);
}
#else
int res = processRestoreCollection(json, overwrite, recycleIds, force,
remoteServerId, errorMsg);
#endif
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
@ -1982,7 +1987,17 @@ void RestReplicationHandler::handleCommandRestoreIndexes () {
TRI_server_id_t remoteServerId = 0; // TODO
string errorMsg;
#ifdef TRI_ENABLE_CLUSTER
int res;
if (ServerState::instance()->isCoordinator()) {
res = processRestoreIndexesCoordinator(json, force, remoteServerId, errorMsg);
}
else {
res = processRestoreIndexes(json, force, remoteServerId, errorMsg);
}
#else
int res = processRestoreIndexes(json, force, remoteServerId, errorMsg);
#endif
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
@ -2124,6 +2139,135 @@ int RestReplicationHandler::processRestoreCollection (TRI_json_t const* collecti
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief restores the structure of a collection, coordinator case
////////////////////////////////////////////////////////////////////////////////
#ifdef TRI_ENABLE_CLUSTER
int RestReplicationHandler::processRestoreCollectionCoordinator (
TRI_json_t const* collection,
bool dropExisting,
bool reuseId,
bool force,
TRI_server_id_t remoteServerId,
string& errorMsg) {
if (! JsonHelper::isArray(collection)) {
errorMsg = "collection declaration is invalid";
return TRI_ERROR_HTTP_BAD_PARAMETER;
}
TRI_json_t const* parameters = JsonHelper::getArrayElement(collection, "parameters");
if (! JsonHelper::isArray(parameters)) {
errorMsg = "collection parameters declaration is invalid";
return TRI_ERROR_HTTP_BAD_PARAMETER;
}
TRI_json_t const* indexes = JsonHelper::getArrayElement(collection, "indexes");
if (! JsonHelper::isList(indexes)) {
errorMsg = "collection indexes declaration is invalid";
return TRI_ERROR_HTTP_BAD_PARAMETER;
}
const string name = JsonHelper::getStringValue(parameters, "name", "");
if (name.empty()) {
errorMsg = "collection name is missing";
return TRI_ERROR_HTTP_BAD_PARAMETER;
}
if (JsonHelper::getBooleanValue(parameters, "deleted", false)) {
// we don't care about deleted collections
return TRI_ERROR_NO_ERROR;
}
TRI_vocbase_col_t* col = 0;
if (reuseId) {
TRI_json_t const* idString = JsonHelper::getArrayElement(parameters, "cid");
if (! JsonHelper::isString(idString)) {
errorMsg = "collection id is missing";
return TRI_ERROR_HTTP_BAD_PARAMETER;
}
TRI_voc_cid_t cid = StringUtils::uint64(idString->_value._string.data, idString->_value._string.length - 1);
// first look up the collection by the cid
col = TRI_LookupCollectionByIdVocBase(_vocbase, cid);
}
if (col == 0) {
// not found, try name next
col = TRI_LookupCollectionByNameVocBase(_vocbase, name.c_str());
}
// drop an existing collection if it exists
if (col != 0) {
if (dropExisting) {
int res = TRI_DropCollectionVocBase(_vocbase, col, remoteServerId);
if (res == TRI_ERROR_FORBIDDEN) {
// some collections must not be dropped
// instead, truncate them
CollectionNameResolver resolver(_vocbase);
SingleCollectionWriteTransaction<EmbeddableTransaction<RestTransactionContext>, UINT64_MAX> trx(_vocbase, resolver, col->_cid);
res = trx.begin();
if (res != TRI_ERROR_NO_ERROR) {
return res;
}
TRI_barrier_t* barrier = TRI_CreateBarrierElement(&(trx.primaryCollection()->_barrierList));
if (barrier == 0) {
return TRI_ERROR_INTERNAL;
}
res = trx.truncate(false);
res = trx.finish(res);
TRI_FreeBarrier(barrier);
return res;
}
if (res != TRI_ERROR_NO_ERROR) {
errorMsg = "unable to drop collection '" + name + "': " + string(TRI_errno_string(res));
return res;
}
}
else {
int res = TRI_ERROR_ARANGO_DUPLICATE_NAME;
errorMsg = "unable to create collection '" + name + "': " + string(TRI_errno_string(res));
return res;
}
}
// now re-create the collection
int res = createCollection(parameters, &col, reuseId, remoteServerId);
if (res != TRI_ERROR_NO_ERROR) {
errorMsg = "unable to create collection: " + string(TRI_errno_string(res));
return res;
}
return TRI_ERROR_NO_ERROR;
}
#endif
////////////////////////////////////////////////////////////////////////////////
/// @brief restores the indexes of a collection TODO MOVE
////////////////////////////////////////////////////////////////////////////////
@ -2226,6 +2370,112 @@ int RestReplicationHandler::processRestoreIndexes (TRI_json_t const* collection,
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief restores the indexes of a collection, coordinator case
////////////////////////////////////////////////////////////////////////////////
#ifdef TRI_ENABLE_CLUSTER
int RestReplicationHandler::processRestoreIndexesCoordinator (
TRI_json_t const* collection,
bool force,
TRI_server_id_t remoteServerId,
string& errorMsg) {
if (! JsonHelper::isArray(collection)) {
errorMsg = "collection declaration is invalid";
return TRI_ERROR_HTTP_BAD_PARAMETER;
}
TRI_json_t const* parameters = JsonHelper::getArrayElement(collection, "parameters");
if (! JsonHelper::isArray(parameters)) {
errorMsg = "collection parameters declaration is invalid";
return TRI_ERROR_HTTP_BAD_PARAMETER;
}
TRI_json_t const* indexes = JsonHelper::getArrayElement(collection, "indexes");
if (! JsonHelper::isList(indexes)) {
errorMsg = "collection indexes declaration is invalid";
return TRI_ERROR_HTTP_BAD_PARAMETER;
}
const size_t n = indexes->_value._objects._length;
if (n == 0) {
// nothing to do
return TRI_ERROR_NO_ERROR;
}
const string name = JsonHelper::getStringValue(parameters, "name", "");
if (name.empty()) {
errorMsg = "collection name is missing";
return TRI_ERROR_HTTP_BAD_PARAMETER;
}
if (JsonHelper::getBooleanValue(parameters, "deleted", false)) {
// we don't care about deleted collections
return TRI_ERROR_NO_ERROR;
}
// look up the collection
TRI_vocbase_col_t* col = TRI_LookupCollectionByNameVocBase(_vocbase, name.c_str());
if (col == 0) {
errorMsg = "could not find collection '" + name + "'";
return TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND;
}
int res = TRI_UseCollectionVocBase(_vocbase, col);
if (res != TRI_ERROR_NO_ERROR) {
return res;
}
TRI_primary_collection_t* primary = col->_collection;
TRI_ReadLockReadWriteLock(&_vocbase->_inventoryLock);
TRI_WRITE_LOCK_DOCUMENTS_INDEXES_PRIMARY_COLLECTION(primary);
for (size_t i = 0; i < n; ++i) {
TRI_json_t const* idxDef = (TRI_json_t const*) TRI_AtVector(&indexes->_value._objects, i);
TRI_index_t* idx = 0;
// {"id":"229907440927234","type":"hash","unique":false,"fields":["x","Y"]}
res = TRI_FromJsonIndexDocumentCollection((TRI_document_collection_t*) primary, idxDef, &idx);
if (res != TRI_ERROR_NO_ERROR) {
errorMsg = "could not create index: " + string(TRI_errno_string(res));
break;
}
else {
assert(idx != 0);
res = TRI_SaveIndex(primary, idx, remoteServerId);
if (res != TRI_ERROR_NO_ERROR) {
errorMsg = "could not save index: " + string(TRI_errno_string(res));
break;
}
}
}
TRI_WRITE_UNLOCK_DOCUMENTS_INDEXES_PRIMARY_COLLECTION(primary);
TRI_ReadUnlockReadWriteLock(&_vocbase->_inventoryLock);
TRI_ReleaseCollectionVocBase(_vocbase, col);
return TRI_ERROR_NO_ERROR;
}
#endif
////////////////////////////////////////////////////////////////////////////////
/// @brief apply the data from a collection dump or the continuous log
////////////////////////////////////////////////////////////////////////////////
@ -2569,6 +2819,63 @@ void RestReplicationHandler::handleCommandRestoreData () {
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief restores the data of a collection, coordinator case
////////////////////////////////////////////////////////////////////////////////
#ifdef TRI_ENABLE_CLUSTER
void RestReplicationHandler::handleCommandRestoreDataCoordinator () {
char const* value = _request->value("collection");
if (value == 0) {
generateError(HttpResponse::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER,
"invalid collection parameter");
return;
}
CollectionNameResolver resolver(_vocbase);
TRI_voc_cid_t cid = resolver.getCollectionId(value);
if (cid == 0) {
generateError(HttpResponse::BAD,
TRI_ERROR_HTTP_BAD_PARAMETER,
"invalid collection parameter");
return;
}
bool recycleIds = false;
value = _request->value("recycleIds");
if (value != 0) {
recycleIds = StringUtils::boolean(value);
}
bool force = false;
value = _request->value("force");
if (value != 0) {
force = StringUtils::boolean(value);
}
TRI_server_id_t remoteServerId = 0; // TODO
string errorMsg;
int res = processRestoreData(resolver, cid, remoteServerId, recycleIds, force, errorMsg);
if (res != TRI_ERROR_NO_ERROR) {
generateError(HttpResponse::SERVER_ERROR, res);
}
else {
TRI_json_t result;
TRI_InitArrayJson(TRI_CORE_MEM_ZONE, &result);
TRI_Insert3ArrayJson(TRI_CORE_MEM_ZONE, &result, "result", TRI_CreateBooleanJson(TRI_CORE_MEM_ZONE, true));
generateResult(&result);
}
}
#endif
////////////////////////////////////////////////////////////////////////////////
/// @brief dumps the data of a collection
///

View File

@ -234,6 +234,19 @@ namespace triagens {
TRI_server_id_t,
std::string&);
////////////////////////////////////////////////////////////////////////////////
/// @brief restores the structure of a collection, coordinator case
////////////////////////////////////////////////////////////////////////////////
#ifdef TRI_ENABLE_CLUSTER
int processRestoreCollectionCoordinator (struct TRI_json_s const*,
bool,
bool,
bool,
TRI_server_id_t,
std::string&);
#endif
////////////////////////////////////////////////////////////////////////////////
/// @brief restores the indexes of a collection TODO MOVE
////////////////////////////////////////////////////////////////////////////////
@ -243,6 +256,17 @@ namespace triagens {
TRI_server_id_t,
std::string&);
////////////////////////////////////////////////////////////////////////////////
/// @brief restores the indexes of a collection, coordinator case
////////////////////////////////////////////////////////////////////////////////
#ifdef TRI_ENABLE_CLUSTER
int processRestoreIndexesCoordinator (struct TRI_json_s const*,
bool,
TRI_server_id_t,
std::string&);
#endif
////////////////////////////////////////////////////////////////////////////////
/// @brief apply a single marker from the collection dump
////////////////////////////////////////////////////////////////////////////////
@ -283,6 +307,14 @@ namespace triagens {
void handleCommandRestoreData ();
////////////////////////////////////////////////////////////////////////////////
/// @brief handle a restore command for a specific collection, coordinator case
////////////////////////////////////////////////////////////////////////////////
#ifdef TRI_ENABLE_CLUSTER
void handleCommandRestoreDataCoordinator ();
#endif
////////////////////////////////////////////////////////////////////////////////
/// @brief handle a dump command for a specific collection
////////////////////////////////////////////////////////////////////////////////

View File

@ -377,7 +377,7 @@ static string GetArangoVersion () {
}
////////////////////////////////////////////////////////////////////////////////
/// @brief fetch the version from the server
/// @brief check if server is a coordinator of a cluster
////////////////////////////////////////////////////////////////////////////////
static bool GetArangoIsCluster () {

View File

@ -142,6 +142,12 @@ static bool RecycleIds = false;
static bool Force = false;
////////////////////////////////////////////////////////////////////////////////
/// @brief cluster mode flag
////////////////////////////////////////////////////////////////////////////////
static bool clusterMode = false;
////////////////////////////////////////////////////////////////////////////////
/// @brief statistics
////////////////////////////////////////////////////////////////////////////////
@ -364,6 +370,47 @@ static string GetArangoVersion () {
return version;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief check if server is a coordinator of a cluster
////////////////////////////////////////////////////////////////////////////////
static bool GetArangoIsCluster () {
map<string, string> headers;
string command = "return ArangoServerState.role();";
SimpleHttpResult* response = Client->request(HttpRequest::HTTP_REQUEST_POST,
"/_admin/execute?returnAsJSON=true",
command.c_str(),
command.size(),
headers);
if (response == 0 || ! response->isComplete()) {
if (response != 0) {
delete response;
}
return false;
}
string role = "UNDEFINED";
if (response->getHttpReturnCode() == HttpResponse::OK) {
// default value
role.assign(response->getBody().c_str(), response->getBody().length());
}
else {
if (response->wasHttpError()) {
Client->setErrorMessage(GetHttpErrorMessage(response), false);
}
Connection->disconnect();
}
delete response;
return role == "\"COORDINATOR\"";
}
////////////////////////////////////////////////////////////////////////////////
/// @brief send the request to re-create a collection
////////////////////////////////////////////////////////////////////////////////
@ -450,8 +497,7 @@ static int SendRestoreIndexes (TRI_json_t const* json,
/// @brief send the request to load data into a collection
////////////////////////////////////////////////////////////////////////////////
static int SendRestoreData (string const& cid,
string const& cname,
static int SendRestoreData (string const& cname,
char const* buffer,
size_t bufferSize,
string& errorMsg) {
@ -743,7 +789,7 @@ static int ProcessInputDirectory (string& errorMsg) {
Stats._totalBatches++;
int res = SendRestoreData(cid, cname, buffer.begin(), length, errorMsg);
int res = SendRestoreData(cname, buffer.begin(), length, errorMsg);
if (res != TRI_ERROR_NO_ERROR) {
TRI_CLOSE(fd);
@ -933,6 +979,10 @@ int main (int argc, char* argv[]) {
}
}
if (major >= 2) {
// Version 1.4 did not yet have a cluster mode
clusterMode = GetArangoIsCluster();
}
if (Progress) {
cout << "Connected to ArangoDB '" << BaseClient.endpointServer()->getSpecification() << endl;

View File

@ -245,6 +245,7 @@ var modalDialogHelper = modalDialogHelper || {};
i,
id = idPre + idPost,
lastId = 1,
buttonTh = document.createElement("th"),
addLineButton = document.createElement("button"),
input = document.createElement("input"),
addNewLine = function(content) {
@ -252,6 +253,7 @@ var modalDialogHelper = modalDialogHelper || {};
var innerTr = document.createElement("tr"),
innerLabelTh = document.createElement("th"),
innerContentTh = document.createElement("th"),
innerButtonTh = document.createElement("th"),
innerInput = document.createElement("input"),
removeRow = document.createElement("button"),
lastItem;
@ -276,14 +278,15 @@ var modalDialogHelper = modalDialogHelper || {};
table.removeChild(innerTr);
rows.splice(rows.indexOf(innerTr), 1 );
};
innerContentTh.appendChild(removeRow);
innerButtonTh.appendChild(removeRow);
innerTr.appendChild(innerButtonTh);
rows.push(innerTr);
};
input.type = "text";
input.id = id + "_1";
contentTh.appendChild(input);
contentTh.appendChild(addLineButton);
buttonTh.appendChild(addLineButton);
tr.appendChild(buttonTh);
addLineButton.onclick = function() {
addNewLine();
};
@ -309,7 +312,7 @@ var modalDialogHelper = modalDialogHelper || {};
// Set Classnames and attributes.
div.id = idprefix + "modal";
div.className = "modal hide fade";
div.className = "modal hide fade createModalDialog";
div.setAttribute("tabindex", "-1");
div.setAttribute("role", "dialog");
div.setAttribute("aria-labelledby", "myModalLabel");

View File

@ -5,7 +5,6 @@
text-align: left;
width: 20% !important;
input,
select,
textarea {
margin-top: 10px;

View File

@ -42,6 +42,7 @@
margin-bottom: 10px;
margin-top: 10px;
}
}
.icon-info-sign {

View File

@ -3424,8 +3424,8 @@ pre.gv-object-view {
margin-left: 0; }
.dashboard-interior-chart {
height: 222px;
background-color: white; }
background-color: white;
height: 222px; }
.dashboard-large-chart {
height: 250px;
@ -4276,7 +4276,6 @@ input.gv-radio-button {
font-weight: 400 !important;
text-align: left;
width: 20% !important; }
.collectionTh input,
.collectionTh select,
.collectionTh textarea {
margin-top: 10px; }

View File

@ -37,7 +37,6 @@
"frontend/js/templates/editListEntryView.ejs",
"frontend/js/templates/footerView.ejs",
"frontend/js/templates/foxxActiveView.ejs",
"frontend/js/templates/foxxEditView.ejs",
"frontend/js/templates/foxxInstalledView.ejs",
"frontend/js/templates/graphManagementView.ejs",
"frontend/js/templates/graphView.ejs",
@ -260,12 +259,6 @@
"cluster.js": {
"files": [
"clusterFrontend/js/collections/arangoClusterStatisticsCollection.js",
"clusterFrontend/js/collections/clusterCollections.js",
"clusterFrontend/js/collections/clusterCoordinators.js",
"clusterFrontend/js/collections/clusterDatabases.js",
"clusterFrontend/js/collections/clusterServers.js",
"clusterFrontend/js/collections/clusterShards.js",
"clusterFrontend/js/models/clusterCollection.js",
"clusterFrontend/js/models/clusterCoordinator.js",
"clusterFrontend/js/models/clusterDatabase.js",
@ -273,6 +266,12 @@
"clusterFrontend/js/models/clusterServer.js",
"clusterFrontend/js/models/clusterShard.js",
"clusterFrontend/js/models/clusterType.js",
"clusterFrontend/js/collections/arangoClusterStatisticsCollection.js",
"clusterFrontend/js/collections/clusterCollections.js",
"clusterFrontend/js/collections/clusterCoordinators.js",
"clusterFrontend/js/collections/clusterDatabases.js",
"clusterFrontend/js/collections/clusterServers.js",
"clusterFrontend/js/collections/clusterShards.js",
"frontend/js/models/arangoDocument.js",
"frontend/js/models/arangoStatistics.js",
"frontend/js/models/arangoStatisticsDescription.js",