Tools to streamline development of Wasm UDFs for SingleStoreDB.

Overview

SingleStore Wasm Toolkit And Examples

This repository provides utilities intended to help you streamline development of Wasm UDFs for SingleStoreDB. It consists of development containers, documentation, and a collection of example Wasm programs.

To use the tools in this repo, you will need to have Docker installed on your system. Most of these tools can be installed locally as well.

Tools

In this repo, you will find two development containers -- one standalone and one designed specifically for VS Code. These containers attempt to strike a balance between providing a fairly comprehensive set of Wasm-oriented development tools, while still being mindful of image sizes. Still, the container sizes currently range between 2-3 GB.

The following tools are available within each container:

clang

The Clang compiler and toolchain. The exact compiler version may differ between containers; see below for specifics.

gcc/g++

The GCC compiler and toolchain. The exact compiler version may differ between containers; see below for specifics.

rust/cargo

The Rust compiler with the stable toolchain. It has been configured with compilation targets for the default platform, wasm32-wasi, and wasm32-unknown-unknown. The exact compiler version may differ between containers; see below for specifics.

wasmtime

A popular Wasm compiler and runtime.

WASI SDK

Utilities to support the WASI toolchain.

wit-bindgen

A language binding generator for the WIT IDL.

writ

A utility to help test Wasm functions locally without the need to create a separate driver program. Please see its dedicated Git Repository for more information.

pushwasm

A utility that allows you to easily import your locally-built Wasm function into SingleStoreDB as a UDF. Please see its dedicated Git Repository for more information.

Remote Debugging Tool (VS Code Only)

The VS Code container includes an experimental remote debugging tool that can be run as an external function from SingleStoreDB. For instructions on how to use this utility, please see this document.

Sudo

Finally, both containers give you access to password-less sudo so that you can further customize instances of them if you prefer.

Suggested Workflow

This section suggests a possible workflow for developing a Wasm UDF for use in SingleStoreDB.

Before you start, you'll need to clone this repository. For the purposes of example, we'll assume you are cloning to $HOME/singlestore-wasm-toolkit.

git clone https://github.com/singlestore-labs/singlestore-wasm-toolkit.git

Getting Started With VS Code

One-Time Setup

  1. Install VS Code.

  2. In VS Code, press Ctrl-Shift-X. This will take you to the Extensions Marketplace. Type Remote - Containers in the search field and click the Install button.

  3. In VS Code, press F1 and type Remote Containers: Install Docker.

  4. By default, VS Code will mount just this repo in the container file system. This is only really useful if you want to work with the examples. If you'd like to work on other directories in this environment, then you will also need to do the following:

    1. Edit the .devcontainer/devcontainer.json file.
    2. Search for the mounts section and uncomment it.
    3. Change the value after source= to the local directory you want to mount.
    4. Change the value after target= to the path where you want the directory mounted in the container. If you intend to develop in this directory, things will flow more smoothly if it is a child of the /workspaces directory. For example: target=/workspaces/mycode.
    5. You can add a new entry for each additional path you want mounted.

Beginning Development

  1. Start VS Code.

  2. Press F1 and search for Remote-Containers: Open Folder in Container.

  3. Navigate to the $HOME/singlestore-wasm-toolkit (or the place where you cloned this repo). Click Open.

  4. If this is your first time opening the container, it will now be built. This can take quite a while, so please be patient -- it only needs to happen once.

  5. If you intend to work on a project outside of this repo, then you will add this code to the current project. Here's how:

    1. First make sure you've completed Step 4 in the Preparation section, above.
    2. Press F1 and search for Workspaces: Add Folder to Workspace.
    3. In the drop-down list, if you followed the convention suggested in Step 4 of Preparation, you should see the name of the folder you mounted into the /workspaces directory. If you chose a different location, then navigate to that folder instead. When you are ready, make sure the proper folder is selected and click the OK button.
    4. The project will reload automatically.
    5. Your new folder can be found in the project navigator window. If you want to save this workspace configuration for later, then press F1, search for Workspaces: Save Workspace As, and pick a name.
  6. Edit the source code as necessary.

  7. When you are ready to compile the Wasm module, press Ctrl-` (that's the backtick character) to open a console window in the IDE. You should see a prompt prefixed with s2-dev-shell. Be sure to change (cd) to the directory of the code you intend to compile.

Getting Started With the Standalone Container

  1. From this repo, run the script scripts/dev-shell. It takes a single argument with the location of the local source directory where you intend to work. For example: scripts/dev-shell /home/pete/mycoolproject.

  2. If this is your first time running this container, it will be downloaded from the GitHub Docker registry. This may take a few minutes, depending on your internet connection.

  3. You should now see a prompt prefixed with s2-dev-shell. The directory you supplied in the argument will be mounted to ~/src in the container, and will be the current working directory when the prompt appears.

  4. Edit your source code locally, using whatever tools your prefer. You only need to use the dev-shell when you are ready to compile, test, or deploy.

Iterative Development

For both container types, iterative development proceeds the same. We'll use the split example included in this repo as a case study to describe a possible workflow.

  1. To start:

    1. In the container, ensure that you are in the root directory of the code you intend to compile. For our demonstration, we will be in ~/src/examples/rust/split.
    2. Ensure that you have created a WIT file to describe the common interface of your Wasm function and UDF. The WIT syntax is described here. For the split example, we have placed this file at the root of the example's source tree.
  2. Compile your program using the appropriate compiler. Clang/GCC and Rust are both available in the container. The process of compiling is described in more detail for C/C++ here, and for Rust here.
    To compile split for Rust in optimized mode, we would use this command:

    cargo wasi build --lib --release
  3. Now, test your program using the writ tool. It should already be included in your $PATH. Specific instructions on its usage are available in its repository. As an example, we might use it to test one input of split like this:

    % writ --wit split.wit target/wasm32-wasi/release/split.wasm split_str 'hello_you_fine_folks' '_'
    [
      {
        "str": "hello",
        "idx": 0
      },
      {
        "str": "you",
        "idx": 6
      },
      {
        "str": "fine",
        "idx": 10
      },
      {
        "str": "folks",
        "idx": 15
      }
    ]
    
  4. When you are satisfied with your program, you can import it into SingleStoreDB using the pushwasm tool, also included in your default $PATH. Usage instructions can be found in its source repository. For example, we could use it like this to create a Wasm TVF from our split module:

    % pushwasm --tvf --prompt mysql://[email protected]:3306/testing --wit split.wit target/wasm32-wasi/release/split.wasm split_str
    Wasm UDF 'split_str' was created successfully.
  5. The last step is verify that the Wasm UDF or TVF works in your database. Using the SQL Editor in the SingleStore Customer Portal, you can check that the function has been created using the SHOW FUNCTIONS statement. Then, you might try running using your UDF or TVF on a table. Here's an example using the split TVF:

    SELECT * from example_table t, split_str(t.name, ' ');

Additional Information

To learn about the process of developing a Wasm UDF or TVF in more detail, please have a look at our tutorial.

Information about setting up the remote debugging tool can be found here.

For instructions on using the writ tool, please go here.

For instructions on using the pushwasm tool, please go here.

Information about the Rust examples can be found here.

The SingleStoreDB Wasm UDF/TVF documentation is here.

Getting SingleStoreDB

  1. Sign up for a free SingleStore license. This allows you to run up to 4 nodes up to 32 gigs each for free.

  2. Grab your license key from SingleStore portal and set it as an environment variable.

export SINGLESTORE_LICENSE="singlestore license"

Resources

Comments
  • Rust UDF error

    Rust UDF error

    I have built a Rust UDF and added the function to Singlestore database using this command

    CREATE FUNCTION <function name> AS WASM FROM HTTP 'https://<>.wasm' with WIT from HTTP 'https://<>.wit'

    when I ran select function(1,2,3) AS Result observing this error

    ERROR 2654 UNKNOWN_ERR_CODE: Wasm module instantiation failed with error. unknown import:env::__extenddftf2has not been defined

    Can someone help me fix this issue?

    opened by ravi-k4 5
  • fix: remove generated c source from git

    fix: remove generated c source from git

    I split out the c example of power-of from generated bindings vs the implementation. Since the generation defaults to taking the power.c name, I opted to create a new file "_impl.c". WDYT?

    opened by ricochet 5
  • Remote Debugger

    Remote Debugger

    This diff implements a remote debugger which can help test wasm udfs being called by SingleStore.

    The goals are:

    • support running in lldb + breakpoints
    • use external functions in singlestore
    • be able to log to the console for print() style debugging
    • minimum amount of additional overhead to enable debugging

    I tried building this in a bunch of different ways - but ended up deciding to have the debugger depend on the wasm module exporting a specific entrypoint. This is currently simpler than dynamically generating hander code for each of the example projects.

    With this model, the debugger binary will listen on an http port for requests from SingleStore (external functions). Since external functions heavily batches requests, the debugger will unpack the rows list at the top level and then invoke the wasm module for each row. The input to the wasm module will be a "name" derived from the endpoint along with the current row encoded as a json array (basically passthrough from SingleStore). The wasm module will have to export the debugger's handle_json method, process the incoming row, call it's internal behavior, and then return a json array as the result.

    To simplify usage a proc macro is included. See the debugger readme for examples and documentation.

    For now, you will need to manually create the external function in SingleStore. Also, as external functions only support scalar-inputs, if you want to pass records in you will need to wrap them in to_json. Something like this should work:

    select * from t(to_json(row("hi"):>record(t text)));
    
    opened by carlsverre 3
  • Enhancements to the standalone dev container

    Enhancements to the standalone dev container

    I've decoupled the standalone dev container from the VS Code one. This allows us to better customize the standalone development experience.

    As part of this, I've added a parameter to the script that allows the user to "target" the container to a particular source directory. Before, it was only possible to edit the contents of the current repo.

    I've also renamed docker-shell.sh to dev-shell to be slightly more descriptive and concise.

    opened by pvetere 2
  • unicode normalization example

    unicode normalization example

    This example uses the unicode_normalization rust crate to define NFD and NFC normalization UDFs. A good overview of unicode normalization as well as the difference between NFD and NFC can be found here: https://towardsdatascience.com/what-on-earth-is-unicode-normalization-56c005c55ad0

    opened by carlsverre 1
  • Add example which defines some PostGIS functions

    Add example which defines some PostGIS functions

    This was my hackathon project:

    • Add the following functions to a new example (rust/geo):
      • ST_ConvexHull
      • ST_Centroid
      • ST_PointN
      • ST_ClosestPoint
      • ST_Envelope
      • ST_Intersects
      • ST_Translate
      • ST_Rotate
      • ST_FrechetDistance

    The functions are implemented using the crates geo and wkt. Some functionality (for example, ST_Buffer, which was requested) is missing since geo didn't support it out of the box.

    opened by RiscadoA 1
  • fix: share wasi-sdk and wasmtime install

    fix: share wasi-sdk and wasmtime install

    The previous version had differences in versions.

    Instead of creating clang aliases, this adds wasi-sdk to the beginning of the PATH. This technique is taken from common-debian.sh in vscode-devcontainers so that it is compatible with vscode and regular containers.

    opened by ricochet 1
  • Examples: s2regex in Rust

    Examples: s2regex in Rust

    General

    This PR adds a simple s2regex example WASM rust crate supporting arbitrary regex matches on an input string.

    Misc

    • [X] Add missing Makefile & writ tests to the jsonpath example
    opened by sadroeck 0
  • Add xpath and jsonpath functions

    Add xpath and jsonpath functions

    This PR adds examples that implement XPath and JSONPath functions. There are a total of four functions: 2 UDFs and 2 TVFs. They are:

    eval_xpath('xml-str', 'xpath-str') -> 'str'
    eval_xpaths('xml-str', 'xpath-str') -> list('str')
    eval_jsonpath('json-str', 'jsonpath-str') -> 'json-str'
    eval_jsonpaths('json-str', 'jsonpath-str') -> list('json-str')
    
    opened by kesmit13 0
  • Copying from Rust Example Adds Extra Code

    Copying from Rust Example Adds Extra Code

    When doing the tutorial for power-of, I copied the Rust code from the doc site and it embedded the code into a main fn:

    
    #![allow(unused)]
    fn main() {
    wit_bindgen_rust::export!("power.wit");
    struct Power;
    
    impl power::Power for Power {
        fn power_of(base: i32, exp: i32) -> i32 {
            let mut res = 1;
            for _i in 0..exp {
                res *= base;
            }
            res
        }
    }
    }
    
    

    This caused an E0412 error when compiling. Checked with @pvetere and this is not intended. Not sure if this affects other tutorials/code examples or not (I'm guessing it probably does). Doesn't seem to happen when copying directly from the GitHub docs, just the doc site.

    opened by mitchwadair 0
  • ci: add github workflow

    ci: add github workflow

    This change runs the make build scripts for rust and cpp examples. Because we've seen some awkward differences between release and debug, this runs these in a matrix.

    I have the paths commented out to get an e2e build and will add them back in a follow-up commit. Note that this does not yet run make test (missing writ).

    Tested locally with https://github.com/nektos/act

    act push -j test
    
    opened by ricochet 0
  • ci: add writ tests

    ci: add writ tests

    • changed make target for test to depend on a wasm module. That way we can test both release and debug in the CI.
    • If I spied rust unit tests, I added those to the make target. We could also consider gtests for C++ examples in the future.
    opened by ricochet 0
  • Create a SIMD example

    Create a SIMD example

    Fixed SIMD is enabled by default in the wasmtime runtime.

    A very straightforward example with few dependencies is desired before adding a more complex real-world use-case. For example multiply_arrays from https://v8.dev/features/simd might be a good place to start.

    Some more interesting examples beyond neural networks could include:

    • https://github.com/intel/hyperscan (C++)
    • https://github.com/ermig1979/Simd/blob/master/src/Use/UseFaceDetection.cpp
    • https://github.com/SnellerInc/sneller (golang)
    • https://github.com/minio/sha256-simd (golang)
    • https://github.com/echamudi/opencv-wasm
    example 
    opened by ricochet 1
Owner
SingleStore Labs
The home of SingleStore community content
SingleStore Labs
Seed your development database with real data ⚡️

Seed Your Development Database With Real Data ⚡️ Replibyte is a blazingly fast tool to seed your databases with your production data while keeping sen

Qovery 3.4k Jan 2, 2023
A very WIP RISCV64 OS written in Rust to learn about low-level and OS development

river A very WIP Rust-based RISCV64 OS for learning. The name is based off of the name RISCV with some added letters: "riscv" + er Make sure you have

James [Undefined] 5 Dec 18, 2022
Async Lightweight HTTP client using system native library if possible. (Currently under heavy development)

Async Lightweight HTTP Client (aka ALHC) What if we need async but also lightweight http client without using such a large library like reqwest, isahc

SteveXMH 7 Dec 15, 2022
SQLite compiled to WASM with pluggable data storage

wasm-sqlite SQLite compiled to WASM with pluggable data storage. Useful to save SQLite in e.g. Cloudflare Durable Objects (example: https://github.com

Markus Ast 36 Dec 7, 2022
Plugin for macro-, mini-quad (quads) to save data in simple local storage using Web Storage API in WASM and local file on a native platforms.

quad-storage This is the crate to save data in persistent local storage in miniquad/macroquad environment. In WASM the data persists even if tab or br

ilya sheprut 9 Jan 4, 2023
Easy c̵̰͠r̵̛̠ö̴̪s̶̩̒s̵̭̀-t̶̲͝h̶̯̚r̵̺͐e̷̖̽ḁ̴̍d̶̖̔ ȓ̵͙ė̶͎ḟ̴͙e̸̖͛r̶̖͗ë̶̱́ṉ̵̒ĉ̷̥e̷͚̍ s̷̹͌h̷̲̉a̵̭͋r̷̫̊ḭ̵̊n̷̬͂g̵̦̃ f̶̻̊ơ̵̜ṟ̸̈́ R̵̞̋ù̵̺s̷̖̅ţ̸͗!̸̼͋

Rust S̵̓i̸̓n̵̉ I̴n̴f̶e̸r̵n̷a̴l mutability! Howdy, friendly Rust developer! Ever had a value get m̵̯̅ð̶͊v̴̮̾ê̴̼͘d away right under your nose just when

null 294 Dec 23, 2022
Rust-powered CLI tool designed to simplify and streamline the release process with help of ChatGPT

$ releasecraftsman ????‍♂️?? Automate Your Release Process with Precision and Ease. ?? Features Generate well-crafted release notes using GPT-3.5 and

Tornike Gomareli 7 Sep 21, 2023
Call is an easy-to-use command tools for remote development.

Call is an easy-to-use command tools for remote development. It helps you to build remote development easily and elegant. It can work with makefile and justfile.

null 21 Dec 14, 2022
Rust-verification-tools - RVT is a collection of tools/libraries to support both static and dynamic verification of Rust programs.

Rust verification tools This is a collection of tools/libraries to support both static and dynamic verification of Rust programs. We see static verifi

null 253 Dec 31, 2022
⚙️ A curated list of static analysis (SAST) tools for all programming languages, config files, build tools, and more.

This repository lists static analysis tools for all programming languages, build tools, config files and more. The official website, analysis-tools.de

Analysis Tools 10.7k Jan 2, 2023
Simple devcontainer for Rust + WASM development

Devcontainer WASM-Rust Simple devcontainer for Rust development Usage Github Codespaces Just click the button: Visual Studio Code Note this assumes th

null 2 Dec 22, 2022
Low level tooling for WebAssembly in JavaScript using wasm-tools

js-wasm-tools js-wasm-tools compiles some of the API of wasm-tools to JavaScript and WebAssembly via wasm-bindgen. This offers low level tooling for W

Dominic Elm 59 Dec 19, 2022
WASM runtime for Deku and Michelson-to-WASM compiler

Tuna This repository has two different projects, a plugable VM for running WASM contracts on Deku and a Michelson to WASM compiler which also has some

Marigold 6 Nov 17, 2022
Distribute a wasm SPA as HTML by wrapping it as a polyglot "html+wasm+zip"

A packer that adds a webpage to WASM module, making it self-hosted! Motivation At the moment, Browsers can not execute WebAssembly as a native single

Andreas Molzer 3 Jan 2, 2023
A Wasm component optimizer (mostly a wrapper around wasm-opt)

component-opt An optimizer for Wasm Components Current Status This project currently only offers one optimization and does not allow it to be configur

Robin Brown 6 Mar 4, 2024
Materialize simplifies application development with streaming data. Incrementally-updated materialized views - in PostgreSQL and in real time. Materialize is powered by Timely Dataflow.

Materialize is a streaming database for real-time applications. Get started Check out our getting started guide. About Materialize lets you ask questi

Materialize, Inc. 4.7k Jan 8, 2023
A personal etude into rust software (RPG<-it's more fun to debug) development: Tales of the Great White Moose

TGWM (Tales of the Great White Moose) NB: Currently compiles. Should compile and run on both 1.28.0 and 1.31.1 if the Cargo.lock files are deleted. A

null 15 Nov 17, 2021
A command-line tool collection to assist development written in RUST

dtool dtool is a command-line tool collection to assist development Table of Contents Description Usage Tips Installation Description Now dtool suppor

GB 314 Dec 18, 2022
Rust development environment for Emacs

Rustic Table of Contents Rustic Intro Installation straight Compilation Faces rustc errors Rustfmt edition 2018 LSP Server Client eglot lsp-mode lsp-e

null 612 Dec 30, 2022
A Software Development Kit (SDK) for Zero-Knowledge Transactions

Aleo SDK The Aleo SDK is a developer framework to make it simple to create a new account, craft a transaction, and broadcast it to the network. Table

Aleo 270 Jan 5, 2023