Skip to content

Commit

Permalink
Merge pull request #173 from cloudflare/swarfield/testingGc
Browse files Browse the repository at this point in the history
During testing the GC will run after every test.
  • Loading branch information
Warfields committed Nov 18, 2022
2 parents ad645e8 + db6784b commit 1f8a561
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 4 deletions.
47 changes: 43 additions & 4 deletions src/workerd/io/worker-entrypoint.c++
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <workerd/util/sentry.h>
#include <workerd/api/global-scope.h>
#include <workerd/util/own-util.h>
#include <workerd/util/thread-scopes.h>

namespace workerd {

Expand Down Expand Up @@ -181,7 +182,14 @@ kj::Promise<void> WorkerEntrypoint::request(
failOpenClient = context.getHttpClientNoChecks(IoContext::NEXT_CLIENT_CHANNEL, false,
kj::mv(cfBlobJson));
}
waitUntilTasks.add(incomingRequest->drain().attach(kj::mv(incomingRequest)));
auto promise = incomingRequest->drain().attach(kj::mv(incomingRequest));
if (isPredictableModeForTest()) {
promise = promise.then([worker = kj::atomicAddRef(context.getWorker())]() {
auto lock = worker->getIsolate().getApiIsolate().lock();
lock->requestGcForTesting();
});
}
waitUntilTasks.add(kj::mv(promise));
})).then([this]() -> kj::Promise<void> {
// Now that the IoContext is dropped (unless it had waitUntil()s), we can finish proxying
// without pinning it or the isolate into memory.
Expand Down Expand Up @@ -349,12 +357,22 @@ kj::Promise<WorkerInterface::ScheduledResult> WorkerEntrypoint::runScheduled(
lock.getExportedHandler(entrypointName, context.getActor()));
}));

return incomingRequest->finishScheduled().then([&context](bool completed) mutable {
auto promise = incomingRequest->finishScheduled().then([&context](bool completed) mutable {
return WorkerInterface::ScheduledResult {
.retry = context.shouldRetryScheduled(),
.outcome = completed ? context.waitUntilStatus() : EventOutcome::EXCEEDED_CPU
};
}).attach(kj::mv(incomingRequest));

if (isPredictableModeForTest()) {
promise = promise.then([worker = kj::atomicAddRef(context.getWorker())](auto res) {
auto lock = worker->getIsolate().getApiIsolate().lock();
lock->requestGcForTesting();
return res;
});
}

return promise;
}

kj::Promise<WorkerInterface::AlarmResult> WorkerEntrypoint::runAlarm(
Expand All @@ -368,7 +386,7 @@ kj::Promise<WorkerInterface::AlarmResult> WorkerEntrypoint::runAlarm(
//alarm() should only work with actors
auto& actor = KJ_REQUIRE_NONNULL(context.getActor());

return actor.dedupAlarm(scheduledTime,
auto promise = actor.dedupAlarm(scheduledTime,
[this,&context,scheduledTime,incomingRequest = kj::mv(incomingRequest)]() mutable
-> kj::Promise<WorkerInterface::AlarmResult> {
incomingRequest->delivered();
Expand All @@ -395,6 +413,16 @@ kj::Promise<WorkerInterface::AlarmResult> WorkerEntrypoint::runAlarm(
}));
});
});

if (isPredictableModeForTest()) {
promise = promise.then([worker = kj::atomicAddRef(context.getWorker())](auto res) {
auto lock = worker->getIsolate().getApiIsolate().lock();
lock->requestGcForTesting();
return res;
});
}

return promise;
}

kj::Promise<WorkerInterface::CustomEvent::Result>
Expand All @@ -403,7 +431,18 @@ kj::Promise<WorkerInterface::CustomEvent::Result>
"customEvent() can only be called once"));
this->incomingRequest = nullptr;

return event->run(kj::mv(incomingRequest), entrypointName).attach(kj::mv(event));
auto& context = incomingRequest->getContext();
auto worker = kj::atomicAddRef(context.getWorker());
auto promise = event->run(kj::mv(incomingRequest), entrypointName).attach(kj::mv(event));

if (isPredictableModeForTest()) {
promise = promise.then([worker = kj::mv(worker)](auto res) {
auto lock = worker->getIsolate().getApiIsolate().lock();
lock->requestGcForTesting();
return res;
});
}
return promise;
}

} // namespace workerd
10 changes: 10 additions & 0 deletions src/workerd/jsg/jsg.c++
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "jsg.h"
#include "setup.h"
#include <execinfo.h>
#include <workerd/util/thread-scopes.h>

namespace workerd::jsg {

Expand Down Expand Up @@ -149,6 +150,15 @@ void Lock::setLoggerCallback(kj::Function<Logger>&& logger) {
IsolateBase::from(v8Isolate).setLoggerCallback({}, kj::mv(logger));
}

void Lock::requestGcForTesting() const {
if (!isPredictableModeForTest()) {
KJ_LOG(ERROR, "Test GC used while not in a test");
return;
}
v8Isolate->RequestGarbageCollectionForTesting(
v8::Isolate::GarbageCollectionType::kFullGarbageCollection);
}

Name Lock::newSymbol(kj::StringPtr symbol) {
return Name(*this, v8::Symbol::New(v8Isolate, v8StrIntern(v8Isolate, symbol)));
}
Expand Down
9 changes: 9 additions & 0 deletions src/workerd/jsg/jsg.h
Original file line number Diff line number Diff line change
Expand Up @@ -1906,6 +1906,7 @@ class Lock {

// ---------------------------------------------------------------------------
// Name/Symbol stuff

Name newSymbol(kj::StringPtr symbol);
// Creates a Name encapsulating a new unique v8::Symbol.

Expand Down Expand Up @@ -1970,6 +1971,14 @@ class Lock {
using Logger = void(Lock&, kj::StringPtr);
void setLoggerCallback(kj::Function<Logger>&& logger);

// ---------------------------------------------------------------------------
// Misc. Stuff

void requestGcForTesting() const;
// Sends an immediate request for full GC, this function is to ONLY be used in testing, otherwise
// it will throw. If a need for a minor GC is needed look at the call in jsg.c++ and the
// implementation in setup.c++. Use responsibly.

private:
friend class IsolateBase;
template <typename TypeWrapper>
Expand Down

0 comments on commit 1f8a561

Please sign in to comment.