Skip to content

Commit 564df68

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 41b97ba commit 564df68

File tree

1 file changed

+68
-18
lines changed

1 file changed

+68
-18
lines changed

index.bs

Lines changed: 68 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,8 @@ never be allowed using this API, rather than leaving it entirely up to underlyin
125125
systems.
126126

127127
A <dfn>lock type</dfn> is a [=string=] that may exclusively be "`open`",
128-
"`exclusive`", or "`shared`".
128+
"`exclusive`", "`writable-siloed`", "`sync-access-handle-read-only`",
129+
"`sync-access-handle-read-write-unsafe`".
129130

130131
A <dfn export id=file>file entry</dfn> additionally consists of
131132
<dfn for="file entry" export>binary data</dfn> (a [=byte sequence=]), a
@@ -170,8 +171,7 @@ Note: These steps have to be run on the [=file system queue=].
170171

171172
</div>
172173

173-
Note: Locks help prevent concurrent modifications to a file. A {{FileSystemWritableFileStream}}
174-
requires a shared lock, while a {{FileSystemSyncAccessHandle}} requires an exclusive one.
174+
Note: Locks help prevent concurrent modifications to a file that are incompatible.
175175

176176
A <dfn export id=directory>directory entry</dfn> additionally consists of a [=/set=] of
177177
<dfn for="directory entry">children</dfn>, which are themselves [=/file system entries=].
@@ -417,16 +417,32 @@ The <dfn method for=FileSystemHandle>isSameEntry(|other|)</dfn> method steps are
417417
## The {{FileSystemFileHandle}} interface ## {#api-filesystemfilehandle}
418418

419419
<xmp class=idl>
420+
enum FileSystemWritableFileStreamMode {
421+
"exclusive",
422+
"siloed",
423+
};
424+
420425
dictionary FileSystemCreateWritableOptions {
421426
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";
422438
};
423439

424440
[Exposed=(Window,Worker), SecureContext, Serializable]
425441
interface FileSystemFileHandle : FileSystemHandle {
426442
Promise<File> getFile();
427443
Promise<FileSystemWritableFileStream> createWritable(optional FileSystemCreateWritableOptions options = {});
428444
[Exposed=DedicatedWorker]
429-
Promise<FileSystemSyncAccessHandle> createSyncAccessHandle();
445+
Promise<FileSystemSyncAccessHandle> createSyncAccessHandle(optional FileSystemCreateSyncAccessHandleOptions options = {});
430446
};
431447
</xmp>
432448

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

538-
Creating a {{FileSystemWritableFileStream}} [=file entry/take a lock|takes a shared lock=] on the
539-
[=file entry=] [=locate an entry|locatable=] with |fileHandle|'s [=FileSystemHandle/locator=].
540-
This prevents the creation of {{FileSystemSyncAccessHandle|FileSystemSyncAccessHandles}}
541-
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 the [=file entry=], but "`siloed`" will allow the creation of other
559+
{{FileSystemWritableFileStream}} in "`siloed`" {{FileSystemCreateWritableOptions/mode}}.
542560
</div>
543561

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

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`".
575600
1. Let |lockResult| be the result of [=file entry/take a lock|taking a lock=]
576-
with "`shared`" on |entry|.
601+
with |lockType| on |entry|.
577602

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

603-
Creating a {{FileSystemSyncAccessHandle}} [=file entry/take a lock|takes an exclusive lock=] on the
604-
[=file entry=] [=locate an entry|locatable=] with |fileHandle|'s [=FileSystemHandle/locator=].
605-
This prevents the creation of further {{FileSystemSyncAccessHandle|FileSystemSyncAccessHandles}}
606-
or {{FileSystemWritableFileStream|FileSystemWritableFileStreams}}
607-
for the entry, until the access handle is closed.
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 the [=file entry=], but "`read-only`" and "`readwrite-unsafe`" will allow the creation of other
633+
{{FileSystemSyncAccessHandle}} in their respective {{FileSystemCreateSyncAccessHandleOptions/mode|modes}}.
608634

609635
The returned {{FileSystemSyncAccessHandle}} offers synchronous methods. This allows for higher performance
610636
on contexts where asynchronous operations come with high overhead, e.g., WebAssembly.
@@ -614,7 +640,7 @@ The <dfn method for=FileSystemFileHandle>createWritable(|options|)</dfn> method
614640
</div>
615641

616642
<div algorithm>
617-
The <dfn method for=FileSystemFileHandle>createSyncAccessHandle()</dfn> method steps are:
643+
The <dfn method for=FileSystemFileHandle>createSyncAccessHandle(|options|)</dfn> method steps are:
618644

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

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`".
645684
1. Let |lockResult| be the result of [=file entry/take a lock|taking a lock=]
646-
with "`exclusive`" on |entry|.
685+
with |lockType| on |entry|.
647686

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

652691
1. Let |handle| be the result of <a>creating a new `FileSystemSyncAccessHandle`</a>
653-
for |entry| in |realm|.
692+
with |entry| and |writeAccess| in |realm|.
654693
1. [=/Resolve=] |result| with |handle|.
655694

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

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

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

1495+
1. [=Assert=]: |writeAccess| is "`writable`" or "`not-writable`".
14531496
1. Let |handle| be a [=new=] {{FileSystemSyncAccessHandle}} in |realm|.
14541497
1. Set |handle|'s [=FileSystemSyncAccessHandle/[[file]]=] to |file|.
14551498
1. Set |handle|'s [=FileSystemSyncAccessHandle/[[state]]=] to "`open`".
1499+
1. Set |handle|'s [=FileSystemSyncAccessHandle/[[writeAccess]]=] to |writeAccess|.
14561500
1. Return |handle|.
14571501

14581502
</div>
@@ -1515,6 +1559,8 @@ The <dfn method for=FileSystemSyncAccessHandle>write(|buffer|, {{FileSystemReadW
15151559

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

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

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

0 commit comments

Comments
 (0)