2024-03-09 12:39:39 +01:00
|
|
|
use std::time::Duration;
|
|
|
|
|
2023-12-11 15:35:35 -05:00
|
|
|
use libsql::Database;
|
|
|
|
use serde_json::json;
|
|
|
|
use tempfile::tempdir;
|
|
|
|
use turmoil::Builder;
|
|
|
|
|
|
|
|
use crate::common::{http::Client, net::TurmoilConnector};
|
|
|
|
|
|
|
|
use super::make_primary;
|
|
|
|
|
2024-01-09 16:19:04 -05:00
|
|
|
#[test]
|
|
|
|
fn replicated_config() {
|
2024-03-09 12:39:39 +01:00
|
|
|
let mut sim = Builder::new()
|
|
|
|
.simulation_duration(Duration::from_secs(1000))
|
|
|
|
.build();
|
2024-01-09 16:19:04 -05:00
|
|
|
|
|
|
|
crate::cluster::make_cluster(&mut sim, 1, false);
|
|
|
|
|
|
|
|
sim.client("client", async {
|
|
|
|
let client = Client::new();
|
|
|
|
|
|
|
|
client
|
|
|
|
.post("http://primary:9090/v1/namespaces/foo/create", json!({}))
|
|
|
|
.await
|
|
|
|
.unwrap();
|
|
|
|
|
|
|
|
// Update the config since we can't pass these specific items
|
|
|
|
// to create.
|
|
|
|
client
|
|
|
|
.post(
|
|
|
|
"http://primary:9090/v1/namespaces/foo/config",
|
|
|
|
json!({
|
|
|
|
"block_reads": true,
|
|
|
|
"block_writes": false,
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
// Query primary
|
|
|
|
{
|
|
|
|
let foo = Database::open_remote_with_connector(
|
|
|
|
"http://foo.primary:8080",
|
|
|
|
"",
|
|
|
|
TurmoilConnector,
|
|
|
|
)?;
|
|
|
|
let foo_conn = foo.connect()?;
|
|
|
|
|
|
|
|
foo_conn.execute("select 1", ()).await.unwrap_err();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Query replica
|
|
|
|
{
|
|
|
|
let foo = Database::open_remote_with_connector(
|
|
|
|
"http://foo.replica1:8080",
|
|
|
|
"",
|
|
|
|
TurmoilConnector,
|
|
|
|
)?;
|
|
|
|
let foo_conn = foo.connect()?;
|
|
|
|
|
|
|
|
foo_conn.execute("select 1", ()).await.unwrap_err();
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
});
|
|
|
|
|
|
|
|
sim.run().unwrap();
|
|
|
|
}
|
|
|
|
|
2023-12-11 15:35:35 -05:00
|
|
|
#[test]
|
|
|
|
fn meta_store() {
|
2024-03-09 12:39:39 +01:00
|
|
|
let mut sim = Builder::new()
|
|
|
|
.simulation_duration(Duration::from_secs(1000))
|
|
|
|
.build();
|
2023-12-11 15:35:35 -05:00
|
|
|
let tmp = tempdir().unwrap();
|
|
|
|
make_primary(&mut sim, tmp.path().to_path_buf());
|
|
|
|
|
|
|
|
sim.client("client", async {
|
|
|
|
let client = Client::new();
|
|
|
|
|
|
|
|
// STEP 1: create namespace and check that it can be read from
|
|
|
|
client
|
|
|
|
.post(
|
|
|
|
"http://primary:9090/v1/namespaces/foo/create",
|
|
|
|
json!({
|
|
|
|
"max_db_size": "5mb"
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
{
|
|
|
|
let foo = Database::open_remote_with_connector(
|
|
|
|
"http://foo.primary:8080",
|
|
|
|
"",
|
|
|
|
TurmoilConnector,
|
|
|
|
)?;
|
|
|
|
let foo_conn = foo.connect()?;
|
|
|
|
|
|
|
|
foo_conn.execute("select 1", ()).await.unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
// STEP 2: update namespace config to block reads
|
|
|
|
client
|
|
|
|
.post(
|
|
|
|
"http://primary:9090/v1/namespaces/foo/config",
|
|
|
|
json!({
|
|
|
|
"block_reads": true,
|
|
|
|
"block_writes": false,
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
{
|
|
|
|
let foo = Database::open_remote_with_connector(
|
|
|
|
"http://foo.primary:8080",
|
|
|
|
"",
|
|
|
|
TurmoilConnector,
|
|
|
|
)?;
|
|
|
|
let foo_conn = foo.connect()?;
|
|
|
|
|
|
|
|
foo_conn.execute("select 1", ()).await.unwrap_err();
|
|
|
|
}
|
|
|
|
|
|
|
|
// STEP 3: update config again to un-block reads
|
|
|
|
client
|
|
|
|
.post(
|
|
|
|
"http://primary:9090/v1/namespaces/foo/config",
|
|
|
|
json!({
|
|
|
|
"block_reads": false,
|
|
|
|
"block_writes": false,
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
{
|
|
|
|
let foo = Database::open_remote_with_connector(
|
|
|
|
"http://foo.primary:8080",
|
|
|
|
"",
|
|
|
|
TurmoilConnector,
|
|
|
|
)?;
|
|
|
|
let foo_conn = foo.connect()?;
|
|
|
|
|
|
|
|
foo_conn.execute("select 1", ()).await.unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
});
|
|
|
|
|
|
|
|
sim.run().unwrap();
|
|
|
|
}
|
libsql: attach databases from other namespaces as readonly (#784)
* libsql: attach databases from other namespaces as readonly
With this proof-of-concept patch, other namespaces hosted
on the same sqld machine can now be attached in readonly mode,
so that users can read from other databases when connected
to a particular one.
* connection: add allow_attach to config
Default is false, which means connections are blocked from attaching
databases. If allowed, colocated databases can be attached in readonly
mode.
Example:
→ attach another as another; select * from another.sqlite_master;
TYPE NAME TBL NAME ROOTPAGE SQL
table t3 t3 2 CREATE TABLE t3(id)
* libsql,namespaces: add client-side ATTACH support
* attach: support ATTACH x AS y aliasing
We're going to need it, because the internal database names in sqld
are uuids, and we don't expect users to know or use them.
* attach: fix quoted db names
In libsql-server, raw db names are uuids that need to be quoted,
so that needs to be supported in the ATTACH layer.
As a bonus, "names" that are actually file system paths are refused
to prevent abuse.
* libsql-server: drop stray serde(default) from allow_attach
* libsql-replication: update proto files
* libsql-replication: regenerate protobuf
* tests: move attach to its own test
* libsql-replication: fix proto number after rebase
2024-02-14 11:41:45 +01:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn meta_attach() {
|
2024-03-09 12:39:39 +01:00
|
|
|
let mut sim = Builder::new()
|
|
|
|
.simulation_duration(Duration::from_secs(1000))
|
|
|
|
.build();
|
libsql: attach databases from other namespaces as readonly (#784)
* libsql: attach databases from other namespaces as readonly
With this proof-of-concept patch, other namespaces hosted
on the same sqld machine can now be attached in readonly mode,
so that users can read from other databases when connected
to a particular one.
* connection: add allow_attach to config
Default is false, which means connections are blocked from attaching
databases. If allowed, colocated databases can be attached in readonly
mode.
Example:
→ attach another as another; select * from another.sqlite_master;
TYPE NAME TBL NAME ROOTPAGE SQL
table t3 t3 2 CREATE TABLE t3(id)
* libsql,namespaces: add client-side ATTACH support
* attach: support ATTACH x AS y aliasing
We're going to need it, because the internal database names in sqld
are uuids, and we don't expect users to know or use them.
* attach: fix quoted db names
In libsql-server, raw db names are uuids that need to be quoted,
so that needs to be supported in the ATTACH layer.
As a bonus, "names" that are actually file system paths are refused
to prevent abuse.
* libsql-server: drop stray serde(default) from allow_attach
* libsql-replication: update proto files
* libsql-replication: regenerate protobuf
* tests: move attach to its own test
* libsql-replication: fix proto number after rebase
2024-02-14 11:41:45 +01:00
|
|
|
let tmp = tempdir().unwrap();
|
|
|
|
make_primary(&mut sim, tmp.path().to_path_buf());
|
|
|
|
|
|
|
|
sim.client("client", async {
|
|
|
|
let client = Client::new();
|
|
|
|
|
|
|
|
// STEP 1: create namespace and check that it can be read from
|
|
|
|
client
|
|
|
|
.post(
|
|
|
|
"http://primary:9090/v1/namespaces/foo/create",
|
|
|
|
json!({
|
|
|
|
"max_db_size": "5mb"
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
{
|
|
|
|
let foo = Database::open_remote_with_connector(
|
|
|
|
"http://foo.primary:8080",
|
|
|
|
"",
|
|
|
|
TurmoilConnector,
|
|
|
|
)?;
|
|
|
|
let foo_conn = foo.connect()?;
|
|
|
|
|
|
|
|
foo_conn.execute("select 1", ()).await.unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
// STEP 2: try attaching a database
|
|
|
|
{
|
|
|
|
let foo = Database::open_remote_with_connector(
|
|
|
|
"http://foo.primary:8080",
|
|
|
|
"",
|
|
|
|
TurmoilConnector,
|
|
|
|
)?;
|
|
|
|
let foo_conn = foo.connect()?;
|
|
|
|
|
|
|
|
foo_conn.execute("attach foo as foo", ()).await.unwrap_err();
|
|
|
|
}
|
|
|
|
|
|
|
|
// STEP 3: update config to allow attaching databases
|
|
|
|
client
|
|
|
|
.post(
|
|
|
|
"http://primary:9090/v1/namespaces/foo/config",
|
|
|
|
json!({
|
|
|
|
"block_reads": false,
|
|
|
|
"block_writes": false,
|
|
|
|
"allow_attach": true,
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
{
|
|
|
|
let foo = Database::open_remote_with_connector(
|
|
|
|
"http://foo.primary:8080",
|
|
|
|
"",
|
|
|
|
TurmoilConnector,
|
|
|
|
)?;
|
|
|
|
let foo_conn = foo.connect()?;
|
|
|
|
|
|
|
|
foo_conn
|
|
|
|
.execute_batch("attach foo as foo; select * from foo.sqlite_master")
|
|
|
|
.await
|
|
|
|
.unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
});
|
|
|
|
|
|
|
|
sim.run().unwrap();
|
|
|
|
}
|
2024-03-20 05:41:05 -07:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn meta_attach_shared_schema() {
|
|
|
|
let mut sim = Builder::new()
|
|
|
|
.simulation_duration(Duration::from_secs(1000))
|
|
|
|
.build();
|
|
|
|
let tmp = tempdir().unwrap();
|
|
|
|
make_primary(&mut sim, tmp.path().to_path_buf());
|
|
|
|
|
|
|
|
sim.client("client", async {
|
|
|
|
let client = Client::new();
|
|
|
|
|
|
|
|
// STEP 1: create two namespaces, one for the shared schema and one that borrows that
|
|
|
|
// shared schema and check that it can be read from
|
|
|
|
client
|
|
|
|
.post(
|
|
|
|
"http://primary:9090/v1/namespaces/schema/create",
|
|
|
|
json!({
|
|
|
|
"shared_schema": true
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
client
|
|
|
|
.post(
|
|
|
|
"http://primary:9090/v1/namespaces/foo/create",
|
|
|
|
json!({
|
|
|
|
"shared_schema_name": "schema"
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
// STEP 3: update config to allow attaching databases
|
|
|
|
client
|
|
|
|
.post(
|
|
|
|
"http://primary:9090/v1/namespaces/foo/config",
|
|
|
|
json!({
|
|
|
|
"block_reads": false,
|
|
|
|
"block_writes": false,
|
|
|
|
"allow_attach": true,
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
{
|
|
|
|
let foo = Database::open_remote_with_connector(
|
|
|
|
"http://foo.primary:8080",
|
|
|
|
"",
|
|
|
|
TurmoilConnector,
|
|
|
|
)?;
|
|
|
|
let foo_conn = foo.connect()?;
|
|
|
|
|
|
|
|
foo_conn
|
|
|
|
.execute_batch("attach foo as foo; select * from foo.sqlite_master")
|
|
|
|
.await
|
|
|
|
.unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
});
|
|
|
|
|
|
|
|
sim.run().unwrap();
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn meta_config_update() {
|
|
|
|
let mut sim = Builder::new()
|
|
|
|
.simulation_duration(Duration::from_secs(1000))
|
|
|
|
.build();
|
|
|
|
let tmp = tempdir().unwrap();
|
|
|
|
make_primary(&mut sim, tmp.path().to_path_buf());
|
|
|
|
|
|
|
|
sim.client("client", async {
|
|
|
|
let client = Client::new();
|
|
|
|
|
|
|
|
// STEP 1: create two namespaces, one for the shared schema and one that borrows that
|
|
|
|
// shared schema and check that it can be read from
|
|
|
|
client
|
|
|
|
.post(
|
|
|
|
"http://primary:9090/v1/namespaces/foo/create",
|
|
|
|
json!({
|
|
|
|
"max_db_size": "5mb"
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
// STEP 3: update config to allow attaching databases
|
|
|
|
client
|
|
|
|
.post(
|
|
|
|
"http://primary:9090/v1/namespaces/foo/config",
|
|
|
|
json!({
|
|
|
|
"block_reads": false,
|
|
|
|
"block_writes": false,
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
// STEP 4: update config again
|
|
|
|
client
|
|
|
|
.post(
|
|
|
|
"http://primary:9090/v1/namespaces/foo/config",
|
|
|
|
json!({
|
|
|
|
"block_reads": false,
|
|
|
|
"block_writes": true,
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
});
|
|
|
|
|
|
|
|
sim.run().unwrap();
|
|
|
|
}
|