ok/jj
1
0
Fork 0
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:
Yuya Nishihara 2023-07-15 23:57:35 +09:00
parent 2382ae09e2
commit 8351a743f6
3 changed files with 87 additions and 9 deletions

View file

@ -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;
}
}

View file

@ -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),
}
}

View file

@ -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);
}
}