ok/jj
1
0
Fork 0
forked from mirrors/jj

git_store: extract function for retrying note-writing

I'll add a second call to it very soon.
This commit is contained in:
Martin von Zweigbergk 2020-12-24 23:21:06 -08:00
parent ddf8416d92
commit 8cca56ee77

View file

@ -28,9 +28,9 @@ use crate::store::{
Signature, Store, StoreError, StoreResult, SymlinkId, Timestamp, Tree, TreeId, TreeValue,
};
use backoff::{ExponentialBackoff, Operation};
use std::ops::Deref;
const NOTES_REF: &str = "refs/notes/jj/commits";
const NOTES_REF_LOCK: &str = "refs/notes/jj/commits.lock";
const CONFLICT_SUFFIX: &str = ".jjconflict";
impl From<git2::Error> for StoreError {
@ -108,6 +108,39 @@ fn deserialize_note(commit: &mut Commit, note: &str) {
}
}
fn write_note(
git_repo: &git2::Repository,
committer: &git2::Signature,
notes_ref: &str,
oid: git2::Oid,
note: &str,
) -> Result<(), git2::Error> {
// It seems that libgit2 doesn't retry when .git/refs/notes/jj/commits.lock
// already exists, so we do the retrying ourselves.
// TODO: Report this to libgit2.
let notes_ref_lock = format!("{}.lock", notes_ref);
let mut try_write_note = || {
let note_status = git_repo.note(&committer, &committer, Some(notes_ref), oid, note, false);
match note_status {
Err(err) if err.message().contains(&notes_ref_lock) => {
Err(backoff::Error::Transient(err))
}
Err(err) => Err(backoff::Error::Permanent(err)),
Ok(_) => Ok(()),
}
};
let mut backoff = ExponentialBackoff::default();
backoff.initial_interval = Duration::from_millis(1);
backoff.max_elapsed_time = Some(Duration::from_secs(10));
try_write_note
.retry(&mut backoff)
.map_err(|err| match err {
backoff::Error::Permanent(err) => err,
backoff::Error::Transient(err) => err,
})?;
Ok(())
}
impl Debug for GitStore {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
f.debug_struct("GitStore")
@ -317,36 +350,7 @@ impl Store for GitStore {
// TODO: Include the extra commit data in commit headers instead of a ref.
// Unfortunately, it doesn't seem like libgit2-rs supports that. Perhaps
// we'll have to serialize/deserialize the commit data ourselves.
// It seems that libgit2 doesn't retry when .git/refs/notes/jj/commits.lock
// already exists, so we do the retrying ourselves.
// TODO: Report this to libgit2.
let mut try_write_note = || {
let note_status = locked_repo.note(
&committer,
&committer,
Some(NOTES_REF),
git_id,
&note,
false,
);
match note_status {
Err(err) if err.message().contains(NOTES_REF_LOCK) => {
Err(backoff::Error::Transient(err))
}
Err(err) => Err(backoff::Error::Permanent(err)),
Ok(_) => Ok(()),
}
};
let mut backoff = ExponentialBackoff::default();
backoff.initial_interval = Duration::from_millis(1);
backoff.max_elapsed_time = Some(Duration::from_secs(10));
try_write_note
.retry(&mut backoff)
.map_err(|err| match err {
backoff::Error::Permanent(err) => err,
backoff::Error::Transient(err) => err,
})?;
write_note(locked_repo.deref(), &committer, NOTES_REF, git_id, &note)?;
Ok(id)
}