Skip to content

Commit 2bcd421

Browse files
committed
Implement MigratableKVStore for sqlite
This was unimplemented for the sqlite kv store. Useful if the user wants to migrate to a different database and also in tests so we don't have to re-init and setup a node. AI-assisted-by: OpenAI Codex
1 parent c66676c commit 2bcd421

1 file changed

Lines changed: 82 additions & 1 deletion

File tree

src/io/sqlite_store/mod.rs

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ use std::sync::atomic::{AtomicI64, AtomicU64, Ordering};
1414
use std::sync::{Arc, Mutex};
1515

1616
use lightning::io;
17-
use lightning::util::persist::{KVStore, PageToken, PaginatedKVStore, PaginatedListResponse};
17+
use lightning::util::persist::{
18+
KVStore, MigratableKVStore, PageToken, PaginatedKVStore, PaginatedListResponse,
19+
};
1820
use lightning_types::string::PrintableString;
1921
use rusqlite::{named_params, Connection};
2022

@@ -202,6 +204,21 @@ impl PaginatedKVStore for SqliteStore {
202204
}
203205
}
204206

207+
impl MigratableKVStore for SqliteStore {
208+
fn list_all_keys(
209+
&self,
210+
) -> impl Future<Output = Result<Vec<(String, String, String)>, io::Error>> + 'static + Send {
211+
let inner = Arc::clone(&self.inner);
212+
let fut = tokio::task::spawn_blocking(move || inner.list_all_keys_internal());
213+
async move {
214+
fut.await.unwrap_or_else(|e| {
215+
let msg = format!("Failed to IO operation due join error: {}", e);
216+
Err(io::Error::new(io::ErrorKind::Other, msg))
217+
})
218+
}
219+
}
220+
}
221+
205222
struct SqliteStoreInner {
206223
connection: Arc<Mutex<Connection>>,
207224
data_dir: PathBuf,
@@ -486,6 +503,42 @@ impl SqliteStoreInner {
486503
Ok(keys)
487504
}
488505

506+
fn list_all_keys_internal(&self) -> io::Result<Vec<(String, String, String)>> {
507+
let locked_conn = self.connection.lock().expect("lock");
508+
509+
let sql = format!(
510+
"SELECT primary_namespace, secondary_namespace, key FROM {}",
511+
self.kv_table_name
512+
);
513+
let count_sql = format!("SELECT COUNT(*) FROM {}", self.kv_table_name);
514+
let count: usize =
515+
locked_conn.query_row(&count_sql, [], |row| row.get(0)).map_err(|e| {
516+
let msg = format!("Failed to count rows: {}", e);
517+
io::Error::new(io::ErrorKind::Other, msg)
518+
})?;
519+
520+
let mut stmt = locked_conn.prepare_cached(&sql).map_err(|e| {
521+
let msg = format!("Failed to prepare statement: {}", e);
522+
io::Error::new(io::ErrorKind::Other, msg)
523+
})?;
524+
525+
let mut keys = Vec::with_capacity(count);
526+
let rows_iter =
527+
stmt.query_map([], |row| Ok((row.get(0)?, row.get(1)?, row.get(2)?))).map_err(|e| {
528+
let msg = format!("Failed to retrieve queried rows: {}", e);
529+
io::Error::new(io::ErrorKind::Other, msg)
530+
})?;
531+
532+
for key in rows_iter {
533+
keys.push(key.map_err(|e| {
534+
let msg = format!("Failed to retrieve queried rows: {}", e);
535+
io::Error::new(io::ErrorKind::Other, msg)
536+
})?);
537+
}
538+
539+
Ok(keys)
540+
}
541+
489542
fn list_paginated_internal(
490543
&self, primary_namespace: &str, secondary_namespace: &str, page_token: Option<PageToken>,
491544
) -> io::Result<PaginatedListResponse> {
@@ -679,6 +732,34 @@ mod tests {
679732
do_test_store(&store_0, &store_1)
680733
}
681734

735+
#[tokio::test]
736+
async fn test_sqlite_store_list_all_keys() {
737+
let mut temp_path = random_storage_path();
738+
temp_path.push("test_sqlite_store_list_all_keys");
739+
let store = SqliteStore::new(
740+
temp_path,
741+
Some("test_db".to_string()),
742+
Some("test_table".to_string()),
743+
)
744+
.unwrap();
745+
746+
KVStore::write(&store, "ns_a", "sub_a", "key_a", vec![1u8]).await.unwrap();
747+
KVStore::write(&store, "ns_a", "sub_b", "key_b", vec![2u8]).await.unwrap();
748+
KVStore::write(&store, "ns_b", "", "key_c", vec![3u8]).await.unwrap();
749+
750+
let mut keys = MigratableKVStore::list_all_keys(&store).await.unwrap();
751+
keys.sort();
752+
753+
assert_eq!(
754+
keys,
755+
vec![
756+
("ns_a".to_string(), "sub_a".to_string(), "key_a".to_string()),
757+
("ns_a".to_string(), "sub_b".to_string(), "key_b".to_string()),
758+
("ns_b".to_string(), "".to_string(), "key_c".to_string()),
759+
]
760+
);
761+
}
762+
682763
#[tokio::test]
683764
async fn test_sqlite_store_paginated_listing() {
684765
let mut temp_path = random_storage_path();

0 commit comments

Comments
 (0)