|
@@ -13,28 +13,93 @@
|
|
|
|
|
|
|
|
|
|
|
|
-
|
|
|
- var USELOCALGUN = true;
|
|
|
+
|
|
|
+ *
|
|
|
+ * Usage: require the file in your application
|
|
|
+ *
|
|
|
+ * Gun Params: these are passed to the new gun constructor
|
|
|
+ *
|
|
|
+ * - gc_enable : enables the gc, good if you are running multiple instances of gun, etc... def. true
|
|
|
+ * - gc_delay : sets the amount of time between attempted garbage collections in milliseconds
|
|
|
+ * - gc_info_enable : Enables or Disables the info printout
|
|
|
+ * - gc_info : sets the ~ amount of time between info messages
|
|
|
+ * this is checked everytime the gc is ran
|
|
|
+ * - gc_info_mini : this will use a smaller, less user friendly info printout
|
|
|
+ * - gc_importance_func : This will be the function used for finding the importance of a potental collect
|
|
|
+ * takes the form of func(timestamp, ctime, memoryUsageRatio) {return val}
|
|
|
+ * Collects when returned value is 100
|
|
|
+ */
|
|
|
|
|
|
-
|
|
|
+
|
|
|
+ var USELOCALGUN = false;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
var DEBUG = false;
|
|
|
|
|
|
+ if(!(typeof window !== "undefined") && USELOCALGUN)
|
|
|
+ console.log("NOTE: You currently have LES.js set to use the 'local' file version of gun, This might crash if set wrong!");
|
|
|
|
|
|
var Gun = (typeof window !== "undefined") ? window.Gun : (USELOCALGUN ? require('../gun') : require("gun"));
|
|
|
- var ev = {};
|
|
|
- var empty = {};
|
|
|
-
|
|
|
+
|
|
|
+
|
|
|
+ Gun.chain.gcDequeue = function() {
|
|
|
+
|
|
|
+ if(this._.root.dequeueNode) {
|
|
|
+ let ctx = this;
|
|
|
+
|
|
|
+ this.get(function (soul) {
|
|
|
+ ctx._.root.dequeueNode(soul);
|
|
|
+ }, true);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ Gun.chain.gcCollect = function() {
|
|
|
+ if(this._.root.collectNode) {
|
|
|
+ let ctx = this;
|
|
|
+
|
|
|
+ this.get(function (soul) {
|
|
|
+ ctx._.root.collectNode(soul);
|
|
|
+ }, true);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
Gun.on('opt', function(root) {
|
|
|
+
|
|
|
+
|
|
|
+ const gc_enable = root.opt.gc_enable ? root.opt.gc_enable : true;
|
|
|
+ const gc_delay = root.opt.gc_delay ? root.opt.gc_delay : 1000;
|
|
|
+
|
|
|
+ const gc_info_enable = root.opt.gc_info_enable ? root.opt.gc_info_enable : true;
|
|
|
+ const gc_info = root.opt.gc_info ? root.opt.gc_info : 5000;
|
|
|
+ const gc_info_mini = root.opt.gc_info_mini ? root.opt.gc_info_mini : false;
|
|
|
+
|
|
|
+
|
|
|
+ const calcRemoveImportance = root.opt.gc_importance_func ? root.opt.gc_importance_func : function (timestamp, ctime, memoryUsageRatio) {
|
|
|
+ var time = (ctime - timestamp) * 0.001;
|
|
|
+ return time * 10 * (memoryUsageRatio * memoryUsageRatio);
|
|
|
+ }
|
|
|
+
|
|
|
+ if(DEBUG) console.log(root.opt);
|
|
|
+
|
|
|
this.to.next(root);
|
|
|
+
|
|
|
if (root.once)
|
|
|
return;
|
|
|
if (typeof process == 'undefined')
|
|
|
return
|
|
|
var mem = process.memoryUsage;
|
|
|
|
|
|
+ if(!gc_enable)
|
|
|
+ return;
|
|
|
+
|
|
|
if (!mem)
|
|
|
return;
|
|
|
|
|
|
+ var ev = {};
|
|
|
+ var empty = {};
|
|
|
+
|
|
|
|
|
|
ev.max = parseFloat(root.opt.memory || process.env.WEB_MEMORY || 512) * 0.8;
|
|
|
|
|
@@ -42,20 +107,29 @@
|
|
|
var nodesArray = [];
|
|
|
var memoryUpdate = 0;
|
|
|
|
|
|
+ root.dequeueNode = (soul) => {
|
|
|
+ dequeueNode(soul);
|
|
|
+ }
|
|
|
+
|
|
|
+ root.collectNode = (soul) => {
|
|
|
+ collectNode(soul);
|
|
|
+ }
|
|
|
+
|
|
|
var check = function() {
|
|
|
ev.used = mem().rss / 1024 / 1024;
|
|
|
setTimeout(function() {
|
|
|
GC(ev.used / ev.max);
|
|
|
+
|
|
|
}, 1);
|
|
|
}
|
|
|
|
|
|
- setInterval(check, 1000);
|
|
|
+ setInterval(check, gc_delay);
|
|
|
|
|
|
-
|
|
|
+
|
|
|
root.on("put", function(e) {
|
|
|
var ctime = Date.now();
|
|
|
- var souls = Object.keys(e.put || empty);
|
|
|
- for (var i = 0; i < souls.length; i++) {
|
|
|
+ var souls = Object.keys(e.put || empty);
|
|
|
+ for (var i = 0; i < souls.length; i++) {
|
|
|
enqueueNode(souls[i], ctime);
|
|
|
}
|
|
|
});
|
|
@@ -67,10 +141,10 @@
|
|
|
return e[0] === soul;
|
|
|
});
|
|
|
if (index == -1) {
|
|
|
- console.err("Something happened and the node '" + soul + "' won't get garbage collection unless the value is updated agian");
|
|
|
+ console.error("Something happened and the node '" + soul + "' won't get garbage collection unless the value is updated again");
|
|
|
return;
|
|
|
} else {
|
|
|
- nodesArray.splice(index, 1);
|
|
|
+ nodesArray.splice(index, 1);
|
|
|
nodesArray.push([soul, ctime]);
|
|
|
}
|
|
|
} else {
|
|
@@ -79,18 +153,50 @@
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ function dequeueNode(soul) {
|
|
|
+ if (nodes[soul] == true) {
|
|
|
+ var index = nodesArray.findIndex(function(e) {
|
|
|
+ return e[0] === soul;
|
|
|
+ });
|
|
|
+ if (index != -1) {
|
|
|
+
|
|
|
+ nodesArray.shift();
|
|
|
+ nodes[soul] = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ function collectNode(soul) {
|
|
|
+ if (nodes[soul] == true) {
|
|
|
+ var index = nodesArray.findIndex(function(e) {
|
|
|
+ return e[0] === soul;
|
|
|
+ });
|
|
|
+ if (index != -1) {
|
|
|
+
|
|
|
+ nodesArray.shift();
|
|
|
+ }
|
|
|
+ nodesArray.unshift([soul, nodesArray[0][1]]);
|
|
|
+ nodes[soul] = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
|
|
|
function GC(memRatio) {
|
|
|
var curTime = Date.now();
|
|
|
|
|
|
- if (curTime - memoryUpdate >= 5000) {
|
|
|
- console.log("|GC| %s | Current Memory Ratio: %d | Current Ram Usage %sMB | Nodes in Memory %s", new Date().toLocaleString(), round(memRatio, 2), round(ev.used, 2), Object.keys(root.graph || empty).length);
|
|
|
- memoryUpdate = curTime;
|
|
|
+ if (gc_info_enable && curTime - memoryUpdate >= gc_info) {
|
|
|
+ if(!gc_info_mini)
|
|
|
+ console.log("|GC| %s | Current Memory Ratio: %d | Current Ram Usage %sMB | Nodes in Memory %s", new Date().toLocaleString(), round(memRatio, 2), round(ev.used, 2), Object.keys(root.graph || empty).length);
|
|
|
+ else
|
|
|
+ console.log("|GC| %s, Mem Ratio %d, Ram %sMB, Nodes in mem %s, Tracked Nodes %s", new Date().toLocaleString(), round(memRatio, 2), round(ev.used, 2), Object.keys(root.graph || empty).length, nodesArray.length);
|
|
|
+ memoryUpdate = curTime;
|
|
|
}
|
|
|
|
|
|
- var freed = 0;
|
|
|
+ var freed = 0;
|
|
|
|
|
|
- while (nodesArray.length > 0) {
|
|
|
+ while (nodesArray.length > 0) {
|
|
|
var soul = nodesArray[0][0];
|
|
|
var nts = nodesArray[0][1];
|
|
|
if (DEBUG)
|
|
@@ -99,21 +205,16 @@
|
|
|
if (calcRemoveImportance(nodesArray[0][1], curTime, memRatio) >= 100) {
|
|
|
root.gun.get(nodesArray[0][0]).off();
|
|
|
delete nodes[nodesArray[0][0]];
|
|
|
- nodesArray.splice(0, 1);
|
|
|
- freed++;
|
|
|
+
|
|
|
+ nodesArray.shift();
|
|
|
+ freed++;
|
|
|
} else
|
|
|
- break;
|
|
|
+ break;
|
|
|
}
|
|
|
if (freed > 0)
|
|
|
console.log("|GC| Removed %s nodes in %s seconds-----------------------------------------------------------------", freed, (Date.now() - curTime) * 0.001);
|
|
|
}
|
|
|
-
|
|
|
-
|
|
|
- function calcRemoveImportance(timestamp, ctime, memoryUsageRatio) {
|
|
|
- var time = (ctime - timestamp) * 0.001;
|
|
|
- return time * 10 * (memoryUsageRatio * memoryUsageRatio)
|
|
|
- }
|
|
|
-
|
|
|
+
|
|
|
function round(value, decimals) {
|
|
|
return Number(Math.round(value + 'e' + decimals) + 'e-' + decimals);
|
|
|
}
|