Skip to content
This repository was archived by the owner on Sep 9, 2025. It is now read-only.

Commit d093083

Browse files
author
Hendrik van Antwerpen
authored
Merge pull request #288 from github/binary-database
Store messagepack values in database instead of JSON
2 parents 3a02ff5 + acb0fab commit d093083

File tree

3 files changed

+40
-35
lines changed

3 files changed

+40
-35
lines changed

stack-graphs/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111

1212
- The `Appendable` trait has been simplified. Its `Ctx` type parameter is gone, in favor of a separate trait `ToAppendable` that is used to find appendables for a handle. The type itself moved from the `cycles` to the `stitching` module.
1313
- The `ForwardPartialPathStitcher` has been generalized so that it can be used to build paths from a database or from graph edges. It now takes a type parameter indicating the type of candidates it uses. Instead of a `Database` instance, it expects a value that implements the `Candidates` and `ToAppendable` traits. The `ForwardPartialPathStitcher::process_next_phase` expects an additional `extend_until` closure that controls whether the extended paths are considered for further extension or not (using `|_,_,_| true` retains old behavior).
14+
- The SQLite database implementation is using a new schema which stores binary instead of JSON values, resulting in faster write times and smaller databases.
1415

1516
### Fixed
1617

stack-graphs/Cargo.toml

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ edition = "2018"
1515
[features]
1616
copious-debugging = []
1717
serde = ["dep:serde", "lsp-positions/serde"]
18-
storage = ["rusqlite", "serde"]
18+
storage = ["rusqlite", "serde", "rmp-serde"]
1919
visualization = ["serde", "serde_json"]
2020

2121
[lib]
@@ -30,19 +30,20 @@ enumset = "1.0"
3030
fxhash = "0.2"
3131
itertools = "0.10"
3232
libc = "0.2"
33-
lsp-positions = { version="0.3", path="../lsp-positions" }
34-
rusqlite = { version = "0.28", optional=true, features = ["bundled", "functions"] }
35-
serde = { version="1.0", optional=true, features = ["derive"] }
36-
serde_json = { version="1.0", optional=true }
37-
smallvec = { version="1.6", features=["union"] }
38-
thiserror = { version="1.0" }
33+
lsp-positions = { version = "0.3", path = "../lsp-positions" }
34+
rmp-serde = { version = "1.1", optional = true }
35+
rusqlite = { version = "0.28", optional = true, features = ["bundled", "functions"] }
36+
serde = { version = "1.0", optional = true, features = ["derive"] }
37+
serde_json = { version = "1.0", optional = true }
38+
smallvec = { version = "1.6", features = ["union"] }
39+
thiserror = { version = "1.0" }
3940

4041
[dev-dependencies]
4142
assert-json-diff = "2"
4243
itertools = "0.10"
4344
maplit = "1.0"
4445
pretty_assertions = "0.7"
45-
serde_json = { version="1.0" }
46+
serde_json = { version = "1.0" }
4647

4748
[package.metadata.docs.rs]
4849
all-features = true

stack-graphs/src/storage.rs

Lines changed: 30 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use crate::stitching::ForwardPartialPathStitcher;
3030
use crate::CancellationError;
3131
use crate::CancellationFlag;
3232

33-
const VERSION: usize = 2;
33+
const VERSION: usize = 3;
3434

3535
const SCHEMA: &str = r#"
3636
CREATE TABLE metadata (
@@ -40,18 +40,18 @@ const SCHEMA: &str = r#"
4040
file TEXT PRIMARY KEY,
4141
tag TEXT NOT NULL,
4242
error TEXT,
43-
json BLOB NOT NULL
43+
value BLOB NOT NULL
4444
) STRICT;
4545
CREATE TABLE file_paths (
4646
file TEXT NOT NULL,
4747
local_id INTEGER NOT NULL,
48-
json BLOB NOT NULL,
48+
value BLOB NOT NULL,
4949
FOREIGN KEY(file) REFERENCES graphs(file)
5050
) STRICT;
5151
CREATE TABLE root_paths (
5252
file TEXT NOT NULL,
5353
symbol_stack TEXT NOT NULL,
54-
json BLOB NOT NULL,
54+
value BLOB NOT NULL,
5555
FOREIGN KEY(file) REFERENCES graphs(file)
5656
) STRICT;
5757
"#;
@@ -75,7 +75,9 @@ pub enum StorageError {
7575
#[error(transparent)]
7676
Serde(#[from] serde::Error),
7777
#[error(transparent)]
78-
SerdeJson(#[from] serde_json::Error),
78+
RmpSerdeDecode(#[from] rmp_serde::decode::Error),
79+
#[error(transparent)]
80+
RmpSerdeEncode(#[from] rmp_serde::encode::Error),
7981
}
8082

8183
pub type Result<T> = std::result::Result<T, StorageError>;
@@ -274,14 +276,14 @@ impl SQLiteWriter {
274276
error: &str,
275277
) -> Result<()> {
276278
copious_debugging!("--> Store error for {}", file.display());
277-
let mut stmt =
278-
conn.prepare_cached("INSERT INTO graphs (file, tag, error, json) VALUES (?, ?, ?, ?)")?;
279+
let mut stmt = conn
280+
.prepare_cached("INSERT INTO graphs (file, tag, error, value) VALUES (?, ?, ?, ?)")?;
279281
let graph = crate::serde::StackGraph::default();
280282
stmt.execute((
281283
&file.to_string_lossy(),
282284
tag,
283285
error,
284-
&serde_json::to_vec(&graph)?,
286+
&rmp_serde::to_vec(&graph)?,
285287
))?;
286288
Ok(())
287289
}
@@ -319,9 +321,9 @@ impl SQLiteWriter {
319321
let file_str = graph[file].name();
320322
copious_debugging!("--> Store graph for {}", file_str);
321323
let mut stmt =
322-
conn.prepare_cached("INSERT INTO graphs (file, tag, json) VALUES (?, ?, ?)")?;
324+
conn.prepare_cached("INSERT INTO graphs (file, tag, value) VALUES (?, ?, ?)")?;
323325
let graph = serde::StackGraph::from_graph_filter(graph, &FileFilter(file));
324-
stmt.execute((file_str, tag, &serde_json::to_vec(&graph)?))?;
326+
stmt.execute((file_str, tag, &rmp_serde::to_vec(&graph)?))?;
325327
Ok(())
326328
}
327329

@@ -340,9 +342,10 @@ impl SQLiteWriter {
340342
{
341343
let file_str = graph[file].name();
342344
let mut node_stmt =
343-
conn.prepare_cached("INSERT INTO file_paths (file, local_id, json) VALUES (?, ?, ?)")?;
344-
let mut root_stmt = conn
345-
.prepare_cached("INSERT INTO root_paths (file, symbol_stack, json) VALUES (?, ?, ?)")?;
345+
conn.prepare_cached("INSERT INTO file_paths (file, local_id, value) VALUES (?, ?, ?)")?;
346+
let mut root_stmt = conn.prepare_cached(
347+
"INSERT INTO root_paths (file, symbol_stack, value) VALUES (?, ?, ?)",
348+
)?;
346349
#[cfg_attr(not(feature = "copious-debugging"), allow(unused))]
347350
let mut node_path_count = 0usize;
348351
#[cfg_attr(not(feature = "copious-debugging"), allow(unused))]
@@ -361,7 +364,7 @@ impl SQLiteWriter {
361364
);
362365
let symbol_stack = path.symbol_stack_precondition.storage_key(graph, partials);
363366
let path = serde::PartialPath::from_partial_path(graph, partials, path);
364-
root_stmt.execute((file_str, symbol_stack, &serde_json::to_vec(&path)?))?;
367+
root_stmt.execute((file_str, symbol_stack, &rmp_serde::to_vec(&path)?))?;
365368
root_path_count += 1;
366369
} else if start_node.is_in_file(file) {
367370
copious_debugging!(
@@ -372,7 +375,7 @@ impl SQLiteWriter {
372375
node_stmt.execute((
373376
file_str,
374377
path.start_node.local_id,
375-
&serde_json::to_vec(&path)?,
378+
&rmp_serde::to_vec(&path)?,
376379
))?;
377380
node_path_count += 1;
378381
} else {
@@ -499,8 +502,8 @@ impl SQLiteReader {
499502
}
500503
copious_debugging!(" * Load from database");
501504
let mut stmt = conn.prepare_cached("SELECT json FROM graphs WHERE file = ?")?;
502-
let json_graph = stmt.query_row([file], |row| row.get::<_, Vec<u8>>(0))?;
503-
let file_graph = serde_json::from_slice::<serde::StackGraph>(&json_graph)?;
505+
let value = stmt.query_row([file], |row| row.get::<_, Vec<u8>>(0))?;
506+
let file_graph = rmp_serde::from_slice::<serde::StackGraph>(&value)?;
504507
file_graph.load_into(graph)?;
505508
Ok(())
506509
}
@@ -539,24 +542,24 @@ impl SQLiteReader {
539542
let file = self.graph[file].name();
540543
let mut stmt = self
541544
.conn
542-
.prepare_cached("SELECT file,json from file_paths WHERE file = ? AND local_id = ?")?;
545+
.prepare_cached("SELECT file,value from file_paths WHERE file = ? AND local_id = ?")?;
543546
let paths = stmt.query_map((file, id.local_id()), |row| {
544547
let file = row.get::<_, String>(0)?;
545-
let json = row.get::<_, Vec<u8>>(1)?;
546-
Ok((file, json))
548+
let value = row.get::<_, Vec<u8>>(1)?;
549+
Ok((file, value))
547550
})?;
548551
#[cfg_attr(not(feature = "copious-debugging"), allow(unused))]
549552
let mut count = 0usize;
550553
for path in paths {
551554
cancellation_flag.check("loading node paths")?;
552-
let (file, json) = path?;
555+
let (file, value) = path?;
553556
Self::load_graph_for_file_inner(
554557
&file,
555558
&mut self.graph,
556559
&mut self.loaded_graphs,
557560
&self.conn,
558561
)?;
559-
let path = serde_json::from_slice::<serde::PartialPath>(&json)?;
562+
let path = rmp_serde::from_slice::<serde::PartialPath>(&value)?;
560563
let path = path.to_partial_path(&mut self.graph, &mut self.partials)?;
561564
copious_debugging!(
562565
" > Loaded {}",
@@ -593,24 +596,24 @@ impl SQLiteReader {
593596
}
594597
let mut stmt = self
595598
.conn
596-
.prepare_cached("SELECT file,json from root_paths WHERE symbol_stack = ?")?;
599+
.prepare_cached("SELECT file,value from root_paths WHERE symbol_stack = ?")?;
597600
let paths = stmt.query_map([symbol_stack], |row| {
598601
let file = row.get::<_, String>(0)?;
599-
let json = row.get::<_, Vec<u8>>(1)?;
600-
Ok((file, json))
602+
let value = row.get::<_, Vec<u8>>(1)?;
603+
Ok((file, value))
601604
})?;
602605
#[cfg_attr(not(feature = "copious-debugging"), allow(unused))]
603606
let mut count = 0usize;
604607
for path in paths {
605608
cancellation_flag.check("loading root paths")?;
606-
let (file, json) = path?;
609+
let (file, value) = path?;
607610
Self::load_graph_for_file_inner(
608611
&file,
609612
&mut self.graph,
610613
&mut self.loaded_graphs,
611614
&self.conn,
612615
)?;
613-
let path = serde_json::from_slice::<serde::PartialPath>(&json)?;
616+
let path = rmp_serde::from_slice::<serde::PartialPath>(&value)?;
614617
let path = path.to_partial_path(&mut self.graph, &mut self.partials)?;
615618
copious_debugging!(
616619
" > Loaded {}",

0 commit comments

Comments
 (0)