Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor Observer and LimitEnforcer cleaner for... #3114

Merged
merged 2 commits into from
Dec 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/workerd/io/limit-enforcer.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ static constexpr size_t DEFAULT_MAX_PBKDF2_ITERATIONS = 100'000;
// Interface for an object that enforces resource limits on an Isolate level.
//
// See also LimitEnforcer, which enforces on a per-request level.
class IsolateLimitEnforcer {
class IsolateLimitEnforcer: public kj::Refcounted {
danlapid marked this conversation as resolved.
Show resolved Hide resolved
public:
// Get CreateParams to pass when constructing a new isolate.
virtual v8::Isolate::CreateParams getCreateParams() = 0;
Expand Down
4 changes: 3 additions & 1 deletion src/workerd/io/observer.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,9 @@ class RequestObserver: public kj::Refcounted {
}
};

class IsolateObserver: public kj::AtomicRefcounted, public jsg::IsolateObserver {
class JsgIsolateObserver: public kj::AtomicRefcounted, public jsg::IsolateObserver {};

class IsolateObserver: public kj::AtomicRefcounted {
public:
virtual ~IsolateObserver() noexcept(false) {}

Expand Down
17 changes: 11 additions & 6 deletions src/workerd/io/worker.c++
Original file line number Diff line number Diff line change
Expand Up @@ -672,6 +672,8 @@ struct Worker::Isolate::Impl {
actorCacheLru(limitEnforcer.getActorCacheLruOptions()) {
jsg::runInV8Stack([&](jsg::V8StackScope& stackScope) {
auto lock = api.lock(stackScope);

limitEnforcer.customizeIsolate(lock->v8Isolate);
danlapid marked this conversation as resolved.
Show resolved Hide resolved
if (inspectorPolicy != InspectorPolicy::DISALLOW) {
// We just created our isolate, so we don't need to use Isolate::Impl::Lock.
KJ_ASSERT(!isMultiTenantProcess(), "inspector is not safe in multi-tenant processes");
Expand Down Expand Up @@ -969,18 +971,21 @@ const HeapSnapshotDeleter HeapSnapshotDeleter::INSTANCE;
} // namespace

Worker::Isolate::Isolate(kj::Own<Api> apiParam,
kj::Own<IsolateObserver> metricsParam,
kj::StringPtr id,
kj::Own<IsolateLimitEnforcer> limitEnforcerParam,
InspectorPolicy inspectorPolicy,
ConsoleMode consoleMode)
: metrics(kj::atomicAddRef(apiParam->getMetrics())),
: metrics(kj::mv(metricsParam)),
id(kj::str(id)),
limitEnforcer(kj::mv(limitEnforcerParam)),
api(kj::mv(apiParam)),
limitEnforcer(api->getLimitEnforcer()),
consoleMode(consoleMode),
featureFlagsForFl(makeCompatJson(decompileCompatibilityFlagsForFl(api->getFeatureFlags()))),
impl(kj::heap<Impl>(*api, *metrics, limitEnforcer, inspectorPolicy)),
impl(kj::heap<Impl>(*api, *metrics, *limitEnforcer, inspectorPolicy)),
weakIsolateRef(WeakIsolateRef::wrap(this)),
traceAsyncContextKey(kj::refcounted<jsg::AsyncContextFrame::StorageKey>()) {
api->setIsolateObserver(*metrics);
metrics->created();
// We just created our isolate, so we don't need to use Isolate::Impl::Lock (nor an async lock).
jsg::runInV8Stack([&](jsg::V8StackScope& stackScope) {
Expand Down Expand Up @@ -1329,7 +1334,7 @@ Worker::Script::Script(kj::Own<const Isolate> isolateParam,
KJ_SWITCH_ONEOF(source) {
KJ_CASE_ONEOF(script, ScriptSource) {
impl->globals =
script.compileGlobals(lock, isolate->getApi(), isolate->impl->metrics);
script.compileGlobals(lock, isolate->getApi(), isolate->getApi().getObserver());

{
// It's unclear to me if CompileUnboundScript() can get trapped in any infinite loops or
Expand Down Expand Up @@ -1387,7 +1392,7 @@ Worker::Isolate::~Isolate() noexcept(false) {

// Update the isolate stats one last time to make sure we're accurate for cleanup in
// `evicted()`.
limitEnforcer.reportMetrics(*metrics);
limitEnforcer->reportMetrics(*metrics);

metrics->evicted();
weakIsolateRef->invalidate();
Expand Down Expand Up @@ -3808,7 +3813,7 @@ kj::Own<const Worker::Script> Worker::Isolate::newScript(kj::StringPtr scriptId,
}

void Worker::Isolate::completedRequest() const {
limitEnforcer.completedRequest(id);
limitEnforcer->completedRequest(id);
}

bool Worker::Isolate::isInspectorEnabled() const {
Expand Down
17 changes: 10 additions & 7 deletions src/workerd/io/worker.h
Original file line number Diff line number Diff line change
Expand Up @@ -274,8 +274,13 @@ class Worker::Isolate: public kj::AtomicRefcounted {
// Usually it matches the script ID. An exception is preview isolates: there, each preview
// session has one isolate which may load many iterations of the script (this allows the
// inspector session to stay open across them).
// The Isolate object owns the Api object and outlives it in order to report teardown timing.
// The Api object is created before the Isolate object and does not strictly require
// request-specific information.
explicit Isolate(kj::Own<Api> api,
danlapid marked this conversation as resolved.
Show resolved Hide resolved
kj::Own<IsolateObserver> metrics,
kj::StringPtr id,
kj::Own<IsolateLimitEnforcer> limitEnforcer,
InspectorPolicy inspectorPolicy,
ConsoleMode consoleMode = ConsoleMode::INSPECTOR_ONLY);

Expand Down Expand Up @@ -305,11 +310,11 @@ class Worker::Isolate: public kj::AtomicRefcounted {
kj::Maybe<ValidationErrorReporter&> errorReporter = kj::none) const;

inline IsolateLimitEnforcer& getLimitEnforcer() {
return limitEnforcer;
return *limitEnforcer;
}

inline const IsolateLimitEnforcer& getLimitEnforcer() const {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-blocking nit: We have the kj::Rc<T> and kj::Arc<T> types now for safer handling of references to refcounted and atomic refcounted types. It would be nice if we could start working on replacing uses of bare references for these where it's not too cumbersome of a change.

return limitEnforcer;
return *limitEnforcer;
}

inline Api& getApi() {
Expand Down Expand Up @@ -408,8 +413,8 @@ class Worker::Isolate: public kj::AtomicRefcounted {
TeardownFinishedGuard<IsolateObserver&> teardownGuard{*metrics};

kj::String id;
kj::Own<IsolateLimitEnforcer> limitEnforcer;
kj::Own<Api> api;
IsolateLimitEnforcer& limitEnforcer;
ConsoleMode consoleMode;

// If non-null, a serialized JSON object with a single "flags" property, which is a list of
Expand Down Expand Up @@ -532,10 +537,8 @@ class Worker::Api {
virtual jsg::JsObject wrapExecutionContext(
jsg::Lock& lock, jsg::Ref<api::ExecutionContext> ref) const = 0;

virtual IsolateLimitEnforcer& getLimitEnforcer() = 0;
virtual const IsolateLimitEnforcer& getLimitEnforcer() const = 0;
virtual IsolateObserver& getMetrics() = 0;
virtual const IsolateObserver& getMetrics() const = 0;
virtual const jsg::IsolateObserver& getObserver() const = 0;
virtual void setIsolateObserver(IsolateObserver&) = 0;

// Set the module fallback service callback, if any.
using ModuleFallbackCallback = kj::Maybe<kj::OneOf<kj::String, jsg::ModuleRegistry::ModuleInfo>>(
Expand Down
14 changes: 8 additions & 6 deletions src/workerd/server/server.c++
Original file line number Diff line number Diff line change
Expand Up @@ -2921,27 +2921,29 @@ kj::Own<Server::Service> Server::makeWorker(kj::StringPtr name,
}
};

auto jsgobserver = kj::atomicRefcounted<JsgIsolateObserver>();
auto observer = kj::atomicRefcounted<IsolateObserver>();
auto limitEnforcer = kj::heap<NullIsolateLimitEnforcer>();
auto limitEnforcer = kj::refcounted<NullIsolateLimitEnforcer>();

kj::Maybe<kj::Own<jsg::modules::ModuleRegistry>> newModuleRegistry;
if (featureFlags.getNewModuleRegistry()) {
KJ_REQUIRE(experimental,
"The new ModuleRegistry implementation is an experimental feature. "
"You must run workerd with `--experimental` to use this feature.");
newModuleRegistry = WorkerdApi::initializeBundleModuleRegistry(
*observer, conf, featureFlags.asReader(), pythonConfig);
*jsgobserver, conf, featureFlags.asReader(), pythonConfig);
}

auto api =
kj::heap<WorkerdApi>(globalContext->v8System, featureFlags.asReader(), kj::mv(limitEnforcer),
kj::mv(observer), *memoryCacheProvider, pythonConfig, kj::mv(newModuleRegistry));
auto api = kj::heap<WorkerdApi>(globalContext->v8System, featureFlags.asReader(),
limitEnforcer->getCreateParams(), kj::mv(jsgobserver), *memoryCacheProvider, pythonConfig,
kj::mv(newModuleRegistry));
auto inspectorPolicy = Worker::Isolate::InspectorPolicy::DISALLOW;
if (inspectorOverride != kj::none) {
// For workerd, if the inspector is enabled, it is always fully trusted.
inspectorPolicy = Worker::Isolate::InspectorPolicy::ALLOW_FULLY_TRUSTED;
}
auto isolate = kj::atomicRefcounted<Worker::Isolate>(kj::mv(api), name, inspectorPolicy,
auto isolate = kj::atomicRefcounted<Worker::Isolate>(kj::mv(api), kj::mv(observer), name,
kj::mv(limitEnforcer), inspectorPolicy,
conf.isServiceWorkerScript() ? Worker::ConsoleMode::INSPECTOR_ONLY : consoleMode);

// If we are using the inspector, we need to register the Worker::Isolate
Expand Down
38 changes: 10 additions & 28 deletions src/workerd/server/workerd-api.c++
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,7 @@ static const PythonConfig defaultConfig{
struct WorkerdApi::Impl final {
kj::Own<CompatibilityFlags::Reader> features;
kj::Maybe<kj::Own<jsg::modules::ModuleRegistry>> maybeOwnedModuleRegistry;
kj::Own<IsolateLimitEnforcer> limitEnforcer;
kj::Own<IsolateObserver> observer;
kj::Own<JsgIsolateObserver> observer;
JsgWorkerdIsolate jsgIsolate;
api::MemoryCacheProvider& memoryCacheProvider;
const PythonConfig& pythonConfig;
Expand All @@ -160,24 +159,17 @@ struct WorkerdApi::Impl final {

Impl(jsg::V8System& v8System,
CompatibilityFlags::Reader featuresParam,
kj::Own<IsolateLimitEnforcer> limitEnforcerParam,
kj::Own<IsolateObserver> observerParam,
v8::Isolate::CreateParams createParams,
kj::Own<JsgIsolateObserver> observerParam,
api::MemoryCacheProvider& memoryCacheProvider,
const PythonConfig& pythonConfig = defaultConfig,
kj::Maybe<kj::Own<jsg::modules::ModuleRegistry>> newModuleRegistry = kj::none)
: features(capnp::clone(featuresParam)),
maybeOwnedModuleRegistry(kj::mv(newModuleRegistry)),
limitEnforcer(kj::mv(limitEnforcerParam)),
observer(kj::atomicAddRef(*observerParam)),
jsgIsolate(v8System,
Configuration(*this),
kj::mv(observerParam),
limitEnforcer->getCreateParams()),
jsgIsolate(v8System, Configuration(*this), kj::mv(observerParam), kj::mv(createParams)),
memoryCacheProvider(memoryCacheProvider),
pythonConfig(pythonConfig) {
jsgIsolate.runInLockScope(
[&](JsgWorkerdIsolate::Lock& lock) { limitEnforcer->customizeIsolate(lock.v8Isolate); });
}
pythonConfig(pythonConfig) {}

static v8::Local<v8::String> compileTextGlobal(
JsgWorkerdIsolate::Lock& lock, capnp::Text::Reader reader) {
Expand Down Expand Up @@ -219,14 +211,14 @@ struct WorkerdApi::Impl final {

WorkerdApi::WorkerdApi(jsg::V8System& v8System,
CompatibilityFlags::Reader features,
kj::Own<IsolateLimitEnforcer> limitEnforcer,
kj::Own<IsolateObserver> observer,
v8::Isolate::CreateParams createParams,
kj::Own<JsgIsolateObserver> observer,
api::MemoryCacheProvider& memoryCacheProvider,
const PythonConfig& pythonConfig,
kj::Maybe<kj::Own<jsg::modules::ModuleRegistry>> newModuleRegistry)
: impl(kj::heap<Impl>(v8System,
features,
kj::mv(limitEnforcer),
kj::mv(createParams),
kj::mv(observer),
memoryCacheProvider,
pythonConfig,
Expand Down Expand Up @@ -276,21 +268,11 @@ jsg::JsObject WorkerdApi::wrapExecutionContext(
kj::downcast<JsgWorkerdIsolate::Lock>(lock).wrap(lock.v8Context(), kj::mv(ref)));
}

IsolateLimitEnforcer& WorkerdApi::getLimitEnforcer() {
return *impl->limitEnforcer;
}

const IsolateLimitEnforcer& WorkerdApi::getLimitEnforcer() const {
return *impl->limitEnforcer;
}

IsolateObserver& WorkerdApi::getMetrics() {
const jsg::IsolateObserver& WorkerdApi::getObserver() const {
return *impl->observer;
}

const IsolateObserver& WorkerdApi::getMetrics() const {
return *impl->observer;
}
void WorkerdApi::setIsolateObserver(IsolateObserver&) {};

Worker::Script::Source WorkerdApi::extractSource(kj::StringPtr name,
config::Worker::Reader conf,
Expand Down
10 changes: 4 additions & 6 deletions src/workerd/server/workerd-api.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ class WorkerdApi final: public Worker::Api {
public:
WorkerdApi(jsg::V8System& v8System,
CompatibilityFlags::Reader features,
kj::Own<IsolateLimitEnforcer> limitEnforcer,
kj::Own<IsolateObserver> observer,
v8::Isolate::CreateParams createParams,
kj::Own<JsgIsolateObserver> observer,
api::MemoryCacheProvider& memoryCacheProvider,
const PythonConfig& pythonConfig,
kj::Maybe<kj::Own<jsg::modules::ModuleRegistry>> newModuleRegistry);
Expand All @@ -55,10 +55,8 @@ class WorkerdApi final: public Worker::Api {
jsg::Lock& lock) const override;
jsg::JsObject wrapExecutionContext(
jsg::Lock& lock, jsg::Ref<api::ExecutionContext> ref) const override;
IsolateLimitEnforcer& getLimitEnforcer() override;
const IsolateLimitEnforcer& getLimitEnforcer() const override;
IsolateObserver& getMetrics() override;
const IsolateObserver& getMetrics() const override;
const jsg::IsolateObserver& getObserver() const override;
void setIsolateObserver(IsolateObserver&) override;

static Worker::Script::Source extractSource(kj::StringPtr name,
config::Worker::Reader conf,
Expand Down
11 changes: 7 additions & 4 deletions src/workerd/tests/test-fixture.c++
Original file line number Diff line number Diff line change
Expand Up @@ -323,13 +323,16 @@ TestFixture::TestFixture(SetupParams&& params)
memoryCacheProvider(kj::heap<api::MemoryCacheProvider>(*timer)),
api(kj::heap<server::WorkerdApi>(testV8System,
params.featureFlags.orDefault(CompatibilityFlags::Reader()),
kj::heap<MockIsolateLimitEnforcer>(),
kj::atomicRefcounted<IsolateObserver>(),
kj::heap<MockIsolateLimitEnforcer>()->getCreateParams(),
kj::atomicRefcounted<JsgIsolateObserver>(),
*memoryCacheProvider,
defaultPythonConfig,
kj::none)),
workerIsolate(kj::atomicRefcounted<Worker::Isolate>(
kj::mv(api), scriptId, Worker::Isolate::InspectorPolicy::DISALLOW)),
workerIsolate(kj::atomicRefcounted<Worker::Isolate>(kj::mv(api),
kj::atomicRefcounted<IsolateObserver>(),
scriptId,
kj::heap<MockIsolateLimitEnforcer>(),
Worker::Isolate::InspectorPolicy::DISALLOW)),
workerScript(kj::atomicRefcounted<Worker::Script>(kj::atomicAddRef(*workerIsolate),
scriptId,
server::WorkerdApi::extractSource(mainModuleName,
Expand Down
Loading