storage.js: Cleanup `StorageAwareMap` key corpses after 90 days

This commit is contained in:
Johannes Meyer 2019-07-09 15:55:52 +02:00
parent cbd1e1bb92
commit c5beabf891
1 changed files with 67 additions and 29 deletions

View File

@ -4,6 +4,8 @@
'use strict'; 'use strict';
const KEY_TTL = 7776000000; // 90 days (90×24×60×60×1000)
/** /**
* Icinga.Storage * Icinga.Storage
* *
@ -184,7 +186,21 @@
* @returns {Icinga.Storage.StorageAwareMap} * @returns {Icinga.Storage.StorageAwareMap}
*/ */
Icinga.Storage.StorageAwareMap.withStorage = function(storage, key) { Icinga.Storage.StorageAwareMap.withStorage = function(storage, key) {
return (new Icinga.Storage.StorageAwareMap(storage.get(key)).setStorage(storage, key)); var items = storage.get(key);
if (typeof items !== 'undefined' && !! items) {
Object.keys(items).forEach(function(key) {
var value = items[key];
if (typeof value !== 'object' || typeof value['lastAccess'] === 'undefined') {
items[key] = {'value': value, 'lastAccess': Date.now()};
} else if (Date.now() - value['lastAccess'] > KEY_TTL) {
delete items[key];
}
}, this);
}
storage.set(key, items);
return (new Icinga.Storage.StorageAwareMap(items).setStorage(storage, key));
}; };
Icinga.Storage.StorageAwareMap.prototype = { Icinga.Storage.StorageAwareMap.prototype = {
@ -214,13 +230,31 @@
return typeof this.storage !== 'undefined' && typeof this.key !== 'undefined'; return typeof this.storage !== 'undefined' && typeof this.key !== 'undefined';
}, },
/**
* Update the storage
*
* @returns {void}
*/
updateStorage: function() {
if (! this.hasStorage()) {
return;
}
if (this.size > 0) {
this.storage.set(this.key, this.toObject());
} else {
this.storage.remove(this.key);
}
},
/** /**
* Update the map * Update the map
* *
* @param {object} newValue * @param {object} newValue
* @param {object} oldValue
*/ */
onChange: function(newValue) { onChange: function(newValue, oldValue) {
// Check for deletions first // Check for deletions first. Uses keys() to iterate over a copy
this.keys().forEach(function (key) { this.keys().forEach(function (key) {
if (typeof newValue[key] === 'undefined') { if (typeof newValue[key] === 'undefined') {
this.data.delete(key); this.data.delete(key);
@ -230,8 +264,11 @@
// Now check for new entries // Now check for new entries
Object.keys(newValue).forEach(function(key) { Object.keys(newValue).forEach(function(key) {
if (! this.data.has(key)) { var known = this.data.has(key);
this.data.set(key, newValue[key]); // Always override any known value as we want to keep track of all `lastAccess` changes
this.data.set(key, newValue[key]);
if (! known) {
$(window).trigger('StorageAwareMapAdd', key); $(window).trigger('StorageAwareMapAdd', key);
} }
}, this); }, this);
@ -276,12 +313,9 @@
* @returns {this} * @returns {this}
*/ */
set: function(key, value) { set: function(key, value) {
this.data.set(key, value); this.data.set(key, {'value': value, 'lastAccess': Date.now()});
if (this.hasStorage()) {
this.storage.set(this.key, this.toObject());
}
this.updateStorage();
return this; return this;
}, },
@ -291,11 +325,8 @@
* @returns {void} * @returns {void}
*/ */
clear: function() { clear: function() {
if (this.hasStorage()) { this.data.clear();
this.storage.remove(this.key); this.updateStorage();
}
return this.data.clear();
}, },
/** /**
@ -308,10 +339,7 @@
delete: function(key) { delete: function(key) {
var retVal = this.data.delete(key); var retVal = this.data.delete(key);
if (this.hasStorage()) { this.updateStorage();
this.storage.set(this.key, this.toObject());
}
return retVal; return retVal;
}, },
@ -324,8 +352,8 @@
var list = []; var list = [];
if (this.size > 0) { if (this.size > 0) {
this.forEach(function (value, key) { this.data.forEach(function (value, key) {
list.push([key, value]); list.push([key, value['value']]);
}); });
} }
@ -336,11 +364,18 @@
* Execute a provided function once for each item in the map, in insertion order * Execute a provided function once for each item in the map, in insertion order
* *
* @param {function} callback * @param {function} callback
* @param {object} thisArg
* *
* @returns {void} * @returns {void}
*/ */
forEach: function(callback) { forEach: function(callback, thisArg) {
return this.data.forEach(callback); if (typeof thisArg === 'undefined') {
thisArg = this;
}
return this.data.forEach(function(value, key) {
callback.call(thisArg, value['value'], key);
});
}, },
/** /**
@ -351,7 +386,10 @@
* @returns {*} * @returns {*}
*/ */
get: function(key) { get: function(key) {
return this.data.get(key); var value = this.data.get(key)['value'];
this.set(key, value); // Update `lastAccess`
return value;
}, },
/** /**
@ -375,7 +413,7 @@
if (this.size > 0) { if (this.size > 0) {
// .forEach() is used because IE11 doesn't support .keys() // .forEach() is used because IE11 doesn't support .keys()
this.forEach(function(_, key) { this.data.forEach(function(_, key) {
list.push(key); list.push(key);
}); });
} }
@ -393,8 +431,8 @@
if (this.size > 0) { if (this.size > 0) {
// .forEach() is used because IE11 doesn't support .values() // .forEach() is used because IE11 doesn't support .values()
this.forEach(function(value) { this.data.forEach(function(value) {
list.push(value); list.push(value['value']);
}); });
} }
@ -410,7 +448,7 @@
var obj = {}; var obj = {};
if (this.size > 0) { if (this.size > 0) {
this.forEach(function (value, key) { this.data.forEach(function (value, key) {
obj[key] = value; obj[key] = value;
}); });
} }