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

Add experimental support for snapshot/restore #1808

Merged
merged 13 commits into from
Jan 24, 2024

Conversation

anuraaga
Copy link
Contributor

This allows a user to opt-in to having snapshot/restore functionality exposed to host functions. This can be used to implement host-based exception handling, for example with wasix's implementation of setjmp and longjmp. The basic machinery can also likely be reused if implementing WebAssembly exceptions in the future.

This is intended to stay in experimental as there is no official standard for exceptions yet, but as there are compilers such as wasix SDK that can compile them, this unblocks allowing wazero to run such programs. For example, the sqlc tool is popular in Go but has cgo issues, this is a step towards using wasix to compile it's Postgres parser and have a pure Go sqlc binary.

Discussed in this slack thread: https://gophers.slack.com/archives/C04CG4A2NKX/p1697555612115509?thread_ts=1697441543.851059&cid=C04CG4A2NKX

wasix
stack_checkpoint: https://wasix.org/docs/api-reference/wasix/stack_checkpoint
stack_restore: https://wasix.org/docs/api-reference/wasix/stack_restore

Example usage in wasix built app:
https://github.com/wasilibs/go-pgquery/blob/main/internal/wasix_32v1/wasix.go#L130

@anuraaga
Copy link
Contributor Author

/cc @ncruces who was interested in checking this

err = require.CapturePanic(func() {
_, _ = mod.ExportedFunction("restore").Call(ctx, snapshotPtr)
})
require.EqualError(t, err, "unhandled snapshot restore, this generally indicates restore was called from a different "+
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Assuming ctx is propagated through a nested invocation, I think it'd be possible to handle this as an error, but I don't know if it's worth it since it would be an error either way but add some tricky handling

Signed-off-by: Anuraag Agrawal <anuraaga@gmail.com>
Signed-off-by: Anuraag Agrawal <anuraaga@gmail.com>
Signed-off-by: Anuraag Agrawal <anuraaga@gmail.com>
Signed-off-by: Anuraag Agrawal <anuraaga@gmail.com>
Signed-off-by: Anuraag Agrawal <anuraaga@gmail.com>
Signed-off-by: Anuraag Agrawal <anuraaga@gmail.com>
Signed-off-by: Anuraag Agrawal <anuraaga@gmail.com>
@ncruces
Copy link
Collaborator

ncruces commented Oct 24, 2023

Issue #1495 is relevant.

Signed-off-by: Anuraag Agrawal <anuraaga@gmail.com>
fn.Call(ctx, stack)
}
func() {
defer func() {
Copy link
Member

Choose a reason for hiding this comment

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

this defer causes allocation every time a Go host func is called. would it be possible to avoid when snapshot is disabled?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point, I made it only happen when snapshotting.

For interpreter, I read from context again since it seemed the plumbing for the otherwise experimental feature would be quite large in its case. Let me know if that seems ok or better to plumb

Signed-off-by: Anuraag Agrawal <anuraaga@gmail.com>
@mathetake mathetake requested review from ncruces and removed request for codefromthecrypt and evacchi January 22, 2024 05:19
@anuraaga
Copy link
Contributor Author

@ncruces Just to refresh memory :)

https://gophers.slack.com/archives/C04CG4A2NKX/p1698068979958989?thread_ts=1697441543.851059&cid=C04CG4A2NKX

The biggest reason for holding off at the time was that a "real world test", aka using wasix-sdk, requires enabling threads. Now that wazero has threads support, the issue is gone or at least reduced.

Copy link
Collaborator

@ncruces ncruces left a comment

Choose a reason for hiding this comment

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

Thanks for the refresher, @anuraaga!

Curious: if this was merged, would you be able to use wazero (instead of wazerox)?

I'm asking to figure out if (with threads) this is "standalone useful" or if wasix-sdk still requires a bunch of juggling to get something that works with wazero.

Don't take me wrong, I'd like to make life easier for you, SQLC, etc.

// EnableSnapshotterKey is a context key to indicate that snapshotting should be enabled.
// The context.Context passed to a exported function invocation should have this key set
// to a non-nil value, and host functions will be able to retrieve it using SnapshotterKey.
type EnableSnapshotterKey struct{}
Copy link
Collaborator

Choose a reason for hiding this comment

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

I wonder if this API should be more akin to:
https://pkg.go.dev/github.com/tetratelabs/wazero@v1.6.0/experimental/sock#WithConfig

So a WithSnapshotter that adds something like an internalEnableSnapshotter to a context.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I followed the pattern of function listener when writing this, I could change it to the sock pattern instead though. Any suggestion on what package the internal context key would go in?

internal/engine/interpreter/interpreter.go Outdated Show resolved Hide resolved
internal/engine/compiler/engine.go Outdated Show resolved Hide resolved
@anuraaga
Copy link
Contributor Author

Great point, that is indeed my intention so I should verify with a replace directive, I'll check it tomorrow.

Copy link
Contributor Author

@anuraaga anuraaga left a comment

Choose a reason for hiding this comment

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

@ncruces Here I confirm replacing wazerox with wazero

wasilibs/go-pgquery#23

As for the juggling, I guess it's mostly just stubbing out unused functions that make it into the binary

https://github.com/wasilibs/go-pgquery/blob/main/internal/wasix_32v1/wasix.go

I don't think we can say it's really easy to use wasix with wazero but I guess it's not terrible either

// EnableSnapshotterKey is a context key to indicate that snapshotting should be enabled.
// The context.Context passed to a exported function invocation should have this key set
// to a non-nil value, and host functions will be able to retrieve it using SnapshotterKey.
type EnableSnapshotterKey struct{}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I followed the pattern of function listener when writing this, I could change it to the sock pattern instead though. Any suggestion on what package the internal context key would go in?

internal/engine/compiler/engine.go Outdated Show resolved Hide resolved
@ncruces
Copy link
Collaborator

ncruces commented Jan 23, 2024

I don't think we can say it's really easy to use wasix with wazero but I guess it's not terrible either

This is good enough. I mean, we can't correctly extend wasi into wasix outside wazero because em we'd need access to internals of wasi implementation (e.g. filesystem).

But you can usefully stub stuff emitted by wasix-sdk, or you can likely implement wasix from scratch outside wazero (same as stealthrocket/wasi-go).

Good enough for me.

Copy link
Collaborator

@ncruces ncruces left a comment

Choose a reason for hiding this comment

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

I'd like a second opinion on the enabling API, but other than that, LGTM.

@mathetake mathetake merged commit 4185e53 into tetratelabs:main Jan 24, 2024
56 of 57 checks passed
@iameli iameli mentioned this pull request Mar 4, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants