Commit a933d01
committed
Implement in-memory worker file system
So this is a fun one. In preparation for the
implementation of node:fs (and eventually also the
Web file system API), we need to implement a
virtual file system for the worker.
There's quite a bit to unpack here so let's go
through it a bit.
First, let's talk about the file system itself.
Every worker instance will have its own root
directory (`/`). In this root directory we will
have at least two special directories, the
"bundle" root and the "temp" root.
* The bundle root is where all of the modules that
are included in the worker bundle will be
accessible. Everything in this directory will be
strictly read-only. The contents are populated
by the worker configuration bundle. By default,
the bundle root will be `/bundle` but this can
be overridden.
* The temp root is where we will allow temporary
files to be created. Everything in this
directory is read-write but will be transient.
By default, the temp root will be `/tmp` but
this can also be overridden.
Let's imagine the following simple workerd
configuration:
```
const helloWorld :Workerd.Worker = (
modules = [
(name = "worker",
esModule = embed "worker.js"),
(name = "foo", text = "Hello World!"),
],
compatibilityDate = "2023-02-28",
);
```
Given this configuration, the worker fs will
initially have the following structure:
```
/
├── bundle
│ ├── worker
│ └── foo
└── tmp
```
We can then use the `jsg::Lock&` to access the
file system at the C++ level. We reuse the
existing `kj::Filesystem` API to provide the
interface.
```cpp
jsg::Lock& js = ...
// Resolve the root of the file system
KJ_IF_SOME(node,
js.resolveVfsNode("file:///"_url)) {
auto& dir =
kj::downcast<const kj::ReadableDirectory>(
node);
// List the contents of the directory
KJ_DBG(dir.listNames());
}
KJ_IF_SOME(node, js.resolveVfsNode(
"file:///bundle/worker"_url)) {
auto& file =
kj::downcast<const kj::ReadableFile>(node);
KJ_DBG(file.readAllText());
}
KJ_IF_SOME(node,
js.resolveVfsNode("file:///tmp"_url)) {
auto& dir =
kj::downcast<const kj::Directory>(node);
auto tmpFile = dir.createTemporary();
// tmpFile is an anonymous temporary file
}
```
The temporary file directory is a bit special in
that the contents are fully transient based on
whether there is or is not an active IoContext.
We use a special RAII `TempDirStoreScope` scope to
manage the contents of the temporary directory.
For example,
```cpp
KJ_IF_SOME(node,
js.resolveVfsNode("file:///tmp"_url)) {
auto& dir =
kj::downcast<const kj::Directory>(node);
kj::Path path("a/b/c/foo.txt")
{
TempDirStoreScope temp_dir_scope;
auto tmpFile = dir.openFile(path,
kj::FileMode::CREATE);
KJ_ASSERT(tmpFile.write(0,
"Hello World!"_kjb) == 12);
KJ_DBG(dir.exists(path)); // true!
}
// The temp dir scope is destructed and the file
// is deleted
KJ_DBG(dir.exists(path)); // false!
}
```
However, if there is an active IoContext, the
temporary file will instead be created within
that IoContext's TempDirStoreScope, and will be
deleted when the IoContext is destructed. This
allows us to have a single virtual file system
whose temporary directories are either deleted
immediately as soon as the execution scope is
exited, or are specific to the IoContext and are
deleted when the IoContext is destructed. This
mechanism allows us to have multiple IoContexts
active at the same time while still having a
single virtual file system whose contents
correctly reflect the current IoContext.
Temporary files can be created, copied, etc only
within the temporary directory. All other
directories are read-only.
When there is no active IoContext, all temporary
files will have a timestamp set to the Unix epoch.
When there is an active IoContext, the temporary
files will acquire the current timestamp from the
IoContext ensuring that the file system's view of
time is consistent within a request.
The design here is intended to be extensible. We
can add new root directories in the future with
different semantics and implementations. For
example, to support python workers we can
introduce a new root directory that is backed,
for instance, by a tar/zip file containing the
python standard library, etc.
What isn't implemented yet? Great question! The
following todos are remaining:
* Implementing memory accounting for the temporary
file system. Currently the implementation is
using the default in-memory file factory
provided by kj. This is not ideal as it doesn't
provide any mechanisms for memory accounting
that integrates with the Isolate heap limits.
As a next step, before this work is complete,
we will need to implement a custom in-memory
file factory that does integrate with the memory
accounting system. The intention is that the
total size of the temporary files will be
limited to the Isolate heap limit.
* Implmenting "file descriptors". Currently the
file system will return `kj::none` for all file
descriptors. As a next step, the file system
will implement a custom file descriptor counter
that will ensure that all files are assigned a
unique monotonically increasing file descriptor.
When the counter reaches a maximum threshold of
opened files, the worker will be condemned. We
can also just track the number of active
`kj::Own<const kj::File>` objects and use that
internally for accounting but the `node:fs` impl
does a lot with integer fds so we will need them
at some point for that.
The implementation currently does not support
symbolic links in any way. I do not anticipate
implementing this in the future.
The implementation is split across several
files/components:
`worker-fs.h/c++` - These provide the main
interfaces for the worker file system.
`bundle-fs.h/c++` - These provide the interfaces
for interfacing the workerd configuration with
the worker file system. A similar interface will
need to be provided for the internal repo since
the two use different configuration schemas.
The integration via the `jsg::Lock&` is provided
as the most convenient way to access the file
system where it is needed.1 parent a44255f commit a933d01
File tree
23 files changed
+1872
-156
lines changed- src/workerd
- api/tests
- io
- jsg
- server
23 files changed
+1872
-156
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
13 | 13 | | |
14 | 14 | | |
15 | 15 | | |
16 | | - | |
| 16 | + | |
17 | 17 | | |
18 | 18 | | |
19 | 19 | | |
| |||
44 | 44 | | |
45 | 45 | | |
46 | 46 | | |
47 | | - | |
| 47 | + | |
| 48 | + | |
48 | 49 | | |
49 | 50 | | |
50 | 51 | | |
| |||
58 | 59 | | |
59 | 60 | | |
60 | 61 | | |
61 | | - | |
| 62 | + | |
62 | 63 | | |
63 | 64 | | |
64 | 65 | | |
| |||
78 | 79 | | |
79 | 80 | | |
80 | 81 | | |
81 | | - | |
| 82 | + | |
82 | 83 | | |
83 | 84 | | |
84 | 85 | | |
| |||
91 | 92 | | |
92 | 93 | | |
93 | 94 | | |
94 | | - | |
| 95 | + | |
95 | 96 | | |
96 | 97 | | |
97 | 98 | | |
| |||
109 | 110 | | |
110 | 111 | | |
111 | 112 | | |
112 | | - | |
| 113 | + | |
113 | 114 | | |
114 | 115 | | |
115 | 116 | | |
| |||
160 | 161 | | |
161 | 162 | | |
162 | 163 | | |
163 | | - | |
164 | | - | |
165 | | - | |
166 | | - | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
167 | 168 | | |
168 | 169 | | |
169 | 170 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
52 | 52 | | |
53 | 53 | | |
54 | 54 | | |
| 55 | + | |
55 | 56 | | |
56 | 57 | | |
57 | 58 | | |
| |||
64 | 65 | | |
65 | 66 | | |
66 | 67 | | |
| 68 | + | |
67 | 69 | | |
68 | 70 | | |
69 | 71 | | |
| |||
368 | 370 | | |
369 | 371 | | |
370 | 372 | | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
131 | 131 | | |
132 | 132 | | |
133 | 133 | | |
| 134 | + | |
| 135 | + | |
134 | 136 | | |
135 | 137 | | |
136 | 138 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
14 | 14 | | |
15 | 15 | | |
16 | 16 | | |
| 17 | + | |
17 | 18 | | |
18 | 19 | | |
19 | 20 | | |
| |||
224 | 225 | | |
225 | 226 | | |
226 | 227 | | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
227 | 242 | | |
228 | 243 | | |
229 | 244 | | |
| |||
623 | 638 | | |
624 | 639 | | |
625 | 640 | | |
| 641 | + | |
| 642 | + | |
| 643 | + | |
| 644 | + | |
| 645 | + | |
| 646 | + | |
| 647 | + | |
| 648 | + | |
| 649 | + | |
626 | 650 | | |
627 | 651 | | |
628 | 652 | | |
| |||
839 | 863 | | |
840 | 864 | | |
841 | 865 | | |
| 866 | + | |
| 867 | + | |
| 868 | + | |
842 | 869 | | |
843 | 870 | | |
844 | 871 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
0 commit comments