Skip to content

Commit 9475e66

Browse files
author
Nathan Memmott
committed
Add new SAH and WFS locking modes
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.
1 parent b03688d commit 9475e66

File tree

1 file changed

+84
-34
lines changed

1 file changed

+84
-34
lines changed

index.bs

Lines changed: 84 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -124,34 +124,35 @@ Issue: We should consider having further normative restrictions on file names th
124124
never be allowed using this API, rather than leaving it entirely up to underlying file
125125
systems.
126126

127+
A <dfn for="file entry">lock type</dfn> is a [=string=] that may exclusively be "`open`",
128+
"`exclusive`", "`writable-siloed`", "`sync-access-handle-read-only`",
129+
"`sync-access-handle-read-write-unsafe`".
130+
127131
A <dfn export id=file>file entry</dfn> additionally consists of
128132
<dfn for="file entry" export>binary data</dfn> (a [=byte sequence=]), a
129133
<dfn for="file entry">modification timestamp</dfn> (a number representing the number of milliseconds since the <a spec=FileAPI>Unix Epoch</a>),
130-
a <dfn for="file entry">lock</dfn> (a string that may exclusively be "`open`", "`taken-exclusive`" or "`taken-shared`")
134+
a <dfn for="file entry">lock</dfn> (a [=file entry/lock type=]),
131135
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).
132136

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

137141
<div algorithm>
138-
To <dfn for="file entry" id=file-entry-lock-take>take a lock</dfn> with a |value| of
139-
"`exclusive`" or "`shared`" on a given [=file entry=] |file|:
142+
To <dfn for="file entry" id=file-entry-lock-take>take a lock</dfn> with a |lockType| (a [=file entry/lock type=])
143+
on a given [=file entry=] |file|:
140144

145+
1. [=Assert=]: |lockType| is not "`open`".
141146
1. Let |lock| be the |file|'s [=file entry/lock=].
142147
1. Let |count| be the |file|'s [=file entry/shared lock count=].
143-
1. If |value| is "`exclusive`":
144-
1. If |lock| is "`open`":
145-
1. Set lock to "`taken-exclusive`".
146-
1. Return "`success`".
147-
1. If |value| is "`shared`":
148-
1. If |lock| is "`open`":
149-
1. Set |lock| to "`taken-shared`".
150-
1. Set |count| to 1.
151-
1. Return "`success`".
152-
1. Otherwise, if |lock| is "`taken-shared`":
153-
1. Increase |count| by 1.
154-
1. Return "`success`".
148+
1. If |lock| is "`open`":
149+
1. Set |lock| to |lockType|.
150+
1. Set |count| to 1.
151+
1. Return "`success`".
152+
1. If |lock| is not "`exclusive`":
153+
1. If |lock| equals |lockType|:
154+
1. Increase |count| by 1.
155+
1. Return "`success`".
155156
1. Return "`failure`".
156157

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

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

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

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

422422
<xmp class=idl>
423+
enum FileSystemWritableFileStreamMode {
424+
"exclusive",
425+
"siloed",
426+
};
427+
423428
dictionary FileSystemCreateWritableOptions {
424429
boolean keepExistingData = false;
430+
FileSystemWritableFileStreamMode mode = "siloed";
431+
};
432+
433+
enum FileSystemSyncAccessHandleMode {
434+
"readwrite",
435+
"read-only",
436+
"readwrite-unsafe",
437+
};
438+
439+
dictionary FileSystemCreateSyncAccessHandleOptions {
440+
FileSystemSyncAccessHandleMode mode = "readwrite";
425441
};
426442

427443
[Exposed=(Window,Worker), SecureContext, Serializable]
428444
interface FileSystemFileHandle : FileSystemHandle {
429445
Promise<File> getFile();
430446
Promise<FileSystemWritableFileStream> createWritable(optional FileSystemCreateWritableOptions options = {});
431447
[Exposed=DedicatedWorker]
432-
Promise<FileSystemSyncAccessHandle> createSyncAccessHandle();
448+
Promise<FileSystemSyncAccessHandle> createSyncAccessHandle(optional FileSystemCreateSyncAccessHandleOptions options = {});
433449
};
434450
</xmp>
435451

@@ -538,10 +554,12 @@ The <dfn method for=FileSystemFileHandle>getFile()</dfn> method steps are:
538554
the temporary file starts out empty,
539555
otherwise the existing file is first copied to this temporary file.
540556

541-
Creating a {{FileSystemWritableFileStream}} [=file entry/take a lock|takes a shared lock=] on the
542-
[=file entry=] [=locate an entry|locatable=] with |fileHandle|'s [=FileSystemHandle/locator=].
543-
This prevents the creation of {{FileSystemSyncAccessHandle|FileSystemSyncAccessHandles}}
544-
for the entry, until the stream is closed.
557+
Creating a {{FileSystemWritableFileStream}} [=file entry/take a lock|takes a lock=] on the
558+
[=file entry=] [=locate an entry|locatable=] with |fileHandle|'s [=FileSystemHandle/locator=]
559+
and a |lockType| determined by {{FileSystemCreateWritableOptions/mode}}. Until the stream is
560+
closed, both {{FileSystemCreateWritableOptions/mode|modes}} prevent any file operation or the
561+
creation of a file primitive on the [=file entry=], but "`siloed`" will allow the creation of other
562+
{{FileSystemWritableFileStream}} in "`siloed`" {{FileSystemCreateWritableOptions/mode}}.
545563
</div>
546564

547565
<p class=XXX>See <a href=https://github.com/WICG/file-system-access/issues/67>WICG/file-system-access issue #67</a>
@@ -575,8 +593,15 @@ The <dfn method for=FileSystemFileHandle>createWritable(|options|)</dfn> method
575593
|result| with a "{{NotFoundError}}" {{DOMException}} and abort these steps.
576594
1. [=Assert=]: |entry| is a [=file entry=].
577595

596+
1. Let |lockType| be the empty string.
597+
1. Let |mode| be |options|["{{FileSystemCreateWritableOptions/mode}}"].
598+
1. If |mode| is "`exclusive`":
599+
1. Set |lockType| to "`exclusive`".
600+
1. Otherwise:
601+
1. [=Assert=]: |mode| is "`siloed`".
602+
1. Set |lockType| to "`writable-siloed`".
578603
1. Let |lockResult| be the result of [=file entry/take a lock|taking a lock=]
579-
with "`shared`" on |entry|.
604+
with |lockType| on |entry|.
580605

581606
1. [=Queue a storage task=] with |global| to run these steps:
582607
1. If |lockResult| is "`failure`", [=/reject=] |result| with a
@@ -603,11 +628,12 @@ The <dfn method for=FileSystemFileHandle>createWritable(|options|)</dfn> method
603628
[=file entry=] [=locate an entry|locatable=] by |fileHandle|'s [=FileSystemHandle/locator=].
604629
To ensure the changes are reflected in this file, the handle can be flushed.
605630

606-
Creating a {{FileSystemSyncAccessHandle}} [=file entry/take a lock|takes an exclusive lock=] on the
607-
[=file entry=] [=locate an entry|locatable=] with |fileHandle|'s [=FileSystemHandle/locator=].
608-
This prevents the creation of further {{FileSystemSyncAccessHandle|FileSystemSyncAccessHandles}}
609-
or {{FileSystemWritableFileStream|FileSystemWritableFileStreams}}
610-
for the entry, until the access handle is closed.
631+
Creating a {{FileSystemSyncAccessHandle}} [=file entry/take a lock|takes a lock=] on the
632+
[=file entry=] [=locate an entry|locatable=] with |fileHandle|'s [=FileSystemHandle/locator=]
633+
and a |lockType| determined by {{FileSystemCreateSyncAccessHandleOptions/mode}}. Until the access handle is
634+
closed, all {{FileSystemCreateSyncAccessHandleOptions/mode|modes}} prevent any file operation or the
635+
creation of a file primitive on the [=file entry=], but "`read-only`" and "`readwrite-unsafe`" will allow the creation of other
636+
{{FileSystemSyncAccessHandle}} in their respective {{FileSystemCreateSyncAccessHandleOptions/mode|modes}}.
611637

612638
The returned {{FileSystemSyncAccessHandle}} offers synchronous methods. This allows for higher performance
613639
on contexts where asynchronous operations come with high overhead, e.g., WebAssembly.
@@ -617,7 +643,7 @@ The <dfn method for=FileSystemFileHandle>createWritable(|options|)</dfn> method
617643
</div>
618644

619645
<div algorithm>
620-
The <dfn method for=FileSystemFileHandle>createSyncAccessHandle()</dfn> method steps are:
646+
The <dfn method for=FileSystemFileHandle>createSyncAccessHandle(|options|)</dfn> method steps are:
621647

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

674+
1. Let |lockType| be the empty string.
675+
1. Let |writeAccess| be the empty string.
676+
1. Let |mode| be |options|["{{FileSystemCreateSyncAccessHandleOptions/mode}}"].
677+
1. If |mode| is "`readwrite`":
678+
1. Set |lockType| to "`exclusive`".
679+
1. Set |writeAccess| to "`writable`".
680+
1. Otherwise, if |mode| is "`read-only`":
681+
1. Set |lockType| to "`sync-access-handle-read-only`".
682+
1. Set |writeAccess| to "`not-writable`".
683+
1. Otherwise:
684+
1. [=Assert=]: |mode| is "`readwrite-unsafe`".
685+
1. Set |lockType| to "`sync-access-handle-read-write-unsafe`".
686+
1. Set |writeAccess| to "`writable`".
648687
1. Let |lockResult| be the result of [=file entry/take a lock|taking a lock=]
649-
with "`exclusive`" on |entry|.
688+
with |lockType| on |entry|.
650689

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

655694
1. Let |handle| be the result of <a>creating a new `FileSystemSyncAccessHandle`</a>
656-
for |entry| in |realm|.
695+
with |entry| and |writeAccess| in |realm|.
657696
1. [=/Resolve=] |result| with |handle|.
658697

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

1482+
A {{FileSystemSyncAccessHandle}} has an associated <dfn for=FileSystemSyncAccessHandle>\[[writeAccess]]</dfn>,
1483+
a [=string=] that may exclusively be "`writable`" or "`not-writable`".
1484+
14431485
A {{FileSystemSyncAccessHandle}} is an object that is capable of reading from/writing to,
14441486
as well as obtaining and changing the size of, a single file.
14451487

@@ -1451,11 +1493,13 @@ A {{FileSystemSyncAccessHandle}} has a <dfn for="FileSystemSyncAccessHandle">fil
14511493
<div algorithm>
14521494
To
14531495
<dfn local-lt="creating a new FileSystemSyncAccessHandle">create a new `FileSystemSyncAccessHandle`</dfn>
1454-
given a [=file entry=] |file| in a [=/Realm=] |realm|:
1496+
given a [=file entry=] |file| and a [=string=] |writeAccess| in a [=/Realm=] |realm|:
14551497

1498+
1. [=Assert=]: |writeAccess| is "`writable`" or "`not-writable`".
14561499
1. Let |handle| be a [=new=] {{FileSystemSyncAccessHandle}} in |realm|.
14571500
1. Set |handle|'s [=FileSystemSyncAccessHandle/[[file]]=] to |file|.
14581501
1. Set |handle|'s [=FileSystemSyncAccessHandle/[[state]]=] to "`open`".
1502+
1. Set |handle|'s [=FileSystemSyncAccessHandle/[[writeAccess]]=] to |writeAccess|.
14591503
1. Return |handle|.
14601504

14611505
</div>
@@ -1518,6 +1562,8 @@ The <dfn method for=FileSystemSyncAccessHandle>write(|buffer|, {{FileSystemReadW
15181562

15191563
1. If [=this=]'s [=[[state]]=] is "`closed`",
15201564
[=throw=] an "{{InvalidStateError}}" {{DOMException}}.
1565+
1. If [=this=]'s [=[[writeAccess]]=]' is "`not-writable`",
1566+
[=throw=] a "{{NoModificationAllowedError}}" {{DOMException}}.
15211567
1. Let |writePosition| be |options|["{{FileSystemReadWriteOptions/at}}"] if
15221568
|options|["{{FileSystemReadWriteOptions/at}}"] [=map/exists=]; otherwise
15231569
[=this=]'s [=FileSystemSyncAccessHandle/file position cursor=].
@@ -1578,6 +1624,8 @@ The <dfn method for=FileSystemSyncAccessHandle>truncate(|newSize|)</dfn> method
15781624

15791625
1. If [=this=]'s [=[[state]]=] is "`closed`",
15801626
[=throw=] an "{{InvalidStateError}}" {{DOMException}}.
1627+
1. If [=this=]'s [=[[writeAccess]]=]' is "`not-writable`",
1628+
[=throw=] a "{{NoModificationAllowedError}}" {{DOMException}}.
15811629
1. Let |fileContents| be a copy of [=this=]'s
15821630
[=FileSystemSyncAccessHandle/[[file]]=]'s [=file entry/binary data=].
15831631
1. Let |oldSize| be the [=byte sequence/length=] of [=this=]'s
@@ -1634,6 +1682,8 @@ The <dfn method for=FileSystemSyncAccessHandle>flush()</dfn> method steps are:
16341682

16351683
1. If [=this=]'s [=[[state]]=] is "`closed`",
16361684
[=throw=] an "{{InvalidStateError}}" {{DOMException}}.
1685+
1. If [=this=]'s [=[[writeAccess]]=]' is "`not-writable`",
1686+
[=throw=] a "{{NoModificationAllowedError}}" {{DOMException}}.
16371687
1. Attempt to transfer all cached modifications of the file's content to the
16381688
file system's underlying storage device.
16391689

0 commit comments

Comments
 (0)