Skip to content

Commit

Permalink
Start incorporating revised API from #10
Browse files Browse the repository at this point in the history
  • Loading branch information
inexorabletash committed Nov 6, 2017
1 parent 7a5377d commit b116905
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 62 deletions.
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,13 +90,13 @@ granted.

```js
async function get_lock_then_write() {
await requestLock('resource', async lock => {
await locks.acquire('resource', async lock => {
await async_write_func();
});
}

async function get_lock_then_read() {
await requestLock('resource', async lock => {
await locks.acquire('resource', async lock => {
await async_read_func();
}, {mode: 'shared'});
}
Expand All @@ -122,7 +122,7 @@ const controller = new AbortController();
setTimeout(() => controller.abort(), 200); // wait at most 200ms

try {
await requestLock('resource', async lock => {
await locks.acquire('resource', async lock => {
// Use |lock| here.
}, {signal: controller.signal});
// Done with lock here.
Expand Down Expand Up @@ -159,23 +159,23 @@ around formalizing these states and notifications.
*How do you _compose_ IndexedDB transactions with these locks?*

* To wrap a lock around a transaction:

```js
requestLock(scope, lock => {
locks.acquire(scope, lock => {
return new Promise((resolve, reject) => {
const tx = db.transaction(...);
tx.oncomplete = resolve;
tx.onabort = e => reject(tx.error);
tx.onabort = e => reject(tx.error);
// use tx...
});
}, options);
```

* To wrap a transaction around a lock is harder, since you can't keep an IndexedDB transaction alive arbitrarily. If [transactions supported `waitUntil()`](https://github.com/inexorabletash/indexeddb-promises) this would be possible:

```js
const tx = db.transaction(...);
tx.waitUntil(requestLock(scope, async lock => {
tx.waitUntil(locks.acquire(scope, async lock => {
// use lock and tx
}, options);
```
Expand Down
72 changes: 21 additions & 51 deletions interface.webidl
Original file line number Diff line number Diff line change
@@ -1,70 +1,40 @@
//
// Common
//

enum LockMode { "shared", "exclusive" };

dictionary LockOptions {
LockMode mode = "exclusive";
boolean ifAvailable = false;
AbortSignal signal;
partial interface Navigator {
[SecureContext] readonly attribute LockManager locks;
};

// ======================================================================
// Proposal 1 - Auto-Release with waitUntil()
//

[SecureContext]
interface LockManager {
Promise<any> acquire((DOMString or sequence<DOMString>) scope,
LockRequestCallback callback,
optional LockOptions options);

partial interface WindowOrWorkerGlobalScope {
[SecureContext]
Promise<Lock> requestLock((DOMString or sequence<DOMString>) scope,
optional LockOptions options);
Promise<LockState> queryState();
void forceRelease((DOMString or sequence<DOMString>) scope);
};

[SecureContext, Exposed=(Window,Worker)]
interface Lock {
readonly attribute FrozenArray<DOMString> scope;
readonly attribute LockMode mode;
readonly attribute Promise<void> released;

void waitUntil(Promise<any> p);
};
callback LockRequestCallback = Promise<any> (Lock lock);

// ======================================================================
// Proposal 2 - Explicit Release
//
enum LockMode { "shared", "exclusive" };

partial interface WindowOrWorkerGlobalScope {
[SecureContext]
Promise<Lock> requestLock((DOMString or sequence<DOMString>) scope,
optional LockOptions options);
dictionary LockOptions {
LockMode mode = "exclusive";
boolean ifAvailable = false;
AbortSignal signal;
};

[SecureContext, Exposed=(Window,Worker)]
interface Lock {
readonly attribute FrozenArray<DOMString> scope;
readonly attribute LockMode mode;
readonly attribute Promise<void> released;

void release();
};

// ======================================================================
// Proposal 3 - Scoped Release
//

callback LockRequestCallback = Promise<any> (Lock lock);

partial interface WindowOrWorkerGlobalScope {
[SecureContext]
Promise<any> requestLock((DOMString or sequence<DOMString>) scope,
LockRequestCallback callback,
optional LockOptions options);
dictionary LockState {
held sequence<LockRequest>;
pending sequence<LockRequest>;
};

[SecureContext, Exposed=(Window,Worker)]
interface Lock {
readonly attribute FrozenArray<DOMString> scope;
readonly attribute LockMode mode;
readonly attribute Promise<void> released;
dictionary LockRequest {
sequence<DOMString> scope;
LockMode mode;
};
20 changes: 17 additions & 3 deletions proto-spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,10 @@ Returns a frozen array containing the DOMStrings from the associated **scope** o

Returns a DOMString containing the associated **mode** of the **lock**.

#### `requestLock(scope, callback, options)`
#### `LockManager.prototype.acquire(scope, callback, options)`

1. Let _origin_ be the origin of the global scope.
2. If _origin_ is an opaque origin, return a promise rejected with a "`SecurityError`" DOMException and abort these steps.
2. If _origin_ is an opaque origin, return a Promise rejected with a "`SecurityError`" DOMException and abort these steps.
3. Let _scope_ be the set of unique DOMStrings in `scope` if a sequence was passed, otherwise a set containing just the string passed as `scope`
4. If _scope_ is empty, return a new Promise rejected with `TypeError`
5. Return the result of running the **request a lock** algorithm, passing _origin_, _callback_, _scope_, _option_'s _mode_, _option_'s _ifAvailable_, and _options_'s _signal_ (if present).
Expand All @@ -66,7 +66,7 @@ Returns a DOMString containing the associated **mode** of the **lock**.

To *request a lock* with _origin_, _callback_, _scope_, _mode_, _ifAvailable_, and optional _signal_:

1. Let _p_ be a new promise.
1. Let _p_ be a new Promise.
2. Let _queue_ be _origin_'s **lock request queue**.
2. Let _held_ be _origin_'s **held lock set**.
3. Let _request_ be a new **lock request** (_scope_, _mode_).
Expand Down Expand Up @@ -100,3 +100,17 @@ To *request a lock* with _origin_, _callback_, _scope_, _mode_, _ifAvailable_, a
> TODO: Define how a lock held in a terminated agent is released.
> TODO: More explicitly define _"in the origin"_
#### `LockManager.prototype.queryState()`

1. Let _origin_ be the origin of the global scope.
2. Let _p_ be a new Promise.
3. Let _queue_ be _origin_'s **lock request queue**.
4. Let _held_ be _origin_'s **held lock set**.
5. Run the following in parallel:
1. _TODO: Define producing LockRequest instances from held/queue._
2. ...
6. Return _p_.


> TODO: `LockManager.prototype.forceRelease()`

0 comments on commit b116905

Please sign in to comment.