Skip to content

Commit dc89f60

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 dc89f60

File tree

1 file changed

+82
-35
lines changed

1 file changed

+82
-35
lines changed

index.bs

Lines changed: 82 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -127,31 +127,29 @@ systems.
127127
A <dfn export id=file>file entry</dfn> additionally consists of
128128
<dfn for="file entry" export>binary data</dfn> (a [=byte sequence=]), a
129129
<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`")
130+
a <dfn for="file entry">lock</dfn> (a [=string=] that may exclusively be "`open`", "`exclusive`", "`writable-siloed`",
131+
"`sync-access-handle-read-only`", "`sync-access-handle-read-write-unsafe`")
131132
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).
132133

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

137138
<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|:
139+
To <dfn for="file entry" id=file-entry-lock-take>take a lock</dfn> with a |lockType| (a [=string=])
140+
on a given [=file entry=] |file|:
140141

142+
1. [=Assert=]: |lockType| is "`exclusive`", "`writable-siloed`", "`sync-access-handle-read-only`", or "`sync-access-handle-read-write-unsafe`".
141143
1. Let |lock| be the |file|'s [=file entry/lock=].
142144
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`".
145+
1. If |lock| is "`open`":
146+
1. Set |lock| to |lockType|.
147+
1. Set |count| to 1.
148+
1. Return "`success`".
149+
1. If |lock| is not "`exclusive`":
150+
1. If |lock| equals |lockType|:
151+
1. Increase |count| by 1.
152+
1. Return "`success`".
155153
1. Return "`failure`".
156154

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

165163
1. Let |lock| be the |file|'s associated [=file entry/lock=].
166164
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`".
165+
1. [=Assert=]: |count| is greater than 0.
166+
1. Decrease |count| by 1.
167+
1. If |count| is 0, set |lock| to "`open`".
171168

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

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

422419
<xmp class=idl>
420+
enum FileSystemWritableFileStreamMode {
421+
"exclusive",
422+
"siloed",
423+
};
424+
423425
dictionary FileSystemCreateWritableOptions {
424426
boolean keepExistingData = false;
427+
FileSystemWritableFileStreamMode mode = "siloed";
428+
};
429+
430+
enum FileSystemSyncAccessHandleMode {
431+
"readwrite",
432+
"read-only",
433+
"readwrite-unsafe",
434+
};
435+
436+
dictionary FileSystemCreateSyncAccessHandleOptions {
437+
FileSystemSyncAccessHandleMode mode = "readwrite";
425438
};
426439

427440
[Exposed=(Window,Worker), SecureContext, Serializable]
428441
interface FileSystemFileHandle : FileSystemHandle {
429442
Promise<File> getFile();
430443
Promise<FileSystemWritableFileStream> createWritable(optional FileSystemCreateWritableOptions options = {});
431444
[Exposed=DedicatedWorker]
432-
Promise<FileSystemSyncAccessHandle> createSyncAccessHandle();
445+
Promise<FileSystemSyncAccessHandle> createSyncAccessHandle(optional FileSystemCreateSyncAccessHandleOptions options = {});
433446
};
434447
</xmp>
435448

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

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.
554+
Creating a {{FileSystemWritableFileStream}} [=file entry/take a lock|takes a lock=] on the
555+
[=file entry=] [=locate an entry|locatable=] with |fileHandle|'s [=FileSystemHandle/locator=]
556+
and a |lockType| determined by {{FileSystemCreateWritableOptions/mode}}. Until the stream is
557+
closed, both {{FileSystemCreateWritableOptions/mode|modes}} prevent any file operation or the
558+
creation of a file primitive on entry, but "`siloed`" will allow the creation of other
559+
{{FileSystemWritableFileStream}} in "`siloed`" {{FileSystemCreateWritableOptions/mode}}.
545560
</div>
546561

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

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

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

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.
611-
628+
Creating a {{FileSystemSyncAccessHandle}} [=file entry/take a lock|takes a lock=] on the
629+
[=file entry=] [=locate an entry|locatable=] with |fileHandle|'s [=FileSystemHandle/locator=]
630+
and a |lockType| determined by {{FileSystemCreateSyncAccessHandleOptions/mode}}. Until the access handle is
631+
closed, all {{FileSystemCreateSyncAccessHandleOptions/mode|modes}} prevent any file operation or the
632+
creation of a file primitive on entry, but "`read-only`" and "`readwrite-unsafe`" will allow the creation of other
633+
{{FileSystemSyncAccessHandle}} in their respective {{FileSystemCreateSyncAccessHandleOptions/mode|modes}}.
634+
612635
The returned {{FileSystemSyncAccessHandle}} offers synchronous methods. This allows for higher performance
613636
on contexts where asynchronous operations come with high overhead, e.g., WebAssembly.
614637

@@ -617,7 +640,7 @@ The <dfn method for=FileSystemFileHandle>createWritable(|options|)</dfn> method
617640
</div>
618641

619642
<div algorithm>
620-
The <dfn method for=FileSystemFileHandle>createSyncAccessHandle()</dfn> method steps are:
643+
The <dfn method for=FileSystemFileHandle>createSyncAccessHandle(|options|)</dfn> method steps are:
621644

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

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

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

655691
1. Let |handle| be the result of <a>creating a new `FileSystemSyncAccessHandle`</a>
656-
for |entry| in |realm|.
692+
with |entry| and |writeAccess| in |realm|.
657693
1. [=/Resolve=] |result| with |handle|.
658694

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

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

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

1495+
1. [=Assert=]: |writeAccess| is "`writable`" or "`not-writable`".
14561496
1. Let |handle| be a [=new=] {{FileSystemSyncAccessHandle}} in |realm|.
14571497
1. Set |handle|'s [=FileSystemSyncAccessHandle/[[file]]=] to |file|.
14581498
1. Set |handle|'s [=FileSystemSyncAccessHandle/[[state]]=] to "`open`".
1499+
1. Set |handle|'s [=FileSystemSyncAccessHandle/[[writeAccess]]=] to |writeAccess|.
14591500
1. Return |handle|.
14601501

14611502
</div>
@@ -1518,6 +1559,8 @@ The <dfn method for=FileSystemSyncAccessHandle>write(|buffer|, {{FileSystemReadW
15181559

15191560
1. If [=this=]'s [=[[state]]=] is "`closed`",
15201561
[=throw=] an "{{InvalidStateError}}" {{DOMException}}.
1562+
1. If [=this=]'s [=[[writeAccess]]=]' is "`not-writable`",
1563+
[=throw=] a "{{NoModificationAllowedError}}" {{DOMException}}.
15211564
1. Let |writePosition| be |options|["{{FileSystemReadWriteOptions/at}}"] if
15221565
|options|["{{FileSystemReadWriteOptions/at}}"] [=map/exists=]; otherwise
15231566
[=this=]'s [=FileSystemSyncAccessHandle/file position cursor=].
@@ -1578,6 +1621,8 @@ The <dfn method for=FileSystemSyncAccessHandle>truncate(|newSize|)</dfn> method
15781621

15791622
1. If [=this=]'s [=[[state]]=] is "`closed`",
15801623
[=throw=] an "{{InvalidStateError}}" {{DOMException}}.
1624+
1. If [=this=]'s [=[[writeAccess]]=]' is "`not-writable`",
1625+
[=throw=] a "{{NoModificationAllowedError}}" {{DOMException}}.
15811626
1. Let |fileContents| be a copy of [=this=]'s
15821627
[=FileSystemSyncAccessHandle/[[file]]=]'s [=file entry/binary data=].
15831628
1. Let |oldSize| be the [=byte sequence/length=] of [=this=]'s
@@ -1634,6 +1679,8 @@ The <dfn method for=FileSystemSyncAccessHandle>flush()</dfn> method steps are:
16341679

16351680
1. If [=this=]'s [=[[state]]=] is "`closed`",
16361681
[=throw=] an "{{InvalidStateError}}" {{DOMException}}.
1682+
1. If [=this=]'s [=[[writeAccess]]=]' is "`not-writable`",
1683+
[=throw=] a "{{NoModificationAllowedError}}" {{DOMException}}.
16371684
1. Attempt to transfer all cached modifications of the file's content to the
16381685
file system's underlying storage device.
16391686

0 commit comments

Comments
 (0)