UNPKG

rw-resource

Version:

A simple helper to protect access to a resource across async operations

121 lines 3.63 kB
"use strict"; // let debug = require('debug')('rw-resource'); Object.defineProperty(exports, "__esModule", { value: true }); class NotLockedError extends Error { constructor(msg) { super(msg); this.name = 'NotLockedError'; } } exports.NotLockedError = NotLockedError; class RWRes { constructor(initialValue) { /* The actual value */ this.value = initialValue; /* Current counts */ this.readers = 0; this.writers = 0; /* Queues of promises resolve callbacks to be resolved when the resource becomes available. */ this.exclusiveWaiters = []; this.waiters = []; } take(exclusive) { return new Promise((resolve, reject) => { if (exclusive) { if (this.readers === 0 && this.writers === 0) { /* Nothing else is accessing the resource now, so exclusive access is available. */ this.writers++; resolve(this.value); } else { /* This can't be resolved yet */ this.exclusiveWaiters.push(resolve); } } else { if (this.writers === 0 && this.exclusiveWaiters.length === 0) { /* Nothing has exclusive access now, and nothing is waiting for exclusive access so read access can be given. */ this.readers++; resolve(this.value); } else { /* This can't be resolved yet */ this.waiters.push(resolve); } } }); } leave() { if (this.writers) { this.writers--; } else if (this.readers) { this.readers--; } else { throw new NotLockedError("Resource released that was not in use"); } /* If something is waiting for exclusive access then that should be granted first. */ if (this.writers === 0 && this.readers === 0 && this.exclusiveWaiters.length > 0) { this.giveExclusive(); return; } /* If nothing has exclusive access, and nothing is waiting for it then we can give out read access to anything that is waiting. */ if (this.writers === 0 && this.exclusiveWaiters.length === 0) { this.giveReaders(); return; } } lock(exclusive) { let lock = this; return lock.take(exclusive) .then((value) => { return (() => { if (lock) { /* Only the first caller gets to act on the lock */ let l = lock; lock = null; l.leave(); } }); }); } giveExclusive() { let w; if ((w = this.exclusiveWaiters.shift())) { this.writers++; w(this.value); } } giveReaders() { let w; while ((w = this.waiters.shift())) { this.readers++; w(this.value); } } check() { return this.readers + this.writers + this.waiters.length + this.exclusiveWaiters.length; } } exports.default = RWRes; //# sourceMappingURL=index.js.map