Improve set and clear data model functions

This commit is contained in:
Zaid Abdulla committed 2017-08-04 19:29:25 -07:00
1 parent 4eb1c61c4b
commit 7306f7a8a5
2 files changed
+106 -98

No files matched your search

+88 -94
View File
@@ -22,9 +22,9 @@ const common = require('./common');
const CHANGE_FLAGS = {
object: 4,
writable: 16,
value: 64
object: 2,
writable: 4,
value: 8
};
@@ -63,6 +63,7 @@ function sanitizeParameterValue(parameterValue) {
throw new Error(`Parameter value type "${parameterValue[1]}" not recognized.`);
parameterValue[0] = JSON.parse(JSON.stringify(parameterValue[0]));
break;
}
}
return parameterValue;
@@ -171,36 +172,59 @@ function unpack(deviceData, path, revision) {
}
function clear(deviceData, path, timestamp, attributes) {
for (let p of deviceData.paths.find(path, true, true, timestamp ? 99 : path.length)) {
for (let k in deviceData.trackers.get(p))
deviceData.changes.add(k);
function clear(deviceData, path, timestamp, attributes, changeFlags = 0) {
let changeTrackers = {};
let t = deviceData.timestamps.get(p);
if (!t)
timestamp = timestamp || 0;
let descendantsTimestamp = timestamp;
if (attributes && attributes.object) {
if (attributes.object > descendantsTimestamp)
descendantsTimestamp = attributes.object;
if (!(attributes.object <= attributes.value))
attributes.value = attributes.object;
}
for (let p of deviceData.paths.find(path, true, true, descendantsTimestamp ? 99 : path.length)) {
let tracker = deviceData.trackers.get(p);
for (let k in tracker)
changeTrackers[k] |= tracker[k];
let currentTimestamp = deviceData.timestamps.get(p);
if (currentTimestamp === undefined)
continue;
if (!(timestamp <= t)) {
if (timestamp > currentTimestamp ||
(descendantsTimestamp > currentTimestamp && p.length > path.length)) {
deviceData.timestamps.delete(p);
deviceData.attributes.delete(p);
} else if (t && attributes) {
changeFlags |= 1;
}
else if (attributes && p.length == path.length) {
let currentAttributes = deviceData.attributes.get(p);
if (currentAttributes) {
let newAttrs;
for (let attrName in attributes) {
if (attrName in currentAttributes &&
attributes[attrName][0] > currentAttributes[attrName][0]) {
if (!newAttrs)
newAttrs = JSON.parse(JSON.stringify(currentAttributes));
attributes[attrName] > currentAttributes[attrName][0]) {
changeFlags |= CHANGE_FLAGS[attrName];
if (!newAttrs) {
newAttrs = Object.assign({}, currentAttributes);
deviceData.attributes.set(p, newAttrs);
}
delete newAttrs[attrName];
}
}
if (newAttrs)
deviceData.attributes.set(p, newAttrs);
}
}
}
// Note: For performance, we're merging all changes together rather than
// mark changes based the exact parameters affected.
for (let k in changeTrackers) {
if (changeTrackers[k] & changeFlags)
deviceData.changes.add(k);
}
}
@@ -227,9 +251,11 @@ function set(deviceData, path, timestamp, attributes, toClear) {
if (path.wildcard)
attributes = undefined;
else
else if (currentTimestamp)
currentAttributes = deviceData.attributes.get(path);
let changeFlags = 0;
if (attributes) {
if (attributes.value && attributes.value[1]
&& attributes.value[0] >= (attributes.object ? attributes.object[0] : 0))
@@ -239,67 +265,29 @@ function set(deviceData, path, timestamp, attributes, toClear) {
&& attributes.object[0] >= (attributes.value ? attributes.value[0] : 0))
attributes.value = [attributes.object[0]];
if (currentAttributes) {
let changeFlags = 0;
let newAttributes = Object.assign({}, currentAttributes, attributes);
if (currentAttributes) {
for (let attrName in attributes) {
timestamp = Math.max(timestamp, attributes[attrName][0]);
if (attrName in currentAttributes) {
if (attributes[attrName][0] > currentAttributes[attrName][0]) {
changeFlags |= CHANGE_FLAGS[attrName];
if (!compareEquality(attributes[attrName][1], currentAttributes[attrName][1]))
changeFlags |= CHANGE_FLAGS[attrName] << 1;
}
else
delete attributes[attrName];
}
else {
if (!(attrName in currentAttributes))
changeFlags |= CHANGE_FLAGS[attrName];
else if (attributes[attrName][0] <= currentAttributes[attrName][0])
newAttributes[attrName] = currentAttributes[attrName];
else if (!compareEquality(attributes[attrName][1], currentAttributes[attrName][1]))
changeFlags |= CHANGE_FLAGS[attrName];
changeFlags |= CHANGE_FLAGS[attrName] << 1;
}
}
if (Object.keys(attributes).length) {
if (attributes.object && currentAttributes.object &&
attributes.object[1] !== currentAttributes.object[1]) {
toClear = toClear || [];
toClear.push([path.concat('*'), attributes.object[0]]);
}
for (let attrName in currentAttributes)
if (!(attrName in attributes))
attributes[attrName] = currentAttributes[attrName];
deviceData.attributes.set(path, attributes);
}
if (timestamp > currentTimestamp) {
changeFlags |= 1;
deviceData.timestamps.set(path, timestamp);
if (path.length > 1)
toClear = set(deviceData, path.slice(0, path.length - 1), timestamp,
{object: [timestamp, 1]}, toClear);
}
if (changeFlags)
for (let sup of deviceData.paths.find(path, true, false)) {
let c = deviceData.trackers.get(sup);
for (let k in c)
if (c[k] & changeFlags) {
deviceData.changes.add(k);
}
}
}
else if (!(timestamp <= currentTimestamp)) {
deviceData.timestamps.set(path, timestamp);
deviceData.attributes.set(path, attributes);
else
changeFlags |= 1;
deviceData.attributes.set(path, newAttributes);
if (!(timestamp <= currentTimestamp)) {
deviceData.timestamps.set(path, timestamp);
if (path.length > 1)
toClear = set(deviceData, path.slice(0, path.length - 1), timestamp,
{object: [timestamp, 1]}, toClear);
toClear = toClear || [];
toClear.push([path, timestamp]);
}
}
else if (!(timestamp <= currentTimestamp)) {
@@ -307,43 +295,49 @@ function set(deviceData, path, timestamp, attributes, toClear) {
if (currentAttributes) {
deviceData.attributes.delete(path);
toClear = toClear || [];
toClear.push([path, timestamp]);
changeFlags |= 1;
}
if (path.wildcard)
for (let sub of deviceData.paths.find(path, false, true))
if (timestamp > deviceData.timestamps.get(sub)) {
deviceData.timestamps.delete(sub);
if (deviceData.attributes.delete(sub)) {
toClear = toClear || [];
toClear.push([sub, timestamp]);
}
else if (path.wildcard) {
for (let p of deviceData.paths.find(path, false, true, path.length))
if (timestamp > deviceData.timestamps.get(p)) {
toClear = toClear || [];
toClear.push([p, timestamp]);
}
}
}
if (changeFlags) {
if (changeFlags & 1) {
toClear = toClear || [];
toClear.push([path, timestamp, null, changeFlags]);
}
else if (changeFlags & CHANGE_FLAGS.object) {
toClear = toClear || [];
toClear.push([path, 0, {object: attributes.object[0]}, changeFlags]);
}
else {
for (let p of deviceData.paths.find(path, true, false, path.length)) {
let tracker = deviceData.trackers.get(p);
for (let k in tracker) {
if (tracker[k] & changeFlags)
deviceData.changes.add(k);
}
}
}
}
return toClear;
}
function track(deviceData, path, marker, timestamp, attributeTimestamps, exist, attributeValues) {
function track(deviceData, path, marker, attributes) {
path = deviceData.paths.add(path);
let f = 0;
let f = 1;
if (timestamp)
f |= 1;
if (exist)
f |= 2;
if (attributeTimestamps)
for (let attrName of attributeTimestamps)
if (attributes)
for (let attrName of attributes)
f |= CHANGE_FLAGS[attrName];
if (attributeValues)
for (let attrName of attributeValues)
f |= CHANGE_FLAGS[attrName] << 1;
let cur = deviceData.trackers.get(path);
if (!cur) {
cur = {};