Skip to content

Commit

Permalink
Add new SAH and WFS locking modes
Browse files Browse the repository at this point in the history
Adds new locking modes for sync access handles and writable file
streams. Updates "file entry/take a lock" and "file entry/lock/release"
to support these new modes.
  • Loading branch information
Nathan Memmott committed Nov 13, 2023
1 parent b03688d commit bc3475c
Showing 1 changed file with 64 additions and 25 deletions.
89 changes: 64 additions & 25 deletions index.bs
Original file line number Diff line number Diff line change
Expand Up @@ -127,31 +127,27 @@ systems.
A <dfn export id=file>file entry</dfn> additionally consists of
<dfn for="file entry" export>binary data</dfn> (a [=byte sequence=]), a
<dfn for="file entry">modification timestamp</dfn> (a number representing the number of milliseconds since the <a spec=FileAPI>Unix Epoch</a>),
a <dfn for="file entry">lock</dfn> (a string that may exclusively be "`open`", "`taken-exclusive`" or "`taken-shared`")
a <dfn for="file entry">lock</dfn> (a [=string=] or null)
and a <dfn for="file entry">shared lock count</dfn> (a number representing the number of shared locks that are taken at a given point in time).

A user agent has an associated <dfn>file system queue</dfn> which is the
result of [=starting a new parallel queue=]. This queue is to be used for all
file system operations.

<div algorithm>
To <dfn for="file entry" id=file-entry-lock-take>take a lock</dfn> with a |value| of
"`exclusive`" or "`shared`" on a given [=file entry=] |file|:
To <dfn for="file entry" id=file-entry-lock-take>take a lock</dfn> with a |lockType| (a [=string=])
on a given [=file entry=] |file|:

1. Let |lock| be the |file|'s [=file entry/lock=].
1. Let |count| be the |file|'s [=file entry/shared lock count=].
1. If |value| is "`exclusive`":
1. If |lock| is "`open`":
1. Set lock to "`taken-exclusive`".
1. Return "`success`".
1. If |value| is "`shared`":
1. If |lock| is "`open`":
1. Set |lock| to "`taken-shared`".
1. Set |count| to 1.
1. Return "`success`".
1. Otherwise, if |lock| is "`taken-shared`":
1. Increase |count| by 1.
1. Return "`success`".
1. If |lock| is null:
1. Set |lock| to |lockType|.
1. Set |count| to 1.
1. Return "`success`".
1. If |lock| is not "`exclusive`":
1. If |lock| equals |lockType|:
1. Increase |count| by 1.
1. Return "`success`".
1. Return "`failure`".

Note: These steps have to be run on the [=file system queue=].
Expand All @@ -164,10 +160,9 @@ To <dfn for="file entry/lock">release</dfn> a [=file entry/lock=] on a given

1. Let |lock| be the |file|'s associated [=file entry/lock=].
1. Let |count| be the |file|'s [=file entry/shared lock count=].
1. If |lock| is "`taken-shared`":
1. Decrease |count| by 1.
1. If |count| is 0, set |lock| to "`open`".
1. Otherwise, set |lock| to "`open`".
1. [=Assert=]: |count| greater than 0.
1. Decrease |count| by 1.
1. If |count| is 0, set |lock| to null.

Note: These steps have to be run on the [=file system queue=].

Expand Down Expand Up @@ -420,16 +415,32 @@ The <dfn method for=FileSystemHandle>isSameEntry(|other|)</dfn> method steps are
## The {{FileSystemFileHandle}} interface ## {#api-filesystemfilehandle}

<xmp class=idl>
enum FileSystemWritableFileStreamMode {
"exclusive",
"siloed",
};

dictionary FileSystemCreateWritableOptions {
boolean keepExistingData = false;
FileSystemWritableFileStreamMode mode = "siloed";
};

enum FileSystemSyncAccessHandleMode {
"readwrite",
"read-only",
"readwrite-unsafe",
};

dictionary FileSystemCreateSyncAccessHandleOptions {
FileSystemSyncAccessHandleMode mode = "readwrite";
};

[Exposed=(Window,Worker), SecureContext, Serializable]
interface FileSystemFileHandle : FileSystemHandle {
Promise<File> getFile();
Promise<FileSystemWritableFileStream> createWritable(optional FileSystemCreateWritableOptions options = {});
[Exposed=DedicatedWorker]
Promise<FileSystemSyncAccessHandle> createSyncAccessHandle();
Promise<FileSystemSyncAccessHandle> createSyncAccessHandle(optional FileSystemCreateSyncAccessHandleOptions options = {});
};
</xmp>

Expand Down Expand Up @@ -575,8 +586,14 @@ The <dfn method for=FileSystemFileHandle>createWritable(|options|)</dfn> method
|result| with a "{{NotFoundError}}" {{DOMException}} and abort these steps.
1. [=Assert=]: |entry| is a [=file entry=].

1. Let |lockType| be a [=string=].
1. Let |mode| be |options|["{{FileSystemCreateWritableOptions/mode}}"].
1. If |mode| is "`exclusive`":
1. Set |lockType| to "`exclusive`".
1. Otherwise, if |mode| is "`siloed`":
1. Set |lockType| to "`writableSiloed`".
1. Let |lockResult| be the result of [=file entry/take a lock|taking a lock=]
with "`shared`" on |entry|.
with |lockType| on |entry|.

1. [=Queue a storage task=] with |global| to run these steps:
1. If |lockResult| is "`failure`", [=/reject=] |result| with a
Expand Down Expand Up @@ -617,7 +634,7 @@ The <dfn method for=FileSystemFileHandle>createWritable(|options|)</dfn> method
</div>

<div algorithm>
The <dfn method for=FileSystemFileHandle>createSyncAccessHandle()</dfn> method steps are:
The <dfn method for=FileSystemFileHandle>createSyncAccessHandle(|options|)</dfn> method steps are:

1. Let |result| be [=a new promise=].
1. Let |locator| be [=this=]'s [=FileSystemHandle/locator=].
Expand Down Expand Up @@ -645,15 +662,27 @@ The <dfn method for=FileSystemFileHandle>createSyncAccessHandle()</dfn> method s
|result| with a "{{NotFoundError}}" {{DOMException}} and abort these steps.
1. [=Assert=]: |entry| is a [=file entry=].

1. Let |lockType| be a [=string=].
1. Let |writePermission| be a [=string=].
1. Let |mode| be |options|["{{FileSystemCreateSyncAccessHandleOptions/mode}}"].
1. If |mode| is "`readwrite`":
1. Set |lockType| to "`exclusive`".
1. Set |writePermission| to "`writable`".
1. Otherwise, if |mode| is "`read-only`":
1. Set |lockType| to "`syncAccessHandleReadOnly`".
1. Set |writePermission| to "`notWritable`".
1. Otherwise, if |mode| is "`readwrite-unsafe`":
1. Set |lockType| to "`syncAccessHandleReadWriteUnsafe`".
1. Set |writePermission| to "`writable`".
1. Let |lockResult| be the result of [=file entry/take a lock|taking a lock=]
with "`exclusive`" on |entry|.
with |lockType| on |entry|.

1. [=Queue a storage task=] with |global| to run these steps:
1. If |lockResult| is "`failure`", [=/reject=] |result| with a
"{{NoModificationAllowedError}}" {{DOMException}} and abort these steps.

1. Let |handle| be the result of <a>creating a new `FileSystemSyncAccessHandle`</a>
for |entry| in |realm|.
with |entry| and |writePermission| in |realm|.
1. [=/Resolve=] |result| with |handle|.

1. Return |result|.
Expand Down Expand Up @@ -1440,6 +1469,9 @@ A {{FileSystemSyncAccessHandle}} has an associated <dfn for=FileSystemSyncAccess
A {{FileSystemSyncAccessHandle}} has an associated <dfn for=FileSystemSyncAccessHandle>\[[state]]</dfn>,
a string that may exclusively be "`open`" or "`closed`".

A {{FileSystemSyncAccessHandle}} has an associated <dfn for=FileSystemSyncAccessHandle>\[[writePermission]]</dfn>,
a string that may exclusively be "`writable`" or "`notWritable`".

A {{FileSystemSyncAccessHandle}} is an object that is capable of reading from/writing to,
as well as obtaining and changing the size of, a single file.

Expand All @@ -1451,11 +1483,12 @@ A {{FileSystemSyncAccessHandle}} has a <dfn for="FileSystemSyncAccessHandle">fil
<div algorithm>
To
<dfn local-lt="creating a new FileSystemSyncAccessHandle">create a new `FileSystemSyncAccessHandle`</dfn>
given a [=file entry=] |file| in a [=/Realm=] |realm|:
given a [=file entry=] |file| and a |writePermission| of "`writable`" or "`notWritable`" in a [=/Realm=] |realm|:

1. Let |handle| be a [=new=] {{FileSystemSyncAccessHandle}} in |realm|.
1. Set |handle|'s [=FileSystemSyncAccessHandle/[[file]]=] to |file|.
1. Set |handle|'s [=FileSystemSyncAccessHandle/[[state]]=] to "`open`".
1. Set |handle|'s [=FileSystemSyncAccessHandle/[[writePermission]]=] to |writePermission|.
1. Return |handle|.

</div>
Expand Down Expand Up @@ -1518,6 +1551,8 @@ The <dfn method for=FileSystemSyncAccessHandle>write(|buffer|, {{FileSystemReadW

1. If [=this=]'s [=[[state]]=] is "`closed`",
[=throw=] an "{{InvalidStateError}}" {{DOMException}}.
1. If [=this=]'s [=[[writePermission]]=]' is "`notWritable`",
[=throw=] a "{{NoModificationAllowedError}}" {{DOMException}}.
1. Let |writePosition| be |options|["{{FileSystemReadWriteOptions/at}}"] if
|options|["{{FileSystemReadWriteOptions/at}}"] [=map/exists=]; otherwise
[=this=]'s [=FileSystemSyncAccessHandle/file position cursor=].
Expand Down Expand Up @@ -1578,6 +1613,8 @@ The <dfn method for=FileSystemSyncAccessHandle>truncate(|newSize|)</dfn> method

1. If [=this=]'s [=[[state]]=] is "`closed`",
[=throw=] an "{{InvalidStateError}}" {{DOMException}}.
1. If [=this=]'s [=[[writePermission]]=]' is "`notWritable`",
[=throw=] a "{{NoModificationAllowedError}}" {{DOMException}}.
1. Let |fileContents| be a copy of [=this=]'s
[=FileSystemSyncAccessHandle/[[file]]=]'s [=file entry/binary data=].
1. Let |oldSize| be the [=byte sequence/length=] of [=this=]'s
Expand Down Expand Up @@ -1634,6 +1671,8 @@ The <dfn method for=FileSystemSyncAccessHandle>flush()</dfn> method steps are:

1. If [=this=]'s [=[[state]]=] is "`closed`",
[=throw=] an "{{InvalidStateError}}" {{DOMException}}.
1. If [=this=]'s [=[[writePermission]]=]' is "`notWritable`",
[=throw=] a "{{NoModificationAllowedError}}" {{DOMException}}.
1. Attempt to transfer all cached modifications of the file's content to the
file system's underlying storage device.

Expand Down

0 comments on commit bc3475c

Please sign in to comment.