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

Perspective Virtual API (JavaScript) #2615

Draft
wants to merge 6 commits into
base: master
Choose a base branch
from
Draft

Perspective Virtual API (JavaScript) #2615

wants to merge 6 commits into from

Conversation

texodus
Copy link
Member

@texodus texodus commented May 11, 2024

Summary

This PR introduces a radical new design for Perspective's client/server API. The basis of this work will enable the next version of Perspective UX to directly support streaming (* where supported), virtual access to non-Perspective databases such as DuckDB, SQLite and Postgres without copying the entire dataset into either the Browser or perspective-python, using an efficient Virtual API.

The ad-hoc, JSON-based wire format of the 2.x series has been re-written as a set of Protobuf messages. This enables easier portability of this message protocol to new host languages, decreases message handling overhead on the server, and makes possible improved multi-thread utilization on platform which support multi-threading - e.g. in Python, where messages were previously dispatched with the GIL acquired, they can now be parsed and handled entirely on an internal thread pool.

In 2.x, Perspective's client, session manager, message processing loop, multiplexing, etc. was implemented in the domain language itself, and the native C++ API resembled a lower-level version of this public API. This resulted in a lot of duplicate (and subtle-y buggy) code, inconsistencies in implementation and performance, and made it difficult to add new features as they had to be custom-embedded in Python and Javascript. We had exported over 100 symbols from the Emscripten+Embind JavaScript API in C++, and had over 1,000 LoC of C++ in Python for PyBind. It also limited concurrent throughput in language like Python that have a GIL associated with interpreted evaluation.

In 3.0, the Server API is implement entirely in C++ and exports only 2 methods, both of which take only [uint8_t] arguments (the serialized Protobuf engine messages), and subsumes session management, client IDs, multiplexing and the lot. The new Client API is written in purely in Rust, and need only emit and consume this duplex binary message stream in order to communicate with a Perspective Server over any transport. As the Rust ecosystem has exceptional Python (PyO3) and JavaScript (wasm-bindgen) bindings, we can mostly get away with transparently wrapping this common Client library for these languages. This drastically decreases the volume of code we must write to expose Perspective's API to new language, simplifying the maintenance of these language bindings.

Rust Library

As a bonus which came together quite naturally, this PR also introduces a native Rust client and server for Perspective, which allows hosting the Perspective engine in e.g. axum, as well as the entirety of the Perspective API as previously implement for JavaScript and Python. The following new crates are introduced:

  • perspective (native) has been repurposed as the root native-Rust crate, re-exporting the Rust Client and Server APIs as well as conveniences for linking the two with other libraries like tokio.
  • perspective-viewer (wasm32)is the renamed 2.x perspective crate, and contains the <perspective-viewer> component .
  • perspective-js (wasm32) contains the JavaScript client/server bindings.
  • perspective-python (native) contains the Python (pyO3) bindings, replacing the old C++ based perspective-python.
  • perspective-server (native) wraps the C++ engine for both perspective and perspective-python.
  • perspective-client (native + wasm32) implements the new Protobuf client, both as an abstract base for perspective-js and perspective-python, and as a native Rust client for perspective.

An axum server example has also been added to the examples/ directory.

API Changes

There are a number of API changes. In JavaScript:

  • perspective.table() constructor no longer supports inference for Date and Datetime for JSON columns and rows formats. These non-JSON compatible types can still be coerced into Perspective (or rather - the browser will auto coerce these to numeric types, which Perspective can coerce further), but a schema must be provided to the constructor to inform Perspective to do so. This change simplifies the API quite a bit as well as making it consistent in behavior between Python, JavaScript and Rust.
  • perspective.worker() and perspective.websocket() are now asynchronous and must be await-ed.
  • View.on_update(), View.on_remove(), View.on_delete() now return callback ID values that must be provided to their reciprocal View.remove_update() (etc., respectively).
  • perspective.memory_usage() is renamed perspective.system_info().
    In Python:
  • Perspective now has native sync and async clients, with async being the default.
  • pandas.DataFrame is not longer directly supported by perspective.table(), but they may still be loaded internall if pyarrow is available in the environment. This load path is both dramatically less code and faster than 2.x, but pyarrow is much stringent about type coercion/inference than Perspective 2.x is.

Performance

Linear performance is not the point of this change, nevertheless the benchmarks track a ~15% improvement for the JavaScript (linear) suite.

Screenshot 2024-05-11 at 2 43 25 AM

TODO: Concurrent benchmarks against Python (Tornado) and Rust (Axum) are still pending.

Other project improvements

The documentation content, build process, format, and publication platform have also been updated. Previously, Perspective's docs were built to Markdown via an arcane amalgam of sphinx and jsdoc and then built as docusaurus artifacts. While much of this content has been preserved, it has been mostly moved into the Rustdoc annotations in the API code itself, which allows us to use cargo docs to build the docs site. While this eliminates the language-specific API docs in favor of one unified cross-language (but Rust-centric) doc, the new API is much more consistent between languages.

Perspective's benchmarks have been updated to take advantage of the new API modularity as well, and we can now run the same benchmark suite with the same client across multiple different language & runtime implementations at once, giving us true apples-to-apples performance across feature, version, number of cores, size of dataset, and platform.

@texodus texodus changed the title Virtual API, Rust bindings, Virtual API, Rust bindings, Perspective 3.0 May 11, 2024
@texodus texodus added enhancement Feature requests or improvements breaking labels May 11, 2024
@texodus texodus added this to the 3.0 milestone May 11, 2024
@texodus texodus force-pushed the new-api branch 4 times, most recently from 4396022 to 374150b Compare May 21, 2024 03:39
@texodus texodus changed the title Virtual API, Rust bindings, Perspective 3.0 Perspective Virtual API (JavaScript) May 21, 2024
@texodus texodus force-pushed the new-api branch 2 times, most recently from b32d234 to 6e30bd0 Compare May 21, 2024 07:26
texodus and others added 2 commits May 23, 2024 00:27
Signed-off-by: Timothy Bess <[email protected]>
Signed-off-by: Andrew Stein <[email protected]>
timbess and others added 3 commits May 24, 2024 14:38
Signed-off-by: Timothy Bess <[email protected]>
Signed-off-by: Andrew Stein <[email protected]>
Signed-off-by: Davis Silverman <[email protected]>
Signed-off-by: Andrew Stein <[email protected]>

# Conflicts:
#	Cargo.lock
@texodus texodus force-pushed the new-api branch 2 times, most recently from 51af72f to 56c27f0 Compare May 25, 2024 02:11
Signed-off-by: Andrew Stein <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking enhancement Feature requests or improvements
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants