@@ -32,6 +32,13 @@ kj::Maybe<kj::Path> parseRestorePath(kj::StringPtr path) {
3232 }
3333}
3434
35+ uint64_t validateSnapshotSize (double size) {
36+ JSG_REQUIRE (std::isfinite (size) && size >= 0 &&
37+ size <= static_cast <double >(jsg::MAX_SAFE_INTEGER) && std::floor (size) == size,
38+ RangeError, " Snapshot size must be a non-negative integer <= Number.MAX_SAFE_INTEGER" );
39+ return static_cast <uint64_t >(size);
40+ }
41+
3542} // namespace
3643
3744// =======================================================================================
@@ -99,14 +106,16 @@ void Container::start(jsg::Lock& js, jsg::Optional<StartupOptions> maybeOptions)
99106 }
100107
101108 if (!flags.getWorkerdExperimental ()) {
102- JSG_REQUIRE (options.snapshots == kj::none, Error,
109+ JSG_REQUIRE (options.directorySnapshots == kj::none, Error,
103110 " Container snapshot restore requires the 'experimental' compatibility flag." );
111+ JSG_REQUIRE (options.containerSnapshot == kj::none, Error,
112+ " Container full snapshot restore requires the 'experimental' compatibility flag." );
104113 } else {
105- KJ_IF_SOME (snapshots , options.snapshots ) {
106- auto list = req.initSnapshots (snapshots .size ());
107- for (auto i: kj::indices (snapshots )) {
114+ KJ_IF_SOME (directorySnapshots , options.directorySnapshots ) {
115+ auto list = req.initDirectorySnapshots (directorySnapshots .size ());
116+ for (auto i: kj::indices (directorySnapshots )) {
108117 auto entry = list[i];
109- auto & restore = snapshots [i];
118+ auto & restore = directorySnapshots [i];
110119 auto & snap = restore.snapshot ;
111120 auto effectiveRestoreDir = snap.dir .asPtr ();
112121 KJ_IF_SOME (mp, restore.mountPoint ) {
@@ -116,13 +125,9 @@ void Container::start(jsg::Lock& js, jsg::Optional<StartupOptions> maybeOptions)
116125 JSG_REQUIRE_NONNULL (parseRestorePath (effectiveRestoreDir), Error,
117126 " Directory snapshot cannot be restored to root directory." );
118127
119- double size = snap.size ;
120- JSG_REQUIRE (std::isfinite (size) && size >= 0 &&
121- size <= static_cast <double >(jsg::MAX_SAFE_INTEGER) && std::floor (size) == size,
122- RangeError, " Snapshot size must be a non-negative integer <= Number.MAX_SAFE_INTEGER" );
123128 auto snapshotBuilder = entry.initSnapshot ();
124129 snapshotBuilder.setId (snap.id );
125- snapshotBuilder.setSize (static_cast < uint64_t >( size));
130+ snapshotBuilder.setSize (validateSnapshotSize (snap. size ));
126131 snapshotBuilder.setDir (snap.dir );
127132 KJ_IF_SOME (name, snap.name ) {
128133 snapshotBuilder.setName (name);
@@ -132,6 +137,15 @@ void Container::start(jsg::Lock& js, jsg::Optional<StartupOptions> maybeOptions)
132137 }
133138 }
134139 }
140+
141+ KJ_IF_SOME (containerSnapshot, options.containerSnapshot ) {
142+ auto builder = req.initContainerSnapshot ();
143+ builder.setId (containerSnapshot.id );
144+ builder.setSize (validateSnapshotSize (containerSnapshot.size ));
145+ KJ_IF_SOME (name, containerSnapshot.name ) {
146+ builder.setName (name);
147+ }
148+ }
135149 }
136150
137151 req.setCompatibilityFlags (flags);
@@ -160,17 +174,45 @@ jsg::Promise<Container::DirectorySnapshot> Container::snapshotDirectory(
160174 .then (
161175 js, [](jsg::Lock& js, capnp::Response<rpc::Container::SnapshotDirectoryResults> results) {
162176 auto snapshot = results.getSnapshot ();
177+ JSG_REQUIRE (snapshot.getSize () <= jsg::MAX_SAFE_INTEGER, RangeError,
178+ " Snapshot size exceeds Number.MAX_SAFE_INTEGER" );
179+
163180 jsg::Optional<kj::String> name = kj::none;
164- auto snapshotName = snapshot.getName ();
165- if (snapshotName.size () > 0 ) {
166- name = kj::str (snapshotName);
181+ if (snapshot.getName ().size () > 0 ) {
182+ name = kj::str (snapshot.getName ());
167183 }
168184
185+ return Container::DirectorySnapshot{kj::str (snapshot.getId ()),
186+ static_cast <double >(snapshot.getSize ()), kj::str (snapshot.getDir ()), kj::mv (name)};
187+ });
188+ }
189+
190+ jsg::Promise<Container::Snapshot> Container::snapshotContainer (
191+ jsg::Lock& js, SnapshotOptions options) {
192+ JSG_REQUIRE (
193+ running, Error, " snapshotContainer() cannot be called on a container that is not running." );
194+
195+ auto req = rpcClient->snapshotContainerRequest ();
196+
197+ KJ_IF_SOME (name, options.name ) {
198+ req.setName (name);
199+ }
200+
201+ return IoContext::current ()
202+ .awaitIo (js, req.send ())
203+ .then (
204+ js, [](jsg::Lock& js, capnp::Response<rpc::Container::SnapshotContainerResults> results) {
205+ auto snapshot = results.getSnapshot ();
169206 JSG_REQUIRE (snapshot.getSize () <= jsg::MAX_SAFE_INTEGER, RangeError,
170207 " Snapshot size exceeds Number.MAX_SAFE_INTEGER" );
171208
172- return Container::DirectorySnapshot{kj::str (snapshot.getId ()),
173- static_cast <double >(snapshot.getSize ()), kj::str (snapshot.getDir ()), kj::mv (name)};
209+ jsg::Optional<kj::String> name = kj::none;
210+ if (snapshot.getName ().size () > 0 ) {
211+ name = kj::str (snapshot.getName ());
212+ }
213+
214+ return Container::Snapshot{
215+ kj::str (snapshot.getId ()), static_cast <double >(snapshot.getSize ()), kj::mv (name)};
174216 });
175217}
176218
0 commit comments