forked from mirrors/jj
simple_op_store: add deserialization support of new Conflict-based RefTarget
CommitId is wrapped with a message since we need a representation for None. This is different from TreeConflict in which an empty tree has an id.
This commit is contained in:
parent
2382ae09e2
commit
8351a743f6
3 changed files with 87 additions and 9 deletions
|
@ -16,15 +16,25 @@ syntax = "proto3";
|
|||
|
||||
package op_store;
|
||||
|
||||
message RefConflictLegacy {
|
||||
repeated bytes removes = 1 [deprecated = true];
|
||||
repeated bytes adds = 2 [deprecated = true];
|
||||
}
|
||||
|
||||
message RefConflict {
|
||||
repeated bytes removes = 1;
|
||||
repeated bytes adds = 2;
|
||||
message Term {
|
||||
optional bytes value = 1;
|
||||
}
|
||||
repeated Term removes = 1;
|
||||
repeated Term adds = 2;
|
||||
}
|
||||
|
||||
message RefTarget {
|
||||
// New `RefConflict` type represents both `commit_id` and `conflict_legacy`.
|
||||
oneof value {
|
||||
bytes commit_id = 1;
|
||||
RefConflict conflict = 2;
|
||||
bytes commit_id = 1 [deprecated = true];
|
||||
RefConflictLegacy conflict_legacy = 2 [deprecated = true];
|
||||
RefConflict conflict = 3;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,25 +1,48 @@
|
|||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct RefConflict {
|
||||
pub struct RefConflictLegacy {
|
||||
#[deprecated]
|
||||
#[prost(bytes = "vec", repeated, tag = "1")]
|
||||
pub removes: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec<u8>>,
|
||||
#[deprecated]
|
||||
#[prost(bytes = "vec", repeated, tag = "2")]
|
||||
pub adds: ::prost::alloc::vec::Vec<::prost::alloc::vec::Vec<u8>>,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct RefConflict {
|
||||
#[prost(message, repeated, tag = "1")]
|
||||
pub removes: ::prost::alloc::vec::Vec<ref_conflict::Term>,
|
||||
#[prost(message, repeated, tag = "2")]
|
||||
pub adds: ::prost::alloc::vec::Vec<ref_conflict::Term>,
|
||||
}
|
||||
/// Nested message and enum types in `RefConflict`.
|
||||
pub mod ref_conflict {
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct Term {
|
||||
#[prost(bytes = "vec", optional, tag = "1")]
|
||||
pub value: ::core::option::Option<::prost::alloc::vec::Vec<u8>>,
|
||||
}
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct RefTarget {
|
||||
#[prost(oneof = "ref_target::Value", tags = "1, 2")]
|
||||
/// New `RefConflict` type represents both `commit_id` and `conflict_legacy`.
|
||||
#[prost(oneof = "ref_target::Value", tags = "1, 2, 3")]
|
||||
pub value: ::core::option::Option<ref_target::Value>,
|
||||
}
|
||||
/// Nested message and enum types in `RefTarget`.
|
||||
pub mod ref_target {
|
||||
/// New `RefConflict` type represents both `commit_id` and `conflict_legacy`.
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Oneof)]
|
||||
pub enum Value {
|
||||
#[prost(bytes, tag = "1")]
|
||||
CommitId(::prost::alloc::vec::Vec<u8>),
|
||||
#[prost(message, tag = "2")]
|
||||
ConflictLegacy(super::RefConflictLegacy),
|
||||
#[prost(message, tag = "3")]
|
||||
Conflict(super::RefConflict),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ use tempfile::{NamedTempFile, PersistError};
|
|||
use thiserror::Error;
|
||||
|
||||
use crate::backend::{CommitId, MillisSinceEpoch, ObjectId, Timestamp};
|
||||
use crate::conflicts::Conflict;
|
||||
use crate::content_hash::blake2b_hash;
|
||||
use crate::file_util::persist_content_addressed_temp_file;
|
||||
use crate::op_store::{
|
||||
|
@ -355,6 +356,7 @@ fn view_from_proto(proto: crate::protos::op_store::View) -> View {
|
|||
view
|
||||
}
|
||||
|
||||
#[allow(deprecated)]
|
||||
fn ref_target_to_proto(value: &RefTarget) -> Option<crate::protos::op_store::RefTarget> {
|
||||
if let Some(id) = value.as_normal() {
|
||||
let proto = crate::protos::op_store::RefTarget {
|
||||
|
@ -365,12 +367,12 @@ fn ref_target_to_proto(value: &RefTarget) -> Option<crate::protos::op_store::Ref
|
|||
Some(proto)
|
||||
} else if value.has_conflict() {
|
||||
// TODO: Preserve "absent" targets, and remove op_store::RefTargetMap hack.
|
||||
let ref_conflict_proto = crate::protos::op_store::RefConflict {
|
||||
let ref_conflict_proto = crate::protos::op_store::RefConflictLegacy {
|
||||
removes: value.removed_ids().map(|id| id.to_bytes()).collect(),
|
||||
adds: value.added_ids().map(|id| id.to_bytes()).collect(),
|
||||
};
|
||||
let proto = crate::protos::op_store::RefTarget {
|
||||
value: Some(crate::protos::op_store::ref_target::Value::Conflict(
|
||||
value: Some(crate::protos::op_store::ref_target::Value::ConflictLegacy(
|
||||
ref_conflict_proto,
|
||||
)),
|
||||
};
|
||||
|
@ -383,17 +385,29 @@ fn ref_target_to_proto(value: &RefTarget) -> Option<crate::protos::op_store::Ref
|
|||
|
||||
fn ref_target_from_proto(maybe_proto: Option<crate::protos::op_store::RefTarget>) -> RefTarget {
|
||||
let Some(proto) = maybe_proto else {
|
||||
// Legacy absent id
|
||||
return RefTarget::absent();
|
||||
};
|
||||
match proto.value.unwrap() {
|
||||
#[allow(deprecated)]
|
||||
crate::protos::op_store::ref_target::Value::CommitId(id) => {
|
||||
// Legacy non-conflicting id
|
||||
RefTarget::normal(CommitId::new(id))
|
||||
}
|
||||
crate::protos::op_store::ref_target::Value::Conflict(conflict) => {
|
||||
#[allow(deprecated)]
|
||||
crate::protos::op_store::ref_target::Value::ConflictLegacy(conflict) => {
|
||||
// Legacy conflicting ids
|
||||
let removes = conflict.removes.into_iter().map(CommitId::new);
|
||||
let adds = conflict.adds.into_iter().map(CommitId::new);
|
||||
RefTarget::from_legacy_form(removes, adds)
|
||||
}
|
||||
crate::protos::op_store::ref_target::Value::Conflict(conflict) => {
|
||||
let term_from_proto =
|
||||
|term: crate::protos::op_store::ref_conflict::Term| term.value.map(CommitId::new);
|
||||
let removes = conflict.removes.into_iter().map(term_from_proto).collect();
|
||||
let adds = conflict.adds.into_iter().map(term_from_proto).collect();
|
||||
RefTarget::from_conflict(Conflict::new(removes, adds))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -519,4 +533,35 @@ mod tests {
|
|||
let read_operation = store.read_operation(&op_id).unwrap();
|
||||
assert_eq!(read_operation, operation);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ref_target_legacy_roundtrip() {
|
||||
let target = RefTarget::absent();
|
||||
let maybe_proto = ref_target_to_proto(&target);
|
||||
assert_eq!(ref_target_from_proto(maybe_proto), target);
|
||||
|
||||
let target = RefTarget::normal(CommitId::from_hex("111111"));
|
||||
let maybe_proto = ref_target_to_proto(&target);
|
||||
assert_eq!(ref_target_from_proto(maybe_proto), target);
|
||||
|
||||
// N-way conflict
|
||||
let target = RefTarget::from_legacy_form(
|
||||
[CommitId::from_hex("111111"), CommitId::from_hex("222222")],
|
||||
[
|
||||
CommitId::from_hex("333333"),
|
||||
CommitId::from_hex("444444"),
|
||||
CommitId::from_hex("555555"),
|
||||
],
|
||||
);
|
||||
let maybe_proto = ref_target_to_proto(&target);
|
||||
assert_eq!(ref_target_from_proto(maybe_proto), target);
|
||||
|
||||
// Change-delete conflict
|
||||
let target = RefTarget::from_legacy_form(
|
||||
[CommitId::from_hex("111111")],
|
||||
[CommitId::from_hex("222222")],
|
||||
);
|
||||
let maybe_proto = ref_target_to_proto(&target);
|
||||
assert_eq!(ref_target_from_proto(maybe_proto), target);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue