Refactor local cache
This commit is contained in:
1 parent
8b18f97d12
commit
e909d783e2
3 files changed
+128
-149
No files matched your search
+8
-23
@@ -278,8 +278,7 @@ function appendProvisions(original, toAppend) {
|
||||
|
||||
function applyPresets(sessionContext) {
|
||||
const deviceData = sessionContext.deviceData;
|
||||
localCache.getPresets((err, presetsHash, presets) => {
|
||||
if (err) return void throwError(err, sessionContext.httpResponse);
|
||||
const presets = localCache.getPresets(sessionContext.cacheSnapshot);
|
||||
|
||||
// Filter presets based on existing faults
|
||||
const blackList = {};
|
||||
@@ -412,8 +411,7 @@ function applyPresets(sessionContext) {
|
||||
provisions
|
||||
)
|
||||
) {
|
||||
if (!sessionContext.faultsTouched)
|
||||
sessionContext.faultsTouched = {};
|
||||
if (!sessionContext.faultsTouched) sessionContext.faultsTouched = {};
|
||||
sessionContext.faultsTouched[channel] = true;
|
||||
}
|
||||
}
|
||||
@@ -430,18 +428,14 @@ function applyPresets(sessionContext) {
|
||||
};
|
||||
recordFault(sessionContext, fault);
|
||||
// No need to save retryNow
|
||||
for (const f of Object.values(sessionContext.faults))
|
||||
delete f.retryNow;
|
||||
for (const f of Object.values(sessionContext.faults)) delete f.retryNow;
|
||||
session.clearProvisions(sessionContext);
|
||||
return void sendAcsRequest(sessionContext);
|
||||
}
|
||||
|
||||
deviceData.timestamps.dirty = 0;
|
||||
deviceData.attributes.dirty = 0;
|
||||
session.rpcRequest(
|
||||
sessionContext,
|
||||
null,
|
||||
(err, fault, id, acsRequest) => {
|
||||
session.rpcRequest(sessionContext, null, (err, fault, id, acsRequest) => {
|
||||
if (err) return void throwError(err, sessionContext.httpResponse);
|
||||
|
||||
if (fault) {
|
||||
@@ -470,11 +464,9 @@ function applyPresets(sessionContext) {
|
||||
}
|
||||
|
||||
sendAcsRequest(sessionContext, id, acsRequest);
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function nextRpc(sessionContext) {
|
||||
@@ -718,6 +710,7 @@ function sendAcsRequest(sessionContext, id, acsRequest) {
|
||||
return void writeResponse(sessionContext, soap.response(null), true);
|
||||
|
||||
if (acsRequest.name === "Download") {
|
||||
acsRequest.fileSize = 0;
|
||||
if (!acsRequest.url) {
|
||||
const FS_PORT = config.get("FS_PORT");
|
||||
const FS_HOSTNAME = config.get("FS_HOSTNAME");
|
||||
@@ -726,18 +719,10 @@ function sendAcsRequest(sessionContext, id, acsRequest) {
|
||||
acsRequest.url += FS_HOSTNAME;
|
||||
if (FS_PORT !== 80) acsRequest.url += ":" + FS_PORT;
|
||||
acsRequest.url += "/" + encodeURI(acsRequest.fileName);
|
||||
}
|
||||
|
||||
if (acsRequest.fileSize == null) {
|
||||
return void localCache.getFiles((err, hash, files) => {
|
||||
if (err) return void throwError(err, sessionContext.httpResponse);
|
||||
|
||||
const files = localCache.getFiles(sessionContext.cacheSnapshot);
|
||||
if (files[acsRequest.fileName])
|
||||
acsRequest.fileSize = files[acsRequest.fileName].length;
|
||||
else acsRequest.fileSize = 0;
|
||||
|
||||
sendAcsRequest(sessionContext, id, acsRequest);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+103
-98
@@ -28,15 +28,16 @@ const logger = require("./logger");
|
||||
const scheduling = require("./scheduling");
|
||||
|
||||
const REFRESH = 3000;
|
||||
const EVICT_TIMEOUT = 60000;
|
||||
|
||||
const snapshots = new Map();
|
||||
let currentSnapshot = null;
|
||||
let nextRefresh = 1;
|
||||
let hash = null;
|
||||
let presets, provisions, virtualParameters, files;
|
||||
|
||||
function computeHash() {
|
||||
function computeHash(snapshot) {
|
||||
// MD5 hash for presets, provisions, virtual parameters for detecting changes
|
||||
const h = crypto.createHash("md5");
|
||||
for (const p of presets) {
|
||||
for (const p of snapshot.presets) {
|
||||
h.update(JSON.stringify(p.name));
|
||||
h.update(JSON.stringify(p.channel));
|
||||
h.update(JSON.stringify(p.schedule));
|
||||
@@ -47,15 +48,15 @@ function computeHash() {
|
||||
|
||||
let keys;
|
||||
|
||||
keys = Object.keys(provisions).sort();
|
||||
keys = Object.keys(snapshot.provisions).sort();
|
||||
h.update(JSON.stringify(keys));
|
||||
for (const k of keys) h.update(provisions[k].md5);
|
||||
for (const k of keys) h.update(snapshot.provisions[k].md5);
|
||||
|
||||
keys = Object.keys(virtualParameters).sort();
|
||||
keys = Object.keys(snapshot.virtualParameters).sort();
|
||||
h.update(JSON.stringify(keys));
|
||||
for (const k of keys) h.update(virtualParameters[k].md5);
|
||||
for (const k of keys) h.update(snapshot.virtualParameters[k].md5);
|
||||
|
||||
hash = h.digest("hex");
|
||||
return h.digest("hex");
|
||||
}
|
||||
|
||||
function flattenObject(src, prefix = "", dst = {}) {
|
||||
@@ -81,7 +82,7 @@ function refresh(callback) {
|
||||
cache.get("presets_hash", (err, dbHash) => {
|
||||
if (err) return void callback(err);
|
||||
|
||||
if (hash && dbHash === hash) {
|
||||
if (currentSnapshot && dbHash === currentSnapshot) {
|
||||
nextRefresh = now + (REFRESH - (now % REFRESH));
|
||||
return void callback();
|
||||
}
|
||||
@@ -89,20 +90,15 @@ function refresh(callback) {
|
||||
cache.lock("presets_hash_lock", 3, (err, unlockOrExtend) => {
|
||||
if (err) return void callback(err);
|
||||
|
||||
let counter = 3;
|
||||
const promises = [];
|
||||
|
||||
counter += 2;
|
||||
promises.push(
|
||||
new Promise((resolve, reject) => {
|
||||
db.getPresets((err, res) => {
|
||||
if (err) {
|
||||
if (counter & 1) callback(err);
|
||||
return void (counter = 0);
|
||||
}
|
||||
if (err) return void reject(err);
|
||||
|
||||
db.getObjects((err, objects) => {
|
||||
if (err) {
|
||||
if (counter & 1) callback(err);
|
||||
return void (counter = 0);
|
||||
}
|
||||
if (err) return void reject(err);
|
||||
|
||||
objects = objects.map(obj => {
|
||||
// Flatten object
|
||||
@@ -110,8 +106,11 @@ function refresh(callback) {
|
||||
|
||||
// If no keys are defined, consider all parameters as keys to keep the
|
||||
// same behavior from v1.0
|
||||
if (!obj["_keys"] || !obj["_keys"].length)
|
||||
obj["_keys"] = Object.keys(obj).filter(k => !k.startsWith("_"));
|
||||
if (!obj["_keys"] || !obj["_keys"].length) {
|
||||
obj["_keys"] = Object.keys(obj).filter(
|
||||
k => !k.startsWith("_")
|
||||
);
|
||||
}
|
||||
|
||||
return obj;
|
||||
});
|
||||
@@ -121,7 +120,7 @@ function refresh(callback) {
|
||||
else return a.weight - b.weight;
|
||||
});
|
||||
|
||||
presets = [];
|
||||
const presets = [];
|
||||
for (const preset of res) {
|
||||
let schedule = null;
|
||||
if (preset.schedule) {
|
||||
@@ -210,9 +209,9 @@ function refresh(callback) {
|
||||
break;
|
||||
|
||||
default:
|
||||
if (counter & 1)
|
||||
callback(new Error(`Unknown configuration type ${c.type}`));
|
||||
return void (counter = 0);
|
||||
return void reject(
|
||||
new Error(`Unknown configuration type ${c.type}`)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,25 +225,18 @@ function refresh(callback) {
|
||||
});
|
||||
}
|
||||
|
||||
if ((counter -= 2) === 1) {
|
||||
computeHash();
|
||||
cache.set("presets_hash", hash, 300, err => {
|
||||
unlockOrExtend(0);
|
||||
nextRefresh = now + (REFRESH - (now % REFRESH));
|
||||
callback(err);
|
||||
});
|
||||
}
|
||||
resolve(presets);
|
||||
});
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
counter += 2;
|
||||
promises.push(
|
||||
new Promise((resolve, reject) => {
|
||||
db.getProvisions((err, res) => {
|
||||
if (err) {
|
||||
if (counter & 1) callback(err);
|
||||
return void (counter = 0);
|
||||
}
|
||||
if (err) return void reject(err);
|
||||
|
||||
provisions = {};
|
||||
const provisions = {};
|
||||
for (const r of res) {
|
||||
provisions[r._id] = {};
|
||||
provisions[r._id].md5 = crypto
|
||||
@@ -257,24 +249,17 @@ function refresh(callback) {
|
||||
);
|
||||
}
|
||||
|
||||
if ((counter -= 2) === 1) {
|
||||
computeHash();
|
||||
cache.set("presets_hash", hash, 300, err => {
|
||||
unlockOrExtend(0);
|
||||
nextRefresh = now + (REFRESH - (now % REFRESH));
|
||||
callback(err);
|
||||
});
|
||||
}
|
||||
resolve(provisions);
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
counter += 2;
|
||||
promises.push(
|
||||
new Promise((resolve, reject) => {
|
||||
db.getVirtualParameters((err, res) => {
|
||||
if (err) {
|
||||
if (counter & 1) callback(err);
|
||||
return void (counter = 0);
|
||||
}
|
||||
if (err) return void reject(err);
|
||||
|
||||
virtualParameters = {};
|
||||
const virtualParameters = {};
|
||||
for (const r of res) {
|
||||
virtualParameters[r._id] = {};
|
||||
virtualParameters[r._id].md5 = crypto
|
||||
@@ -287,24 +272,17 @@ function refresh(callback) {
|
||||
);
|
||||
}
|
||||
|
||||
if ((counter -= 2) === 1) {
|
||||
computeHash();
|
||||
cache.set("presets_hash", hash, 300, err => {
|
||||
unlockOrExtend(0);
|
||||
nextRefresh = now + (REFRESH - (now % REFRESH));
|
||||
callback(err);
|
||||
});
|
||||
}
|
||||
resolve(virtualParameters);
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
counter += 2;
|
||||
promises.push(
|
||||
new Promise((resolve, reject) => {
|
||||
db.getFiles((err, res) => {
|
||||
if (err) {
|
||||
if (counter & 1) callback(err);
|
||||
return void (counter = 0);
|
||||
}
|
||||
if (err) return void reject(err);
|
||||
|
||||
files = {};
|
||||
const files = {};
|
||||
for (const r of res) {
|
||||
const id = r.filename || r._id.toString();
|
||||
files[id] = {};
|
||||
@@ -313,53 +291,80 @@ function refresh(callback) {
|
||||
files[id].contentType = r.contentType;
|
||||
}
|
||||
|
||||
if ((counter -= 2) === 1) {
|
||||
computeHash();
|
||||
cache.set("presets_hash", hash, 300, err => {
|
||||
unlockOrExtend(0);
|
||||
nextRefresh = now + (REFRESH - (now % REFRESH));
|
||||
callback(err);
|
||||
resolve(files);
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
Promise.all(promises)
|
||||
.then(res => {
|
||||
const snapshot = {
|
||||
presets: res[0],
|
||||
provisions: res[1],
|
||||
virtualParameters: res[2],
|
||||
files: res[3]
|
||||
};
|
||||
|
||||
if (currentSnapshot) {
|
||||
const h = currentSnapshot;
|
||||
const s = snapshots.get(h);
|
||||
setTimeout(() => {
|
||||
if (snapshots.get(h) === s) snapshots.delete(h);
|
||||
}, EVICT_TIMEOUT).unref();
|
||||
}
|
||||
});
|
||||
|
||||
if ((counter -= 2) === 1) {
|
||||
computeHash();
|
||||
cache.set("presets_hash", hash, 300, err => {
|
||||
currentSnapshot = computeHash(snapshot);
|
||||
snapshots.set(currentSnapshot, snapshot);
|
||||
cache.set("presets_hash", currentSnapshot, 300, err => {
|
||||
unlockOrExtend(0);
|
||||
if (err) return void callback(err);
|
||||
nextRefresh = now + (REFRESH - (now % REFRESH));
|
||||
callback(err);
|
||||
callback();
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch(callback);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getPresets(callback) {
|
||||
if (Date.now() < nextRefresh) return void callback(null, hash, presets);
|
||||
|
||||
function getCurrentSnapshot(callback) {
|
||||
if (Date.now() < nextRefresh) return void callback(null, currentSnapshot);
|
||||
refresh(err => {
|
||||
callback(err, hash, presets);
|
||||
callback(err, currentSnapshot);
|
||||
});
|
||||
}
|
||||
|
||||
function getFiles(callback) {
|
||||
if (Date.now() < nextRefresh) return void callback(null, hash, files);
|
||||
|
||||
refresh(err => {
|
||||
callback(err, hash, files);
|
||||
});
|
||||
function hasSnapshot(hash) {
|
||||
return snapshots.has(hash);
|
||||
}
|
||||
|
||||
function getProvisionsAndVirtualParameters(callback) {
|
||||
if (Date.now() < nextRefresh)
|
||||
return void callback(null, hash, provisions, virtualParameters);
|
||||
|
||||
refresh(err => {
|
||||
callback(err, hash, provisions, virtualParameters);
|
||||
});
|
||||
function getPresets(snapshotKey) {
|
||||
const snapshot = snapshots.get(snapshotKey);
|
||||
if (!snapshot) throw new Error("Cache snapshot does not exist");
|
||||
return snapshot.presets;
|
||||
}
|
||||
|
||||
function getProvisions(snapshotKey) {
|
||||
const snapshot = snapshots.get(snapshotKey);
|
||||
if (!snapshot) throw new Error("Cache snapshot does not exist");
|
||||
return snapshot.provisions;
|
||||
}
|
||||
|
||||
function getVirtualParameters(snapshotKey) {
|
||||
const snapshot = snapshots.get(snapshotKey);
|
||||
if (!snapshot) throw new Error("Cache snapshot does not exist");
|
||||
return snapshot.virtualParameters;
|
||||
}
|
||||
|
||||
function getFiles(snapshotKey) {
|
||||
const snapshot = snapshots.get(snapshotKey);
|
||||
if (!snapshot) throw new Error("Cache snapshot does not exist");
|
||||
return snapshot.files;
|
||||
}
|
||||
|
||||
exports.getCurrentSnapshot = getCurrentSnapshot;
|
||||
exports.hasSnapshot = hasSnapshot;
|
||||
exports.getPresets = getPresets;
|
||||
exports.getProvisions = getProvisions;
|
||||
exports.getVirtualParameters = getVirtualParameters;
|
||||
exports.getFiles = getFiles;
|
||||
exports.getProvisionsAndVirtualParameters = getProvisionsAndVirtualParameters;
|
||||
+17
-28
@@ -34,9 +34,6 @@ const gpnHeuristic = require("./gpn-heuristic");
|
||||
// phases: read and update
|
||||
const MAX_ITERATIONS = config.get("MAX_COMMIT_ITERATIONS") * 2;
|
||||
|
||||
const provisionsCache = new WeakMap();
|
||||
const virtualParametersCache = new WeakMap();
|
||||
|
||||
function initDeviceData() {
|
||||
return {
|
||||
paths: new PathSet(),
|
||||
@@ -67,16 +64,11 @@ function init(deviceId, cwmpVersion, timeout, callback) {
|
||||
declarations: []
|
||||
};
|
||||
|
||||
localCache.getProvisionsAndVirtualParameters(
|
||||
(err, hash, provisions, virtualParameters) => {
|
||||
localCache.getCurrentSnapshot((err, cacheSnapshot) => {
|
||||
if (err) return void callback(err);
|
||||
|
||||
sessionContext.presetsHash = hash;
|
||||
provisionsCache.set(sessionContext, provisions);
|
||||
virtualParametersCache.set(sessionContext, virtualParameters);
|
||||
sessionContext.cacheSnapshot = cacheSnapshot;
|
||||
callback(null, sessionContext);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function loadParameters(sessionContext, callback) {
|
||||
@@ -550,7 +542,7 @@ function runProvisions(
|
||||
let allDeclarations = [];
|
||||
let allClear = [];
|
||||
let counter = 3;
|
||||
const allProvisions = provisionsCache.get(sessionContext);
|
||||
const allProvisions = localCache.getProvisions(sessionContext.cacheSnapshot);
|
||||
|
||||
for (const [j, provision] of provisions.entries()) {
|
||||
if (!allProvisions[provision[0]]) {
|
||||
@@ -616,7 +608,9 @@ function runVirtualParameters(
|
||||
let allDeclarations = [];
|
||||
let allClear = [];
|
||||
let counter = 3;
|
||||
const allVirtualParameters = virtualParametersCache.get(sessionContext);
|
||||
const allVirtualParameters = localCache.getVirtualParameters(
|
||||
sessionContext.cacheSnapshot
|
||||
);
|
||||
|
||||
for (const [j, provision] of provisions.entries()) {
|
||||
counter += 2;
|
||||
@@ -777,7 +771,9 @@ function runDeclarations(sessionContext, declarations) {
|
||||
const allDeclareAttributeTimestamps = new Map();
|
||||
const allDeclareAttributeValues = new Map();
|
||||
|
||||
const allVirtualParameters = virtualParametersCache.get(sessionContext);
|
||||
const allVirtualParameters = localCache.getVirtualParameters(
|
||||
sessionContext.cacheSnapshot
|
||||
);
|
||||
|
||||
function mergeAttributeTimestamps(p, attrs) {
|
||||
let cur = allDeclareAttributeTimestamps.get(p);
|
||||
@@ -1118,7 +1114,9 @@ function rpcRequest(sessionContext, _declarations, callback) {
|
||||
|
||||
let toClear;
|
||||
|
||||
const allVirtualParameters = virtualParametersCache.get(sessionContext);
|
||||
const allVirtualParameters = localCache.getVirtualParameters(
|
||||
sessionContext.cacheSnapshot
|
||||
);
|
||||
|
||||
vpd = vpd.filter(declaration => {
|
||||
if (Object.keys(allVirtualParameters).length) {
|
||||
@@ -2595,18 +2593,8 @@ function rpcFault(sessionContext, id, faultResponse, callback) {
|
||||
}
|
||||
|
||||
function deserialize(sessionContextString, callback) {
|
||||
localCache.getProvisionsAndVirtualParameters(
|
||||
(err, hash, provisions, virtualParameters) => {
|
||||
if (err) return void callback(err);
|
||||
|
||||
const sessionContext = JSON.parse(sessionContextString);
|
||||
|
||||
if (sessionContext.presetsHash && sessionContext.presetsHash !== hash)
|
||||
return void callback(new Error("Preset hash mismatch"));
|
||||
|
||||
provisionsCache.set(sessionContext, provisions);
|
||||
virtualParametersCache.set(sessionContext, virtualParameters);
|
||||
|
||||
for (const decs of sessionContext.declarations)
|
||||
for (const d of decs) common.addPathMeta(d.path);
|
||||
|
||||
@@ -2625,9 +2613,10 @@ function deserialize(sessionContextString, callback) {
|
||||
}
|
||||
|
||||
sessionContext.deviceData = deviceData;
|
||||
callback(null, sessionContext);
|
||||
}
|
||||
);
|
||||
// Ensure cache is populated
|
||||
localCache.getCurrentSnapshot(err => {
|
||||
callback(err, sessionContext);
|
||||
});
|
||||
}
|
||||
|
||||
function serialize(sessionContext, callback) {
|
||||
|
||||
Reference in new issue
Block a user