So here is a real-world example. I used to do this: Notice I get to use SQL to update all the relays in the table.

pub async fn clear_all_relay_list_usage_bits() -> Result<(), Error> {

// Keep only bits which are NOT part of relay lists

let sql = format!(

"UPDATE relay SET usage_bits = usage_bits & {}",

!(Self::INBOX | Self::OUTBOX)

);

spawn_blocking(move || {

let db = GLOBALS.db.blocking_lock();

let mut stmt = db.prepare(&sql)?;

rtry!(stmt.execute(()));

Ok::<(), Error>(())

})

.await??;

Ok(())

}

Now I have it like this

pub fn clear_all_relay_list_usage_bits() -> Result<(), Error> {

GLOBALS.storage.modify_all_relays(|relay| {

relay.usage_bits &= Self::INBOX | Self::OUTBOX;

})

}

pub fn modify_all_relays(&self, mut modify: M) -> Result<(), Error>

where

M: FnMut(&mut DbRelay),

{

let mut txn = self.env.begin_rw_txn()?;

let mut cursor = txn.open_rw_cursor(self.relays)?;

let mut iter = cursor.iter_start();

while let Some(result) = iter.next() {

match result {

Err(e) => return Err(e.into()),

Ok((key, val)) => {

let mut dbrelay: DbRelay = serde_json::from_slice(val)?;

modify(&mut dbrelay);

let bytes = serde_json::to_vec(&dbrelay)?;

cursor.put(&key, &bytes, WriteFlags::empty())?;

}

}

}

drop(cursor);

txn.commit()?;

Ok(())

}

(the serde_json serialization is not ideal, but easier since my relay objects have arbitrary JSON content due to containing the NIP-11)

Reply to this note

Please Login to reply.

Discussion

Are you using mozilla/lmdb-rs ?

Was looking at that earlier today but was spooked by the issues mentioning iterator crashes 👀

Seems they've been around at least four years on this repo, and probably longer on the repo this was derived from. If you don't try to drop a cursor and keep using the iterator derived from it, you should be okay. Why they can't have rust enforce that ¯\_(ツ)_/¯