1
0
Fork 0

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

This commit is contained in:
Jan Steemann 2014-02-28 20:00:57 +01:00
commit c08c7c4dfd
11 changed files with 241 additions and 95 deletions

View File

@ -1,5 +1,5 @@
/*jslint indent: 2, nomen: true, maxlen: 100, sloppy: true, vars: true, white: true, plusplus: true, evil: true */
/*global require, exports, module, SYS_CLUSTER_TEST, SYS_TEST_PORT, ArangoServerState */
/*jslint indent: 2, nomen: true, maxlen: 140, sloppy: true, vars: true, white: true, plusplus: true, evil: true */
/*global require, exports, module, SYS_CLUSTER_TEST, SYS_TEST_PORT, ArangoServerState, ArangoClusterComm, ArangoClusterInfo */
////////////////////////////////////////////////////////////////////////////////
/// @brief cluster actions
@ -588,6 +588,79 @@ actions.defineHttp({
}
});
////////////////////////////////////////////////////////////////////////////////
/// @fn JSF_cluster_statistics_GET
/// @brief allows to query the statistics of a DBserver in the cluster
///
/// @RESTHEADER{GET /_admin/clusterStatistics,queries statistics of a DBserver}
///
/// @RESTQUERYPARAMETERS
///
/// @RESTQUERYPARAM{DBserver,string,required}
///
/// @RESTDESCRIPTION Queries the statistics of the given DBserver
///
/// @RESTRETURNCODES
///
/// @RESTRETURNCODE{200} is returned when everything went well.
///
/// @RESTRETURNCODE{400} the parameter DBserver was not given or is not the
/// ID of a DBserver
///
/// @RESTRETURNCODE{403} server is not a coordinator.
////////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url : "_admin/clusterStatistics",
context : "admin",
prefix : "false",
callback : function (req, res) {
if (req.requestType !== actions.GET) {
actions.resultError(req, res, actions.HTTP_FORBIDDEN, 0,
"only GET requests are allowed");
return;
}
if (!require("org/arangodb/cluster").isCoordinator()) {
actions.resultError(req, res, actions.HTTP_FORBIDDEN, 0,
"only allowed on coordinator");
return;
}
if (!req.parameters.hasOwnProperty("DBserver")) {
actions.resultError(req, res, actions.HTTP_BAD,
"required parameter DBserver was not given");
return;
}
var DBserver = req.parameters.DBserver;
var coord = { coordTransactionID: ArangoClusterInfo.uniqid() };
var options = { coordTransactionID: coord.coordTransactionID, timeout:10 };
var op = ArangoClusterComm.asyncRequest("GET","server:"+DBserver,"_system",
"/_admin/statistics","",{},options);
var r = ArangoClusterComm.wait(op);
res.contentType = "application/json; charset=utf-8";
if (r.status === "RECEIVED") {
res.responseCode = actions.HTTP_OK;
res.body = r.body;
}
else if (r.status === "TIMEOUT") {
res.responseCode = actions.HTTP_BAD;
res.body = JSON.stringify( {"error":true,
"errorMessage": "operation timed out"});
}
else {
res.responseCode = actions.HTTP_BAD;
var bodyobj;
try {
bodyobj = JSON.parse(r.body);
}
catch (err) {
}
res.body = JSON.stringify( {"error":true,
"errorMessage": "error from DBserver, possibly DBserver unknown",
"body": bodyobj} );
}
}
});
////////////////////////////////////////////////////////////////////////////////

View File

@ -130,7 +130,7 @@
async:false
});
}
if (this.statistics === undefined) {
if (this.statisticsCollection === undefined) {
this.statisticsCollection = new window.StatisticsCollection();
}
if (this.dashboardView === undefined) {

View File

@ -2,9 +2,9 @@
<div class="control-group dispatcher">
<label class="control-label">Server:</label>
<div class="controls">
<input type="text" placeholder="Server" class="input-xlarge host"></input>
<input type="text" placeholder="Server" class="input-xlarge host" value="<%=host?host:''%>"></input>
<span class="searchEqualsLabel">:</span>
<input type="text" maxlength="5" class="input-small port" placeholder="port"></input>
<input type="text" maxlength="5" class="input-small port" placeholder="port" value="<%=port?port:''%>"></input>
<% if (isFirst) {%>
<button class="graphViewer-icon-button gv-icon-small add"></button>
<% } else { %>
@ -14,10 +14,10 @@
<% if (!isSymmetric) { %>
<div class="controls">
<label class="checkbox inline">
<input type="checkbox" value="isCoordinator" class="isCoordinator" checked="checked"> Coordinator
<input type="checkbox" value="isCoordinator" class="isCoordinator" <%=isCoordinator?'checked="checked"':''%>> Coordinator
</label>
<label class="checkbox inline">
<input type="checkbox" value="isDBServer" class="isDBServer" checked="checked"> DBServer
<input type="checkbox" value="isDBServer" class="isDBServer" <%=isDBServer?'checked="checked"':''%>> DBServer
</label>
</div>
<% } %>

View File

@ -90,10 +90,10 @@
<div class="headerBar">
<a class="arangoHeader">Cluster Statistics</a>
</div>
<div id="clusterGraphs">
</div>
<div id="lineGraph">
<div class="resizecontainer">
<div id="clusterGraphs" class="dashboardChart">
<div>Virtual Memory Size</div>
</div>
<div id="lineGraph" class="dashboardChart"></div>
</div>
</script>

View File

@ -77,7 +77,11 @@
addEntry: function() {
$("#server_list").append(this.entryTemplate.render({
isSymmetric: this.isSymmetric,
isFirst: false
isFirst: false,
isCoordinator: true,
isDBServer: true,
host: '',
port: ''
}));
},
@ -88,12 +92,53 @@
render: function(isSymmetric) {
this.isSymmetric = isSymmetric;
$(this.el).html(this.template.render({
isSymmetric : isSymmetric
}));
$("#server_list").append(this.entryTemplate.render({
isSymmetric: isSymmetric,
isFirst: true
isSymmetric : isSymmetric,
params : params
}));
var params = {},
isFirst = true,
config = this.model.get("config");
if (config) {
var self = this,
isCoordinator = false,
isDBServer = false;
_.each(config.dispatchers, function(dispatcher, key) {
if (dispatcher.allowDBservers === undefined) {
isDBServer = true;
} else {
isDBServer = dispatcher.allowDBservers;
}
if (dispatcher.allowCoordinators === undefined) {
isCoordinator = true;
} else {
isCoordinator = dispatcher.allowCoordinators;
}
var host = dispatcher.endpoint,
ip,
port;
host = host.split("//")[1];
host = host.split(":");
var template = self.entryTemplate.render({
isSymmetric: isSymmetric,
isFirst: isFirst,
host: host[0],
port: host[1],
isCoordinator: isCoordinator,
isDBServer: isDBServer
});
$("#server_list").append(template);
isFirst = false;
});
} else {
$("#server_list").append(this.entryTemplate.render({
isSymmetric: isSymmetric,
isFirst: true,
isCoordinator: true,
isDBServer: true,
host: '',
port: ''
}));
}
$(this.el).append(this.modal.render({}));
}

View File

@ -53,6 +53,7 @@
this.coordinators = new window.ClusterCoordinators([], {
interval: this.interval
});
this.documentStore = new window.arangoDocuments();
this.statisticsDescription = new window.StatisticsDescription();
this.statisticsDescription.fetch({
async: false
@ -105,13 +106,14 @@
this.updateServerStatus();
this.getServerStatistics();
this.updateServerTime();
var data = this.generatePieData();
this.renderPieChart(data);
this.transformForLineChart(data);
this.data = this.generatePieData();
this.renderPieChart(this.data);
this.transformForLineChart();
this.renderLineChart();
},
render: function() {
this.startUpdating();
var byAddress = this.listByAddress();
if (Object.keys(byAddress).length === 1) {
this.type = "testPlan";
@ -124,10 +126,11 @@
type: this.type
}));
$(this.el).append(this.modal.render({}));
this.loadHistory();
this.getServerStatistics();
var data = this.generatePieData();
this.renderPieChart(data);
this.transformForLineChart(data);
this.data = this.generatePieData();
this.renderPieChart(this.data);
this.transformForLineChart();
this.renderLineChart();
this.updateCollections();
},
@ -136,15 +139,16 @@
var pieData = [];
var self = this;
this.data.forEach(function(m) {
pieData.push({key: m.get("name"), value :m.get("client").totalTime.sum / m.get("http").requestsTotal,
time: self.serverTime});
pieData.push({key: m.get("name"), value :m.get("system").virtualSize,
time: self.serverTime});
});
return pieData;
},
transformForLineChart: function(data) {
transformForLineChart: function() {
var c = 0;
var self = this;
var data = this.hist;
data.forEach(function(entry) {
c++;
if (!self.totalTimeChart[entry.time]) {
@ -157,8 +161,6 @@
self.totalTimeChart[entry.time]["ClusterAverage"] =
self.totalTimeChart[entry.time]["ClusterAverage"] + entry.value;
})
self.totalTimeChart[self.serverTime]["ClusterAverage"] =
self.totalTimeChart[self.serverTime]["ClusterAverage"] /c;
self.knownServers.forEach(function (server) {
Object.keys(self.totalTimeChart).sort().forEach(function(entry) {
if (!self.totalTimeChart[entry][server]) {
@ -168,8 +170,40 @@
})
},
loadHistory : function() {
this.hist = [];
var self = this;
this.dbservers.forEach(function (dbserver) {
if (dbserver.get("status") !== "ok") {return;}
if (self.knownServers.indexOf(dbserver.id) === -1) {self.knownServers.push(dbserver.id);}
self.documentStore.getStatisticsHistory({server: dbserver.get("address"), figures : ["client.totalTime"]});
self.history = self.documentStore.history;
self.history.forEach(function(e) {
var h = {};
h.key = dbserver.id;
h.value = e.client.totalTime.sum / e.client.totalTime.count;
h.time = e.time * 1000
self.hist.push(h);
});
});
this.coordinators.forEach(function (coordinator) {
if (coordinator.get("status") !== "ok") {return;}
if (self.knownServers.indexOf(coordinator.id) === -1) {self.knownServers.push(coordinator.id);}
self.documentStore.getStatisticsHistory({server: coordinator.get("address"), figures : ["client.totalTime"]});
self.history = self.documentStore.history;
self.history.forEach(function(e) {
var h = {};
h.key = coordinator.id;
h.value = e.client.totalTime.sum / e.client.totalTime.count;
h.time = e.time * 1000
self.hist.push(h);
});
});
},
getServerStatistics: function() {
var self = this;
this.data = undefined;
var statCollect = new window.ClusterStatisticsCollection();
this.dbservers.forEach(function (dbserver) {
if (dbserver.get("status") !== "ok") {return;}
@ -186,19 +220,22 @@
statCollect.add(stat);
});
statCollect.fetch();
statCollect.forEach(function(m) {
self.hist.push({key: m.get("name"), value :m.get("client").totalTime.sum / m.get("client").totalTime.count,
time: self.serverTime});
});
this.data = statCollect;
},
renderPieChart: function(dataset) {
var w = 620;
var h = 480;
var w = 500;
var h = 250;
var radius = Math.min(w, h) / 2; //change 2 to 1.4. It's hilarious.
var color = d3.scale.category20();
var arc = d3.svg.arc() //each datapoint will create one later.
.outerRadius(radius - 20)
.innerRadius(0);
var pie = d3.layout.pie()
.sort(function (d) {
return d.value;
@ -215,8 +252,8 @@
.attr("transform", "translate(" + w / 2 + "," + h / 2 + ")");
var arc2 = d3.svg.arc()
.outerRadius(radius-4)
.innerRadius(radius-4);
.outerRadius(radius-2)
.innerRadius(radius-2);
var slices = pieChartSvg.selectAll(".arc")
.data(pie(dataset))
@ -232,7 +269,9 @@
.attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")"; })
.attr("dy", ".35em")
.style("text-anchor", "middle")
.text(function(d) { return d.data.value.toFixed(2); });
.text(function(d) {
var v = d.data.value / 1000000000
return v.toFixed(2) + "GB"; });
slices.append("text")
.attr("transform", function(d) { return "translate(" + arc2.centroid(d) + ")"; })
@ -322,52 +361,24 @@
document.getElementById('lineGraph'),
getData(),
{ title: 'Average request time in milliseconds',
yLabelWidth: "15",
labelsDivStyles: { 'backgroundColor': 'transparent','textAlign': 'right' },
hideOverlayOnMouseOut: true,
labelsDivStyles: { 'backgroundColor': '#e1e3e5','textAlign': 'right' },
labelsSeparateLines: true,
connectSeparatedPoints : true,
digitsAfterDecimal: 3,
fillGraph : true,
strokeWidth: 2,
legend: "always",
labelsDivWidth: 150,
labelsShowZeroValues: false,
highlightSeriesBackgroundAlpha: 0.5,
drawPoints: true,
width: 480,
height: 320,
labels: createLabels(),
visibility:getVisibility() ,
valueRange: [self.min -0.1 * self.min, self.max + 0.1 * self.max],
stackedGraph: false,
axes: {
y: {
valueFormatter: function(y) {
return y.toPrecision(2);
},
axisLabelFormatter: function(y) {
return y.toPrecision(2);
}
},
x: {
valueFormatter: function(d) {
if (d === -1) {return "";}
var date = new Date(d);
return Dygraph.zeropad(date.getHours()) + ":"
+ Dygraph.zeropad(date.getMinutes()) + ":"
+ Dygraph.zeropad(date.getSeconds());
}
}
},
highlightCircleSize: 2,
strokeWidth: 1,
strokeBorderWidth: null,
highlightSeriesOpts: {
strokeWidth: 3,
strokeBorderWidth: 1,
highlightCircleSize: 5
}
});
axisLabelFont: "Open Sans",
dateWindow : [new Date().getTime() - 20 * 60 * 1000,new Date().getTime()],
//labels: createLabels(),
//visibility:getVisibility() ,
xAxisLabelWidth : "60",
showRangeSelector: false,
rightGap: 15,
pixelsPerLabel : 60,
labelsKMG2: false,
highlightCircleSize: 2
});
var onclick = function(ev) {
if (self.graph.isSeriesLocked()) {
self.graph.clearSelection();
@ -378,12 +389,13 @@
self.graph.updateOptions({clickCallback: onclick}, true);
self.graph.setSelection(false, 'ClusterAverage', true);
};
makeGraph("lineGraph");
makeGraph('lineGraph');
},
stopUpdating: function () {
window.clearTimeout(this.timer);
delete this.graph;
this.isUpdating = false;
},
@ -415,6 +427,7 @@
},
dashboard: function(e) {
this.stopUpdating();
var id = $(e.currentTarget).attr("id");
window.App.dashboard(id);
}

View File

@ -60,8 +60,7 @@
el: '#content',
contentEl: '.contentDiv',
distributionChartDiv : "#distributionChartDiv",
interval: 10000000, // in milliseconds
defaultHistoryElements: 1, //in days
interval: 8000, // in milliseconds
defaultRollPeriod : 1,
detailTemplate: templateEngine.createTemplate("lineChartDetailView.ejs"),
detailEl: '#modalPlaceholder',
@ -187,6 +186,12 @@
this.options.description.fetch({
async:false
});
if (this.options.server) {
this.getStatisticHistory({
startDate : (new Date().getTime() - 20 * 60 * 1000) / 1000
});
this.calculateSeries();
}
this.description = this.options.description.models[0];
this.detailChart = {};
window.App.navigate("#", {trigger: true});
@ -328,8 +333,7 @@
initialize: function () {
this.documentStore = this.options.documentStore;
this.getStatisticHistory({
startDate : (new Date().getTime() - Math.min(20 * 60 * 1000,
this.defaultHistoryElements * 86400 * 1000 )) / 1000
startDate : (new Date().getTime() - 20 * 60 * 1000) / 1000
});
this.statisticsUrl = "/_admin/statistics";
if (this.options.server) {
@ -377,8 +381,7 @@
strokeWidth: 2,
interactionModel : {},
axisLabelFont: "Open Sans",
dateWindow : [new Date().getTime() - Math.min(20 * 60 * 1000,
this.defaultHistoryElements * 86400 * 1000 ),new Date().getTime()],
dateWindow : [new Date().getTime() - 20 * 60 * 1000,new Date().getTime()],
colors: [this.colors[0]],
xAxisLabelWidth : "60",
rollPeriod: this.defaultRollPeriod,
@ -566,7 +569,7 @@
file.push(e);
} else {
i++;
if (i > 5 && !hideRangeSelector) {
if (i > 3 && !hideRangeSelector) {
file.push(e);
i = 0;
}
@ -589,7 +592,7 @@
chart.options.showLabelsOnHighlight = true;
if (chart.graph.dateWindow_) {
borderLeft = chart.graph.dateWindow_[0];
borderRight = t - chart.graph.dateWindow_[1] - self.interval * 2 > 0 ?
borderRight = t - chart.graph.dateWindow_[1] - self.interval * 5 > 0 ?
chart.graph.dateWindow_[1] : t;
file = self.spliceSeries(chart.data, borderLeft, borderRight, false);
}
@ -638,6 +641,9 @@
},
getStatisticHistory : function (params) {
if (this.options.server) {
params.server = this.options.server;
}
this.documentStore.getStatisticsHistory(params);
this.history = this.documentStore.history;
},

View File

@ -1,3 +1,3 @@
.contentDiv {
background-color: white;
//background-color: white;
}

View File

@ -1,13 +1,13 @@
#dashboardHttpGroup {
width: 100%;
height: 100%;
border: 1px solid black;
border: 1px solid $c_black;
}
#dashboardDetailedChart {
width: 100%;
height: 300px;
border: 1px solid black;
border: 1px solid $c_black;
}
.innerDashboardChart {
@ -27,6 +27,7 @@
}
.dashboardChart {
background-color: $c_white;
position: relative;
width: 31%;
height: 270px;

View File

@ -705,7 +705,17 @@ div.centralContent {
content: ""; }
.clusterInfoIcon {
font-size: 30px; }
float: left;
padding-top: 2px;
padding-left: 5px; }
.waitModal {
text-align: center; }
.waitModal.icon {
font-size: 100px;
height: 120px; }
.waitModal.message {
font-size: 20px; }
div.headerDropdown {
background-color: white;

View File

@ -969,9 +969,6 @@ select.filterSelect {
float: left;
margin-right: 3px; }
.contentDiv {
background-color: white; }
#dashboardHttpGroup {
width: 100%;
height: 100%;
@ -990,6 +987,7 @@ select.filterSelect {
bottom: 10px; }
.dashboardChart {
background-color: white;
position: relative;
width: 31%;
height: 270px;