Defer tail declarations

declare() calls that aren't followed by commit() are applied at the end
of the provision script. This change defers those until all provisions
have been executed. This prevents certain cases of preset loop faults.
This commit is contained in:
Zaid Abdulla committed 2018-09-15 00:09:58 -07:00
1 parent ec215ffb82
commit 1a56915d4b
5 files changed
+163 -83

No files matched your search

+49 -32
View File
@@ -588,6 +588,7 @@ function runProvisions(
if ((counter -= 2) === 1) {
allDeclarations = Array.prototype.concat.apply([], allDeclarations);
if (done) for (const d of allDeclarations) d.defer = false;
allClear = Array.prototype.concat.apply([], allClear);
callback(null, null, done, allDeclarations, allClear);
}
@@ -597,6 +598,7 @@ function runProvisions(
if ((counter -= 2) === 1) {
allDeclarations = Array.prototype.concat.apply([], allDeclarations);
if (done) for (const d of allDeclarations) d.defer = false;
allClear = Array.prototype.concat.apply([], allClear);
callback(null, null, done, allDeclarations, allClear);
}
@@ -720,6 +722,7 @@ function runVirtualParameters(
if ((counter -= 2) === 1) {
allDeclarations = Array.prototype.concat.apply([], allDeclarations);
if (done) for (const d of allDeclarations) d.defer = false;
allClear = Array.prototype.concat.apply([], allClear);
callback(
null,
@@ -735,6 +738,7 @@ function runVirtualParameters(
if ((counter -= 2) === 1) {
allDeclarations = Array.prototype.concat.apply([], allDeclarations);
if (done) for (const d of allDeclarations) d.defer = false;
allClear = Array.prototype.concat.apply([], allClear);
callback(
null,
@@ -787,10 +791,10 @@ function runDeclarations(sessionContext, declarations) {
}
}
function mergeAttributeValues(p, attrs) {
function mergeAttributeValues(p, attrs, defer) {
let cur = allDeclareAttributeValues.get(p);
if (!cur) {
allDeclareAttributeValues.set(p, attrs);
if (!defer) allDeclareAttributeValues.set(p, attrs);
} else {
cur = Object.assign({}, cur, attrs);
allDeclareAttributeValues.set(p, cur);
@@ -798,7 +802,7 @@ function runDeclarations(sessionContext, declarations) {
}
for (const declaration of declarations) {
let path = common.addPathMeta(declaration[0]);
let path = common.addPathMeta(declaration.path);
let unpacked;
if ((path.alias | path.wildcard) & 1 || path[0] === "VirtualParameters") {
@@ -817,17 +821,20 @@ function runDeclarations(sessionContext, declarations) {
sessionContext.deviceData.paths.add(["FactoryReset"]);
if (path.alias) {
const aliasDecs = device.getAliasDeclarations(path, declaration[1] || 1);
const aliasDecs = device.getAliasDeclarations(
path,
declaration.pathGet || 1
);
for (const ad of aliasDecs) {
const p = sessionContext.deviceData.paths.add(ad[0]);
const p = sessionContext.deviceData.paths.add(ad.path);
allDeclareTimestamps.set(
p,
Math.max(ad[1] || 1, allDeclareTimestamps.get(p) || 0)
Math.max(ad.pathGet || 1, allDeclareTimestamps.get(p) || 0)
);
let attrTrackers;
if (ad[2]) {
attrTrackers = Object.keys(ad[2]);
mergeAttributeTimestamps(p, ad[2]);
if (ad.attrGet) {
attrTrackers = Object.keys(ad.attrGet);
mergeAttributeTimestamps(p, ad.attrGet);
}
device.track(
@@ -842,38 +849,41 @@ function runDeclarations(sessionContext, declarations) {
for (const u of unpacked) {
allDeclareTimestamps.set(
u,
Math.max(declaration[1] || 1, allDeclareTimestamps.get(u) || 0)
Math.max(declaration.pathGet || 1, allDeclareTimestamps.get(u) || 0)
);
if (declaration[2]) mergeAttributeTimestamps(u, declaration[2]);
if (declaration.attrGet)
mergeAttributeTimestamps(u, declaration.attrGet);
}
} else {
path = sessionContext.deviceData.paths.add(path);
allDeclareTimestamps.set(
path,
Math.max(declaration[1] || 1, allDeclareTimestamps.get(path) || 0)
Math.max(declaration.pathGet || 1, allDeclareTimestamps.get(path) || 0)
);
if (declaration[2]) mergeAttributeTimestamps(path, declaration[2]);
if (declaration.attrGet)
mergeAttributeTimestamps(path, declaration.attrGet);
device.track(sessionContext.deviceData, path, "prerequisite");
}
if (declaration[4]) {
if (declaration.attrSet) {
if (path.alias | path.wildcard) {
if (!unpacked)
unpacked = device.unpack(sessionContext.deviceData, path);
for (const u of unpacked) mergeAttributeValues(u, declaration[4]);
for (const u of unpacked)
mergeAttributeValues(u, declaration.attrSet, declaration.defer);
} else {
mergeAttributeValues(path, declaration[4]);
mergeAttributeValues(path, declaration.attrSet, declaration.defer);
}
}
if (declaration[3] != null) {
if (declaration.pathSet != null) {
let minInstances, maxInstances;
if (Array.isArray(declaration[3])) {
minInstances = declaration[3][0];
maxInstances = declaration[3][1];
if (Array.isArray(declaration.pathSet)) {
minInstances = declaration.pathSet[0];
maxInstances = declaration.pathSet[1];
} else {
minInstances = maxInstances = declaration[3];
minInstances = maxInstances = declaration.pathSet;
}
let parent = common.addPathMeta(path.slice(0, -1));
@@ -903,7 +913,8 @@ function runDeclarations(sessionContext, declarations) {
unpacked,
keys,
minInstances,
maxInstances
maxInstances,
declaration.defer
);
} else {
const parentsUnpacked = device.unpack(
@@ -921,7 +932,8 @@ function runDeclarations(sessionContext, declarations) {
),
keys,
minInstances,
maxInstances
maxInstances,
declaration.defer
);
}
}
@@ -1002,14 +1014,15 @@ function rpcRequest(sessionContext, _declarations, callback) {
for (const d of decs) {
// Enforce max timestamp
if (d[1] > sessionContext.timestamp) d[1] = sessionContext.timestamp;
for (const [k, v] of Object.entries(d[2])) {
if (d.pathGet > sessionContext.timestamp)
d.pathGet = sessionContext.timestamp;
for (const [k, v] of Object.entries(d.attrGet)) {
if (v > sessionContext.timestamp)
d[2][k] = sessionContext.timestamp;
d.attrGet[k] = sessionContext.timestamp;
}
for (const ad of device.getAliasDeclarations(d[0], 1))
loadPath(sessionContext, ad[0]);
for (const ad of device.getAliasDeclarations(d.path, 1))
loadPath(sessionContext, ad.path);
}
clear(sessionContext, toClear, err => {
@@ -1032,8 +1045,8 @@ function rpcRequest(sessionContext, _declarations, callback) {
);
for (const d of _declarations) {
for (const ad of device.getAliasDeclarations(d[0], 1))
loadPath(sessionContext, ad[0]);
for (const ad of device.getAliasDeclarations(d.path, 1))
loadPath(sessionContext, ad.path);
}
return void loadParameters(sessionContext, err => {
@@ -2115,7 +2128,8 @@ function processInstances(
parameters,
keys,
minInstances,
maxInstances
maxInstances,
defer
) {
let instancesToCreate, instancesToDelete;
if (parent[0] === "Downloads") {
@@ -2136,6 +2150,9 @@ function processInstances(
}
}
if (defer && instancesToCreate.size === 0 && instancesToDelete.size === 0)
return;
let counter = 0;
for (const p of parameters) {
++counter;
@@ -2559,7 +2576,7 @@ function deserialize(sessionContextString, callback) {
virtualParametersCache.set(sessionContext, virtualParameters);
for (const decs of sessionContext.declarations)
for (const d of decs) common.addPathMeta(d[0]);
for (const d of decs) common.addPathMeta(d.path);
const deviceData = initDeviceData();
for (const r of sessionContext.deviceData) {