Added database counters.
Ylian Saint-Hilaire committed
Mar 1, 2021 at 19:32 UTC
c9035b80c80022520ff6e428bb1695a9ac0248a9
3 files changed
+65
-10
db.js
+51
-7
@@ -38,9 +38,26 @@ module.exports.CreateDB = function (parent, func) {
38
obj.dbRecordsDecryptKey = null;
39
obj.changeStream = false;
40
obj.pluginsActive = ((parent.config) && (parent.config.settings) && (parent.config.settings.plugins != null) && (parent.config.settings.plugins != false) && ((typeof parent.config.settings.plugins != 'object') || (parent.config.settings.plugins.enabled != false)));
41
+ obj.dbCounters = {
42
+ fileSet: 0,
43
+ fileRemove: 0,
44
+ powerSet: 0,
45
+ eventsSet: 0
46
+ }
47
48
// MongoDB bulk operations state
49
if (parent.config.settings.mongodbbulkoperations) {
50
+ // Added counters
51
+ obj.dbCounters.fileSetPending = 0;
52
+ obj.dbCounters.fileSetBulk = 0;
53
+ obj.dbCounters.fileRemovePending = 0;
54
+ obj.dbCounters.fileRemoveBulk = 0;
55
+ obj.dbCounters.powerSetPending = 0;
56
+ obj.dbCounters.powerSetBulk = 0;
57
+ obj.dbCounters.eventsSetPending = 0;
58
+ obj.dbCounters.eventsSetBulk = 0;
59
+
60
+ /// Added bulk accumulators
61
obj.filePendingGet = null;
62
obj.filePendingGets = null;
63
obj.filePendingRemove = null;
@@ -514,12 +531,15 @@ module.exports.CreateDB = function (parent, func) {
531
532
// Setup the changeStream on the MongoDB main collection if possible
533
if (parent.args.mongodbchangestream == true) {
534
+ obj.dbCounters.changeStream = { change: 0, update: 0, insert: 0, delete: 0 };
535
if (typeof obj.file.watch != 'function') {
536
console.log('WARNING: watch() is not a function, MongoDB ChangeStream not supported.');
537
} else {
538
obj.fileChangeStream = obj.file.watch([{ $match: { $or: [{ 'fullDocument.type': { $in: ['node', 'mesh', 'user', 'ugrp'] } }, { 'operationType': 'delete' }] } }], { fullDocument: 'updateLookup' });
539
obj.fileChangeStream.on('change', function (change) {
540
+ obj.dbCounters.changeStream.change++;
541
if ((change.operationType == 'update') || (change.operationType == 'replace')) {
542
+ obj.dbCounters.changeStream.update++;
543
switch (change.fullDocument.type) {
544
case 'node': { dbNodeChange(change, false); break; } // A node has changed
545
case 'mesh': { dbMeshChange(change, false); break; } // A device group has changed
@@ -527,6 +547,7 @@ module.exports.CreateDB = function (parent, func) {
547
case 'ugrp': { dbUGrpChange(change, false); break; } // A user account has changed
548
}
549
} else if (change.operationType == 'insert') {
550
+ obj.dbCounters.changeStream.insert++;
551
switch (change.fullDocument.type) {
552
case 'node': { dbNodeChange(change, true); break; } // A node has added
553
case 'mesh': { dbMeshChange(change, true); break; } // A device group has created
@@ -534,6 +555,7 @@ module.exports.CreateDB = function (parent, func) {
555
case 'ugrp': { dbUGrpChange(change, true); break; } // A user account has created
556
}
557
} else if (change.operationType == 'delete') {
558
+ obj.dbCounters.changeStream.delete++;
559
if ((change.documentKey == null) || (change.documentKey._id == null)) return;
560
var splitId = change.documentKey._id.split('/');
561
switch (splitId[0]) {
@@ -898,6 +920,7 @@ module.exports.CreateDB = function (parent, func) {
920
if ((obj.databaseType == 4) || (obj.databaseType == 5)) {
921
// Database actions on the main collection (MariaDB or MySQL)
922
obj.Set = function (value, func) {
923
+ obj.dbCounters.fileSet++;
924
var extra = null, extraex = null;
925
value = common.escapeLinksFieldNameEx(value);
926
if (value.meshid) { extra = value.meshid; } else if (value.email) { extra = 'email/' + value.email; } else if (value.nodeid) { extra = value.nodeid; }
@@ -947,6 +970,7 @@ module.exports.CreateDB = function (parent, func) {
970
// Database actions on the events collection
971
obj.GetAllEvents = function (func) { sqlDbQuery('SELECT doc FROM meshcentral.events', null, func); };
972
obj.StoreEvent = function (event, func) {
973
+ obj.dbCounters.eventsSet++;
974
var batchQuery = [['INSERT INTO meshcentral.events VALUE (?, ?, ?, ?, ?, ?, ?)', [null, event.time, ((typeof event.domain == 'string') ? event.domain : null), event.action, event.nodeid ? event.nodeid : null, event.userid ? event.userid : null, JSON.stringify(event)]]];
975
for (var i in event.ids) { if (event.ids[i] != '*') { batchQuery.push(['INSERT INTO meshcentral.eventids VALUE (LAST_INSERT_ID(), ?)', [event.ids[i]]]); } }
976
sqlDbBatchExec(batchQuery, function (err, docs) { if (func != null) { func(err, docs); } });
@@ -991,7 +1015,7 @@ module.exports.CreateDB = function (parent, func) {
1015
1016
// Database actions on the power collection
1017
obj.getAllPower = function (func) { sqlDbQuery('SELECT doc FROM meshcentral.power', null, func); };
994
- obj.storePowerEvent = function (event, multiServer, func) { if (multiServer != null) { event.server = multiServer.serverid; } sqlDbQuery('INSERT INTO meshcentral.power VALUE (?, ?, ?, ?)', [null, event.time, event.nodeid ? event.nodeid : null, JSON.stringify(event)], func); };
1018
+ obj.storePowerEvent = function (event, multiServer, func) { obj.dbCounters.powerSet++; if (multiServer != null) { event.server = multiServer.serverid; } sqlDbQuery('INSERT INTO meshcentral.power VALUE (?, ?, ?, ?)', [null, event.time, event.nodeid ? event.nodeid : null, JSON.stringify(event)], func); };
1019
obj.getPowerTimeline = function (nodeid, func) { sqlDbQuery('SELECT doc FROM meshcentral.power WHERE ((nodeid = ?) OR (nodeid = "*")) ORDER BY time DESC', [nodeid], func); };
1020
obj.removeAllPowerEvents = function () { sqlDbQuery('DELETE FROM meshcentral.power', null, function (err, docs) { }); };
1021
obj.removeAllPowerEventsForNode = function (nodeid) { sqlDbQuery('DELETE FROM meshcentral.power WHERE nodeid = ?', [nodeid], function (err, docs) { }); };
@@ -1055,11 +1079,13 @@ module.exports.CreateDB = function (parent, func) {
1079
obj.Set = function (data, func) { // Fast Set operation using bulkWrite(), this is much faster then using replaceOne()
1080
if (obj.filePendingSet == false) {
1081
// Perform the operation now
1082
+ obj.dbCounters.fileSet++;
1083
obj.filePendingSet = true; obj.filePendingSets = null;
1084
if (func != null) { obj.filePendingCbs = [func]; }
1085
obj.file.bulkWrite([{ replaceOne: { filter: { _id: data._id }, replacement: performTypedRecordEncrypt(common.escapeLinksFieldNameEx(data)), upsert: true } }], fileBulkWriteCompleted);
1086
} else {
1087
// Add this operation to the pending list
1088
+ obj.dbCounters.fileSetPending++;
1089
if (obj.filePendingSets == null) { obj.filePendingSets = {} }
1090
obj.filePendingSets[data._id] = data;
1091
if (func != null) { if (obj.filePendingCb == null) { obj.filePendingCb = [func]; } else { obj.filePendingCb.push(func); } }
@@ -1093,7 +1119,11 @@ module.exports.CreateDB = function (parent, func) {
1119
}
1120
};
1121
} else {
1096
- obj.Set = function (data, func) { data = common.escapeLinksFieldNameEx(data); obj.file.replaceOne({ _id: data._id }, performTypedRecordEncrypt(data), { upsert: true }, func); };
1122
+ obj.Set = function (data, func) {
1123
+ obj.dbCounters.fileSet++;
1124
+ data = common.escapeLinksFieldNameEx(data);
1125
+ obj.file.replaceOne({ _id: data._id }, performTypedRecordEncrypt(data), { upsert: true }, func);
1126
+ };
1127
obj.Get = function (id, func) {
1128
if (arguments.length > 2) {
1129
var parms = [func];
@@ -1145,18 +1175,20 @@ module.exports.CreateDB = function (parent, func) {
1175
if (parent.config.settings.mongodbbulkoperations) {
1176
obj.Remove = function (id, func) { // Fast remove operation using a bulk find() to reduce round trips to the database.
1177
if (obj.filePendingRemoves == null) {
1148
- // No pending gets, perform the operation now.
1178
+ // No pending removes, perform the operation now.
1179
+ obj.dbCounters.fileRemove++;
1180
obj.filePendingRemoves = {};
1181
obj.filePendingRemoves[id] = [func];
1182
obj.file.deleteOne({ _id: id }, fileBulkRemoveCompleted);
1183
} else {
1184
// Add remove to pending list.
1185
+ obj.dbCounters.fileRemovePending++;
1186
if (obj.filePendingRemove == null) { obj.filePendingRemove = {}; }
1187
if (obj.filePendingRemove[id] == null) { obj.filePendingRemove[id] = [func]; } else { obj.filePendingRemove[id].push(func); }
1188
}
1189
};
1190
} else {
1159
- obj.Remove = function (id, func) { obj.file.deleteOne({ _id: id }, func); };
1191
+ obj.Remove = function (id, func) { obj.dbCounters.fileRemove++; obj.file.deleteOne({ _id: id }, func); };
1192
}
1193
1194
obj.RemoveAll = function (func) { obj.file.deleteMany({}, { multi: true }, func); };
@@ -1189,18 +1221,20 @@ module.exports.CreateDB = function (parent, func) {
1221
obj.StoreEvent = function (event, func) { // Fast MongoDB event store using bulkWrite()
1222
if (obj.eventsFilePendingSet == false) {
1223
// Perform the operation now
1224
+ obj.dbCounters.eventsSet++;
1225
obj.eventsFilePendingSet = true; obj.eventsFilePendingSets = null;
1226
if (func != null) { obj.eventsFilePendingCbs = [func]; }
1227
obj.eventsfile.bulkWrite([{ insertOne: { document: event } }], eventsFileBulkWriteCompleted);
1228
} else {
1229
// Add this operation to the pending list
1230
+ obj.dbCounters.eventsSetPending++;
1231
if (obj.eventsFilePendingSets == null) { obj.eventsFilePendingSets = [] }
1232
obj.eventsFilePendingSets.push(event);
1233
if (func != null) { if (obj.eventsFilePendingCb == null) { obj.eventsFilePendingCb = [func]; } else { obj.eventsFilePendingCb.push(func); } }
1234
}
1235
};
1236
} else {
1203
- obj.StoreEvent = function (event, func) { obj.eventsfile.insertOne(event, func); };
1237
+ obj.StoreEvent = function (event, func) { obj.dbCounters.eventsSet++; obj.eventsfile.insertOne(event, func); };
1238
}
1239
1240
obj.GetEvents = function (ids, domain, func) { obj.eventsfile.find({ domain: domain, ids: { $in: ids } }).project({ type: 0, _id: 0, domain: 0, ids: 0, node: 0 }).sort({ time: -1 }).toArray(func); };
@@ -1230,18 +1264,20 @@ module.exports.CreateDB = function (parent, func) {
1264
if (multiServer != null) { event.server = multiServer.serverid; }
1265
if (obj.powerFilePendingSet == false) {
1266
// Perform the operation now
1267
+ obj.dbCounters.powerSet++;
1268
obj.powerFilePendingSet = true; obj.powerFilePendingSets = null;
1269
if (func != null) { obj.powerFilePendingCbs = [func]; }
1270
obj.powerfile.bulkWrite([{ insertOne: { document: event } }], powerFileBulkWriteCompleted);
1271
} else {
1272
// Add this operation to the pending list
1273
+ obj.dbCounters.powerSetPending++;
1274
if (obj.powerFilePendingSets == null) { obj.powerFilePendingSets = [] }
1275
obj.powerFilePendingSets.push(event);
1276
if (func != null) { if (obj.powerFilePendingCb == null) { obj.powerFilePendingCb = [func]; } else { obj.powerFilePendingCb.push(func); } }
1277
}
1278
};
1279
} else {
1244
- obj.storePowerEvent = function (event, multiServer, func) { if (multiServer != null) { event.server = multiServer.serverid; } obj.powerfile.insertOne(event, func); };
1280
+ obj.storePowerEvent = function (event, multiServer, func) { obj.dbCounters.powerSet++; if (multiServer != null) { event.server = multiServer.serverid; } obj.powerfile.insertOne(event, func); };
1281
}
1282
1283
obj.getPowerTimeline = function (nodeid, func) { obj.powerfile.find({ nodeid: { $in: ['*', nodeid] } }).project({ _id: 0, nodeid: 0, s: 0 }).sort({ time: 1 }).toArray(func); };
@@ -1304,7 +1340,11 @@ module.exports.CreateDB = function (parent, func) {
1340
1341
} else {
1342
// Database actions on the main collection (NeDB and MongoJS)
1307
- obj.Set = function (data, func) { data = common.escapeLinksFieldNameEx(data); var xdata = performTypedRecordEncrypt(data); obj.file.update({ _id: xdata._id }, xdata, { upsert: true }, func); };
1343
+ obj.Set = function (data, func) {
1344
+ obj.dbCounters.fileSet++;
1345
+ data = common.escapeLinksFieldNameEx(data);
1346
+ var xdata = performTypedRecordEncrypt(data); obj.file.update({ _id: xdata._id }, xdata, { upsert: true }, func);
1347
+ };
1348
obj.Get = function (id, func) {
1349
if (arguments.length > 2) {
1350
var parms = [func];
@@ -1578,6 +1618,7 @@ module.exports.CreateDB = function (parent, func) {
1618
obj.filePendingRemoves = obj.filePendingRemove;
1619
obj.filePendingRemove = null;
1620
if (obj.filePendingRemoves != null) {
1621
+ obj.dbCounters.fileRemoveBulk++;
1622
var findlist = [], count = 0;
1623
for (var i in obj.filePendingRemoves) { findlist.push(i); count++; }
1624
obj.file.deleteMany({ _id: { $in: findlist } }, { multi: true }, fileBulkRemoveCompleted);
@@ -1593,6 +1634,7 @@ module.exports.CreateDB = function (parent, func) {
1634
}
1635
if (obj.filePendingSets != null) {
1636
// Perform pending operations
1637
+ obj.dbCounters.fileSetBulk++;
1638
var ops = [];
1639
obj.filePendingCbs = obj.filePendingCb;
1640
obj.filePendingCb = null;
@@ -1611,6 +1653,7 @@ module.exports.CreateDB = function (parent, func) {
1653
if (obj.eventsFilePendingCbs != null) { for (var i in obj.eventsFilePendingCbs) { obj.eventsFilePendingCbs[i](); } obj.eventsFilePendingCbs = null; }
1654
if (obj.eventsFilePendingSets != null) {
1655
// Perform pending operations
1656
+ obj.dbCounters.eventsSetBulk++;
1657
var ops = [];
1658
for (var i in obj.eventsFilePendingSets) { ops.push({ document: obj.eventsFilePendingSets[i] }); }
1659
obj.eventsFilePendingCbs = obj.eventsFilePendingCb;
@@ -1629,6 +1672,7 @@ module.exports.CreateDB = function (parent, func) {
1672
if (obj.powerFilePendingCbs != null) { for (var i in obj.powerFilePendingCbs) { obj.powerFilePendingCbs[i](); } obj.powerFilePendingCbs = null; }
1673
if (obj.powerFilePendingSets != null) {
1674
// Perform pending operations
1675
+ obj.dbCounters.powerSetBulk++;
1676
var ops = [];
1677
for (var i in obj.powerFilePendingSets) { ops.push({ document: obj.powerFilePendingSets[i] }); }
1678
obj.powerFilePendingCbs = obj.powerFilePendingCb;
meshuser.js
+6
-2
@@ -887,7 +887,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
887
888
switch (cmd) {
889
case 'help': {
890
- var fin = '', f = '', availcommands = 'help,maintenance,info,versions,resetserver,usersessions,closeusersessions,tasklimiter,setmaxtasks,cores,migrationagents,agentstats,agentissues,webstats,mpsstats,swarmstats,acceleratorsstats,updatecheck,serverupdate,nodeconfig,heapdump,relays,autobackup,backupconfig,dupagents,dispatchtable,badlogins,showpaths,le,lecheck,leevents,dbstats,sms,amtacm,certhashes,watchdog,amtmanager';
890
+ var fin = '', f = '', availcommands = 'help,maintenance,info,versions,resetserver,usersessions,closeusersessions,tasklimiter,setmaxtasks,cores,migrationagents,agentstats,agentissues,webstats,mpsstats,swarmstats,acceleratorsstats,updatecheck,serverupdate,nodeconfig,heapdump,relays,autobackup,backupconfig,dupagents,dispatchtable,badlogins,showpaths,le,lecheck,leevents,dbstats,dbcounters,sms,amtacm,certhashes,watchdog,amtmanager';
891
if (parent.parent.config.settings.heapdump === true) { availcommands += ',heapdump'; }
892
availcommands = availcommands.split(',').sort();
893
while (availcommands.length > 0) { if (f.length > 80) { fin += (f + ',\r\n'); f = ''; } f += (((f != '') ? ', ' : ' ') + availcommands.shift()); }
@@ -1135,7 +1135,11 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1135
var r2 = '';
1136
for (var i in stats) { r2 += (i + ': ' + stats[i] + '\r\n'); }
1137
try { ws.send(JSON.stringify({ action: 'serverconsole', value: r2, tag: command.tag })); } catch (ex) { }
1138
- })
1138
+ });
1139
+ break;
1140
+ }
1141
+ case 'dbcounters': {
1142
+ try { ws.send(JSON.stringify({ action: 'serverconsole', value: JSON.stringify(parent.parent.db.dbCounters, null, 2), tag: command.tag })); } catch (ex) { }
1143
break;
1144
}
1145
case 'serverupdate': {
views/default.handlebars
+8
-1
@@ -6483,7 +6483,14 @@
6483
}
6484
6485
function deskClipboardOutFunction() {
6486
- if ((navigator.clipboard != null) && (navigator.clipboard.readText != null)) { navigator.clipboard.readText().then(function(text) { meshserver.send({ action: 'msg', type: 'setclip', nodeid: currentNode._id, data: text }); }).catch(function(err) { }); }
6486
+ if ((navigator.clipboard != null) && (navigator.clipboard.readText != null)) {
6487
+ try {
6488
+ navigator.clipboard.readText().then(function(text) {
6489
+ meshserver.send({ action: 'msg', type: 'setclip', nodeid: currentNode._id, data: text });
6490
+ }).catch(function(err) { console.log(err); });
6491
+ } catch (ex) { console.log(ex); }
6492
+ }
6493
+ return true;
6494
}
6495
6496
function deskRefreshFunction() {