Merge "Add helper function to insert with retry."

This commit is contained in:
Treehugger Robot 2020-09-14 16:46:05 +00:00 committed by Gerrit Code Review
commit b6375273ac

View file

@ -269,27 +269,14 @@ impl KeystoreDB {
.context(format!("Domain {:?} must be either App or SELinux.", domain)); .context(format!("Domain {:?} must be either App or SELinux.", domain));
} }
} }
// Loop until we get a unique id. Self::insert_with_retry(|id| {
loop { self.conn.execute(
let newid: i64 = random();
let ret = self.conn.execute(
"INSERT into persistent.keyentry (id, creation_date, domain, namespace, alias) "INSERT into persistent.keyentry (id, creation_date, domain, namespace, alias)
VALUES(?, datetime('now'), ?, ?, NULL);", VALUES(?, datetime('now'), ?, ?, NULL);",
params![newid, domain as i64, namespace], params![id, domain as i64, namespace],
); )
match ret { })
// If the id already existed, try again. .context("In create_key_entry")
Err(rusqlite::Error::SqliteFailure(
libsqlite3_sys::Error {
code: libsqlite3_sys::ErrorCode::ConstraintViolation,
extended_code: libsqlite3_sys::SQLITE_CONSTRAINT_UNIQUE,
},
_,
)) => (),
Err(e) => return Err(e).context("Failed to create key entry."),
_ => return Ok(newid),
}
}
} }
/// Inserts a new blob and associates it with the given key id. Each blob /// Inserts a new blob and associates it with the given key id. Each blob
@ -683,26 +670,14 @@ impl KeystoreDB {
.context("In grant: Failed to update existing grant.")?; .context("In grant: Failed to update existing grant.")?;
grant_id grant_id
} else { } else {
loop { Self::insert_with_retry(|id| {
let newid: i64 = random(); tx.execute(
let ret = tx.execute(
"INSERT INTO perboot.grant (id, grantee, keyentryid, access_vector) "INSERT INTO perboot.grant (id, grantee, keyentryid, access_vector)
VALUES (?, ?, ?, ?);", VALUES (?, ?, ?, ?);",
params![newid, grantee_uid, key_id, i32::from(access_vector)], params![id, grantee_uid, key_id, i32::from(access_vector)],
); )
match ret { })
// If the id already existed, try again. .context("In grant")?
Err(rusqlite::Error::SqliteFailure(
libsqlite3_sys::Error {
code: libsqlite3_sys::ErrorCode::ConstraintViolation,
extended_code: libsqlite3_sys::SQLITE_CONSTRAINT_UNIQUE,
},
_,
)) => (),
Err(e) => return Err(e).context("Failed to insert grant."),
Ok(_) => break newid,
}
}
}; };
tx.commit().context("In grant: failed to commit transaction.")?; tx.commit().context("In grant: failed to commit transaction.")?;
@ -744,6 +719,29 @@ impl KeystoreDB {
Ok(()) Ok(())
} }
// Generates a random id and passes it to the given function, which will
// try to insert it into a database. If that insertion fails, retry;
// otherwise return the id.
fn insert_with_retry(inserter: impl Fn(i64) -> rusqlite::Result<usize>) -> Result<i64> {
loop {
let newid: i64 = random();
match inserter(newid) {
// If the id already existed, try again.
Err(rusqlite::Error::SqliteFailure(
libsqlite3_sys::Error {
code: libsqlite3_sys::ErrorCode::ConstraintViolation,
extended_code: libsqlite3_sys::SQLITE_CONSTRAINT_UNIQUE,
},
_,
)) => (),
Err(e) => {
return Err(e).context("In insert_with_retry: failed to insert into database.")
}
_ => return Ok(newid),
}
}
}
// Takes Rows as returned by a query call on prepared statement. // Takes Rows as returned by a query call on prepared statement.
// Extracts exactly one row with the `row_extractor` and fails if more // Extracts exactly one row with the `row_extractor` and fails if more
// rows are available. // rows are available.