Skip to content

Instantly share code, notes, and snippets.

@andrevinsky
Last active October 6, 2016 14:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save andrevinsky/f9a2b701e6c629ade182710541570386 to your computer and use it in GitHub Desktop.
Save andrevinsky/f9a2b701e6c629ade182710541570386 to your computer and use it in GitHub Desktop.
const KEYS = {
key: 'k',
invoked: 'i',
fulfilled: 'f',
depsOn: 'd',
notify: 'n'
};
function ackProducer(handle, { hashMap = {}, lastKey = null } = {}, diag) {
const state = { hashMap, lastKey };
return makeAck;
// or:
// return { makeAck, ack, getState }
function makeAck() {
const key = (arguments.length == 1) ? ('' + arguments[0]) : Math.random().toString().substr(2);
const dependsOn = state.lastKey;
state.lastKey = key;
state.hashMap[key] = {
[KEYS.key]: key,
[KEYS.invoked]: false,
[KEYS.fulfilled]: false,
[KEYS.depsOn]: dependsOn,
[KEYS.notify]: null
};
diag && diag('Produced ack: ' + key, state);
return getAckForKey(key);
// or:
// return key;
}
function ack(key) {
return getAckForKey(key)();
}
function getState() {
return state;
}
function getAckForKey(key) {
return function () {
diag && diag('Called ack: ' + key);
// no action if there isn't this node or it has been executed once
const node = keyToNode(key);
if (!node || node[KEYS.invoked]) {
return;
}
// need only mark it as invoked and attempt to handle the action
node[KEYS.invoked] = true;
diag && diag('Called & processing ack: ' + key, state);
maybeHandleKey(key);
};
}
function maybeHandleKey(key) {
const node = keyToNode(key); // it is ensured to be there by all outer calls
// only these props matter here
const {
[KEYS.depsOn]: depsOn, // node this one depends on
[KEYS.notify]: notify // node that will be notified if this one gets fulfilled
} = node;
const depNode = keyToNode(depsOn);
// if the key exists and not the node this one depends on,
// we clean it out
if (depsOn && !depNode) {
node[KEYS.depsOn] = null; // cleaning
}
// if this node depends on no node or the one it depends on is fulfilled
// it means this node gets fulfilled as well
if (!depNode || depNode[KEYS.fulfilled]) {
node[KEYS.fulfilled] = true;
}
if (node[KEYS.fulfilled]) {
// if we determined this node is fulfilled
// we need to call a handler with the key
handle(key);
diag && diag('Fulfilling ack: ' + key, state);
// .. remove this node from the hashMap
delete state.hashMap[key];
// and if there is a node to notify, we notify it
notify && maybeHandleKey(notify);
diag && diag('Fulfilled ack: ' + key, state);
} else {
// otherwise, we update the node this one depends on
// to notify this one once it gets fulfilled
if (depNode) {
depNode[KEYS.notify] = key;
}
diag && diag('Pending fulfilling ack: ' + key, state);
}
}
function keyToNode(key) {
return state.hashMap[key];
}
}
function handle(type, key) {
console.log('Acked: T<' + type + '>: ' + key);
}
function diag (type, msg, { hashMap } = {}) {
// if (!hashMap) {
// return;
// }
// console.log(type, msg, JSON.stringify(hashMap || null));
// const results = Object.keys(hashMap).map(k => hashMap[k]).filter(o => (o[KEYS.depsOn].length > 1) || (o[KEYS.notify].length > 1))
// if (results.length) {
// console.warn(results);
// }
}
function timed(fn) {
return function() {
const startTime = new Date() - 0;
fn()
console.log('Execution took ' + (new Date() - startTime) + 'ms');
}
}
const typeAcksGen = {
'type0': ackProducer(handle.bind(null, 'type0'), undefined, diag.bind(null, 'type0')),
'type1': ackProducer(handle.bind(null, 'type1'), undefined, diag.bind(null, 'type1')),
'type2': ackProducer(handle.bind(null, 'type2'), undefined, diag.bind(null, 'type2'))
};
// const acksHere = ackProducer(handle, function(msg, state) {
// console.log(msg, JSON.stringify(state || null));
// });
timed(function(){
let acks = Array(200).fill(0).map((v, k) => typeAcksGen['type' + (k % 3)](k));
while (acks.length) {
const idx = Math.floor(Math.random() * acks.length);
const ack = acks.splice(idx, 1);
ack[0] && ack[0]();
}
})();
// const ack1 = acksHere('1');
// const ack2 = acksHere('2');
// const ack3 = acksHere('3');
// const ack4 = acksHere('4');
// ack4();
// const ack5 = acksHere('5');
// ack2();
// ack3();
// ack1();
// ack5();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment