Buckets:
| const E_TIMEOUT = new Error('timeout while waiting for mutex to become available'); | |
| const E_ALREADY_LOCKED = new Error('mutex already locked'); | |
| const E_CANCELED = new Error('request for lock canceled'); | |
| var __awaiter$2 = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) { | |
| function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | |
| return new (P || (P = Promise))(function (resolve, reject) { | |
| function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | |
| function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | |
| function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | |
| step((generator = generator.apply(thisArg, _arguments || [])).next()); | |
| }); | |
| }; | |
| class Semaphore { | |
| constructor(_value, _cancelError = E_CANCELED) { | |
| this._value = _value; | |
| this._cancelError = _cancelError; | |
| this._queue = []; | |
| this._weightedWaiters = []; | |
| } | |
| acquire(weight = 1, priority = 0) { | |
| if (weight <= 0) | |
| throw new Error(`invalid weight ${weight}: must be positive`); | |
| return new Promise((resolve, reject) => { | |
| const task = { resolve, reject, weight, priority }; | |
| const i = findIndexFromEnd(this._queue, (other) => priority <= other.priority); | |
| if (i === -1 && weight <= this._value) { | |
| // Needs immediate dispatch, skip the queue | |
| this._dispatchItem(task); | |
| } | |
| else { | |
| this._queue.splice(i + 1, 0, task); | |
| } | |
| }); | |
| } | |
| runExclusive(callback_1) { | |
| return __awaiter$2(this, arguments, void 0, function* (callback, weight = 1, priority = 0) { | |
| const [value, release] = yield this.acquire(weight, priority); | |
| try { | |
| return yield callback(value); | |
| } | |
| finally { | |
| release(); | |
| } | |
| }); | |
| } | |
| waitForUnlock(weight = 1, priority = 0) { | |
| if (weight <= 0) | |
| throw new Error(`invalid weight ${weight}: must be positive`); | |
| if (this._couldLockImmediately(weight, priority)) { | |
| return Promise.resolve(); | |
| } | |
| else { | |
| return new Promise((resolve) => { | |
| if (!this._weightedWaiters[weight - 1]) | |
| this._weightedWaiters[weight - 1] = []; | |
| insertSorted(this._weightedWaiters[weight - 1], { resolve, priority }); | |
| }); | |
| } | |
| } | |
| isLocked() { | |
| return this._value <= 0; | |
| } | |
| getValue() { | |
| return this._value; | |
| } | |
| setValue(value) { | |
| this._value = value; | |
| this._dispatchQueue(); | |
| } | |
| release(weight = 1) { | |
| if (weight <= 0) | |
| throw new Error(`invalid weight ${weight}: must be positive`); | |
| this._value += weight; | |
| this._dispatchQueue(); | |
| } | |
| cancel() { | |
| this._queue.forEach((entry) => entry.reject(this._cancelError)); | |
| this._queue = []; | |
| } | |
| _dispatchQueue() { | |
| this._drainUnlockWaiters(); | |
| while (this._queue.length > 0 && this._queue[0].weight <= this._value) { | |
| this._dispatchItem(this._queue.shift()); | |
| this._drainUnlockWaiters(); | |
| } | |
| } | |
| _dispatchItem(item) { | |
| const previousValue = this._value; | |
| this._value -= item.weight; | |
| item.resolve([previousValue, this._newReleaser(item.weight)]); | |
| } | |
| _newReleaser(weight) { | |
| let called = false; | |
| return () => { | |
| if (called) | |
| return; | |
| called = true; | |
| this.release(weight); | |
| }; | |
| } | |
| _drainUnlockWaiters() { | |
| if (this._queue.length === 0) { | |
| for (let weight = this._value; weight > 0; weight--) { | |
| const waiters = this._weightedWaiters[weight - 1]; | |
| if (!waiters) | |
| continue; | |
| waiters.forEach((waiter) => waiter.resolve()); | |
| this._weightedWaiters[weight - 1] = []; | |
| } | |
| } | |
| else { | |
| const queuedPriority = this._queue[0].priority; | |
| for (let weight = this._value; weight > 0; weight--) { | |
| const waiters = this._weightedWaiters[weight - 1]; | |
| if (!waiters) | |
| continue; | |
| const i = waiters.findIndex((waiter) => waiter.priority <= queuedPriority); | |
| (i === -1 ? waiters : waiters.splice(0, i)) | |
| .forEach((waiter => waiter.resolve())); | |
| } | |
| } | |
| } | |
| _couldLockImmediately(weight, priority) { | |
| return (this._queue.length === 0 || this._queue[0].priority < priority) && | |
| weight <= this._value; | |
| } | |
| } | |
| function insertSorted(a, v) { | |
| const i = findIndexFromEnd(a, (other) => v.priority <= other.priority); | |
| a.splice(i + 1, 0, v); | |
| } | |
| function findIndexFromEnd(a, predicate) { | |
| for (let i = a.length - 1; i >= 0; i--) { | |
| if (predicate(a[i])) { | |
| return i; | |
| } | |
| } | |
| return -1; | |
| } | |
| var __awaiter$1 = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) { | |
| function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | |
| return new (P || (P = Promise))(function (resolve, reject) { | |
| function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | |
| function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | |
| function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | |
| step((generator = generator.apply(thisArg, _arguments || [])).next()); | |
| }); | |
| }; | |
| class Mutex { | |
| constructor(cancelError) { | |
| this._semaphore = new Semaphore(1, cancelError); | |
| } | |
| acquire() { | |
| return __awaiter$1(this, arguments, void 0, function* (priority = 0) { | |
| const [, releaser] = yield this._semaphore.acquire(1, priority); | |
| return releaser; | |
| }); | |
| } | |
| runExclusive(callback, priority = 0) { | |
| return this._semaphore.runExclusive(() => callback(), 1, priority); | |
| } | |
| isLocked() { | |
| return this._semaphore.isLocked(); | |
| } | |
| waitForUnlock(priority = 0) { | |
| return this._semaphore.waitForUnlock(1, priority); | |
| } | |
| release() { | |
| if (this._semaphore.isLocked()) | |
| this._semaphore.release(); | |
| } | |
| cancel() { | |
| return this._semaphore.cancel(); | |
| } | |
| } | |
| var __awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) { | |
| function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | |
| return new (P || (P = Promise))(function (resolve, reject) { | |
| function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | |
| function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | |
| function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | |
| step((generator = generator.apply(thisArg, _arguments || [])).next()); | |
| }); | |
| }; | |
| function withTimeout(sync, timeout, timeoutError = E_TIMEOUT) { | |
| return { | |
| acquire: (weightOrPriority, priority) => { | |
| let weight; | |
| if (isSemaphore(sync)) { | |
| weight = weightOrPriority; | |
| } | |
| else { | |
| weight = undefined; | |
| priority = weightOrPriority; | |
| } | |
| if (weight !== undefined && weight <= 0) { | |
| throw new Error(`invalid weight ${weight}: must be positive`); | |
| } | |
| return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () { | |
| let isTimeout = false; | |
| const handle = setTimeout(() => { | |
| isTimeout = true; | |
| reject(timeoutError); | |
| }, timeout); | |
| try { | |
| const ticket = yield (isSemaphore(sync) | |
| ? sync.acquire(weight, priority) | |
| : sync.acquire(priority)); | |
| if (isTimeout) { | |
| const release = Array.isArray(ticket) ? ticket[1] : ticket; | |
| release(); | |
| } | |
| else { | |
| clearTimeout(handle); | |
| resolve(ticket); | |
| } | |
| } | |
| catch (e) { | |
| if (!isTimeout) { | |
| clearTimeout(handle); | |
| reject(e); | |
| } | |
| } | |
| })); | |
| }, | |
| runExclusive(callback, weight, priority) { | |
| return __awaiter(this, void 0, void 0, function* () { | |
| let release = () => undefined; | |
| try { | |
| const ticket = yield this.acquire(weight, priority); | |
| if (Array.isArray(ticket)) { | |
| release = ticket[1]; | |
| return yield callback(ticket[0]); | |
| } | |
| else { | |
| release = ticket; | |
| return yield callback(); | |
| } | |
| } | |
| finally { | |
| release(); | |
| } | |
| }); | |
| }, | |
| release(weight) { | |
| sync.release(weight); | |
| }, | |
| cancel() { | |
| return sync.cancel(); | |
| }, | |
| waitForUnlock: (weightOrPriority, priority) => { | |
| let weight; | |
| if (isSemaphore(sync)) { | |
| weight = weightOrPriority; | |
| } | |
| else { | |
| weight = undefined; | |
| priority = weightOrPriority; | |
| } | |
| if (weight !== undefined && weight <= 0) { | |
| throw new Error(`invalid weight ${weight}: must be positive`); | |
| } | |
| return new Promise((resolve, reject) => { | |
| const handle = setTimeout(() => reject(timeoutError), timeout); | |
| (isSemaphore(sync) | |
| ? sync.waitForUnlock(weight, priority) | |
| : sync.waitForUnlock(priority)).then(() => { | |
| clearTimeout(handle); | |
| resolve(); | |
| }); | |
| }); | |
| }, | |
| isLocked: () => sync.isLocked(), | |
| getValue: () => sync.getValue(), | |
| setValue: (value) => sync.setValue(value), | |
| }; | |
| } | |
| function isSemaphore(sync) { | |
| return sync.getValue !== undefined; | |
| } | |
| // eslint-disable-next-lisne @typescript-eslint/explicit-module-boundary-types | |
| function tryAcquire(sync, alreadyAcquiredError = E_ALREADY_LOCKED) { | |
| // eslint-disable-next-line @typescript-eslint/no-explicit-any | |
| return withTimeout(sync, 0, alreadyAcquiredError); | |
| } | |
| export { E_ALREADY_LOCKED, E_CANCELED, E_TIMEOUT, Mutex, Semaphore, tryAcquire, withTimeout }; | |
Xet Storage Details
- Size:
- 11.2 kB
- Xet hash:
- b0a33c75614aa6917b45b642216a27101a5552954a7bf69644be16f742841084
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.