Skip to content

Commit 4b4a993

Browse files
committed
fix(index): deferr SQLite insertions
1 parent 4ab7aab commit 4b4a993

File tree

1 file changed

+37
-8
lines changed
  • src/cargo/sources/registry/index

1 file changed

+37
-8
lines changed

src/cargo/sources/registry/index/cache.rs

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@
6666
//! [`RemoteRegistry`]: crate::sources::registry::remote::RemoteRegistry
6767
6868
use std::cell::OnceCell;
69+
use std::cell::RefCell;
70+
use std::collections::BTreeMap;
6971
use std::fs;
7072
use std::io;
7173
use std::path::PathBuf;
@@ -337,8 +339,9 @@ struct LocalDatabase<'gctx> {
337339
/// The root path where caches are located.
338340
cache_root: Filesystem,
339341
/// Connection to the SQLite database.
340-
conn: OnceCell<Option<Connection>>,
342+
conn: OnceCell<Option<RefCell<Connection>>>,
341343
/// [`GlobalContext`] reference for convenience.
344+
deferred_writes: RefCell<BTreeMap<String, Vec<u8>>>,
342345
gctx: &'gctx GlobalContext,
343346
}
344347

@@ -348,14 +351,16 @@ impl LocalDatabase<'_> {
348351
LocalDatabase {
349352
cache_root,
350353
conn: OnceCell::new(),
354+
deferred_writes: RefCell::new(BTreeMap::new()),
351355
gctx,
352356
}
353357
}
354358

355-
fn conn(&self) -> Option<&Connection> {
359+
fn conn(&self) -> Option<&RefCell<Connection>> {
356360
self.conn
357361
.get_or_init(|| {
358362
self.conn_init()
363+
.map(RefCell::new)
359364
.map_err(|e| tracing::debug!("cannot open index cache db: {e}"))
360365
.ok()
361366
})
@@ -373,29 +378,53 @@ impl LocalDatabase<'_> {
373378
sqlite::migrate(&mut conn, &migrations())?;
374379
Ok(conn)
375380
}
381+
382+
fn bulk_put(&self) -> CargoResult<()> {
383+
let Some(conn) = self.conn() else {
384+
anyhow::bail!("no connection");
385+
};
386+
let mut conn = conn.borrow_mut();
387+
let tx = conn.transaction()?;
388+
let mut stmt =
389+
tx.prepare_cached("INSERT OR REPLACE INTO summaries (name, value) VALUES (?, ?)")?;
390+
for (key, value) in self.deferred_writes.borrow().iter() {
391+
stmt.execute(params!(key, value))?;
392+
}
393+
drop(stmt);
394+
tx.commit()?;
395+
self.deferred_writes.borrow_mut().clear();
396+
Ok(())
397+
}
398+
}
399+
400+
impl Drop for LocalDatabase<'_> {
401+
fn drop(&mut self) {
402+
let _ = self
403+
.bulk_put()
404+
.map_err(|e| tracing::info!("failed to flush cache: {e}"));
405+
}
376406
}
377407

378408
impl CacheStore for LocalDatabase<'_> {
379409
fn get(&self, key: &str) -> Option<Vec<u8>> {
380410
self.conn()?
411+
.borrow()
381412
.prepare_cached("SELECT value FROM summaries WHERE name = ? LIMIT 1")
382413
.and_then(|mut stmt| stmt.query_row([key], |row| row.get(0)))
383414
.map_err(|e| tracing::debug!(key, "cache missing: {e}"))
384415
.ok()
385416
}
386417

387418
fn put(&self, key: &str, value: &[u8]) {
388-
if let Some(conn) = self.conn() {
389-
_ = conn
390-
.prepare_cached("INSERT OR REPLACE INTO summaries (name, value) VALUES (?, ?)")
391-
.and_then(|mut stmt| stmt.execute(params!(key, value)))
392-
.map_err(|e| tracing::info!(key, "failed to write cache: {e}"));
393-
}
419+
self.deferred_writes
420+
.borrow_mut()
421+
.insert(key.into(), value.into());
394422
}
395423

396424
fn invalidate(&self, key: &str) {
397425
if let Some(conn) = self.conn() {
398426
_ = conn
427+
.borrow()
399428
.prepare_cached("DELETE FROM summaries WHERE name = ?")
400429
.and_then(|mut stmt| stmt.execute([key]))
401430
.map_err(|e| tracing::debug!(key, "failed to remove from cache: {e}"));

0 commit comments

Comments
 (0)