Expand description
§prolly-store-mysql
MySQL-backed remote store adapter for prolly-map.
This crate implements RemoteStoreBackend using sqlx::MySqlPool. Use it
through RemoteProllyStore and AsyncProlly when your deployment standardizes
on MySQL and you want durable Prolly nodes, hints, and named roots in SQL.
§Installation
[dependencies]
prolly-map = "0.4"
prolly-store-mysql = "0.3.0"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }§When to use it
Use this adapter for applications that already operate MySQL and want Prolly map semantics without adding another durable service. It is suitable for transactional application backends, managed MySQL environments, and systems that need ordinary SQL backup, restore, and operational tooling.
Prefer PostgreSQL if your workload benefits from stronger bytea ergonomics or Postgres-specific operational features. Prefer Redis for ephemeral low-latency state and DynamoDB/Cosmos/Spanner for cloud-native managed scale.
§Data model
initialize_schema creates:
prolly_nodes(cid VARBINARY(32) PRIMARY KEY, node LONGBLOB NOT NULL)prolly_hints(namespace VARBINARY(255), key VARBINARY(255), value LONGBLOB)prolly_roots(name VARBINARY(255) PRIMARY KEY, manifest LONGBLOB NOT NULL)
Nodes are content-addressed by CID. Named roots store serialized root manifests and are the stable durable handles for branches, checkpoints, and application heads.
§Setup
Run MySQL locally:
docker run --rm \
-e MYSQL_DATABASE=prolly \
-e MYSQL_USER=prolly \
-e MYSQL_PASSWORD=prolly \
-e MYSQL_ROOT_PASSWORD=prolly \
-p 53306:3306 \
mysql:8.0Or use the Prolly service compose file from the Prolly repo root:
docker compose -p prolly-store-services -f docker-compose.store-services.yml up -d mysqlSet the connection URL:
export PROLLY_STORE_MYSQL_URL=mysql://prolly:prolly@127.0.0.1:53306/prollyInitialize schema during application startup:
let backend = prolly_store_mysql::MySqlBackend::connect(
"mysql://prolly:prolly@127.0.0.1:53306/prolly",
)
.await?;
backend.initialize_schema().await?;§Basic usage
use prolly::{AsyncProlly, Config, Mutation, RemoteProllyStore};
use prolly_store_mysql::MySqlBackend;
let backend = MySqlBackend::connect("mysql://prolly:prolly@127.0.0.1:53306/prolly").await?;
backend.initialize_schema().await?;
let prolly = AsyncProlly::new(RemoteProllyStore::new(backend), Config::default());
let tree = prolly
.batch(
&prolly.create(),
vec![
Mutation::Upsert {
key: b"doc/1".to_vec(),
val: b"draft".to_vec(),
},
Mutation::Upsert {
key: b"doc/2".to_vec(),
val: b"published".to_vec(),
},
],
)
.await?;
prolly.publish_named_root(b"docs/main", &tree).await?;
let loaded = prolly.load_named_root(b"docs/main").await?.expect("root");
assert_eq!(
prolly.get(&loaded, b"doc/1").await?,
Some(b"draft".to_vec())
);§Branching, diff, and merge
let writer_a = prolly
.batch(
&base,
vec![Mutation::Upsert {
key: b"doc/1".to_vec(),
val: b"review".to_vec(),
}],
)
.await?;
let writer_b = prolly
.batch(
&base,
vec![Mutation::Upsert {
key: b"doc/2".to_vec(),
val: b"archived".to_vec(),
}],
)
.await?;
let diffs = prolly.diff(&base, &writer_a).await?;
assert_eq!(diffs.len(), 1);
let merged = prolly.merge(&base, &writer_a, &writer_b, None).await?;
assert_eq!(
prolly.get(&merged, b"doc/2").await?,
Some(b"archived".to_vec())
);§Operational notes
initialize_schemais idempotent.- Strict commits validate named-root preconditions and apply node and root writes in one MySQL transaction.
- MySQL key length limits matter for named roots and hint keys; use compact binary or slash-separated names rather than large serialized metadata in the name itself.
- Node rows are content-addressed and may be shared by many roots.
- Deleting a named root does not immediately delete unreachable nodes.
§Running the example
From the standalone repository root:
export PROLLY_STORE_MYSQL_URL=mysql://prolly:prolly@127.0.0.1:53306/prolly
cargo run --manifest-path stores/prolly-store-mysql/Cargo.toml --example basic_usageThe example initializes schema, writes and branches a tree, diffs and merges branches, resolves a conflict, publishes a named root, and reads it back.
§Testing
The integration test runs when PROLLY_STORE_MYSQL_URL is set and returns
without connecting otherwise:
export PROLLY_STORE_MYSQL_URL=mysql://prolly:prolly@127.0.0.1:53306/prolly
cargo test --manifest-path stores/prolly-store-mysql/Cargo.tomlRun it against a disposable database or schema. The adapter tables are shared by every client using that database.
See the prolly-map API documentation for the
async map, transaction, diff, and merge APIs used with this backend.
Re-exports§
pub use mysql::*;
Modules§
- mysql
- MySQL adapter entry point.
Structs§
- Remote
Named Root - Raw named root manifest returned by a backend scan.
- Remote
Prolly Store - Generic adapter over a remote backend.
- Remote
Root Condition - Serialized named-root value that must still match at transaction commit time.
- Remote
Transaction Conflict - Details for a failed backend-level transaction validation.
Enums§
- Remote
Batch Op - Batch operation passed to a remote backend.
- Remote
Manifest Update - Result of a backend-level root compare-and-swap.
- Remote
Root Write - Serialized named-root write staged by a transaction.
- Remote
Transaction Update - Result of a backend-level transaction commit.
Traits§
- Remote
Store Backend - Backend capability contract used by all provider adapters.