From b7370a6fb980ad3c8aeaaedb5a1cfa9ae90a8ce0 Mon Sep 17 00:00:00 2001 From: Zaid Abdulla Date: Mon, 12 Sep 2016 02:22:25 -0700 Subject: [PATCH] Reimplement and optimize device.set --- lib/common.coffee | 2 + lib/device.js | 156 ++++++++++++++++++++++------------------------ 2 files changed, 75 insertions(+), 83 deletions(-) diff --git a/lib/common.coffee b/lib/common.coffee index 2abefe1..3262db4 100644 --- a/lib/common.coffee +++ b/lib/common.coffee @@ -270,6 +270,8 @@ parsePath = (pattern, start, res) -> addPathMeta = (path) -> + return path if path.alias? or path.wildcard? + path.alias = 0 path.wildcard = 0 diff --git a/lib/device.js b/lib/device.js index 3e925a3..b5c6adb 100644 --- a/lib/device.js +++ b/lib/device.js @@ -16,6 +16,8 @@ */ "use strict"; +const common = require('./common'); + function sanitizeParameterValue(parameterValue) { if (parameterValue[0] != null) { @@ -62,6 +64,7 @@ function sanitizeParameterValue(parameterValue) { function inferTimestamps(deviceData, path) { + common.addPathMeta(path); var res = {}; for (let sup of deviceData.paths.superset(path)) { @@ -73,7 +76,7 @@ function inferTimestamps(deviceData, path) { } for (let i = path.length - 1; i > 0; -- i) { - if (path.wildcard & ((2 << i) - 1) === 0) + if ((path.wildcard & ((1 << i) - 1)) == 0) break; let param = null; @@ -235,8 +238,8 @@ function invalidateSuperset(deviceData, path, attributes) { for (let attrName in deviceData.timestamps) { let t = deviceData.timestamps[attrName].get(sup); if (t <= attributes[attrName] || t <= attributes.exist) { - deviceData.timestamps[attrName].delete(sup); - deviceData.values[attrName].delete(sup); + deviceData.timestamps[attrName].delete(sup); + deviceData.values[attrName].delete(sup); } } } @@ -244,10 +247,6 @@ function invalidateSuperset(deviceData, path, attributes) { function normalizeAttributes(timestamps, values) { - // TODO Consider moving implemention within set function - if (!values) - return; - if ('value' in values && timestamps.value >= (timestamps.object || 0)) { values.object = 0; timestamps.object = timestamps.value; @@ -276,86 +275,82 @@ function normalizeAttributes(timestamps, values) { function set(deviceData, path, timestamps, values) { - // TODO Optimize - // TODO Allow overwriting attribute value with same timestamp - if (values == null) - values = {}; - path = deviceData.paths.add(path); - - if (!path.wildcard) { - normalizeAttributes(timestamps, values); - if (values.exist && path.length > 1) - set(deviceData, path.slice(0, path.length - 1), - {exist: timestamps.exist, object: timestamps.exist}, - {exist: 1, object: 1}); - } - - var current = inferTimestamps(deviceData, path); - - for (let c in current) - if (current[c] > timestamps[c] || (current[c] == timestamps[c] && path.wildcard > 0)) - delete timestamps[c]; - - if (timestamps.exist != null) { - deviceData.timestamps.exist.set(path, timestamps.exist); - if (values.exist != null) - deviceData.values.exist.set(path, values.exist); - } - - current = inferTimestamps(deviceData, path); - - for (let c in current) - if (current[c] > timestamps[c] || (current[c] == timestamps[c] && path.wildcard > 0)) - delete timestamps[c]; + if (path.wildcard || values == null) + values = {}; let toInvalidate = new Map(); - for (let sub of deviceData.paths.subset(path, 0)) { - if (path.wildcard == sub.wildcard) - continue; + if (values.exist) { + normalizeAttributes(timestamps, values); + if (timestamps.exist && path.length > 1) { + set(deviceData, path.slice(0, path.length - 1), + {exist: timestamps.exist, object: timestamps.exist}, + {exist: 1, object: 1}); + } for (let attrName in timestamps) { - if (deviceData.timestamps[attrName].get(sub) <= timestamps[attrName]) { - - if (sub.wildcard || !deviceData.values[attrName].has(sub)) - deviceData.timestamps[attrName].delete(sub); - else if (deviceData.timestamps[attrName].get(sub) < timestamps[attrName]) { - deviceData.timestamps[attrName].delete(sub); - deviceData.values[attrName].delete(sub); - let inv = toInvalidate.get(sub) || {}; - if (!timestamps[attrName] <= inv[attrName]) { - inv[attrName] = timestamps[attrName]; - toInvalidate.set(sub, inv); - } - } + if (deviceData.values[attrName].has(path) != (attrName in values)) { + let inv = toInvalidate.get(path); + if (inv == null) + toInvalidate.set(path, inv = {}); + inv[attrName] = timestamps[attrName]; + if (!(attrName in values)) + deviceData.values[attrName].delete(path); } } } + else { + // Clear redundant timestamps + let current = inferTimestamps(deviceData, path); + for (let c in timestamps) + if (timestamps[c] <= current[c]) + delete timestamps[c]; + else if (c != 'exist' && + (timestamps[c] <= timestamps.exist || timestamps[c] <= current.exist)) + delete timetamps[c]; - for (let attrName in timestamps) { - let existing = deviceData.timestamps[attrName].get(path); + // Clear redundant subsets and deleted params + for (let sub of deviceData.paths.subset(path)) { + if (path.wildcard == sub.wildcard) + continue; - if (existing == null || timestamps[attrName] >= existing) { - deviceData.timestamps[attrName].set(path, timestamps[attrName]); - let invalidate = false; - if (values[attrName] != null) { - if (!deviceData.values[attrName].has(path)) - invalidate = true; - deviceData.values[attrName].set(path, values[attrName]); + if (deviceData.values.exist.has(sub)) { + let existTimestamp = deviceData.timestamps.exist.get(sub); + for (let attrName in timestamps) { + if (timestamps[attrName] > existTimestamp) { + let inv = toInvalidate.get(sub); + if (inv == null) + toInvalidate.set(sub, inv = {}); + for (let attrName in deviceData.timestamps) { + inv[attrName] = timestamps[attrName]; + deviceData.timestamps[attrName].delete(sub); + deviceData.values[attrName].delete(sub); + } + break; + } + + if (timestamps[attrName] > deviceData.timestamps[attrName].get(sub)) + if (deviceData.values[attrName].has(sub)) { + let inv = toInvalidate.get(sub); + if (inv == null) + toInvalidate.set(sub, inv = {}); + inv[attrName] = timestamps[attrName]; + deviceData.values[attrName].delete(sub); + } + } } else { - if (deviceData.values[attrName].has(path)) { - invalidate = true; - deviceData.values[attrName].delete(path); - } - } + for (let attrName in timestamps) { + if (attrName == 'exist') { + for (let an in deviceData.timestamps) + if (timestamps[attrName] > deviceData.timestamps[an].get(sub)) + deviceData.timestamps[an].delete(sub); + continue; + } - if (invalidate) { - let inv = toInvalidate.get(path) || {}; - if (!(timestamps[attrName] <= inv[attrName])) { - inv[attrName] = timestamps[attrName]; - toInvalidate.set(path, inv); + if (timestamps[attrName] > deviceData.timestamps[attrName].get(sub)) + deviceData.timestamps[attrName].delete(sub); } } } @@ -365,16 +360,11 @@ function set(deviceData, path, timestamps, values) { invalidateSuperset(deviceData, p, a); }); - // TODO recalculate descendant superset - // var depth = 0; - // if (timestamps.exist != null) - // depth = 99; - // - // for (let sup of deviceData.paths.superset(path, depth)) { - // if ((sup.wildcard && (3 << path.length) - 1) != path.wildcard) { - // throw new Error('Not implemented'); - // } - // } + for (let attrName in timestamps) { + deviceData.timestamps[attrName].set(path, timestamps[attrName]); + if (attrName in values) + deviceData.values[attrName].set(path, values[attrName]); + } }