diff --git a/lib/dal-test/src/expand_helpers.rs b/lib/dal-test/src/expand_helpers.rs index f624d0e8e4..7c39c017e2 100644 --- a/lib/dal-test/src/expand_helpers.rs +++ b/lib/dal-test/src/expand_helpers.rs @@ -9,7 +9,23 @@ use jwt_simple::claims::Claims; use jwt_simple::prelude::Duration; use tracing_subscriber::{fmt, util::SubscriberInitExt, EnvFilter, Registry}; -use crate::{helpers::generate_fake_name, jwt_private_signing_key, WorkspaceSignup}; +use crate::{ + helpers::create_user, helpers::generate_fake_name, jwt_private_signing_key, WorkspaceSignup, +}; + +/// Creates a user for each test to run as +pub async fn setup_history_actor_ctx(ctx: &mut DalContext) { + let user = create_user(ctx).await.expect("unable to create user"); + user.associate_workspace( + ctx, + ctx.tenancy() + .workspace_pk() + .expect("no workspace pk set on context"), + ) + .await + .expect("unable to associate user with workspace"); + ctx.update_history_actor(dal::HistoryActor::User(user.pk())); +} /// This function is used during macro expansion for setting up a [`ChangeSet`] in an integration test. pub async fn create_change_set_and_update_ctx( diff --git a/lib/dal-test/src/helpers/change_set.rs b/lib/dal-test/src/helpers/change_set.rs index 1f52cb0814..7706f100d2 100644 --- a/lib/dal-test/src/helpers/change_set.rs +++ b/lib/dal-test/src/helpers/change_set.rs @@ -64,7 +64,7 @@ impl ChangeSetTestHelpers { Self::blocking_commit(ctx).await?; - ctx.update_visibility_and_snapshot_to_visibility_no_editing_change_set( + ctx.update_visibility_and_snapshot_to_visibility( applied_change_set.base_change_set_id.ok_or(eyre!( "base change set not found for change set: {}", applied_change_set.id diff --git a/lib/dal/src/action.rs b/lib/dal/src/action.rs index bc7fc0bb6d..9ed8a03cdb 100644 --- a/lib/dal/src/action.rs +++ b/lib/dal/src/action.rs @@ -317,7 +317,7 @@ impl Action { .await? .get_action_node_weight()?; let mut new_node_weight = - node_weight.new_with_incremented_vector_clock(ctx.change_set()?.vector_clock_id()); + node_weight.new_with_incremented_vector_clock(ctx.vector_clock_id()?); new_node_weight.set_state(state); ctx.workspace_snapshot()? .add_node(NodeWeight::Action(new_node_weight)) @@ -341,11 +341,17 @@ impl Action { action_prototype_id: ActionPrototypeId, maybe_component_id: Option, ) -> ActionResult { - let change_set = ctx.change_set()?; - let new_id: ActionId = change_set.generate_ulid()?.into(); + let vector_clock_id = ctx.vector_clock_id()?; + let new_id: ActionId = ctx.workspace_snapshot()?.generate_ulid().await?.into(); + let lineage_id = ctx.workspace_snapshot()?.generate_ulid().await?; + let originating_change_set_id = ctx.change_set_id(); - let node_weight = - NodeWeight::new_action(change_set, originating_change_set_id, new_id.into())?; + let node_weight = NodeWeight::new_action( + vector_clock_id, + originating_change_set_id, + new_id.into(), + lineage_id, + )?; ctx.workspace_snapshot()?.add_node(node_weight).await?; let action_category_id = ctx @@ -388,7 +394,7 @@ impl Action { pub async fn remove_by_id(ctx: &DalContext, action_id: ActionId) -> ActionResult<()> { ctx.workspace_snapshot()? - .remove_node_by_id(ctx.change_set()?, action_id) + .remove_node_by_id(ctx.vector_clock_id()?, action_id) .await?; Ok(()) } @@ -398,13 +404,13 @@ impl Action { action_prototype_id: ActionPrototypeId, maybe_component_id: Option, ) -> ActionResult<()> { - let change_set = ctx.change_set()?; let snap = ctx.workspace_snapshot()?; if let Some(action_id) = Self::find_equivalent(ctx, action_prototype_id, maybe_component_id).await? { - snap.remove_node_by_id(change_set, action_id).await?; + snap.remove_node_by_id(ctx.vector_clock_id()?, action_id) + .await?; } Ok(()) } diff --git a/lib/dal/src/action/prototype.rs b/lib/dal/src/action/prototype.rs index 9044934f76..3b9f28c728 100644 --- a/lib/dal/src/action/prototype.rs +++ b/lib/dal/src/action/prototype.rs @@ -148,10 +148,17 @@ impl ActionPrototype { schema_variant_id: SchemaVariantId, func_id: FuncId, ) -> ActionPrototypeResult { - let change_set = ctx.change_set()?; - let new_id: ActionPrototypeId = change_set.generate_ulid()?.into(); - let node_weight = - NodeWeight::new_action_prototype(change_set, new_id.into(), kind, name, description)?; + let vector_clock_id = ctx.vector_clock_id()?; + let new_id: ActionPrototypeId = ctx.workspace_snapshot()?.generate_ulid().await?.into(); + let lineage_id = ctx.workspace_snapshot()?.generate_ulid().await?; + let node_weight = NodeWeight::new_action_prototype( + vector_clock_id, + new_id.into(), + lineage_id, + kind, + name, + description, + )?; ctx.workspace_snapshot()?.add_node(node_weight).await?; Self::add_edge_to_func(ctx, new_id, func_id, EdgeWeightKind::new_use()).await?; @@ -422,10 +429,8 @@ impl ActionPrototype { Ok(triggered_actions) } pub async fn remove(ctx: &DalContext, id: ActionPrototypeId) -> ActionPrototypeResult<()> { - let change_set = ctx.change_set()?; - ctx.workspace_snapshot()? - .remove_node_by_id(change_set, id) + .remove_node_by_id(ctx.vector_clock_id()?, id) .await?; Ok(()) diff --git a/lib/dal/src/attribute/prototype.rs b/lib/dal/src/attribute/prototype.rs index bab0faef84..503d956a15 100644 --- a/lib/dal/src/attribute/prototype.rs +++ b/lib/dal/src/attribute/prototype.rs @@ -151,11 +151,15 @@ impl AttributePrototype { ) .await?; - let change_set = ctx.change_set()?; - let id = change_set.generate_ulid()?; - let node_weight = - NodeWeight::new_content(change_set, id, ContentAddress::AttributePrototype(hash))?; let workspace_snapshot = ctx.workspace_snapshot()?; + let id = workspace_snapshot.generate_ulid().await?; + let lineage_id = workspace_snapshot.generate_ulid().await?; + let node_weight = NodeWeight::new_content( + ctx.vector_clock_id()?, + id, + lineage_id, + ContentAddress::AttributePrototype(hash), + )?; let _node_index = workspace_snapshot.add_node(node_weight).await?; let prototype = AttributePrototype::assemble(id.into(), &content); @@ -328,10 +332,9 @@ impl AttributePrototype { attribute_prototype_id, ))?; - let change_set = ctx.change_set()?; workspace_snapshot .remove_edge( - change_set, + ctx.vector_clock_id()?, attribute_prototype_idx, current_func_node_idx, EdgeWeightKindDiscriminants::Use, @@ -462,10 +465,8 @@ impl AttributePrototype { ctx: &DalContext, prototype_id: AttributePrototypeId, ) -> AttributePrototypeResult<()> { - let change_set = ctx.change_set()?; - ctx.workspace_snapshot()? - .remove_node_by_id(change_set, prototype_id) + .remove_node_by_id(ctx.vector_clock_id()?, prototype_id) .await?; Ok(()) diff --git a/lib/dal/src/attribute/prototype/argument.rs b/lib/dal/src/attribute/prototype/argument.rs index e00f7a27b7..abd54b5a7c 100644 --- a/lib/dal/src/attribute/prototype/argument.rs +++ b/lib/dal/src/attribute/prototype/argument.rs @@ -197,9 +197,12 @@ impl AttributePrototypeArgument { prototype_id: AttributePrototypeId, arg_id: FuncArgumentId, ) -> AttributePrototypeArgumentResult { - let change_set = ctx.change_set()?; - let id = change_set.generate_ulid()?; - let node_weight = NodeWeight::new_attribute_prototype_argument(change_set, id, None)?; + let vector_clock_id = ctx.vector_clock_id()?; + let id = ctx.workspace_snapshot()?.generate_ulid().await?; + let lineage_id = ctx.workspace_snapshot()?.generate_ulid().await?; + + let node_weight = + NodeWeight::new_attribute_prototype_argument(vector_clock_id, id, lineage_id, None)?; let workspace_snapshot = ctx.workspace_snapshot()?; @@ -230,11 +233,13 @@ impl AttributePrototypeArgument { destination_component_id: ComponentId, destination_attribute_prototype_id: AttributePrototypeId, ) -> AttributePrototypeArgumentResult { - let change_set = ctx.change_set()?; - let id = change_set.generate_ulid()?; + let vector_clock_id = ctx.vector_clock_id()?; + let id = ctx.workspace_snapshot()?.generate_ulid().await?; + let lineage_id = ctx.workspace_snapshot()?.generate_ulid().await?; let node_weight = NodeWeight::new_attribute_prototype_argument( - change_set, + vector_clock_id, id, + lineage_id, Some(ArgumentTargets { source_component_id, destination_component_id, @@ -382,7 +387,6 @@ impl AttributePrototypeArgument { value_id: Ulid, ) -> AttributePrototypeArgumentResult { let workspace_snapshot = ctx.workspace_snapshot()?; - let change_set = ctx.change_set()?; for existing_value_source in workspace_snapshot .outgoing_targets_for_edge_weight_kind( @@ -394,7 +398,7 @@ impl AttributePrototypeArgument { let self_node_index = workspace_snapshot.get_node_index_by_id(self.id).await?; workspace_snapshot .remove_edge( - change_set, + ctx.vector_clock_id()?, self_node_index, existing_value_source, EdgeWeightKindDiscriminants::PrototypeArgumentValue, @@ -646,7 +650,7 @@ impl AttributePrototypeArgument { // Remove the argument ctx.workspace_snapshot()? - .remove_node_by_id(ctx.change_set()?, self.id) + .remove_node_by_id(ctx.vector_clock_id()?, self.id) .await?; // Enqueue a dependent values update with the destination attribute values diff --git a/lib/dal/src/attribute/prototype/argument/static_value.rs b/lib/dal/src/attribute/prototype/argument/static_value.rs index 9147ab1d9d..0b785beac2 100644 --- a/lib/dal/src/attribute/prototype/argument/static_value.rs +++ b/lib/dal/src/attribute/prototype/argument/static_value.rs @@ -56,10 +56,14 @@ impl StaticArgumentValue { ) .await?; - let change_set = ctx.change_set()?; - let id = change_set.generate_ulid()?; - let node_weight = - NodeWeight::new_content(change_set, id, ContentAddress::StaticArgumentValue(hash))?; + let id = ctx.workspace_snapshot()?.generate_ulid().await?; + let lineage_id = ctx.workspace_snapshot()?.generate_ulid().await?; + let node_weight = NodeWeight::new_content( + ctx.vector_clock_id()?, + id, + lineage_id, + ContentAddress::StaticArgumentValue(hash), + )?; ctx.workspace_snapshot()?.add_node(node_weight).await?; diff --git a/lib/dal/src/attribute/value.rs b/lib/dal/src/attribute/value.rs index ef2393ac1d..7ca166f232 100644 --- a/lib/dal/src/attribute/value.rs +++ b/lib/dal/src/attribute/value.rs @@ -295,9 +295,11 @@ impl AttributeValue { maybe_parent_attribute_value: Option, key: Option, ) -> AttributeValueResult { - let change_set = ctx.change_set()?; - let id = change_set.generate_ulid()?; - let node_weight = NodeWeight::new_attribute_value(change_set, id, None, None)?; + let vector_clock_id = ctx.vector_clock_id()?; + let id = ctx.workspace_snapshot()?.generate_ulid().await?; + let lineage_id = ctx.workspace_snapshot()?.generate_ulid().await?; + let node_weight = + NodeWeight::new_attribute_value(vector_clock_id, id, lineage_id, None, None)?; let is_for = is_for.into(); let ordered = if let Some(prop_id) = is_for.prop_id() { @@ -313,7 +315,7 @@ impl AttributeValue { if ordered { ctx.workspace_snapshot()? - .add_ordered_node(change_set, node_weight.clone()) + .add_ordered_node(vector_clock_id, node_weight.clone()) .await?; } else { ctx.workspace_snapshot()? @@ -1131,7 +1133,7 @@ impl AttributeValue { .id(); workspace_snapshot - .remove_node_by_id(ctx.change_set()?, current_target_id) + .remove_node_by_id(ctx.vector_clock_id()?, current_target_id) .await?; } @@ -1770,7 +1772,7 @@ impl AttributeValue { ctx.workspace_snapshot()? .remove_edge_for_ulids( - ctx.change_set()?, + ctx.vector_clock_id()?, attribute_value_id, prototype_id, EdgeWeightKindDiscriminants::Prototype, @@ -1943,7 +1945,7 @@ impl AttributeValue { .await?; let mut new_av_node_weight = - av_node_weight.new_with_incremented_vector_clock(ctx.change_set()?.vector_clock_id()); + av_node_weight.new_with_incremented_vector_clock(ctx.vector_clock_id()?); new_av_node_weight.set_value(value_address.map(ContentAddress::JsonValue)); new_av_node_weight @@ -2192,10 +2194,10 @@ impl AttributeValue { .ok_or(AttributeValueError::RemovingWhenNotChildOrMapOrArray(id))?; ctx.workspace_snapshot()? - .remove_node_by_id(ctx.change_set()?, id) + .remove_node_by_id(ctx.vector_clock_id()?, id) .await?; ctx.workspace_snapshot()? - .remove_dependent_value_root(ctx.change_set()?, id) + .remove_dependent_value_root(ctx.vector_clock_id()?, id) .await?; ctx.add_dependent_values_and_enqueue(vec![parent_av_id]) diff --git a/lib/dal/src/change_set.rs b/lib/dal/src/change_set.rs index 0fefd5c3d5..4ceb2a4278 100644 --- a/lib/dal/src/change_set.rs +++ b/lib/dal/src/change_set.rs @@ -1,12 +1,10 @@ //! The sequel to [`ChangeSets`](crate::ChangeSet). Coming to an SI instance near you! -use std::sync::{Arc, Mutex}; - use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; +use si_events::VectorClockChangeSetId; use si_layer_cache::LayerDbError; use thiserror::Error; -use ulid::Generator; use si_data_pg::{PgError, PgRow}; use si_events::{ulid::Ulid, WorkspaceSnapshotAddress}; @@ -128,9 +126,6 @@ pub struct ChangeSet { pub workspace_snapshot_address: Option, pub workspace_id: Option, pub merge_requested_by_user_id: Option, - - #[serde(skip)] - pub generator: Arc>, } impl TryFrom for ChangeSet { @@ -149,47 +144,23 @@ impl TryFrom for ChangeSet { workspace_snapshot_address: value.try_get("workspace_snapshot_address")?, workspace_id: value.try_get("workspace_id")?, merge_requested_by_user_id: value.try_get("merge_requested_by_user_id")?, - generator: Arc::new(Mutex::new(Default::default())), }) } } impl ChangeSet { - pub fn new_local() -> ChangeSetResult { - let mut generator = Generator::new(); - let id: Ulid = generator.generate()?.into(); - - Ok(Self { - id: id.into(), - created_at: Utc::now(), - updated_at: Utc::now(), - generator: Arc::new(Mutex::new(generator)), - base_change_set_id: None, - workspace_snapshot_address: None, - workspace_id: None, - name: "".to_string(), - status: ChangeSetStatus::Open, - merge_requested_by_user_id: None, - }) - } - - pub fn editing_changeset(&self) -> ChangeSetResult { - let mut new_local = Self::new_local()?; - new_local.base_change_set_id = self.base_change_set_id; - new_local.workspace_snapshot_address = self.workspace_snapshot_address; - new_local.workspace_id = self.workspace_id; - self.name.clone_into(&mut new_local.name); - self.status.clone_into(&mut new_local.status); - Ok(new_local) - } - pub async fn new( ctx: &DalContext, name: impl AsRef, base_change_set_id: Option, workspace_snapshot_address: WorkspaceSnapshotAddress, ) -> ChangeSetResult { - let id: ChangeSetId = Ulid::new().into(); + let id: Ulid = Ulid::new(); + let vector_clock_id = VectorClockId::new( + VectorClockChangeSetId::new(id), + ctx.vector_clock_id()?.actor_id(), + ); + let change_set_id: ChangeSetId = id.into(); let workspace_snapshot = WorkspaceSnapshot::find(ctx, workspace_snapshot_address) .await @@ -200,7 +171,7 @@ impl ChangeSet { // changeset needs to have seen the "to_rebase" or we will treat them as // completely disjoint changesets. let workspace_snapshot_address = workspace_snapshot - .write(ctx, id.into_inner().into()) + .write(ctx, vector_clock_id) .await .map_err(Box::new)?; @@ -212,7 +183,7 @@ impl ChangeSet { .pg() .query_one( "INSERT INTO change_set_pointers (id, name, base_change_set_id, status, workspace_id, workspace_snapshot_address) VALUES ($1, $2, $3, $4, $5, $6) RETURNING *", - &[&id, &name, &base_change_set_id, &ChangeSetStatus::Open.to_string(), &workspace_id, &workspace_snapshot_address], + &[&change_set_id, &name, &base_change_set_id, &ChangeSetStatus::Open.to_string(), &workspace_id, &workspace_snapshot_address], ) .await?; let change_set = Self::try_from(row)?; @@ -259,19 +230,14 @@ impl ChangeSet { Ok(change_set) } - /// Create a [`VectorClockId`] from the [`ChangeSet`]. - pub fn vector_clock_id(&self) -> VectorClockId { - VectorClockId::from(Ulid::from(self.id)) - } - - pub fn generate_ulid(&self) -> ChangeSetResult { - self.generator - .lock() - .map_err(|e| ChangeSetError::Mutex(e.to_string()))? - .generate() - .map(Into::into) - .map_err(Into::into) - } + // pub fn generate_ulid(&self) -> ChangeSetResult { + // self.generator + // .lock() + // .map_err(|e| ChangeSetError::Mutex(e.to_string()))? + // .generate() + // .map(Into::into) + // .map_err(Into::into) + // } pub async fn update_workspace_id( &mut self, @@ -466,7 +432,7 @@ impl ChangeSet { let mut change_set_to_be_applied = Self::find(ctx, ctx.change_set_id()) .await? .ok_or(ChangeSetApplyError::ChangeSetNotFound(ctx.change_set_id()))?; - ctx.update_visibility_and_snapshot_to_visibility_no_editing_change_set(ctx.change_set_id()) + ctx.update_visibility_and_snapshot_to_visibility(ctx.change_set_id()) .await?; change_set_to_be_applied .apply_to_base_change_set_inner(ctx) @@ -499,7 +465,7 @@ impl ChangeSet { .ok_or(ChangeSetError::NoWorkspaceSnapshot(self.id))?; let rebase_request = RebaseRequest { onto_workspace_snapshot_address, - onto_vector_clock_id: self.vector_clock_id(), + onto_vector_clock_id: ctx.vector_clock_id()?, to_rebase_change_set_id, }; ctx.do_rebase_request(rebase_request).await?; diff --git a/lib/dal/src/component.rs b/lib/dal/src/component.rs index bbe658a2c3..19e2fc3746 100644 --- a/lib/dal/src/component.rs +++ b/lib/dal/src/component.rs @@ -407,12 +407,13 @@ impl Component { ) .await?; - let change_set = ctx.change_set()?; - let id = change_set.generate_ulid()?; - let node_weight = NodeWeight::new_component(change_set, id, hash)?; + let workspace_snapshot = ctx.workspace_snapshot()?; + let id = workspace_snapshot.generate_ulid().await?; + let lineage_id = workspace_snapshot.generate_ulid().await?; + + let node_weight = NodeWeight::new_component(ctx.vector_clock_id()?, id, lineage_id, hash)?; // Attach component to category and add use edge to schema variant - let workspace_snapshot = ctx.workspace_snapshot()?; workspace_snapshot.add_node(node_weight).await?; // Root --> Component Category --> Component (this) @@ -574,6 +575,7 @@ impl Component { // The update operation orphans deeply nested values, clear them out to // avoid issues downstream ctx.workspace_snapshot()?.cleanup().await?; + let vector_clock_id = ctx.vector_clock_id()?; // Now, walk the attribute value tree and reset all prototypes to the default @@ -595,7 +597,7 @@ impl Component { if is_dependent_func { ctx.workspace_snapshot()? .remove_edge_for_ulids( - ctx.change_set()?, + vector_clock_id, current_av_id, component_prototype_id, EdgeWeightKindDiscriminants::Prototype, @@ -1173,7 +1175,7 @@ impl Component { .await?; ctx.workspace_snapshot()? - .update_content(ctx.change_set()?, id.into(), hash) + .update_content(ctx.vector_clock_id()?, id.into(), hash) .await?; } let (node_weight, content) = Self::get_node_weight_and_content(ctx, id).await?; @@ -1633,7 +1635,7 @@ impl Component { ) -> ComponentResult<()> { ctx.workspace_snapshot()? .remove_edge_for_ulids( - ctx.change_set()?, + ctx.vector_clock_id()?, parent_id, child_id, EdgeWeightKindDiscriminants::FrameContains, @@ -1860,8 +1862,8 @@ impl Component { .get_node_weight(component_idx) .await? .get_component_node_weight()?; - let mut new_component_node_weight = component_node_weight - .new_with_incremented_vector_clock(ctx.change_set()?.vector_clock_id()); + let mut new_component_node_weight = + component_node_weight.new_with_incremented_vector_clock(ctx.vector_clock_id()?); new_component_node_weight.set_to_delete(component.to_delete); ctx.workspace_snapshot()? .add_node(NodeWeight::Component(new_component_node_weight)) @@ -1884,7 +1886,7 @@ impl Component { ) .await?; ctx.workspace_snapshot()? - .update_content(ctx.change_set()?, component.id.into(), hash) + .update_content(ctx.vector_clock_id()?, component.id.into(), hash) .await?; } @@ -1899,7 +1901,7 @@ impl Component { #[instrument(level = "info", skip(ctx))] pub async fn remove(ctx: &DalContext, id: ComponentId) -> ComponentResult<()> { - let change_set = ctx.change_set()?; + let vector_clock_id = ctx.vector_clock_id()?; let component = Self::get_by_id(ctx, id).await?; @@ -1944,7 +1946,7 @@ impl Component { .await?; ctx.workspace_snapshot()? - .remove_node_by_id(change_set, id) + .remove_node_by_id(vector_clock_id, id) .await?; WsEvent::component_deleted(ctx, id) diff --git a/lib/dal/src/context.rs b/lib/dal/src/context.rs index e4ccca689d..c85d8954bf 100644 --- a/lib/dal/src/context.rs +++ b/lib/dal/src/context.rs @@ -7,6 +7,8 @@ use si_crypto::SymmetricCryptoService; use si_crypto::VeritechEncryptionKey; use si_data_nats::{NatsClient, NatsError, NatsTxn}; use si_data_pg::{InstrumentedClient, PgError, PgPool, PgPoolError, PgPoolResult, PgTxn}; +use si_events::VectorClockActorId; +use si_events::VectorClockChangeSetId; use si_events::WorkspaceSnapshotAddress; use si_layer_cache::activities::rebase::RebaseStatus; use si_layer_cache::activities::ActivityPayload; @@ -334,6 +336,7 @@ impl DalContext { Ok(workspace.default_change_set_id()) } + /// Update the context to use the most recent snapshot pointed to by the current `ChangeSetId`. pub async fn update_snapshot_to_visibility(&mut self) -> Result<(), TransactionsError> { let change_set = ChangeSet::find(self, self.change_set_id()) .await @@ -396,7 +399,7 @@ impl DalContext { &self, ) -> Result, TransactionsError> { if let Some(snapshot) = &self.workspace_snapshot { - let vector_clock_id = self.change_set()?.vector_clock_id(); + let vector_clock_id = self.vector_clock_id()?; Ok(Some(snapshot.write(self, vector_clock_id).await.map_err( |err| TransactionsError::WorkspaceSnapshot(Box::new(err)), @@ -410,7 +413,7 @@ impl DalContext { &self, onto_workspace_snapshot_address: WorkspaceSnapshotAddress, ) -> Result { - let vector_clock_id = self.change_set()?.vector_clock_id(); + let vector_clock_id = self.vector_clock_id()?; Ok(RebaseRequest { onto_workspace_snapshot_address, // the vector clock id of the current change set is just the id @@ -509,6 +512,27 @@ impl DalContext { Ok(()) } + pub fn change_set_id(&self) -> ChangeSetId { + self.visibility.change_set_id + } + + pub fn vector_clock_id(&self) -> Result { + let change_set_id = self.visibility.change_set_id.into_inner(); + let actor_id = match self.history_actor { + HistoryActor::SystemInit => self + .tenancy + .workspace_pk() + .unwrap_or(WorkspacePk::NONE) + .into_inner(), + HistoryActor::User(user_pk) => user_pk.into_inner(), + }; + + Ok(VectorClockId::new( + VectorClockChangeSetId::new(change_set_id.into()), + VectorClockActorId::new(actor_id.into()), + )) + } + pub fn change_set(&self) -> Result<&ChangeSet, TransactionsError> { match self.change_set.as_ref() { Some(csp_ref) => Ok(csp_ref), @@ -531,17 +555,15 @@ impl DalContext { // Ulid generator and new vector clock id so that concurrent editing conflicts can be // resolved by the rebaser. This change set is not persisted to the database (the // rebaser will persist a new one if it can) - self.change_set = Some( - change_set - .editing_changeset() - .map_err(|err| TransactionsError::ChangeSet(err.to_string()))?, - ); - + self.change_set = Some(change_set); self.change_set() } - pub fn set_workspace_snapshot(&mut self, workspace_snapshot: WorkspaceSnapshot) { - self.workspace_snapshot = Some(Arc::new(workspace_snapshot)); + pub fn set_workspace_snapshot( + &mut self, + workspace_snapshot: impl Into>, + ) { + self.workspace_snapshot = Some(workspace_snapshot.into()) } /// Fetch the workspace snapshot for the current visibility @@ -647,16 +669,6 @@ impl DalContext { Ok(()) } - pub async fn update_visibility_and_snapshot_to_visibility_no_editing_change_set( - &mut self, - change_set_id: ChangeSetId, - ) -> Result<(), TransactionsError> { - self.update_visibility_deprecated(Visibility::new(change_set_id)); - self.update_snapshot_to_visibility_no_editing_change_set() - .await?; - Ok(()) - } - /// Clones a new context from this one with a new [`Visibility`]. pub fn clone_with_new_visibility(&self, visibility: Visibility) -> Self { let mut new = self.clone(); @@ -697,10 +709,8 @@ impl DalContext { pub async fn clone_with_head(&self) -> Result { let mut new = self.clone(); let default_change_set_id = new.get_workspace_default_change_set_id().await?; - new.update_visibility_and_snapshot_to_visibility_no_editing_change_set( - default_change_set_id, - ) - .await?; + new.update_visibility_and_snapshot_to_visibility(default_change_set_id) + .await?; Ok(new) } @@ -714,7 +724,7 @@ impl DalContext { .ok_or(TransactionsError::NoBaseChangeSet(change_set.id))?; let mut new = self.clone(); - new.update_visibility_and_snapshot_to_visibility_no_editing_change_set(base_change_set_id) + new.update_visibility_and_snapshot_to_visibility(base_change_set_id) .await?; Ok(new) } @@ -734,7 +744,7 @@ impl DalContext { ) -> Result<(), WorkspaceSnapshotError> { for id in ids { self.workspace_snapshot()? - .add_dependent_value_root(self.change_set()?, id) + .add_dependent_value_root(self.vector_clock_id()?, id) .await?; } @@ -895,11 +905,6 @@ impl DalContext { Ok(is_in_our_tenancy) } - // NOTE(nick,zack,jacob): likely a temporary func to get the change set id from the visibility. - pub fn change_set_id(&self) -> ChangeSetId { - self.visibility.change_set_id - } - pub fn access_builder(&self) -> AccessBuilder { AccessBuilder::new(self.tenancy, self.history_actor) } @@ -1171,6 +1176,8 @@ pub enum TransactionsError { Workspace(String), #[error("workspace not found by pk: {0}")] WorkspaceNotFound(WorkspacePk), + #[error("workspace not set on DalContext")] + WorkspaceNotSet, #[error("workspace snapshot error: {0}")] WorkspaceSnapshot(Box), } @@ -1309,7 +1316,7 @@ async fn rebase( .rebase_and_wait( rebase_request.to_rebase_change_set_id.into(), rebase_request.onto_workspace_snapshot_address, - rebase_request.onto_vector_clock_id.into(), + rebase_request.onto_vector_clock_id, metadata, ) .await?; diff --git a/lib/dal/src/func.rs b/lib/dal/src/func.rs index e020931761..f499391640 100644 --- a/lib/dal/src/func.rs +++ b/lib/dal/src/func.rs @@ -249,10 +249,16 @@ impl Func { let func_kind = FuncKind::new(backend_kind, backend_response_type)?; - let change_set = ctx.change_set()?; - let id = change_set.generate_ulid()?; - let node_weight = - NodeWeight::new_func(change_set, id, name.clone().into(), func_kind, hash)?; + let id = ctx.workspace_snapshot()?.generate_ulid().await?; + let lineage_id = ctx.workspace_snapshot()?.generate_ulid().await?; + let node_weight = NodeWeight::new_func( + ctx.vector_clock_id()?, + id, + lineage_id, + name.clone().into(), + func_kind, + hash, + )?; let workspace_snapshot = ctx.workspace_snapshot()?; workspace_snapshot.add_node(node_weight.clone()).await?; @@ -441,8 +447,7 @@ impl Func { workspace_snapshot .add_node(NodeWeight::Func( - node_weight - .new_with_incremented_vector_clock(ctx.change_set()?.vector_clock_id()), + node_weight.new_with_incremented_vector_clock(ctx.vector_clock_id()?), )) .await?; @@ -464,7 +469,7 @@ impl Func { ) .await?; workspace_snapshot - .update_content(ctx.change_set()?, func.id.into(), hash) + .update_content(ctx.vector_clock_id()?, func.id.into(), hash) .await?; } @@ -508,8 +513,9 @@ impl Func { // Now, we can remove the func. let workspace_snapshot = ctx.workspace_snapshot()?; - let change_set = ctx.change_set()?; - workspace_snapshot.remove_node_by_id(change_set, id).await?; + workspace_snapshot + .remove_node_by_id(ctx.vector_clock_id()?, id) + .await?; Ok(func.name) } diff --git a/lib/dal/src/func/argument.rs b/lib/dal/src/func/argument.rs index e4d372793a..3308ebe940 100644 --- a/lib/dal/src/func/argument.rs +++ b/lib/dal/src/func/argument.rs @@ -201,11 +201,11 @@ impl FuncArgument { ) .await?; - let change_set = ctx.change_set()?; - let id = change_set.generate_ulid()?; - let node_weight = NodeWeight::new_func_argument(change_set, id, name, hash)?; - let workspace_snapshot = ctx.workspace_snapshot()?; + let id = workspace_snapshot.generate_ulid().await?; + let lineage_id = workspace_snapshot.generate_ulid().await?; + let node_weight = + NodeWeight::new_func_argument(ctx.vector_clock_id()?, id, lineage_id, name, hash)?; workspace_snapshot.add_node(node_weight.clone()).await?; Func::add_edge_to_argument(ctx, func_id, id.into(), EdgeWeightKind::new_use()).await?; @@ -389,8 +389,7 @@ impl FuncArgument { workspace_snapshot .add_node(NodeWeight::FuncArgument( - node_weight - .new_with_incremented_vector_clock(ctx.change_set()?.vector_clock_id()), + node_weight.new_with_incremented_vector_clock(ctx.vector_clock_id()?), )) .await?; @@ -412,7 +411,7 @@ impl FuncArgument { ) .await?; workspace_snapshot - .update_content(ctx.change_set()?, func_argument.id.into(), hash) + .update_content(ctx.vector_clock_id()?, func_argument.id.into(), hash) .await?; } @@ -465,9 +464,8 @@ impl FuncArgument { } // Now, we can remove the argument. - let change_set = ctx.change_set()?; ctx.workspace_snapshot()? - .remove_node_by_id(change_set, id) + .remove_node_by_id(ctx.vector_clock_id()?, id) .await?; Ok(()) diff --git a/lib/dal/src/job/definition/dependent_values_update.rs b/lib/dal/src/job/definition/dependent_values_update.rs index 02b2fe1285..641a1fe241 100644 --- a/lib/dal/src/job/definition/dependent_values_update.rs +++ b/lib/dal/src/job/definition/dependent_values_update.rs @@ -138,7 +138,7 @@ impl DependentValuesUpdate { let span = Span::current(); let node_ids = ctx .workspace_snapshot()? - .take_dependent_values(ctx.change_set()?) + .take_dependent_values(ctx.vector_clock_id()?) .await?; let mut dependency_graph = DependentValueGraph::new(ctx, node_ids).await?; diff --git a/lib/dal/src/module.rs b/lib/dal/src/module.rs index 1cedce88bf..39ee872a8d 100644 --- a/lib/dal/src/module.rs +++ b/lib/dal/src/module.rs @@ -134,12 +134,16 @@ impl Module { ) .await?; - let change_set = ctx.change_set()?; - let id = change_set.generate_ulid()?; - - let node_weight = NodeWeight::new_content(change_set, id, ContentAddress::Module(hash))?; - let workspace_snapshot = ctx.workspace_snapshot()?; + let id = workspace_snapshot.generate_ulid().await?; + let lineage_id = workspace_snapshot.generate_ulid().await?; + let node_weight = NodeWeight::new_content( + ctx.vector_clock_id()?, + id, + lineage_id, + ContentAddress::Module(hash), + )?; + workspace_snapshot.add_node(node_weight).await?; let schema_module_index_id = workspace_snapshot @@ -148,7 +152,7 @@ impl Module { workspace_snapshot .add_edge( schema_module_index_id, - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use())?, + EdgeWeight::new(ctx.vector_clock_id()?, EdgeWeightKind::new_use())?, id, ) .await?; @@ -214,10 +218,7 @@ impl Module { workspace_snapshot .add_edge( self.id, - EdgeWeight::new( - ctx.change_set()?.vector_clock_id(), - EdgeWeightKind::new_use(), - )?, + EdgeWeight::new(ctx.vector_clock_id()?, EdgeWeightKind::new_use())?, target_id, ) .await?; diff --git a/lib/dal/src/prop.rs b/lib/dal/src/prop.rs index adb2f67637..b31694df34 100644 --- a/lib/dal/src/prop.rs +++ b/lib/dal/src/prop.rs @@ -497,15 +497,16 @@ impl Prop { ) .await?; - let change_set = ctx.change_set()?; - let id = change_set.generate_ulid()?; - let node_weight = NodeWeight::new_prop(change_set, id, kind, name, hash)?; + let vector_clock_id = ctx.vector_clock_id()?; + let workspace_snapshot = ctx.workspace_snapshot()?; + let id = workspace_snapshot.generate_ulid().await?; + let lineage_id = workspace_snapshot.generate_ulid().await?; + let node_weight = NodeWeight::new_prop(vector_clock_id, id, lineage_id, kind, name, hash)?; let prop_node_weight = node_weight.get_prop_node_weight()?; - let workspace_snapshot = ctx.workspace_snapshot()?; if ordered { workspace_snapshot - .add_ordered_node(change_set, node_weight) + .add_ordered_node(vector_clock_id, node_weight) .await?; } else { workspace_snapshot.add_node(node_weight).await?; @@ -1025,7 +1026,7 @@ impl Prop { .await?; ctx.workspace_snapshot()? - .update_content(ctx.change_set()?, prop.id.into(), hash) + .update_content(ctx.vector_clock_id()?, prop.id.into(), hash) .await?; } Ok(prop) diff --git a/lib/dal/src/schema.rs b/lib/dal/src/schema.rs index a042bd8ce3..b001352c6c 100644 --- a/lib/dal/src/schema.rs +++ b/lib/dal/src/schema.rs @@ -132,11 +132,17 @@ impl Schema { ) .await?; - let change_set = ctx.change_set()?; - let id = change_set.generate_ulid()?; - let node_weight = NodeWeight::new_content(change_set, id, ContentAddress::Schema(hash))?; - let workspace_snapshot = ctx.workspace_snapshot()?; + + let id = workspace_snapshot.generate_ulid().await?; + let lineage_id = workspace_snapshot.generate_ulid().await?; + let node_weight = NodeWeight::new_content( + ctx.vector_clock_id()?, + id, + lineage_id, + ContentAddress::Schema(hash), + )?; + workspace_snapshot.add_node(node_weight).await?; let schema_category_index_id = workspace_snapshot @@ -145,7 +151,7 @@ impl Schema { workspace_snapshot .add_edge( schema_category_index_id, - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use())?, + EdgeWeight::new(ctx.vector_clock_id()?, EdgeWeightKind::new_use())?, id, ) .await?; @@ -250,7 +256,7 @@ impl Schema { // we now need to update that edge to be a Use workspace_snapshot .remove_edge( - ctx.change_set()?, + ctx.vector_clock_id()?, source_index, target_index, edge_weight.kind().into(), @@ -277,7 +283,7 @@ impl Schema { workspace_snapshot .remove_edge( - ctx.change_set()?, + ctx.vector_clock_id()?, source_index, target_index, EdgeWeightKind::new_use().into(), @@ -338,7 +344,7 @@ impl Schema { .await?; ctx.workspace_snapshot()? - .update_content(ctx.change_set()?, schema.id.into(), hash) + .update_content(ctx.vector_clock_id()?, schema.id.into(), hash) .await?; } diff --git a/lib/dal/src/schema/variant.rs b/lib/dal/src/schema/variant.rs index e12bf00aff..50731fa41c 100644 --- a/lib/dal/src/schema/variant.rs +++ b/lib/dal/src/schema/variant.rs @@ -337,10 +337,14 @@ impl SchemaVariant { ) .await?; - let change_set = ctx.change_set()?; - let id = change_set.generate_ulid()?; - let node_weight = - NodeWeight::new_content(change_set, id, ContentAddress::SchemaVariant(hash))?; + let id = workspace_snapshot.generate_ulid().await?; + let lineage_id = workspace_snapshot.generate_ulid().await?; + let node_weight = NodeWeight::new_content( + ctx.vector_clock_id()?, + id, + lineage_id, + ContentAddress::SchemaVariant(hash), + )?; workspace_snapshot.add_node(node_weight).await?; // Schema --Use--> SchemaVariant (this) @@ -377,7 +381,7 @@ impl SchemaVariant { .await?; ctx.workspace_snapshot()? - .update_content(ctx.change_set()?, schema_variant.id.into(), hash) + .update_content(ctx.vector_clock_id()?, schema_variant.id.into(), hash) .await?; } @@ -880,10 +884,9 @@ impl SchemaVariant { func_id: FuncId, schema_variant_id: SchemaVariantId, ) -> SchemaVariantResult<()> { - let change_set = ctx.change_set()?; ctx.workspace_snapshot()? .remove_edge_for_ulids( - change_set, + ctx.vector_clock_id()?, schema_variant_id, func_id, EdgeWeightKindDiscriminants::AuthenticationPrototype, @@ -1692,7 +1695,7 @@ impl SchemaVariant { for (_edge_weight, _source_index, target_index) in maybe_schema_indices { workspace_snapshot .remove_node_by_id( - ctx.change_set()?, + ctx.vector_clock_id()?, workspace_snapshot.get_node_weight(target_index).await?.id(), ) .await?; diff --git a/lib/dal/src/secret.rs b/lib/dal/src/secret.rs index 0d24a91276..63de5b87ac 100644 --- a/lib/dal/src/secret.rs +++ b/lib/dal/src/secret.rs @@ -223,12 +223,12 @@ impl Secret { HistoryActor::User(user_pk) => Some(*user_pk), }; - let change_set = ctx.change_set()?; - let id = change_set.generate_ulid()?; + let id = ctx.workspace_snapshot()?.generate_ulid().await?; + let lineage_id = ctx.workspace_snapshot()?.generate_ulid().await?; let secret_id = id.into(); // Generate a key for the underlying encrypted secret. - let key = Self::generate_key(ctx, secret_id)?; + let key = Self::generate_key(ctx, secret_id).await?; let content = SecretContentV1 { timestamp: Timestamp::now(), @@ -250,7 +250,8 @@ impl Secret { ) .await?; - let node_weight = NodeWeight::new_secret(change_set, id, key, hash)?; + let node_weight = + NodeWeight::new_secret(ctx.vector_clock_id()?, id, lineage_id, key, hash)?; let secret_node_weight = node_weight.get_secret_node_weight()?; let workspace_snapshot = ctx.workspace_snapshot()?; @@ -283,8 +284,11 @@ impl Secret { /// A new key should be assembled anytime an [`EncryptedSecret`] is created or mutated. This /// method is purposefully owned by [`Secret`] to help ensure that we don't generate a key based /// on any encrypted contents or parameters to insert encrypted contents. - fn generate_key(ctx: &DalContext, secret_id: SecretId) -> SecretResult { - let new_ulid = ctx.change_set()?.generate_ulid()?; + async fn generate_key( + ctx: &DalContext, + secret_id: SecretId, + ) -> SecretResult { + let new_ulid = ctx.workspace_snapshot()?.generate_ulid().await?; let mut hasher = EncryptedSecretKey::hasher(); hasher.update(&ctx.tenancy().to_bytes()); @@ -596,7 +600,7 @@ impl Secret { algorithm: SecretAlgorithm, ) -> SecretResult { // Generate a new key and insert a new encrypted secret. - let new_key = Self::generate_key(ctx, self.id)?; + let new_key = Self::generate_key(ctx, self.id).await?; // NOTE(nick): we do not clean up the existing encrypted secret yet. EncryptedSecret::insert(ctx, new_key, crypted, key_pair_pk, version, algorithm).await?; @@ -648,8 +652,7 @@ impl Secret { workspace_snapshot .add_node(NodeWeight::Secret( - secret_node_weight - .new_with_incremented_vector_clock(ctx.change_set()?.vector_clock_id()), + secret_node_weight.new_with_incremented_vector_clock(ctx.vector_clock_id()?), )) .await?; @@ -671,7 +674,7 @@ impl Secret { ) .await?; ctx.workspace_snapshot()? - .update_content(ctx.change_set()?, secret.id.into(), hash) + .update_content(ctx.vector_clock_id()?, secret.id.into(), hash) .await?; } diff --git a/lib/dal/src/socket/input.rs b/lib/dal/src/socket/input.rs index bd7ceb5708..29a377f936 100644 --- a/lib/dal/src/socket/input.rs +++ b/lib/dal/src/socket/input.rs @@ -246,23 +246,25 @@ impl InputSocket { ) .await?; - let change_set = ctx.change_set()?; - let id = change_set.generate_ulid()?; + let workspace_snapshot = ctx.workspace_snapshot()?; + let id = workspace_snapshot.generate_ulid().await?; + let lineage_id = workspace_snapshot.generate_ulid().await?; - { - let workspace_snapshot = ctx.workspace_snapshot()?; - let node_weight = - NodeWeight::new_content(change_set, id, ContentAddress::InputSocket(hash))?; - workspace_snapshot.add_node(node_weight).await?; - SchemaVariant::add_edge_to_input_socket( - ctx, - schema_variant_id, - id.into(), - EdgeWeightKind::Socket, - ) - .await - .map_err(Box::new)?; - } + let node_weight = NodeWeight::new_content( + ctx.vector_clock_id()?, + id, + lineage_id, + ContentAddress::InputSocket(hash), + )?; + workspace_snapshot.add_node(node_weight).await?; + SchemaVariant::add_edge_to_input_socket( + ctx, + schema_variant_id, + id.into(), + EdgeWeightKind::Socket, + ) + .await + .map_err(Box::new)?; let attribute_prototype = AttributePrototype::new(ctx, func_id).await?; diff --git a/lib/dal/src/socket/output.rs b/lib/dal/src/socket/output.rs index 70297816f0..26af8a0e03 100644 --- a/lib/dal/src/socket/output.rs +++ b/lib/dal/src/socket/output.rs @@ -176,12 +176,17 @@ impl OutputSocket { ) .await?; - let change_set = ctx.change_set()?; - let id = change_set.generate_ulid()?; - let node_weight = - NodeWeight::new_content(change_set, id, ContentAddress::OutputSocket(hash))?; - let workspace_snapshot = ctx.workspace_snapshot()?; + + let id = workspace_snapshot.generate_ulid().await?; + let lineage_id = workspace_snapshot.generate_ulid().await?; + let node_weight = NodeWeight::new_content( + ctx.vector_clock_id()?, + id, + lineage_id, + ContentAddress::OutputSocket(hash), + )?; + workspace_snapshot.add_node(node_weight).await?; SchemaVariant::add_edge_to_output_socket( diff --git a/lib/dal/src/standard_connection.rs b/lib/dal/src/standard_connection.rs index fe922801ff..7e7fbb3d56 100644 --- a/lib/dal/src/standard_connection.rs +++ b/lib/dal/src/standard_connection.rs @@ -37,7 +37,7 @@ macro_rules! implement_add_edge_to { ctx.workspace_snapshot()? .add_edge( source_id, - $crate::EdgeWeight::new(ctx.change_set()?.vector_clock_id(), weight)?, + $crate::EdgeWeight::new(ctx.vector_clock_id()?, weight)?, destination_id, ) .await?; @@ -50,11 +50,13 @@ macro_rules! implement_add_edge_to { return Err($crate::HelperError::InvalidEdgeWeight(weight, $discriminant))?; } + let vector_clock_id = ctx.vector_clock_id()?; + ctx.workspace_snapshot()? .add_ordered_edge( - ctx.change_set()?.vector_clock_id(), + vector_clock_id, source_id, - $crate::EdgeWeight::new(ctx.change_set()?.vector_clock_id(), weight)?, + $crate::EdgeWeight::new(vector_clock_id, weight)?, destination_id ) .await?; diff --git a/lib/dal/src/validation.rs b/lib/dal/src/validation.rs index e9b2ff5ac3..26488576fe 100644 --- a/lib/dal/src/validation.rs +++ b/lib/dal/src/validation.rs @@ -159,7 +159,7 @@ impl ValidationOutputNode { .get_content_node_weight_of_kind(ContentAddressDiscriminants::ValidationOutput)?; let mut new_node_weight = - node_weight.new_with_incremented_vector_clock(ctx.change_set()?.vector_clock_id()); + node_weight.new_with_incremented_vector_clock(ctx.vector_clock_id()?); new_node_weight.new_content_hash(hash)?; @@ -170,19 +170,20 @@ impl ValidationOutputNode { id } else { - let change_set = ctx.change_set()?; - let id = change_set.generate_ulid()?; - let node_weight = - NodeWeight::new_content(change_set, id, ContentAddress::ValidationOutput(hash))?; + let id = workspace_snapshot.generate_ulid().await?; + let lineage_id = workspace_snapshot.generate_ulid().await?; + let node_weight = NodeWeight::new_content( + ctx.vector_clock_id()?, + id, + lineage_id, + ContentAddress::ValidationOutput(hash), + )?; workspace_snapshot.add_node(node_weight).await?; workspace_snapshot .add_edge( attribute_value_id, - EdgeWeight::new( - change_set.vector_clock_id(), - EdgeWeightKind::ValidationOutput, - )?, + EdgeWeight::new(ctx.vector_clock_id()?, EdgeWeightKind::ValidationOutput)?, id, ) .await?; @@ -236,6 +237,7 @@ impl ValidationOutputNode { attribute_value_id: AttributeValueId, ) -> ValidationResult<()> { let workspace_snapshot = ctx.workspace_snapshot()?; + let vector_clock_id = ctx.vector_clock_id()?; for validation_idx in workspace_snapshot .outgoing_targets_for_edge_weight_kind( @@ -249,7 +251,7 @@ impl ValidationOutputNode { .await? .id(); workspace_snapshot - .remove_node_by_id(ctx.change_set()?, validation_id) + .remove_node_by_id(vector_clock_id, validation_id) .await?; } diff --git a/lib/dal/src/workspace.rs b/lib/dal/src/workspace.rs index 71c1a42572..8784d666d4 100644 --- a/lib/dal/src/workspace.rs +++ b/lib/dal/src/workspace.rs @@ -3,7 +3,7 @@ use petgraph::Direction; use serde::{Deserialize, Serialize}; use si_data_nats::NatsError; use si_data_pg::{PgError, PgRow}; -use si_events::ContentHash; +use si_events::{ContentHash, VectorClockId}; use si_layer_cache::db::serialize; use si_layer_cache::LayerDbError; use si_pkg::{ @@ -171,8 +171,11 @@ impl Workspace { return Ok(()); } - let initial_change_set = ChangeSet::new_local()?; - let workspace_snapshot = WorkspaceSnapshot::initial(ctx, &initial_change_set).await?; + let initial_vector_clock_id = VectorClockId::new( + WorkspaceId::NONE.into_inner(), + WorkspaceId::NONE.into_inner(), + ); + let workspace_snapshot = WorkspaceSnapshot::initial(ctx, initial_vector_clock_id).await?; // If not, create the builtin workspace with a corresponding base change set and initial // workspace snapshot. @@ -520,10 +523,9 @@ impl Workspace { )?) }; - let local_change_set = ChangeSet::new_local()?; - let new_snap_address = imported_snapshot - .write(ctx, local_change_set.vector_clock_id()) - .await?; + // XXX: fake vector clock here. Figure out the right one + let vector_clock_id = VectorClockId::new(Ulid::new(), Ulid::new()); + let new_snap_address = imported_snapshot.write(ctx, vector_clock_id).await?; let new_change_set = ChangeSet::new( ctx, diff --git a/lib/dal/src/workspace_snapshot.rs b/lib/dal/src/workspace_snapshot.rs index 6bdd270168..79c80162c2 100644 --- a/lib/dal/src/workspace_snapshot.rs +++ b/lib/dal/src/workspace_snapshot.rs @@ -52,7 +52,7 @@ use crate::action::{Action, ActionError}; use crate::attribute::prototype::argument::{ AttributePrototypeArgument, AttributePrototypeArgumentError, AttributePrototypeArgumentId, }; -use crate::change_set::{ChangeSet, ChangeSetError, ChangeSetId}; +use crate::change_set::{ChangeSetError, ChangeSetId}; use crate::workspace_snapshot::edge_weight::{ EdgeWeight, EdgeWeightError, EdgeWeightKind, EdgeWeightKindDiscriminants, }; @@ -87,8 +87,8 @@ pub enum WorkspaceSnapshotError { AttributePrototypeArgument(#[from] Box), #[error("could not find category node of kind: {0:?}")] CategoryNodeNotFound(CategoryNodeKind), - #[error("change set error: {0}")] - ChangeSet(#[from] ChangeSetError), + // #[error("change set error: {0}")] + // ChangeSet(#[from] ChangeSetError), #[error("change set {0} has no workspace snapshot address")] ChangeSetMissingWorkspaceSnapshotAddress(ChangeSetId), #[error("edge weight error: {0}")] @@ -109,6 +109,8 @@ pub enum WorkspaceSnapshotError { Pg(#[from] PgError), #[error("postcard error: {0}")] Postcard(#[from] postcard::Error), + #[error("recently seen clocks missing for change set id {0}")] + RecentlySeenClocksMissing(ChangeSetId), #[error("serde json error: {0}")] SerdeJson(#[from] serde_json::Error), #[error("transactions error: {0}")] @@ -254,26 +256,22 @@ pub(crate) fn serde_value_to_string_type(value: &serde_json::Value) -> String { } impl WorkspaceSnapshot { - #[instrument( - name = "workspace_snapshot.initial", - level = "debug", - skip_all, - fields( - si.change_set.id = %change_set.id, - ) - )] + #[instrument(name = "workspace_snapshot.initial", level = "debug", skip_all)] pub async fn initial( ctx: &DalContext, - change_set: &ChangeSet, + vector_clock_id: VectorClockId, ) -> WorkspaceSnapshotResult { - let mut graph: WorkspaceSnapshotGraph = WorkspaceSnapshotGraph::new(change_set)?; + let mut graph: WorkspaceSnapshotGraph = WorkspaceSnapshotGraph::new(vector_clock_id)?; // Create the category nodes under root. for category_node_kind in CategoryNodeKind::iter() { - let category_node_index = graph.add_category_node(change_set, category_node_kind)?; + let id = graph.generate_ulid()?; + let lineage_id = graph.generate_ulid()?; + let category_node_index = + graph.add_category_node(vector_clock_id, id, lineage_id, category_node_kind)?; graph.add_edge( graph.root(), - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use())?, + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use())?, category_node_index, )?; } @@ -288,11 +286,25 @@ impl WorkspaceSnapshot { dvu_roots: Arc::new(Mutex::new(HashSet::new())), }; - initial.write(ctx, change_set.vector_clock_id()).await?; + initial.write(ctx, vector_clock_id).await?; Ok(initial) } + pub async fn generate_ulid(&self) -> WorkspaceSnapshotResult { + Ok(self.working_copy_mut().await.generate_ulid()?) + } + + pub async fn max_recently_seen_clock_id_for_change_set( + &self, + change_set_id: ChangeSetId, + ) -> WorkspaceSnapshotResult> { + Ok(self + .working_copy() + .await + .max_recently_seen_clock_id_for_change_set(change_set_id)) + } + /// Enables cycle checks on calls to [`Self::add_edge`]. Does not force /// cycle checks for every [`WorkspaceSnapshotGrpah::add_edge`] operation if /// there is a consumer of [`WorkspaceSnapshotGraph`] that calls add_edge @@ -329,13 +341,6 @@ impl WorkspaceSnapshot { ctx: &DalContext, vector_clock_id: VectorClockId, ) -> WorkspaceSnapshotResult { - let open_change_set_clock_ids: Vec = ChangeSet::list_open(ctx) - .await? - .into_iter() - .map(|cs| cs.id.into_inner().into()) - .chain([vector_clock_id]) - .collect(); - // Pull out the working copy and clean it up. let new_address = { let self_clone = self.clone(); @@ -343,9 +348,10 @@ impl WorkspaceSnapshot { let mut working_copy = executor::block_on(self_clone.working_copy_mut()); working_copy.cleanup(); - working_copy.remove_vector_clock_entries(&open_change_set_clock_ids); + // working_copy.remove_vector_clock_entries(&open_change_set_clock_ids); // Mark everything left as seen. + info!("marking seen with: {:?}", vector_clock_id); working_copy.mark_graph_seen(vector_clock_id)?; Ok::<(), WorkspaceSnapshotGraphError>(()) @@ -456,13 +462,13 @@ impl WorkspaceSnapshot { )] pub async fn add_ordered_node( &self, - change_set: &ChangeSet, + vector_clock_id: VectorClockId, node: NodeWeight, ) -> WorkspaceSnapshotResult { let new_node_index = self .working_copy_mut() .await - .add_ordered_node(change_set, node)?; + .add_ordered_node(vector_clock_id, node)?; Ok(new_node_index) } @@ -474,14 +480,14 @@ impl WorkspaceSnapshot { )] pub async fn update_content( &self, - change_set: &ChangeSet, + vector_clock_id: VectorClockId, id: Ulid, new_content_hash: ContentHash, ) -> WorkspaceSnapshotResult<()> { Ok(self .working_copy_mut() .await - .update_content(change_set, id, new_content_hash)?) + .update_content(vector_clock_id, id, new_content_hash)?) } #[instrument( @@ -724,10 +730,25 @@ impl WorkspaceSnapshot { self.working_copy().await.dot(); } + /// Write the entire graph to a file in dot format for debugging. *WARNING*: + /// Can panic! Don't use in production code paths. pub async fn tiny_dot_to_file(&self, suffix: Option<&str>) { self.working_copy().await.tiny_dot_to_file(suffix); } + /// Write a subgraph of the graph to a file in dot format for debugging. + /// *WARNING*: Can panic! Use only for debugging. + pub async fn tiny_dot_subgraph(&self, subgraph_root: impl Into, suffix: Option<&str>) { + let subgraph_root_idx = self + .get_node_index_by_id(subgraph_root) + .await + .expect("unable to find node index for subgraph root"); + + if let Some(subgraph) = self.working_copy().await.subgraph(subgraph_root_idx) { + subgraph.tiny_dot_to_file(suffix); + } + } + #[instrument( name = "workspace_snapshot.get_node_index_by_id", level = "debug", @@ -990,16 +1011,16 @@ impl WorkspaceSnapshot { )] pub async fn remove_all_edges( &self, - change_set: &ChangeSet, + vector_clock_id: VectorClockId, id: impl Into, ) -> WorkspaceSnapshotResult<()> { let id = id.into(); for (edge_weight, source, target) in self.edges_directed(id, Direction::Outgoing).await? { - self.remove_edge(change_set, source, target, edge_weight.kind().into()) + self.remove_edge(vector_clock_id, source, target, edge_weight.kind().into()) .await?; } for (edge_weight, source, target) in self.edges_directed(id, Direction::Incoming).await? { - self.remove_edge(change_set, source, target, edge_weight.kind().into()) + self.remove_edge(vector_clock_id, source, target, edge_weight.kind().into()) .await?; } Ok(()) @@ -1141,7 +1162,7 @@ impl WorkspaceSnapshot { )] pub async fn remove_incoming_edges_of_kind( &self, - change_set: &ChangeSet, + vector_clock_id: VectorClockId, target_id: impl Into, kind: EdgeWeightKindDiscriminants, ) -> WorkspaceSnapshotResult<()> { @@ -1152,7 +1173,7 @@ impl WorkspaceSnapshot { .await?; for source_node_idx in sources { let target_node_idx = self.get_node_index_by_id(target_id).await?; - self.remove_edge(change_set, source_node_idx, target_node_idx, kind) + self.remove_edge(vector_clock_id, source_node_idx, target_node_idx, kind) .await?; } @@ -1190,12 +1211,12 @@ impl WorkspaceSnapshot { )] pub async fn remove_node_by_id( &self, - change_set: &ChangeSet, + vector_clock_id: VectorClockId, id: impl Into, ) -> WorkspaceSnapshotResult<()> { let id: Ulid = id.into(); let node_idx = self.get_node_index_by_id(id).await?; - self.remove_all_edges(change_set, id).await?; + self.remove_all_edges(vector_clock_id, id).await?; self.working_copy_mut().await.remove_node(node_idx); self.working_copy_mut().await.remove_node_id(id); @@ -1210,13 +1231,13 @@ impl WorkspaceSnapshot { )] pub async fn remove_edge( &self, - change_set: &ChangeSet, + vector_clock_id: VectorClockId, source_node_index: NodeIndex, target_node_index: NodeIndex, edge_kind: EdgeWeightKindDiscriminants, ) -> WorkspaceSnapshotResult<()> { Ok(self.working_copy_mut().await.remove_edge( - change_set, + vector_clock_id, source_node_index, target_node_index, edge_kind, @@ -1246,7 +1267,7 @@ impl WorkspaceSnapshot { )] pub async fn remove_edge_for_ulids( &self, - change_set: &ChangeSet, + vector_clock_id: VectorClockId, source_node_id: impl Into, target_node_id: impl Into, edge_kind: EdgeWeightKindDiscriminants, @@ -1259,8 +1280,13 @@ impl WorkspaceSnapshot { .working_copy() .await .get_node_index_by_id(target_node_id)?; - self.remove_edge(change_set, source_node_index, target_node_index, edge_kind) - .await + self.remove_edge( + vector_clock_id, + source_node_index, + target_node_index, + edge_kind, + ) + .await } /// Perform [`Updates`](Update) using [`self`](WorkspaceSnapshot) as the "to rebase" graph and @@ -1273,12 +1299,12 @@ impl WorkspaceSnapshot { )] pub async fn perform_updates( &self, - to_rebase_change_set: &ChangeSet, + to_rebase_vector_clock_id: VectorClockId, onto: &WorkspaceSnapshot, updates: &[Update], ) -> WorkspaceSnapshotResult<()> { Ok(self.working_copy_mut().await.perform_updates( - to_rebase_change_set, + to_rebase_vector_clock_id, &*onto.working_copy().await, updates, )?) @@ -1394,43 +1420,60 @@ impl WorkspaceSnapshot { // under. return Ok(new_component_ids); }; - let conflicts_and_updates = base_snapshot.read_only_graph.detect_conflicts_and_updates( - VectorClockId::from(Ulid::from(base_change_set_id)), - &self.read_only_graph, - VectorClockId::from(Ulid::from(ctx.change_set_id())), - )?; - for update in &conflicts_and_updates.updates { - match update { - Update::RemoveEdge { - source: _, - destination: _, - edge_kind: _, - } - | Update::ReplaceSubgraph { - onto: _, - to_rebase: _, - } - | Update::MergeCategoryNodes { - to_rebase_category_id: _, - onto_category_id: _, - } => { - /* Updates unused for determining if a Component is new with regards to the updates */ - } - Update::NewEdge { - source, - destination, - edge_weight: _, - } => { - if !(source.index == component_category_idx - && destination.node_weight_kind == NodeWeightDiscriminants::Component) - { - // We only care about new edges coming from the Component category node, - // and going to Component nodes, so keep looking. - continue; + let base_vector_clock_id = base_snapshot + .read_only_graph + .max_recently_seen_clock_id_for_change_set(base_change_set_id) + .ok_or(WorkspaceSnapshotError::RecentlySeenClocksMissing( + base_change_set_id, + ))?; + + // If there is no vector clock in this snapshot for the current change + // set, that's because the snapshot has *just* been forked from the base + // change set, and has not been written to yet + if let Some(change_set_vector_clock_id) = self + .read_only_graph + .max_recently_seen_clock_id_for_change_set(ctx.change_set_id()) + { + let conflicts_and_updates = + base_snapshot.read_only_graph.detect_conflicts_and_updates( + base_vector_clock_id, + &self.read_only_graph, + change_set_vector_clock_id, + )?; + + for update in &conflicts_and_updates.updates { + match update { + Update::RemoveEdge { + source: _, + destination: _, + edge_kind: _, + } + | Update::ReplaceSubgraph { + onto: _, + to_rebase: _, + } + | Update::MergeCategoryNodes { + to_rebase_category_id: _, + onto_category_id: _, + } => { + /* Updates unused for determining if a Component is new with regards to the updates */ } + Update::NewEdge { + source, + destination, + edge_weight: _, + } => { + if !(source.index == component_category_idx + && destination.node_weight_kind == NodeWeightDiscriminants::Component) + { + // We only care about new edges coming from the Component category node, + // and going to Component nodes, so keep looking. + continue; + } - new_component_ids.push(ComponentId::from(Ulid::from(destination.id))); + new_component_ids.push(ComponentId::from(Ulid::from(destination.id))); + } } } } @@ -1470,56 +1513,72 @@ impl WorkspaceSnapshot { } let base_snapshot = WorkspaceSnapshot::find_for_change_set(ctx, base_change_set_id).await?; - let conflicts_and_updates = base_snapshot.read_only_graph.detect_conflicts_and_updates( - VectorClockId::from(Ulid::from(base_change_set_id)), - &self.read_only_graph, - VectorClockId::from(Ulid::from(ctx.change_set_id())), - )?; + let base_vector_clock_id = base_snapshot + .read_only_graph + .max_recently_seen_clock_id_for_change_set(base_change_set_id) + .ok_or(WorkspaceSnapshotError::RecentlySeenClocksMissing( + base_change_set_id, + ))?; + + // If there is no vector clock in this snapshot for the current change + // set, that's because the snapshot has *just* been forked from the base + // change set, and has not been written to yet + if let Some(change_set_vector_clock_id) = self + .read_only_graph + .max_recently_seen_clock_id_for_change_set(ctx.change_set_id()) + { + let conflicts_and_updates = + base_snapshot.read_only_graph.detect_conflicts_and_updates( + base_vector_clock_id, + &self.read_only_graph, + change_set_vector_clock_id, + )?; - for update in &conflicts_and_updates.updates { - match update { - Update::RemoveEdge { - source: _, - destination: _, - edge_kind: _, - } - | Update::ReplaceSubgraph { - onto: _, - to_rebase: _, - } - | Update::MergeCategoryNodes { - to_rebase_category_id: _, - onto_category_id: _, - } => { - // Updates unused for determining if a socket to socket connection (in frontend - // terms) is new. - } - Update::NewEdge { - source: _source, - destination, - edge_weight: _, - } => { - if destination.node_weight_kind - != NodeWeightDiscriminants::AttributePrototypeArgument - { - // We're interested in new AttributePrototypeArguments as they represent - // the connection between sockets. (The input socket has the output - // socket as one of its function arguments.) - continue; + for update in &conflicts_and_updates.updates { + match update { + Update::RemoveEdge { + source: _, + destination: _, + edge_kind: _, + } + | Update::ReplaceSubgraph { + onto: _, + to_rebase: _, } + | Update::MergeCategoryNodes { + to_rebase_category_id: _, + onto_category_id: _, + } => { + // Updates unused for determining if a socket to socket connection (in frontend + // terms) is new. + } + Update::NewEdge { + source: _source, + destination, + edge_weight: _, + } => { + if destination.node_weight_kind + != NodeWeightDiscriminants::AttributePrototypeArgument + { + // We're interested in new AttributePrototypeArguments as they represent + // the connection between sockets. (The input socket has the output + // socket as one of its function arguments.) + continue; + } - let prototype_argument = AttributePrototypeArgument::get_by_id( - ctx, - AttributePrototypeArgumentId::from(Ulid::from(destination.id)), - ) - .await - .map_err(Box::new)?; - if prototype_argument.targets().is_some() { - new_attribute_prototype_argument_ids.push(prototype_argument.id()); - } else { - // If the AttributePrototypeArgument doesn't have targets, then it's - // not for a socket to socket connection. - continue; + let prototype_argument = AttributePrototypeArgument::get_by_id( + ctx, + AttributePrototypeArgumentId::from(Ulid::from(destination.id)), + ) + .await + .map_err(Box::new)?; + if prototype_argument.targets().is_some() { + new_attribute_prototype_argument_ids.push(prototype_argument.id()); + } else { + // If the AttributePrototypeArgument doesn't have targets, then it's + // not for a socket to socket connection. + continue; + } } } } @@ -1543,7 +1602,7 @@ impl WorkspaceSnapshot { async fn find_existing_dependent_value_root( &self, - change_set: &ChangeSet, + vector_clock_id: VectorClockId, value_id: Ulid, ) -> WorkspaceSnapshotResult<(Ulid, Option)> { let dv_category_id = match self @@ -1554,11 +1613,17 @@ impl WorkspaceSnapshot { None => { let mut working_copy = self.working_copy_mut().await; let root_idx = working_copy.root(); - let category_node_idx = working_copy - .add_category_node(change_set, CategoryNodeKind::DependentValueRoots)?; + let id = working_copy.generate_ulid()?; + let lineage_id = working_copy.generate_ulid()?; + let category_node_idx = working_copy.add_category_node( + vector_clock_id, + id, + lineage_id, + CategoryNodeKind::DependentValueRoots, + )?; working_copy.add_edge( root_idx, - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use())?, + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use())?, category_node_idx, )?; @@ -1585,7 +1650,7 @@ impl WorkspaceSnapshot { pub async fn add_dependent_value_root( &self, - change_set: &ChangeSet, + vector_clock_id: VectorClockId, value_id: impl Into, ) -> WorkspaceSnapshotResult<()> { let value_id = value_id.into(); @@ -1601,16 +1666,20 @@ impl WorkspaceSnapshot { } let (dv_category_id, _) = self - .find_existing_dependent_value_root(change_set, value_id) + .find_existing_dependent_value_root(vector_clock_id, value_id) .await?; - let new_dependent_value_node = NodeWeight::new_dependent_value_root(change_set, value_id)?; + let id = self.generate_ulid().await?; + let lineage_id = self.generate_ulid().await?; + + let new_dependent_value_node = + NodeWeight::new_dependent_value_root(vector_clock_id, id, lineage_id, value_id)?; let new_dv_node_id = new_dependent_value_node.id(); self.add_node(new_dependent_value_node).await?; self.add_edge( dv_category_id, - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use())?, + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use())?, new_dv_node_id, ) .await?; @@ -1620,16 +1689,16 @@ impl WorkspaceSnapshot { pub async fn remove_dependent_value_root( &self, - change_set: &ChangeSet, + vector_clock_id: VectorClockId, value_id: impl Into, ) -> WorkspaceSnapshotResult<()> { let value_id = value_id.into(); let (_, existing_value_id) = self - .find_existing_dependent_value_root(change_set, value_id) + .find_existing_dependent_value_root(vector_clock_id, value_id) .await?; if let Some(existing_id) = existing_value_id { - self.remove_node_by_id(change_set, existing_id).await?; + self.remove_node_by_id(vector_clock_id, existing_id).await?; } Ok(()) @@ -1656,7 +1725,7 @@ impl WorkspaceSnapshot { /// Removes all the dependent value nodes from the category and returns the value_ids pub async fn take_dependent_values( &self, - change_set: &ChangeSet, + vector_clock_id: VectorClockId, ) -> WorkspaceSnapshotResult> { let dv_category_id = match self .get_category_node(None, CategoryNodeKind::DependentValueRoots) @@ -1684,7 +1753,8 @@ impl WorkspaceSnapshot { } for to_remove_id in pending_removes { - self.remove_node_by_id(change_set, to_remove_id).await?; + self.remove_node_by_id(vector_clock_id, to_remove_id) + .await?; } Ok(value_ids) diff --git a/lib/dal/src/workspace_snapshot/graph.rs b/lib/dal/src/workspace_snapshot/graph.rs index c772f723b5..4299460259 100644 --- a/lib/dal/src/workspace_snapshot/graph.rs +++ b/lib/dal/src/workspace_snapshot/graph.rs @@ -1,6 +1,7 @@ use std::collections::{HashMap, HashSet, VecDeque}; use std::fs::File; use std::io::Write; +use std::sync::{Arc, Mutex}; use chrono::Utc; /// Ensure [`NodeIndex`] is usable by external crates. @@ -14,8 +15,8 @@ use si_events::{ulid::Ulid, ContentHash}; use thiserror::Error; use telemetry::prelude::*; +use ulid::Generator; -use crate::change_set::{ChangeSet, ChangeSetError}; use crate::workspace_snapshot::content_address::ContentAddressDiscriminants; use crate::workspace_snapshot::node_weight::category_node_weight::CategoryNodeKind; use crate::workspace_snapshot::node_weight::{CategoryNodeWeight, NodeWeightDiscriminants}; @@ -28,6 +29,7 @@ use crate::workspace_snapshot::{ update::Update, NodeInformation, }; +use crate::ChangeSetId; use super::edge_weight::DeprecatedEdgeWeight; @@ -41,8 +43,8 @@ pub type LineageId = Ulid; pub enum WorkspaceSnapshotGraphError { #[error("Cannot compare ordering of container elements between ordered, and un-ordered container: {0:?}, {1:?}")] CannotCompareOrderedAndUnorderedContainers(NodeIndex, NodeIndex), - #[error("ChangeSet error: {0}")] - ChangeSet(#[from] ChangeSetError), + // #[error("ChangeSet error: {0}")] + // ChangeSet(#[from] ChangeSetError), #[error("Unable to retrieve content for ContentHash")] ContentMissingForContentHash, #[error("Action would create a graph cycle")] @@ -61,6 +63,10 @@ pub enum WorkspaceSnapshotGraphError { IncompatibleNodeTypes, #[error("Invalid value graph")] InvalidValueGraph, + #[error("monotonic error: {0}")] + Monotonic(#[from] ulid::MonotonicError), + #[error("mutex poisoning: {0}")] + MutexPoison(String), #[error("NodeWeight error: {0}")] NodeWeight(#[from] NodeWeightError), #[error("node weight not found")] @@ -87,6 +93,9 @@ pub struct WorkspaceSnapshotGraph { node_index_by_id: HashMap, node_indices_by_lineage_id: HashMap>, root_index: NodeIndex, + + #[serde(skip)] + ulid_generator: Arc>, } #[derive(Default, Deserialize, Serialize, Clone)] @@ -175,6 +184,7 @@ impl From for WorkspaceSnapshotGraph { node_index_by_id, node_indices_by_lineage_id, root_index, + ulid_generator: Arc::new(Mutex::new(Generator::new())), } } } @@ -190,12 +200,14 @@ impl std::fmt::Debug for WorkspaceSnapshotGraph { } impl WorkspaceSnapshotGraph { - pub fn new(change_set: &ChangeSet) -> WorkspaceSnapshotGraphResult { + pub fn new(vector_clock_id: VectorClockId) -> WorkspaceSnapshotGraphResult { let mut graph: StableDiGraph = StableDiGraph::with_capacity(1024, 1024); + let mut generator = Generator::new(); let root_node = NodeWeight::new_content( - change_set, - change_set.generate_ulid()?, + vector_clock_id, + generator.generate()?.into(), + generator.generate()?.into(), ContentAddress::Root, )?; @@ -206,6 +218,7 @@ impl WorkspaceSnapshotGraph { let mut result = Self { root_index, graph, + ulid_generator: Arc::new(Mutex::new(generator)), ..Default::default() }; @@ -223,6 +236,29 @@ impl WorkspaceSnapshotGraph { &self.graph } + pub fn generate_ulid(&self) -> WorkspaceSnapshotGraphResult { + Ok(self + .ulid_generator + .lock() + .map_err(|e| WorkspaceSnapshotGraphError::MutexPoison(e.to_string()))? + .generate()? + .into()) + } + + pub fn max_recently_seen_clock_id_for_change_set( + &self, + change_set_id: ChangeSetId, + ) -> Option { + self.graph + .node_weight(self.root()) + .and_then(|root_node| { + root_node + .vector_clock_recently_seen() + .max_for_change_set_id(change_set_id) + }) + .map(|(clock_id, _)| clock_id) + } + pub fn get_latest_node_idx_opt( &self, node_idx: NodeIndex, @@ -369,10 +405,12 @@ impl WorkspaceSnapshotGraph { pub fn add_category_node( &mut self, - change_set: &ChangeSet, + vector_clock_id: VectorClockId, + id: Ulid, + lineage_id: Ulid, kind: CategoryNodeKind, ) -> WorkspaceSnapshotGraphResult { - let inner_weight = CategoryNodeWeight::new(change_set, kind)?; + let inner_weight = CategoryNodeWeight::new(id, lineage_id, vector_clock_id, kind)?; let new_node_index = self.add_node(NodeWeight::Category(inner_weight))?; Ok(new_node_index) } @@ -520,15 +558,22 @@ impl WorkspaceSnapshotGraph { pub fn add_ordered_node( &mut self, - change_set: &ChangeSet, + vector_clock_id: VectorClockId, node: NodeWeight, ) -> WorkspaceSnapshotGraphResult { let new_node_index = self.add_node(node)?; - let ordering_node_index = - self.add_node(NodeWeight::Ordering(OrderingNodeWeight::new(change_set)?))?; + + let ordering_node_id = self.generate_ulid()?; + let ordering_node_lineage_id = self.generate_ulid()?; + let ordering_node_index = self.add_node(NodeWeight::Ordering(OrderingNodeWeight::new( + ordering_node_id, + ordering_node_lineage_id, + vector_clock_id, + )?))?; + let edge_index = self.add_edge( new_node_index, - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::Ordering)?, + EdgeWeight::new(vector_clock_id, EdgeWeightKind::Ordering)?, ordering_node_index, )?; let (source, _) = self.edge_endpoints(edge_index)?; @@ -1036,17 +1081,34 @@ impl WorkspaceSnapshotGraph { let source_node_weight = self.graph.node_weight(source_idx)?.to_owned(); let id = source_node_weight.id(); let lineage_id = source_node_weight.lineage_id(); - let new_source_idx = subgraph.add_node(source_node_weight); - index_map.insert(source_idx, new_source_idx); + let new_source_idx = match index_map.get(&source_idx).copied() { + Some(node_idx) => node_idx, + None => { + let new_source_idx = subgraph.add_node(source_node_weight); + index_map.insert(source_idx, new_source_idx); + node_index_by_id.insert(id, new_source_idx); + node_indices_by_lineage_id + .entry(lineage_id) + .and_modify(|set: &mut HashSet| { + set.insert(new_source_idx); + }) + .or_insert_with(|| HashSet::from([new_source_idx])); - add_node_to_idx(id, lineage_id, new_source_idx); + new_source_idx + } + }; let edge_weight = edge_ref.weight().to_owned(); let current_node_idx_in_sub = index_map.get(&node_idx).copied()?; - subgraph.add_edge(new_source_idx, current_node_idx_in_sub, edge_weight); + if subgraph + .find_edge(new_source_idx, current_node_idx_in_sub) + .is_none() + { + subgraph.add_edge(new_source_idx, current_node_idx_in_sub, edge_weight); + } - parent_q.push_back(edge_ref.source()); + parent_q.push_back(source_idx); } if !has_parents { new_root = Some(index_map.get(&node_idx).copied()?); @@ -1054,23 +1116,40 @@ impl WorkspaceSnapshotGraph { } // Walk to leaves from subgraph_root - let mut child_q = VecDeque::from([subgraph_root]); + let mut child_q: VecDeque = VecDeque::from([subgraph_root]); while let Some(node_idx) = child_q.pop_front() { for edge_ref in self.edges_directed(node_idx, Outgoing) { let target_idx = edge_ref.target(); let target_node_weight = self.graph.node_weight(target_idx)?.to_owned(); let id = target_node_weight.id(); let lineage_id = target_node_weight.lineage_id(); - let new_target_idx = subgraph.add_node(target_node_weight); - index_map.insert(target_idx, new_target_idx); - add_node_to_idx(id, lineage_id, new_target_idx); + let new_target_idx = match index_map.get(&target_idx).copied() { + Some(node_idx) => node_idx, + None => { + let new_target_idx = subgraph.add_node(target_node_weight); + index_map.insert(target_idx, new_target_idx); + node_index_by_id.insert(id, new_target_idx); + node_indices_by_lineage_id + .entry(lineage_id) + .and_modify(|set: &mut HashSet| { + set.insert(new_target_idx); + }) + .or_insert_with(|| HashSet::from([new_target_idx])); - let edge_weight = edge_ref.weight().to_owned(); + new_target_idx + } + }; + let edge_weight = edge_ref.weight().to_owned(); let current_node_idx_in_sub = index_map.get(&edge_ref.source()).copied()?; - subgraph.add_edge(current_node_idx_in_sub, new_target_idx, edge_weight); + if subgraph + .find_edge(current_node_idx_in_sub, new_target_idx) + .is_none() + { + subgraph.add_edge(current_node_idx_in_sub, new_target_idx, edge_weight); + } - child_q.push_back(edge_ref.source()); + child_q.push_back(target_idx); } } @@ -1079,6 +1158,7 @@ impl WorkspaceSnapshotGraph { node_index_by_id, node_indices_by_lineage_id, root_index: new_root?, + ..Default::default() }) } @@ -1226,7 +1306,7 @@ impl WorkspaceSnapshotGraph { let color = color.to_string(); let id = node_weight.id(); format!( - "label = \"\n\n{label}\n{node_index:?}\n{id}\n\n{:?}\"\nfontcolor = {color}\ncolor = {color}", node_weight.merkle_tree_hash() + "label = \"\n\n{label}\n{node_index:?}\n{id}\n\n{:?}\n{:?}\"\nfontcolor = {color}\ncolor = {color}", node_weight.merkle_tree_hash(), node_weight.node_hash(), ) }, ); @@ -1336,13 +1416,14 @@ impl WorkspaceSnapshotGraph { debug!("only onto edges: {:?}", &only_onto_edges); // This is the last time that to_rebase knows about onto having seen the snapshot - let to_rebase_last_saw_onto = self - .get_node_weight(self.root_index)? + let to_rebase_root_node = self.get_node_weight(self.root())?; + let onto_root_node = onto.get_node_weight(onto.root())?; + + let to_rebase_last_saw_onto = to_rebase_root_node .vector_clock_recently_seen() .entry_for(onto_vector_clock_id); - let onto_last_saw_to_rebase = onto - .get_node_weight(onto.root_index)? + let onto_last_saw_to_rebase = onto_root_node .vector_clock_recently_seen() .entry_for(to_rebase_vector_clock_id); @@ -1802,13 +1883,13 @@ impl WorkspaceSnapshotGraph { /// [`Self::cleanup()`] has run should be considered invalid. pub fn remove_edge( &mut self, - change_set: &ChangeSet, + vector_clock_id: VectorClockId, source_node_index: NodeIndex, target_node_index: NodeIndex, edge_kind: EdgeWeightKindDiscriminants, ) -> WorkspaceSnapshotGraphResult<()> { self.remove_edge_inner( - change_set, + vector_clock_id, source_node_index, target_node_index, edge_kind, @@ -1821,7 +1902,7 @@ impl WorkspaceSnapshotGraph { /// the node at `source_node_index`. fn remove_edge_inner( &mut self, - change_set: &ChangeSet, + vector_clock_id: VectorClockId, source_node_index: NodeIndex, target_node_index: NodeIndex, edge_kind: EdgeWeightKindDiscriminants, @@ -1853,7 +1934,7 @@ impl WorkspaceSnapshotGraph { // We only want to update the ordering of the container if we removed an edge to // one of the ordered relationships. if new_container_ordering_node_weight.remove_from_order( - change_set.vector_clock_id(), + vector_clock_id, element_id, increment_vector_clocks, ) { @@ -1987,14 +2068,14 @@ impl WorkspaceSnapshotGraph { pub fn update_content( &mut self, - change_set: &ChangeSet, + vector_clock_id: VectorClockId, id: Ulid, new_content_hash: ContentHash, ) -> WorkspaceSnapshotGraphResult<()> { let original_node_index = self.get_node_index_by_id(id)?; let new_node_index = self.copy_node_by_index(original_node_index)?; let node_weight = self.get_node_weight_mut(new_node_index)?; - node_weight.increment_vector_clocks(change_set.vector_clock_id()); + node_weight.increment_vector_clocks(vector_clock_id); node_weight.new_content_hash(new_content_hash)?; self.replace_references(original_node_index)?; @@ -2126,7 +2207,7 @@ impl WorkspaceSnapshotGraph { /// and a provided graph as the "onto" graph. pub fn perform_updates( &mut self, - to_rebase_change_set: &ChangeSet, + to_rebase_vector_clock_id: VectorClockId, onto: &WorkspaceSnapshotGraph, updates: &[Update], ) -> WorkspaceSnapshotGraphResult<()> { @@ -2151,7 +2232,7 @@ impl WorkspaceSnapshotGraph { let updated_source = self.get_latest_node_idx(source.index)?; let destination = self.get_latest_node_idx(destination.index)?; self.remove_edge_inner( - to_rebase_change_set, + to_rebase_vector_clock_id, updated_source, destination, *edge_kind, diff --git a/lib/dal/src/workspace_snapshot/graph/tests.rs b/lib/dal/src/workspace_snapshot/graph/tests.rs index aa39619f4a..2337fee0c1 100644 --- a/lib/dal/src/workspace_snapshot/graph/tests.rs +++ b/lib/dal/src/workspace_snapshot/graph/tests.rs @@ -1,9 +1,9 @@ use std::collections::HashMap; -use si_events::{ulid::Ulid, ContentHash}; +use si_events::{ulid::Ulid, ContentHash, VectorClockId}; use crate::{ - workspace_snapshot::node_weight::NodeWeight, ChangeSet, EdgeWeight, EdgeWeightKind, PropKind, + workspace_snapshot::node_weight::NodeWeight, EdgeWeight, EdgeWeightKind, PropKind, WorkspaceSnapshotGraph, }; @@ -14,7 +14,7 @@ mod rebase; #[allow(dead_code)] fn add_prop_nodes_to_graph<'a, 'b>( graph: &'a mut WorkspaceSnapshotGraph, - change_set: &'a ChangeSet, + vector_clock_id: VectorClockId, nodes: &'a [&'b str], ordered: bool, ) -> HashMap<&'b str, Ulid> { @@ -22,10 +22,12 @@ fn add_prop_nodes_to_graph<'a, 'b>( for node in nodes { // "props" here are just nodes that are easy to create and render the name on the dot // output. there is no domain modeling in this test. - let node_id = change_set.generate_ulid().expect("Unable to generate Ulid"); + let node_id = graph.generate_ulid().expect("Unable to generate Ulid"); + let node_lineage_id = graph.generate_ulid().expect("Unable to generate Ulid"); let prop_node_weight = NodeWeight::new_prop( - change_set, + vector_clock_id, node_id, + node_lineage_id, PropKind::Object, node, ContentHash::new(node.as_bytes()), @@ -33,7 +35,7 @@ fn add_prop_nodes_to_graph<'a, 'b>( .expect("create prop node weight"); if ordered { graph - .add_ordered_node(change_set, prop_node_weight) + .add_ordered_node(vector_clock_id, prop_node_weight) .expect("Unable to add prop"); } else { graph @@ -50,7 +52,7 @@ fn add_prop_nodes_to_graph<'a, 'b>( fn add_edges( graph: &mut WorkspaceSnapshotGraph, node_id_map: &HashMap<&str, Ulid>, - change_set: &ChangeSet, + vector_clock_id: VectorClockId, edges: &[(Option<&str>, &str)], ) { for (source, target) in edges { @@ -78,7 +80,7 @@ fn add_edges( graph .add_edge( source, - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("create edge weight"), target, ) @@ -94,11 +96,11 @@ mod test { use petgraph::Outgoing; use pretty_assertions_sorted::assert_eq; use si_events::merkle_tree_hash::MerkleTreeHash; - use si_events::ContentHash; + use si_events::ulid::Ulid; + use si_events::{ContentHash, VectorClockId}; use std::collections::HashSet; use std::str::FromStr; - use crate::change_set::ChangeSet; use crate::workspace_snapshot::content_address::ContentAddress; use crate::workspace_snapshot::edge_weight::{ EdgeWeight, EdgeWeightKind, EdgeWeightKindDiscriminants, @@ -114,9 +116,8 @@ mod test { #[test] fn new() { - let change_set = ChangeSet::new_local().expect("Unable to create ChangeSet"); - let change_set = &change_set; - let graph = WorkspaceSnapshotGraph::new(change_set) + let vector_clock_id = VectorClockId::new(Ulid::new(), Ulid::new()); + let graph = WorkspaceSnapshotGraph::new(vector_clock_id) .expect("Unable to create WorkspaceSnapshotGraph"); assert!(graph.is_acyclic_directed()); } @@ -126,9 +127,8 @@ mod test { // on a fresh graph (like add_ordered_node) #[test] fn get_root_index_by_root_id_on_fresh_graph() { - let base_change_set = ChangeSet::new_local().expect("Unable to create ChangeSet"); - let active_change_set = &base_change_set; - let graph = WorkspaceSnapshotGraph::new(active_change_set) + let vector_clock_id = VectorClockId::new(Ulid::new(), Ulid::new()); + let graph = WorkspaceSnapshotGraph::new(vector_clock_id) .expect("Unable to create WorkspaceSnapshotGraph"); let root_id = graph @@ -187,13 +187,13 @@ mod test { (Some("a"), "b"), ]; - let change_set = ChangeSet::new_local().expect("Unable to create ChangeSet"); - let change_set = &change_set; - let mut graph = WorkspaceSnapshotGraph::new(change_set) + let vector_clock_id = VectorClockId::new(Ulid::new(), Ulid::new()); + + let mut graph = WorkspaceSnapshotGraph::new(vector_clock_id) .expect("Unable to create WorkspaceSnapshotGraph"); - let node_id_map = add_prop_nodes_to_graph(&mut graph, change_set, &nodes, false); - add_edges(&mut graph, &node_id_map, change_set, &edges); + let node_id_map = add_prop_nodes_to_graph(&mut graph, vector_clock_id, &nodes, false); + add_edges(&mut graph, &node_id_map, vector_clock_id, &edges); graph.cleanup(); @@ -245,17 +245,18 @@ mod test { #[test] fn add_nodes_and_edges() { - let change_set = ChangeSet::new_local().expect("Unable to create ChangeSet"); - let change_set = &change_set; - let mut graph = WorkspaceSnapshotGraph::new(change_set) + let actor_a = Ulid::new(); + let vector_clock_id = VectorClockId::new(Ulid::new(), actor_a); + let mut graph = WorkspaceSnapshotGraph::new(vector_clock_id) .expect("Unable to create WorkspaceSnapshotGraph"); - let schema_id = change_set.generate_ulid().expect("Unable to generate Ulid"); + let schema_id = graph.generate_ulid().expect("Unable to generate Ulid"); let schema_index = graph .add_node( NodeWeight::new_content( - change_set, + vector_clock_id, schema_id, + Ulid::new(), ContentAddress::Schema(ContentHash::new( SchemaId::generate().to_string().as_bytes(), )), @@ -263,12 +264,13 @@ mod test { .expect("Unable to create NodeWeight"), ) .expect("Unable to add schema"); - let schema_variant_id = change_set.generate_ulid().expect("Unable to generate Ulid"); + let schema_variant_id = graph.generate_ulid().expect("Unable to generate Ulid"); let schema_variant_index = graph .add_node( NodeWeight::new_content( - change_set, + vector_clock_id, schema_variant_id, + Ulid::new(), ContentAddress::SchemaVariant(ContentHash::new( SchemaVariantId::generate().to_string().as_bytes(), )), @@ -276,12 +278,13 @@ mod test { .expect("Unable to create NodeWeight"), ) .expect("Unable to add schema variant"); - let component_id = change_set.generate_ulid().expect("Unable to generate Ulid"); + let component_id = graph.generate_ulid().expect("Unable to generate Ulid"); let component_index = graph .add_node( NodeWeight::new_content( - change_set, + vector_clock_id, component_id, + Ulid::new(), ContentAddress::Component(ContentHash::new( ComponentId::generate().to_string().as_bytes(), )), @@ -293,7 +296,7 @@ mod test { graph .add_edge( graph.root_index, - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), component_index, ) @@ -301,7 +304,7 @@ mod test { graph .add_edge( graph.root_index, - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), schema_index, ) @@ -311,7 +314,7 @@ mod test { graph .get_node_index_by_id(schema_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), schema_variant_index, ) @@ -321,7 +324,7 @@ mod test { graph .get_node_index_by_id(component_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), graph .get_node_index_by_id(schema_variant_id) @@ -329,12 +332,13 @@ mod test { ) .expect("Unable to add component -> schema variant edge"); - let func_id = change_set.generate_ulid().expect("Unable to generate Ulid"); + let func_id = graph.generate_ulid().expect("Unable to generate Ulid"); let func_index = graph .add_node( NodeWeight::new_content( - change_set, + vector_clock_id, func_id, + Ulid::new(), ContentAddress::Func(ContentHash::new( FuncId::generate().to_string().as_bytes(), )), @@ -342,12 +346,13 @@ mod test { .expect("Unable to create NodeWeight"), ) .expect("Unable to add func"); - let prop_id = change_set.generate_ulid().expect("Unable to generate Ulid"); + let prop_id = graph.generate_ulid().expect("Unable to generate Ulid"); let prop_index = graph .add_node( NodeWeight::new_content( - change_set, + vector_clock_id, prop_id, + Ulid::new(), ContentAddress::Prop(ContentHash::new( PropId::generate().to_string().as_bytes(), )), @@ -359,7 +364,7 @@ mod test { graph .add_edge( graph.root_index, - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), func_index, ) @@ -369,7 +374,7 @@ mod test { graph .get_node_index_by_id(schema_variant_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), prop_index, ) @@ -379,7 +384,7 @@ mod test { graph .get_node_index_by_id(prop_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), graph .get_node_index_by_id(func_id) @@ -392,17 +397,17 @@ mod test { #[test] fn cyclic_failure() { - let change_set = ChangeSet::new_local().expect("Unable to create ChangeSet"); - let change_set = &change_set; - let mut graph = WorkspaceSnapshotGraph::new(change_set) + let vector_clock_id = VectorClockId::new(Ulid::new(), Ulid::new()); + let mut graph = WorkspaceSnapshotGraph::new(vector_clock_id) .expect("Unable to create WorkspaceSnapshotGraph"); - let schema_id = change_set.generate_ulid().expect("Unable to generate Ulid"); + let schema_id = graph.generate_ulid().expect("Unable to generate Ulid"); let initial_schema_node_index = graph .add_node( NodeWeight::new_content( - change_set, + vector_clock_id, schema_id, + Ulid::new(), ContentAddress::Schema(ContentHash::new( SchemaId::generate().to_string().as_bytes(), )), @@ -410,12 +415,13 @@ mod test { .expect("Unable to create NodeWeight"), ) .expect("Unable to add schema"); - let schema_variant_id = change_set.generate_ulid().expect("Unable to generate Ulid"); + let schema_variant_id = graph.generate_ulid().expect("Unable to generate Ulid"); let initial_schema_variant_node_index = graph .add_node( NodeWeight::new_content( - change_set, + vector_clock_id, schema_variant_id, + Ulid::new(), ContentAddress::SchemaVariant(ContentHash::new( SchemaVariantId::generate().to_string().as_bytes(), )), @@ -423,12 +429,13 @@ mod test { .expect("Unable to create NodeWeight"), ) .expect("Unable to add schema variant"); - let component_id = change_set.generate_ulid().expect("Unable to generate Ulid"); + let component_id = graph.generate_ulid().expect("Unable to generate Ulid"); let initial_component_node_index = graph .add_node( NodeWeight::new_content( - change_set, + vector_clock_id, component_id, + Ulid::new(), ContentAddress::Component(ContentHash::new( ComponentId::generate().to_string().as_bytes(), )), @@ -440,7 +447,7 @@ mod test { graph .add_edge( graph.root_index, - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), initial_component_node_index, ) @@ -448,7 +455,7 @@ mod test { graph .add_edge( graph.root_index, - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), initial_schema_node_index, ) @@ -458,7 +465,7 @@ mod test { graph .get_node_index_by_id(schema_id) .expect("Unable to find NodeIndex"), - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), initial_schema_variant_node_index, ) @@ -468,7 +475,7 @@ mod test { graph .get_node_index_by_id(component_id) .expect("Unable to find NodeIndex"), - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), graph .get_node_index_by_id(schema_variant_id) @@ -484,7 +491,7 @@ mod test { graph .get_node_index_by_id(schema_variant_id) .expect("Unable to find NodeIndex"), - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), graph .get_node_index_by_id(component_id) @@ -497,28 +504,29 @@ mod test { #[test] fn update_content() { - let change_set = ChangeSet::new_local().expect("Unable to create ChangeSet"); - let change_set = &change_set; - let mut graph = WorkspaceSnapshotGraph::new(change_set) + let vector_clock_id = VectorClockId::new(Ulid::new(), Ulid::new()); + let mut graph = WorkspaceSnapshotGraph::new(vector_clock_id) .expect("Unable to create WorkspaceSnapshotGraph"); - let schema_id = change_set.generate_ulid().expect("Unable to generate Ulid"); + let schema_id = graph.generate_ulid().expect("Unable to generate Ulid"); let schema_index = graph .add_node( NodeWeight::new_content( - change_set, + vector_clock_id, schema_id, + Ulid::new(), ContentAddress::Schema(ContentHash::from("Constellation")), ) .expect("Unable to create NodeWeight"), ) .expect("Unable to add schema"); - let schema_variant_id = change_set.generate_ulid().expect("Unable to generate Ulid"); + let schema_variant_id = graph.generate_ulid().expect("Unable to generate Ulid"); let schema_variant_index = graph .add_node( NodeWeight::new_content( - change_set, + vector_clock_id, schema_variant_id, + Ulid::new(), ContentAddress::SchemaVariant(ContentHash::new( "Freestar Collective".as_bytes(), )), @@ -526,12 +534,13 @@ mod test { .expect("Unable to create NodeWeight"), ) .expect("Unable to add schema variant"); - let component_id = change_set.generate_ulid().expect("Unable to generate Ulid"); + let component_id = graph.generate_ulid().expect("Unable to generate Ulid"); let component_index = graph .add_node( NodeWeight::new_content( - change_set, + vector_clock_id, component_id, + Ulid::new(), ContentAddress::Component(ContentHash::from("Crimson Fleet")), ) .expect("Unable to create NodeWeight"), @@ -541,7 +550,7 @@ mod test { graph .add_edge( graph.root_index, - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), component_index, ) @@ -549,7 +558,7 @@ mod test { graph .add_edge( graph.root_index, - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), schema_index, ) @@ -559,7 +568,7 @@ mod test { graph .get_node_index_by_id(schema_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), schema_variant_index, ) @@ -569,7 +578,7 @@ mod test { graph .get_node_index_by_id(component_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), graph .get_node_index_by_id(schema_variant_id) @@ -591,7 +600,7 @@ mod test { let updated_content_hash = ContentHash::from("new_content"); graph - .update_content(change_set, component_id, updated_content_hash) + .update_content(vector_clock_id, component_id, updated_content_hash) .expect("Unable to update Component content hash"); let post_update_root_node_merkle_tree_hash: MerkleTreeHash = @@ -644,17 +653,17 @@ mod test { #[test] fn add_ordered_node() { - let change_set = ChangeSet::new_local().expect("Unable to create ChangeSet"); - let change_set = &change_set; - let mut graph = WorkspaceSnapshotGraph::new(change_set) + let vector_clock_id = VectorClockId::new(Ulid::new(), Ulid::new()); + let mut graph = WorkspaceSnapshotGraph::new(vector_clock_id) .expect("Unable to create WorkspaceSnapshotGraph"); - let schema_id = change_set.generate_ulid().expect("Unable to generate Ulid"); + let schema_id = graph.generate_ulid().expect("Unable to generate Ulid"); let schema_index = graph .add_node( NodeWeight::new_content( - change_set, + vector_clock_id, schema_id, + Ulid::new(), ContentAddress::Schema(ContentHash::new( SchemaId::generate().to_string().as_bytes(), )), @@ -662,12 +671,13 @@ mod test { .expect("Unable to create NodeWeight"), ) .expect("Unable to add schema"); - let schema_variant_id = change_set.generate_ulid().expect("Unable to generate Ulid"); + let schema_variant_id = graph.generate_ulid().expect("Unable to generate Ulid"); let schema_variant_index = graph .add_node( NodeWeight::new_content( - change_set, + vector_clock_id, schema_variant_id, + Ulid::new(), ContentAddress::SchemaVariant(ContentHash::new( SchemaVariantId::generate().to_string().as_bytes(), )), @@ -679,7 +689,7 @@ mod test { graph .add_edge( graph.root_index, - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), schema_index, ) @@ -689,18 +699,19 @@ mod test { graph .get_node_index_by_id(schema_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), schema_variant_index, ) .expect("Unable to add schema -> schema variant edge"); - let func_id = change_set.generate_ulid().expect("Unable to generate Ulid"); + let func_id = graph.generate_ulid().expect("Unable to generate Ulid"); let func_index = graph .add_node( NodeWeight::new_content( - change_set, + vector_clock_id, func_id, + Ulid::new(), ContentAddress::Func(ContentHash::new( FuncId::generate().to_string().as_bytes(), )), @@ -711,19 +722,20 @@ mod test { graph .add_edge( graph.root_index, - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), func_index, ) .expect("Unable to add root -> func edge"); - let prop_id = change_set.generate_ulid().expect("Unable to generate Ulid"); + let prop_id = graph.generate_ulid().expect("Unable to generate Ulid"); let prop_index = graph .add_ordered_node( - change_set, + vector_clock_id, NodeWeight::new_content( - change_set, + vector_clock_id, prop_id, + Ulid::new(), ContentAddress::Prop(ContentHash::new( PropId::generate().to_string().as_bytes(), )), @@ -736,7 +748,7 @@ mod test { graph .get_node_index_by_id(schema_variant_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), prop_index, ) @@ -746,7 +758,7 @@ mod test { graph .get_node_index_by_id(prop_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), graph .get_node_index_by_id(func_id) @@ -756,12 +768,13 @@ mod test { graph.cleanup(); graph.dot(); - let ordered_prop_1_id = change_set.generate_ulid().expect("Unable to generate Ulid"); + let ordered_prop_1_id = graph.generate_ulid().expect("Unable to generate Ulid"); let ordered_prop_1_index = graph .add_node( NodeWeight::new_content( - change_set, + vector_clock_id, ordered_prop_1_id, + Ulid::new(), ContentAddress::Prop(ContentHash::new( ordered_prop_1_id.to_string().as_bytes(), )), @@ -771,22 +784,23 @@ mod test { .expect("Unable to add ordered prop"); graph .add_ordered_edge( - change_set.vector_clock_id(), + vector_clock_id, graph .get_node_index_by_id(prop_id) .expect("Unable to get NodeWeight for prop"), - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create uses edge weight"), ordered_prop_1_index, ) .expect("Unable to add prop -> ordered_prop_1 edge"); - let ordered_prop_2_id = change_set.generate_ulid().expect("Unable to generate Ulid"); + let ordered_prop_2_id = graph.generate_ulid().expect("Unable to generate Ulid"); let ordered_prop_2_index = graph .add_node( NodeWeight::new_content( - change_set, + vector_clock_id, ordered_prop_2_id, + Ulid::new(), ContentAddress::Prop(ContentHash::new( ordered_prop_2_id.to_string().as_bytes(), )), @@ -796,22 +810,23 @@ mod test { .expect("Unable to add ordered prop"); graph .add_ordered_edge( - change_set.vector_clock_id(), + vector_clock_id, graph .get_node_index_by_id(prop_id) .expect("Unable to get NodeWeight for prop"), - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create uses edge weight"), ordered_prop_2_index, ) .expect("Unable to add prop -> ordered_prop_2 edge"); - let ordered_prop_3_id = change_set.generate_ulid().expect("Unable to generate Ulid"); + let ordered_prop_3_id = graph.generate_ulid().expect("Unable to generate Ulid"); let ordered_prop_3_index = graph .add_node( NodeWeight::new_content( - change_set, + vector_clock_id, ordered_prop_3_id, + Ulid::new(), ContentAddress::Prop(ContentHash::new( ordered_prop_3_id.to_string().as_bytes(), )), @@ -821,11 +836,11 @@ mod test { .expect("Unable to add ordered prop"); graph .add_ordered_edge( - change_set.vector_clock_id(), + vector_clock_id, graph .get_node_index_by_id(prop_id) .expect("Unable to get NodeWeight for prop"), - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create uses edge weight"), ordered_prop_3_index, ) @@ -852,20 +867,19 @@ mod test { #[test] fn add_ordered_node_below_root() { - let base_change_set = ChangeSet::new_local().expect("Unable to create ChangeSet"); - let active_change_set = &base_change_set; - let mut graph = WorkspaceSnapshotGraph::new(active_change_set) + let active_vector_clock_id = VectorClockId::new(Ulid::new(), Ulid::new()); + + let mut graph = WorkspaceSnapshotGraph::new(active_vector_clock_id) .expect("Unable to create WorkspaceSnapshotGraph"); - let prop_id = active_change_set - .generate_ulid() - .expect("Unable to generate Ulid"); + let prop_id = graph.generate_ulid().expect("Unable to generate Ulid"); let prop_index = graph .add_ordered_node( - active_change_set, + active_vector_clock_id, NodeWeight::new_content( - active_change_set, + active_vector_clock_id, prop_id, + Ulid::new(), ContentAddress::Prop(ContentHash::new(prop_id.to_string().as_bytes())), ) .expect("Unable to create NodeWeight"), @@ -875,11 +889,8 @@ mod test { graph .add_edge( graph.root_index, - EdgeWeight::new( - active_change_set.vector_clock_id(), - EdgeWeightKind::new_use(), - ) - .expect("Unable to create EdgeWeight"), + EdgeWeight::new(active_vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create EdgeWeight"), prop_index, ) .expect("Unable to add root -> prop edge"); @@ -900,17 +911,18 @@ mod test { #[test] fn reorder_ordered_node() { - let change_set = ChangeSet::new_local().expect("Unable to create ChangeSet"); - let change_set = &change_set; - let mut graph = WorkspaceSnapshotGraph::new(change_set) + let vector_clock_id = VectorClockId::new(Ulid::new(), Ulid::new()); + + let mut graph = WorkspaceSnapshotGraph::new(vector_clock_id) .expect("Unable to create WorkspaceSnapshotGraph"); - let schema_id = change_set.generate_ulid().expect("Unable to generate Ulid"); + let schema_id = graph.generate_ulid().expect("Unable to generate Ulid"); let schema_index = graph .add_node( NodeWeight::new_content( - change_set, + vector_clock_id, schema_id, + Ulid::new(), ContentAddress::Schema(ContentHash::new( SchemaId::generate().to_string().as_bytes(), )), @@ -918,12 +930,13 @@ mod test { .expect("Unable to create NodeWeight"), ) .expect("Unable to add schema"); - let schema_variant_id = change_set.generate_ulid().expect("Unable to generate Ulid"); + let schema_variant_id = graph.generate_ulid().expect("Unable to generate Ulid"); let schema_variant_index = graph .add_node( NodeWeight::new_content( - change_set, + vector_clock_id, schema_variant_id, + Ulid::new(), ContentAddress::SchemaVariant(ContentHash::new( SchemaVariantId::generate().to_string().as_bytes(), )), @@ -935,7 +948,7 @@ mod test { graph .add_edge( graph.root_index, - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), schema_index, ) @@ -945,18 +958,19 @@ mod test { graph .get_node_index_by_id(schema_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), schema_variant_index, ) .expect("Unable to add schema -> schema variant edge"); - let func_id = change_set.generate_ulid().expect("Unable to generate Ulid"); + let func_id = graph.generate_ulid().expect("Unable to generate Ulid"); let func_index = graph .add_node( NodeWeight::new_content( - change_set, + vector_clock_id, func_id, + Ulid::new(), ContentAddress::Func(ContentHash::new( FuncId::generate().to_string().as_bytes(), )), @@ -967,19 +981,20 @@ mod test { graph .add_edge( graph.root_index, - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), func_index, ) .expect("Unable to add root -> func edge"); - let prop_id = change_set.generate_ulid().expect("Unable to generate Ulid"); + let prop_id = graph.generate_ulid().expect("Unable to generate Ulid"); let prop_index = graph .add_ordered_node( - change_set, + vector_clock_id, NodeWeight::new_content( - change_set, + vector_clock_id, prop_id, + Ulid::new(), ContentAddress::Prop(ContentHash::new( PropId::generate().to_string().as_bytes(), )), @@ -992,7 +1007,7 @@ mod test { graph .get_node_index_by_id(schema_variant_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), prop_index, ) @@ -1002,7 +1017,7 @@ mod test { graph .get_node_index_by_id(prop_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), graph .get_node_index_by_id(func_id) @@ -1012,12 +1027,13 @@ mod test { graph.cleanup(); graph.dot(); - let ordered_prop_1_id = change_set.generate_ulid().expect("Unable to generate Ulid"); + let ordered_prop_1_id = graph.generate_ulid().expect("Unable to generate Ulid"); let ordered_prop_1_index = graph .add_node( NodeWeight::new_content( - change_set, + vector_clock_id, ordered_prop_1_id, + Ulid::new(), ContentAddress::Prop(ContentHash::new( ordered_prop_1_id.to_string().as_bytes(), )), @@ -1027,22 +1043,23 @@ mod test { .expect("Unable to add ordered prop"); graph .add_ordered_edge( - change_set.vector_clock_id(), + vector_clock_id, graph .get_node_index_by_id(prop_id) .expect("Unable to get NodeWeight for prop"), - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create uses edge weight"), ordered_prop_1_index, ) .expect("Unable to add prop -> ordered_prop_1 edge"); - let ordered_prop_2_id = change_set.generate_ulid().expect("Unable to generate Ulid"); + let ordered_prop_2_id = graph.generate_ulid().expect("Unable to generate Ulid"); let ordered_prop_2_index = graph .add_node( NodeWeight::new_content( - change_set, + vector_clock_id, ordered_prop_2_id, + Ulid::new(), ContentAddress::Prop(ContentHash::new( ordered_prop_2_id.to_string().as_bytes(), )), @@ -1052,22 +1069,23 @@ mod test { .expect("Unable to add ordered prop"); graph .add_ordered_edge( - change_set.vector_clock_id(), + vector_clock_id, graph .get_node_index_by_id(prop_id) .expect("Unable to get NodeWeight for prop"), - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create uses edge weight"), ordered_prop_2_index, ) .expect("Unable to add prop -> ordered_prop_2 edge"); - let ordered_prop_3_id = change_set.generate_ulid().expect("Unable to generate Ulid"); + let ordered_prop_3_id = graph.generate_ulid().expect("Unable to generate Ulid"); let ordered_prop_3_index = graph .add_node( NodeWeight::new_content( - change_set, + vector_clock_id, ordered_prop_3_id, + Ulid::new(), ContentAddress::Prop(ContentHash::new( ordered_prop_3_id.to_string().as_bytes(), )), @@ -1077,22 +1095,23 @@ mod test { .expect("Unable to add ordered prop"); graph .add_ordered_edge( - change_set.vector_clock_id(), + vector_clock_id, graph .get_node_index_by_id(prop_id) .expect("Unable to get NodeWeight for prop"), - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create uses edge weight"), ordered_prop_3_index, ) .expect("Unable to add prop -> ordered_prop_3 edge"); - let ordered_prop_4_id = change_set.generate_ulid().expect("Unable to generate Ulid"); + let ordered_prop_4_id = graph.generate_ulid().expect("Unable to generate Ulid"); let ordered_prop_4_index = graph .add_node( NodeWeight::new_content( - change_set, + vector_clock_id, ordered_prop_4_id, + Ulid::new(), ContentAddress::Prop(ContentHash::new( ordered_prop_4_id.to_string().as_bytes(), )), @@ -1102,11 +1121,11 @@ mod test { .expect("Unable to add ordered prop"); graph .add_ordered_edge( - change_set.vector_clock_id(), + vector_clock_id, graph .get_node_index_by_id(prop_id) .expect("Unable to get NodeWeight for prop"), - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create uses edge weight"), ordered_prop_4_index, ) @@ -1140,7 +1159,7 @@ mod test { ]; graph - .update_order(change_set.vector_clock_id(), prop_id, new_order) + .update_order(vector_clock_id, prop_id, new_order) .expect("Unable to update order of prop's children"); assert_eq!( @@ -1163,19 +1182,18 @@ mod test { #[test] fn remove_unordered_node_and_detect_edge_removal() { - let initial_change_set = ChangeSet::new_local().expect("Unable to create ChangeSet"); - let initial_change_set = &initial_change_set; - let mut graph = WorkspaceSnapshotGraph::new(initial_change_set) + let initial_vector_clock_id = VectorClockId::new(Ulid::new(), Ulid::new()); + + let mut graph = WorkspaceSnapshotGraph::new(initial_vector_clock_id) .expect("Unable to create WorkspaceSnapshotGraph"); - let schema_id = initial_change_set - .generate_ulid() - .expect("Unable to generate Ulid"); + let schema_id = graph.generate_ulid().expect("Unable to generate Ulid"); let schema_index = graph .add_node( NodeWeight::new_content( - initial_change_set, + initial_vector_clock_id, schema_id, + Ulid::new(), ContentAddress::Schema(ContentHash::new( SchemaId::generate().to_string().as_bytes(), )), @@ -1183,14 +1201,13 @@ mod test { .expect("Unable to create NodeWeight"), ) .expect("Unable to add schema"); - let schema_variant_id = initial_change_set - .generate_ulid() - .expect("Unable to generate Ulid"); + let schema_variant_id = graph.generate_ulid().expect("Unable to generate Ulid"); let schema_variant_index = graph .add_node( NodeWeight::new_content( - initial_change_set, + initial_vector_clock_id, schema_variant_id, + Ulid::new(), ContentAddress::SchemaVariant(ContentHash::new( SchemaVariantId::generate().to_string().as_bytes(), )), @@ -1202,11 +1219,8 @@ mod test { graph .add_edge( graph.root_index, - EdgeWeight::new( - initial_change_set.vector_clock_id(), - EdgeWeightKind::new_use(), - ) - .expect("Unable to create EdgeWeight"), + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create EdgeWeight"), schema_index, ) .expect("Unable to add root -> schema edge"); @@ -1215,23 +1229,19 @@ mod test { graph .get_node_index_by_id(schema_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new( - initial_change_set.vector_clock_id(), - EdgeWeightKind::new_use(), - ) - .expect("Unable to create EdgeWeight"), + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create EdgeWeight"), schema_variant_index, ) .expect("Unable to add schema -> schema variant edge"); - let schema_variant_2_id = initial_change_set - .generate_ulid() - .expect("Unable to generate Ulid"); + let schema_variant_2_id = graph.generate_ulid().expect("Unable to generate Ulid"); let schema_variant_2_index = graph .add_node( NodeWeight::new_content( - initial_change_set, + initial_vector_clock_id, schema_variant_2_id, + Ulid::new(), ContentAddress::SchemaVariant(ContentHash::new( SchemaVariantId::generate().to_string().as_bytes(), )), @@ -1245,11 +1255,8 @@ mod test { graph .get_node_index_by_id(schema_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new( - initial_change_set.vector_clock_id(), - EdgeWeightKind::new_use(), - ) - .expect("Unable to create EdgeWeight"), + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create EdgeWeight"), schema_variant_2_index, ) .expect("Unable to add schema -> schema variant edge"); @@ -1272,18 +1279,17 @@ mod test { ); graph - .mark_graph_seen(initial_change_set.vector_clock_id()) + .mark_graph_seen(initial_vector_clock_id) .expect("Unable to mark initial graph as seen"); let mut graph_with_deleted_edge = graph.clone(); - let new_change_set = ChangeSet::new_local().expect("Unable to create ChangeSet"); - let new_change_set = &new_change_set; + let new_vector_clock_id = VectorClockId::new(Ulid::new(), Ulid::new()); graph_with_deleted_edge.dot(); graph_with_deleted_edge .remove_edge( - new_change_set, + new_vector_clock_id, graph_with_deleted_edge .get_node_index_by_id(schema_id) .expect("Unable to get NodeIndex for schema"), @@ -1311,14 +1317,14 @@ mod test { ); graph_with_deleted_edge - .mark_graph_seen(new_change_set.vector_clock_id()) + .mark_graph_seen(new_vector_clock_id) .expect("Unable to mark new graph as seen"); let ConflictsAndUpdates { conflicts, updates } = graph .detect_conflicts_and_updates( - initial_change_set.vector_clock_id(), + initial_vector_clock_id, &graph_with_deleted_edge, - new_change_set.vector_clock_id(), + new_vector_clock_id, ) .expect("Failed to detect conflicts and updates"); @@ -1333,17 +1339,17 @@ mod test { #[test] fn remove_unordered_node() { - let change_set = ChangeSet::new_local().expect("Unable to create ChangeSet"); - let change_set = &change_set; - let mut graph = WorkspaceSnapshotGraph::new(change_set) + let vector_clock_id = VectorClockId::new(Ulid::new(), Ulid::new()); + let mut graph = WorkspaceSnapshotGraph::new(vector_clock_id) .expect("Unable to create WorkspaceSnapshotGraph"); - let schema_id = change_set.generate_ulid().expect("Unable to generate Ulid"); + let schema_id = graph.generate_ulid().expect("Unable to generate Ulid"); let schema_index = graph .add_node( NodeWeight::new_content( - change_set, + vector_clock_id, schema_id, + Ulid::new(), ContentAddress::Schema(ContentHash::new( SchemaId::generate().to_string().as_bytes(), )), @@ -1351,11 +1357,12 @@ mod test { .expect("Unable to create NodeWeight"), ) .expect("Unable to add schema"); - let schema_variant_id = change_set.generate_ulid().expect("Unable to generate Ulid"); + let schema_variant_id = graph.generate_ulid().expect("Unable to generate Ulid"); let schema_variant_index = graph .add_node( NodeWeight::new_content( - change_set, + vector_clock_id, + Ulid::new(), schema_variant_id, ContentAddress::SchemaVariant(ContentHash::new( SchemaVariantId::generate().to_string().as_bytes(), @@ -1368,7 +1375,7 @@ mod test { graph .add_edge( graph.root_index, - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), schema_index, ) @@ -1378,18 +1385,19 @@ mod test { graph .get_node_index_by_id(schema_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), schema_variant_index, ) .expect("Unable to add schema -> schema variant edge"); - let schema_variant_2_id = change_set.generate_ulid().expect("Unable to generate Ulid"); + let schema_variant_2_id = graph.generate_ulid().expect("Unable to generate Ulid"); let schema_variant_2_index = graph .add_node( NodeWeight::new_content( - change_set, + vector_clock_id, schema_variant_2_id, + Ulid::new(), ContentAddress::SchemaVariant(ContentHash::new( SchemaVariantId::generate().to_string().as_bytes(), )), @@ -1403,7 +1411,7 @@ mod test { graph .get_node_index_by_id(schema_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), schema_variant_2_index, ) @@ -1428,7 +1436,7 @@ mod test { graph .remove_edge( - change_set, + vector_clock_id, graph .get_node_index_by_id(schema_id) .expect("Unable to get NodeIndex for schema"), @@ -1456,17 +1464,17 @@ mod test { #[test] fn remove_ordered_node() { - let change_set = ChangeSet::new_local().expect("Unable to create ChangeSet"); - let change_set = &change_set; - let mut graph = WorkspaceSnapshotGraph::new(change_set) + let vector_clock_id = VectorClockId::new(Ulid::new(), Ulid::new()); + let mut graph = WorkspaceSnapshotGraph::new(vector_clock_id) .expect("Unable to create WorkspaceSnapshotGraph"); - let schema_id = change_set.generate_ulid().expect("Unable to generate Ulid"); + let schema_id = graph.generate_ulid().expect("Unable to generate Ulid"); let schema_index = graph .add_node( NodeWeight::new_content( - change_set, + vector_clock_id, schema_id, + Ulid::new(), ContentAddress::Schema(ContentHash::new( SchemaId::generate().to_string().as_bytes(), )), @@ -1474,12 +1482,13 @@ mod test { .expect("Unable to create NodeWeight"), ) .expect("Unable to add schema"); - let schema_variant_id = change_set.generate_ulid().expect("Unable to generate Ulid"); + let schema_variant_id = graph.generate_ulid().expect("Unable to generate Ulid"); let schema_variant_index = graph .add_node( NodeWeight::new_content( - change_set, + vector_clock_id, schema_variant_id, + Ulid::new(), ContentAddress::SchemaVariant(ContentHash::new( SchemaVariantId::generate().to_string().as_bytes(), )), @@ -1491,7 +1500,7 @@ mod test { graph .add_edge( graph.root_index, - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), schema_index, ) @@ -1501,18 +1510,19 @@ mod test { graph .get_node_index_by_id(schema_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), schema_variant_index, ) .expect("Unable to add schema -> schema variant edge"); - let func_id = change_set.generate_ulid().expect("Unable to generate Ulid"); + let func_id = graph.generate_ulid().expect("Unable to generate Ulid"); let func_index = graph .add_node( NodeWeight::new_content( - change_set, + vector_clock_id, func_id, + Ulid::new(), ContentAddress::Func(ContentHash::new( FuncId::generate().to_string().as_bytes(), )), @@ -1523,19 +1533,20 @@ mod test { graph .add_edge( graph.root_index, - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), func_index, ) .expect("Unable to add root -> func edge"); - let root_prop_id = change_set.generate_ulid().expect("Unable to generate Ulid"); + let root_prop_id = graph.generate_ulid().expect("Unable to generate Ulid"); let root_prop_index = graph .add_ordered_node( - change_set, + vector_clock_id, NodeWeight::new_content( - change_set, + vector_clock_id, root_prop_id, + Ulid::new(), ContentAddress::Prop(ContentHash::new( PropId::generate().to_string().as_bytes(), )), @@ -1548,7 +1559,7 @@ mod test { graph .get_node_index_by_id(schema_variant_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), root_prop_index, ) @@ -1558,7 +1569,7 @@ mod test { graph .get_node_index_by_id(root_prop_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), graph .get_node_index_by_id(func_id) @@ -1568,12 +1579,13 @@ mod test { graph.cleanup(); graph.dot(); - let ordered_prop_1_id = change_set.generate_ulid().expect("Unable to generate Ulid"); + let ordered_prop_1_id = graph.generate_ulid().expect("Unable to generate Ulid"); let ordered_prop_1_index = graph .add_node( NodeWeight::new_content( - change_set, + vector_clock_id, ordered_prop_1_id, + Ulid::new(), ContentAddress::Prop(ContentHash::new( ordered_prop_1_id.to_string().as_bytes(), )), @@ -1583,22 +1595,23 @@ mod test { .expect("Unable to add ordered prop"); graph .add_ordered_edge( - change_set.vector_clock_id(), + vector_clock_id, graph .get_node_index_by_id(root_prop_id) .expect("Unable to get NodeWeight for prop"), - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create uses edge weight"), ordered_prop_1_index, ) .expect("Unable to add prop -> ordered_prop_1 edge"); - let ordered_prop_2_id = change_set.generate_ulid().expect("Unable to generate Ulid"); + let ordered_prop_2_id = graph.generate_ulid().expect("Unable to generate Ulid"); let ordered_prop_2_index = graph .add_node( NodeWeight::new_content( - change_set, + vector_clock_id, ordered_prop_2_id, + Ulid::new(), ContentAddress::Prop(ContentHash::new( ordered_prop_2_id.to_string().as_bytes(), )), @@ -1608,22 +1621,23 @@ mod test { .expect("Unable to add ordered prop"); graph .add_ordered_edge( - change_set.vector_clock_id(), + vector_clock_id, graph .get_node_index_by_id(root_prop_id) .expect("Unable to get NodeWeight for prop"), - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create uses edge weight"), ordered_prop_2_index, ) .expect("Unable to add prop -> ordered_prop_2 edge"); - let ordered_prop_3_id = change_set.generate_ulid().expect("Unable to generate Ulid"); + let ordered_prop_3_id = graph.generate_ulid().expect("Unable to generate Ulid"); let ordered_prop_3_index = graph .add_node( NodeWeight::new_content( - change_set, + vector_clock_id, ordered_prop_3_id, + Ulid::new(), ContentAddress::Prop(ContentHash::new( ordered_prop_3_id.to_string().as_bytes(), )), @@ -1633,22 +1647,23 @@ mod test { .expect("Unable to add ordered prop"); graph .add_ordered_edge( - change_set.vector_clock_id(), + vector_clock_id, graph .get_node_index_by_id(root_prop_id) .expect("Unable to get NodeWeight for prop"), - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create uses edge weight"), ordered_prop_3_index, ) .expect("Unable to add prop -> ordered_prop_3 edge"); - let ordered_prop_4_id = change_set.generate_ulid().expect("Unable to generate Ulid"); + let ordered_prop_4_id = graph.generate_ulid().expect("Unable to generate Ulid"); let ordered_prop_4_index = graph .add_node( NodeWeight::new_content( - change_set, + vector_clock_id, ordered_prop_4_id, + Ulid::new(), ContentAddress::Prop(ContentHash::new( ordered_prop_4_id.to_string().as_bytes(), )), @@ -1658,11 +1673,11 @@ mod test { .expect("Unable to add ordered prop"); graph .add_ordered_edge( - change_set.vector_clock_id(), + vector_clock_id, graph .get_node_index_by_id(root_prop_id) .expect("Unable to get NodeWeight for prop"), - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create uses edge weight"), ordered_prop_4_index, ) @@ -1690,7 +1705,7 @@ mod test { graph .remove_edge( - change_set, + vector_clock_id, graph .get_node_index_by_id(root_prop_id) .expect("Unable to get NodeIndex for prop"), diff --git a/lib/dal/src/workspace_snapshot/graph/tests/detect_conflicts_and_updates.rs b/lib/dal/src/workspace_snapshot/graph/tests/detect_conflicts_and_updates.rs index 71e5a08d5d..68622783da 100644 --- a/lib/dal/src/workspace_snapshot/graph/tests/detect_conflicts_and_updates.rs +++ b/lib/dal/src/workspace_snapshot/graph/tests/detect_conflicts_and_updates.rs @@ -6,6 +6,7 @@ mod test { use pretty_assertions_sorted::assert_eq; use si_events::ulid::Ulid; use si_events::ContentHash; + use si_events::VectorClockId; use std::collections::HashMap; use std::collections::HashSet; @@ -21,7 +22,7 @@ mod test { conflict::Conflict, graph::ConflictsAndUpdates, vector_clock::HasVectorClocks, NodeInformation, }; - use crate::{change_set::ChangeSet, NodeWeightDiscriminants}; + use crate::NodeWeightDiscriminants; use crate::{PropKind, WorkspaceSnapshotGraph}; #[derive(Debug, Eq, PartialEq)] @@ -83,32 +84,34 @@ mod test { #[test] fn detect_conflicts_and_updates_simple_no_conflicts_no_updates_in_base() { - let initial_change_set = ChangeSet::new_local().expect("Unable to create ChangeSet"); - let initial_change_set = &initial_change_set; - let mut initial_graph = WorkspaceSnapshotGraph::new(initial_change_set) + let actor_id = Ulid::new(); + let initial_vector_clock_id = VectorClockId::new(Ulid::new(), actor_id); + let mut initial_graph = WorkspaceSnapshotGraph::new(initial_vector_clock_id) .expect("Unable to create WorkspaceSnapshotGraph"); - let schema_id = initial_change_set + let schema_id = initial_graph .generate_ulid() .expect("Unable to generate Ulid"); let schema_index = initial_graph .add_node( NodeWeight::new_content( - initial_change_set, + initial_vector_clock_id, schema_id, + Ulid::new(), ContentAddress::Schema(ContentHash::from("Schema A")), ) .expect("Unable to create NodeWeight"), ) .expect("Unable to add Schema A"); - let schema_variant_id = initial_change_set + let schema_variant_id = initial_graph .generate_ulid() .expect("Unable to generate Ulid"); let schema_variant_index = initial_graph .add_node( NodeWeight::new_content( - initial_change_set, + initial_vector_clock_id, schema_variant_id, + Ulid::new(), ContentAddress::SchemaVariant(ContentHash::from("Schema Variant A")), ) .expect("Unable to create NodeWeight"), @@ -118,11 +121,8 @@ mod test { initial_graph .add_edge( initial_graph.root_index, - EdgeWeight::new( - initial_change_set.vector_clock_id(), - EdgeWeightKind::new_use(), - ) - .expect("Unable to create EdgeWeight"), + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create EdgeWeight"), schema_index, ) .expect("Unable to add root -> schema edge"); @@ -131,31 +131,26 @@ mod test { initial_graph .get_node_index_by_id(schema_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new( - initial_change_set.vector_clock_id(), - EdgeWeightKind::new_use(), - ) - .expect("Unable to create EdgeWeight"), + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create EdgeWeight"), schema_variant_index, ) .expect("Unable to add schema -> schema variant edge"); initial_graph - .mark_graph_seen(initial_change_set.vector_clock_id()) + .mark_graph_seen(initial_vector_clock_id) .expect("unable to mark seen"); - let new_change_set = ChangeSet::new_local().expect("Unable to create ChangeSet"); - let new_change_set = &new_change_set; + let new_vector_clock_id = VectorClockId::new(Ulid::new(), actor_id); let mut new_graph = initial_graph.clone(); - let component_id = new_change_set - .generate_ulid() - .expect("Unable to generate Ulid"); + let component_id = new_graph.generate_ulid().expect("Unable to generate Ulid"); let component_index = new_graph .add_node( NodeWeight::new_content( - new_change_set, + new_vector_clock_id, component_id, + Ulid::new(), ContentAddress::Schema(ContentHash::from("Component A")), ) .expect("Unable to create NodeWeight"), @@ -164,7 +159,7 @@ mod test { new_graph .add_edge( new_graph.root_index, - EdgeWeight::new(new_change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(new_vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), component_index, ) @@ -174,7 +169,7 @@ mod test { new_graph .get_node_index_by_id(component_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new(new_change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(new_vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), new_graph .get_node_index_by_id(schema_variant_id) @@ -183,14 +178,14 @@ mod test { .expect("Unable to add component -> schema variant edge"); new_graph - .mark_graph_seen(new_change_set.vector_clock_id()) + .mark_graph_seen(new_vector_clock_id) .expect("unable to mark seen"); let conflicts_and_updates = new_graph .detect_conflicts_and_updates( - new_change_set.vector_clock_id(), + new_vector_clock_id, &initial_graph, - initial_change_set.vector_clock_id(), + initial_vector_clock_id, ) .expect("Unable to detect conflicts and updates"); @@ -205,32 +200,31 @@ mod test { #[test] fn detect_conflicts_and_updates_simple_no_conflicts_with_purely_new_content_in_base() { - let initial_change_set = ChangeSet::new_local().expect("Unable to create ChangeSet"); - let base_change_set = &initial_change_set; - let mut base_graph = WorkspaceSnapshotGraph::new(base_change_set) + let actor_id = Ulid::new(); + let initial_vector_clock_id = VectorClockId::new(Ulid::new(), actor_id); + + let mut base_graph = WorkspaceSnapshotGraph::new(initial_vector_clock_id) .expect("Unable to create WorkspaceSnapshotGraph"); - let schema_id = base_change_set - .generate_ulid() - .expect("Unable to generate Ulid"); + let schema_id = base_graph.generate_ulid().expect("Unable to generate Ulid"); let schema_index = base_graph .add_node( NodeWeight::new_content( - base_change_set, + initial_vector_clock_id, schema_id, + Ulid::new(), ContentAddress::Schema(ContentHash::from("Schema A")), ) .expect("Unable to create NodeWeight"), ) .expect("Unable to add Schema A"); - let schema_variant_id = base_change_set - .generate_ulid() - .expect("Unable to generate Ulid"); + let schema_variant_id = base_graph.generate_ulid().expect("Unable to generate Ulid"); let schema_variant_index = base_graph .add_node( NodeWeight::new_content( - base_change_set, + initial_vector_clock_id, schema_variant_id, + Ulid::new(), ContentAddress::SchemaVariant(ContentHash::from("Schema Variant A")), ) .expect("Unable to create NodeWeight"), @@ -240,7 +234,7 @@ mod test { base_graph .add_edge( base_graph.root_index, - EdgeWeight::new(base_change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), schema_index, ) @@ -250,7 +244,7 @@ mod test { base_graph .get_node_index_by_id(schema_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new(base_change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), schema_variant_index, ) @@ -258,21 +252,19 @@ mod test { base_graph.dot(); base_graph - .mark_graph_seen(initial_change_set.vector_clock_id()) + .mark_graph_seen(initial_vector_clock_id) .expect("unable to mark graph seen"); - let new_change_set = ChangeSet::new_local().expect("Unable to create ChangeSet"); - let new_change_set = &new_change_set; + let new_vector_clock_id = VectorClockId::new(Ulid::new(), actor_id); let mut new_graph = base_graph.clone(); - let new_onto_component_id = base_change_set - .generate_ulid() - .expect("Unable to generate Ulid"); + let new_onto_component_id = new_graph.generate_ulid().expect("Unable to generate Ulid"); let new_onto_component_index = base_graph .add_node( NodeWeight::new_content( - base_change_set, + initial_vector_clock_id, new_onto_component_id, + Ulid::new(), ContentAddress::Component(ContentHash::from("Component B")), ) .expect("Unable to create NodeWeight"), @@ -281,7 +273,7 @@ mod test { let _new_onto_root_component_edge_index = base_graph .add_edge( base_graph.root_index, - EdgeWeight::new(base_change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), new_onto_component_index, ) @@ -291,7 +283,7 @@ mod test { base_graph .get_node_index_by_id(new_onto_component_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new(base_change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), base_graph .get_node_index_by_id(schema_variant_id) @@ -301,15 +293,11 @@ mod test { base_graph.dot(); new_graph - .mark_graph_seen(new_change_set.vector_clock_id()) + .mark_graph_seen(new_vector_clock_id) .expect("unable to mark seen"); let conflicts_and_updates = new_graph - .detect_conflicts_and_updates( - new_change_set.vector_clock_id(), - &base_graph, - base_change_set.vector_clock_id(), - ) + .detect_conflicts_and_updates(new_vector_clock_id, &base_graph, initial_vector_clock_id) .expect("Unable to detect conflicts and updates"); assert!(conflicts_and_updates.conflicts.is_empty()); @@ -333,19 +321,19 @@ mod test { #[test] fn detect_conflicts_and_updates_with_purely_new_content_in_new_graph() { - let initial_change_set = ChangeSet::new_local().expect("Unable to create ChangeSet"); - let base_change_set = &initial_change_set; - let mut base_graph = WorkspaceSnapshotGraph::new(base_change_set) + let actor_id = Ulid::new(); + let initial_vector_clock_id = VectorClockId::new(Ulid::new(), actor_id); + + let mut base_graph = WorkspaceSnapshotGraph::new(initial_vector_clock_id) .expect("Unable to create WorkspaceSnapshotGraph"); - let component_id = base_change_set - .generate_ulid() - .expect("Unable to generate Ulid"); + let component_id = base_graph.generate_ulid().expect("Unable to generate Ulid"); let component_index = base_graph .add_node( NodeWeight::new_content( - base_change_set, + initial_vector_clock_id, component_id, + Ulid::new(), ContentAddress::Component(ContentHash::from("Component A")), ) .expect("Unable to create NodeWeight"), @@ -354,7 +342,7 @@ mod test { base_graph .add_edge( base_graph.root_index, - EdgeWeight::new(base_change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), component_index, ) @@ -363,21 +351,19 @@ mod test { base_graph.cleanup(); base_graph.dot(); base_graph - .mark_graph_seen(initial_change_set.vector_clock_id()) + .mark_graph_seen(initial_vector_clock_id) .expect("unable to mark seen"); - let new_change_set = ChangeSet::new_local().expect("Unable to create ChangeSet"); - let new_change_set = &new_change_set; + let new_vector_clock_id = VectorClockId::new(Ulid::new(), actor_id); let mut new_graph = base_graph.clone(); - let new_component_id = new_change_set - .generate_ulid() - .expect("Unable to generate Ulid"); + let new_component_id = new_graph.generate_ulid().expect("Unable to generate Ulid"); let new_component_index = new_graph .add_node( NodeWeight::new_content( - new_change_set, + new_vector_clock_id, new_component_id, + Ulid::new(), ContentAddress::Component(ContentHash::from("Component B")), ) .expect("Unable to create NodeWeight"), @@ -386,7 +372,7 @@ mod test { new_graph .add_edge( new_graph.root_index, - EdgeWeight::new(new_change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(new_vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), new_component_index, ) @@ -395,26 +381,18 @@ mod test { new_graph.cleanup(); new_graph.dot(); new_graph - .mark_graph_seen(new_change_set.vector_clock_id()) + .mark_graph_seen(new_vector_clock_id) .expect("unable to mark seen"); let conflicts_and_updates = new_graph - .detect_conflicts_and_updates( - new_change_set.vector_clock_id(), - &base_graph, - base_change_set.vector_clock_id(), - ) + .detect_conflicts_and_updates(new_vector_clock_id, &base_graph, initial_vector_clock_id) .expect("Unable to detect conflicts and updates"); assert!(conflicts_and_updates.updates.is_empty()); assert!(conflicts_and_updates.conflicts.is_empty()); let conflicts_and_updates = base_graph - .detect_conflicts_and_updates( - base_change_set.vector_clock_id(), - &new_graph, - new_change_set.vector_clock_id(), - ) + .detect_conflicts_and_updates(initial_vector_clock_id, &new_graph, new_vector_clock_id) .expect("Unable to detect conflicts and updates"); assert!(conflicts_and_updates.conflicts.is_empty()); @@ -435,32 +413,30 @@ mod test { #[test] fn detect_conflicts_and_updates_simple_no_conflicts_with_updates_on_both_sides() { - let initial_change_set = ChangeSet::new_local().expect("Unable to create ChangeSet"); - let base_change_set = &initial_change_set; - let mut base_graph = WorkspaceSnapshotGraph::new(base_change_set) + let actor_id = Ulid::new(); + let initial_vector_clock_id = VectorClockId::new(Ulid::new(), actor_id); + let mut base_graph = WorkspaceSnapshotGraph::new(initial_vector_clock_id) .expect("Unable to create WorkspaceSnapshotGraph"); - let schema_id = base_change_set - .generate_ulid() - .expect("Unable to generate Ulid"); + let schema_id = base_graph.generate_ulid().expect("Unable to generate Ulid"); let schema_index = base_graph .add_node( NodeWeight::new_content( - base_change_set, + initial_vector_clock_id, schema_id, + Ulid::new(), ContentAddress::Schema(ContentHash::from("Schema A")), ) .expect("Unable to create NodeWeight"), ) .expect("Unable to add Schema A"); - let schema_variant_id = base_change_set - .generate_ulid() - .expect("Unable to generate Ulid"); + let schema_variant_id = base_graph.generate_ulid().expect("Unable to generate Ulid"); let schema_variant_index = base_graph .add_node( NodeWeight::new_content( - base_change_set, + initial_vector_clock_id, schema_variant_id, + Ulid::new(), ContentAddress::SchemaVariant(ContentHash::from("Schema Variant A")), ) .expect("Unable to create NodeWeight"), @@ -470,7 +446,7 @@ mod test { base_graph .add_edge( base_graph.root_index, - EdgeWeight::new(base_change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), schema_index, ) @@ -480,7 +456,7 @@ mod test { base_graph .get_node_index_by_id(schema_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new(base_change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), schema_variant_index, ) @@ -488,21 +464,19 @@ mod test { base_graph.dot(); base_graph - .mark_graph_seen(initial_change_set.vector_clock_id()) + .mark_graph_seen(initial_vector_clock_id) .expect("unable to mark seen"); - let new_change_set = ChangeSet::new_local().expect("Unable to create ChangeSet"); - let new_change_set = &new_change_set; + let new_vector_clock_id = VectorClockId::new(Ulid::new(), actor_id); let mut new_graph = base_graph.clone(); - let component_id = new_change_set - .generate_ulid() - .expect("Unable to generate Ulid"); + let component_id = new_graph.generate_ulid().expect("Unable to generate Ulid"); let component_index = new_graph .add_node( NodeWeight::new_content( - new_change_set, + new_vector_clock_id, component_id, + Ulid::new(), ContentAddress::Component(ContentHash::from("Component A")), ) .expect("Unable to create NodeWeight"), @@ -511,7 +485,7 @@ mod test { new_graph .add_edge( new_graph.root_index, - EdgeWeight::new(new_change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(new_vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), component_index, ) @@ -521,7 +495,7 @@ mod test { new_graph .get_node_index_by_id(component_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new(new_change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(new_vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), new_graph .get_node_index_by_id(schema_variant_id) @@ -531,17 +505,16 @@ mod test { new_graph.dot(); new_graph - .mark_graph_seen(new_change_set.vector_clock_id()) + .mark_graph_seen(new_vector_clock_id) .expect("unable to mark graph seen"); - let new_onto_component_id = base_change_set - .generate_ulid() - .expect("Unable to generate Ulid"); + let new_onto_component_id = new_graph.generate_ulid().expect("Unable to generate Ulid"); let new_onto_component_index = base_graph .add_node( NodeWeight::new_content( - base_change_set, + initial_vector_clock_id, new_onto_component_id, + Ulid::new(), ContentAddress::Component(ContentHash::from("Component B")), ) .expect("Unable to create NodeWeight"), @@ -550,7 +523,7 @@ mod test { base_graph .add_edge( base_graph.root_index, - EdgeWeight::new(base_change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), new_onto_component_index, ) @@ -560,7 +533,7 @@ mod test { base_graph .get_node_index_by_id(new_onto_component_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new(base_change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), base_graph .get_node_index_by_id(schema_variant_id) @@ -570,15 +543,11 @@ mod test { base_graph.dot(); base_graph - .mark_graph_seen(initial_change_set.vector_clock_id()) + .mark_graph_seen(initial_vector_clock_id) .expect("unable to mark graph seen"); let conflicts_and_updates = new_graph - .detect_conflicts_and_updates( - new_change_set.vector_clock_id(), - &base_graph, - base_change_set.vector_clock_id(), - ) + .detect_conflicts_and_updates(new_vector_clock_id, &base_graph, initial_vector_clock_id) .expect("Unable to detect conflicts and updates"); assert!(conflicts_and_updates.conflicts.is_empty()); @@ -602,32 +571,30 @@ mod test { #[test] fn detect_conflicts_and_updates_simple_with_content_conflict() { - let initial_change_set = ChangeSet::new_local().expect("Unable to create ChangeSet"); - let base_change_set = &initial_change_set; - let mut base_graph = WorkspaceSnapshotGraph::new(base_change_set) + let actor_id = Ulid::new(); + let initial_vector_clock_id = VectorClockId::new(Ulid::new(), actor_id); + let mut base_graph = WorkspaceSnapshotGraph::new(initial_vector_clock_id) .expect("Unable to create WorkspaceSnapshotGraph"); - let schema_id = base_change_set - .generate_ulid() - .expect("Unable to generate Ulid"); + let schema_id = base_graph.generate_ulid().expect("Unable to generate Ulid"); let schema_index = base_graph .add_node( NodeWeight::new_content( - base_change_set, + initial_vector_clock_id, schema_id, + Ulid::new(), ContentAddress::Schema(ContentHash::from("Schema A")), ) .expect("Unable to create NodeWeight"), ) .expect("Unable to add Schema A"); - let schema_variant_id = base_change_set - .generate_ulid() - .expect("Unable to generate Ulid"); + let schema_variant_id = base_graph.generate_ulid().expect("Unable to generate Ulid"); let schema_variant_index = base_graph .add_node( NodeWeight::new_content( - base_change_set, + initial_vector_clock_id, schema_variant_id, + Ulid::new(), ContentAddress::SchemaVariant(ContentHash::from("Schema Variant A")), ) .expect("Unable to create NodeWeight"), @@ -637,7 +604,7 @@ mod test { base_graph .add_edge( base_graph.root_index, - EdgeWeight::new(base_change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), schema_index, ) @@ -647,20 +614,19 @@ mod test { base_graph .get_node_index_by_id(schema_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new(base_change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), schema_variant_index, ) .expect("Unable to add schema -> schema variant edge"); - let component_id = base_change_set - .generate_ulid() - .expect("Unable to generate Ulid"); + let component_id = base_graph.generate_ulid().expect("Unable to generate Ulid"); let component_index = base_graph .add_node( NodeWeight::new_content( - base_change_set, + initial_vector_clock_id, component_id, + Ulid::new(), ContentAddress::Component(ContentHash::from("Component A")), ) .expect("Unable to create NodeWeight"), @@ -669,7 +635,7 @@ mod test { base_graph .add_edge( base_graph.root_index, - EdgeWeight::new(base_change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), component_index, ) @@ -679,7 +645,7 @@ mod test { base_graph .get_node_index_by_id(component_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new(base_change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), base_graph .get_node_index_by_id(schema_variant_id) @@ -690,16 +656,15 @@ mod test { base_graph.cleanup(); base_graph.dot(); base_graph - .mark_graph_seen(initial_change_set.vector_clock_id()) + .mark_graph_seen(initial_vector_clock_id) .expect("mark graph seen"); - let new_change_set = ChangeSet::new_local().expect("Unable to create ChangeSet"); - let new_change_set = &new_change_set; + let new_vector_clock_id = VectorClockId::new(Ulid::new(), actor_id); let mut new_graph = base_graph.clone(); new_graph .update_content( - new_change_set, + new_vector_clock_id, component_id, ContentHash::from("Updated Component A"), ) @@ -708,12 +673,12 @@ mod test { new_graph.cleanup(); new_graph.dot(); new_graph - .mark_graph_seen(new_change_set.vector_clock_id()) + .mark_graph_seen(new_vector_clock_id) .expect("mark graph seen"); base_graph .update_content( - base_change_set, + initial_vector_clock_id, component_id, ContentHash::from("Base Updated Component A"), ) @@ -722,15 +687,11 @@ mod test { base_graph.cleanup(); base_graph.dot(); base_graph - .mark_graph_seen(initial_change_set.vector_clock_id()) + .mark_graph_seen(initial_vector_clock_id) .expect("mark graph seen"); let conflicts_and_updates = new_graph - .detect_conflicts_and_updates( - new_change_set.vector_clock_id(), - &base_graph, - base_change_set.vector_clock_id(), - ) + .detect_conflicts_and_updates(new_vector_clock_id, &base_graph, initial_vector_clock_id) .expect("Unable to detect conflicts and updates"); assert_eq!( @@ -755,34 +716,183 @@ mod test { assert!(conflicts_and_updates.updates.is_empty()); } + #[test] + fn detect_conflicts_and_updates_simple_with_content_conflict_but_no_conflict_same_vector_clocks( + ) { + let actor_id = Ulid::new(); + let vector_clock_id = VectorClockId::new(Ulid::new(), actor_id); + let mut base_graph = WorkspaceSnapshotGraph::new(vector_clock_id) + .expect("Unable to create WorkspaceSnapshotGraph"); + + let schema_id = base_graph.generate_ulid().expect("Unable to generate Ulid"); + let schema_index = base_graph + .add_node( + NodeWeight::new_content( + vector_clock_id, + schema_id, + Ulid::new(), + ContentAddress::Schema(ContentHash::from("Schema A")), + ) + .expect("Unable to create NodeWeight"), + ) + .expect("Unable to add Schema A"); + let schema_variant_id = base_graph.generate_ulid().expect("Unable to generate Ulid"); + let schema_variant_index = base_graph + .add_node( + NodeWeight::new_content( + vector_clock_id, + schema_variant_id, + Ulid::new(), + ContentAddress::SchemaVariant(ContentHash::from("Schema Variant A")), + ) + .expect("Unable to create NodeWeight"), + ) + .expect("Unable to add Schema Variant A"); + + base_graph + .add_edge( + base_graph.root_index, + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create EdgeWeight"), + schema_index, + ) + .expect("Unable to add root -> schema edge"); + base_graph + .add_edge( + base_graph + .get_node_index_by_id(schema_id) + .expect("Unable to get NodeIndex"), + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create EdgeWeight"), + schema_variant_index, + ) + .expect("Unable to add schema -> schema variant edge"); + + let component_id = base_graph.generate_ulid().expect("Unable to generate Ulid"); + let component_index = base_graph + .add_node( + NodeWeight::new_content( + vector_clock_id, + component_id, + Ulid::new(), + ContentAddress::Component(ContentHash::from("Component A")), + ) + .expect("Unable to create NodeWeight"), + ) + .expect("Unable to add Component A"); + base_graph + .add_edge( + base_graph.root_index, + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create EdgeWeight"), + component_index, + ) + .expect("Unable to add root -> component edge"); + base_graph + .add_edge( + base_graph + .get_node_index_by_id(component_id) + .expect("Unable to get NodeIndex"), + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create EdgeWeight"), + base_graph + .get_node_index_by_id(schema_variant_id) + .expect("Unable to get NodeIndex"), + ) + .expect("Unable to add component -> schema variant edge"); + + base_graph.cleanup(); + base_graph.dot(); + base_graph + .mark_graph_seen(vector_clock_id) + .expect("mark graph seen"); + + let mut new_graph = base_graph.clone(); + + new_graph + .update_content( + vector_clock_id, + component_id, + ContentHash::from("Updated Component A"), + ) + .expect("Unable to update Component A"); + + new_graph.cleanup(); + new_graph.dot(); + new_graph + .mark_graph_seen(vector_clock_id) + .expect("mark graph seen"); + + base_graph + .update_content( + vector_clock_id, + component_id, + ContentHash::from("Base Updated Component A"), + ) + .expect("Unable to update Component A"); + + base_graph.cleanup(); + base_graph.dot(); + base_graph + .mark_graph_seen(vector_clock_id) + .expect("mark graph seen"); + + let conflicts_and_updates = new_graph + .detect_conflicts_and_updates(vector_clock_id, &base_graph, vector_clock_id) + .expect("Unable to detect conflicts and updates"); + + // With identical vector clocks, we should not hit conflicts + assert!(conflicts_and_updates.conflicts.is_empty()); + + // Instead, we receive the "inverse" of the NodeContent conflict: A + // ReplaceSubgraph update for the node. + assert_eq!( + vec![Update::ReplaceSubgraph { + onto: NodeInformation { + id: component_id.into(), + index: base_graph + .get_node_index_by_id(component_id) + .expect("Unable to get component NodeIndex"), + node_weight_kind: NodeWeightDiscriminants::Content, + }, + to_rebase: NodeInformation { + id: component_id.into(), + index: new_graph + .get_node_index_by_id(component_id) + .expect("Unable to get component NodeIndex"), + node_weight_kind: NodeWeightDiscriminants::Content, + }, + }], + conflicts_and_updates.updates + ); + } + #[test] fn detect_conflicts_and_updates_simple_with_modify_removed_item_conflict() { - let initial_change_set = ChangeSet::new_local().expect("Unable to create ChangeSet"); - let base_change_set = &initial_change_set; - let mut base_graph = WorkspaceSnapshotGraph::new(base_change_set) + let actor_id = Ulid::new(); + let initial_vector_clock_id = VectorClockId::new(Ulid::new(), actor_id); + let mut base_graph = WorkspaceSnapshotGraph::new(initial_vector_clock_id) .expect("Unable to create WorkspaceSnapshotGraph"); - let schema_id = base_change_set - .generate_ulid() - .expect("Unable to generate Ulid"); + let schema_id = base_graph.generate_ulid().expect("Unable to generate Ulid"); let schema_index = base_graph .add_node( NodeWeight::new_content( - base_change_set, + initial_vector_clock_id, schema_id, + Ulid::new(), ContentAddress::Schema(ContentHash::from("Schema A")), ) .expect("Unable to create NodeWeight"), ) .expect("Unable to add Schema A"); - let schema_variant_id = base_change_set - .generate_ulid() - .expect("Unable to generate Ulid"); + let schema_variant_id = base_graph.generate_ulid().expect("Unable to generate Ulid"); let schema_variant_index = base_graph .add_node( NodeWeight::new_content( - base_change_set, + initial_vector_clock_id, schema_variant_id, + Ulid::new(), ContentAddress::SchemaVariant(ContentHash::from("Schema Variant A")), ) .expect("Unable to create NodeWeight"), @@ -792,7 +902,7 @@ mod test { base_graph .add_edge( base_graph.root_index, - EdgeWeight::new(base_change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), schema_index, ) @@ -802,20 +912,19 @@ mod test { base_graph .get_node_index_by_id(schema_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new(base_change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), schema_variant_index, ) .expect("Unable to add schema -> schema variant edge"); - let component_id = base_change_set - .generate_ulid() - .expect("Unable to generate Ulid"); + let component_id = base_graph.generate_ulid().expect("Unable to generate Ulid"); let component_index = base_graph .add_node( NodeWeight::new_content( - base_change_set, + initial_vector_clock_id, component_id, + Ulid::new(), ContentAddress::Component(ContentHash::from("Component A")), ) .expect("Unable to create NodeWeight"), @@ -824,7 +933,7 @@ mod test { base_graph .add_edge( base_graph.root_index, - EdgeWeight::new(base_change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), component_index, ) @@ -834,7 +943,7 @@ mod test { base_graph .get_node_index_by_id(component_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new(base_change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), base_graph .get_node_index_by_id(schema_variant_id) @@ -845,16 +954,15 @@ mod test { base_graph.cleanup(); base_graph.dot(); base_graph - .mark_graph_seen(initial_change_set.vector_clock_id()) + .mark_graph_seen(initial_vector_clock_id) .expect("mark graph seen"); - let new_change_set = ChangeSet::new_local().expect("Unable to create ChangeSet"); - let new_change_set = &new_change_set; + let new_vector_clock_id = VectorClockId::new(Ulid::new(), actor_id); let mut new_graph = base_graph.clone(); base_graph .remove_edge( - base_change_set, + initial_vector_clock_id, base_graph.root_index, base_graph .get_node_index_by_id(component_id) @@ -866,12 +974,12 @@ mod test { base_graph.cleanup(); base_graph.dot(); base_graph - .mark_graph_seen(initial_change_set.vector_clock_id()) + .mark_graph_seen(initial_vector_clock_id) .expect("mark graph seen"); new_graph .update_content( - new_change_set, + new_vector_clock_id, component_id, ContentHash::from("Updated Component A"), ) @@ -880,15 +988,11 @@ mod test { new_graph.cleanup(); new_graph.dot(); new_graph - .mark_graph_seen(new_change_set.vector_clock_id()) + .mark_graph_seen(new_vector_clock_id) .expect("unable to mark graph seen"); let conflicts_and_updates = new_graph - .detect_conflicts_and_updates( - new_change_set.vector_clock_id(), - &base_graph, - base_change_set.vector_clock_id(), - ) + .detect_conflicts_and_updates(new_vector_clock_id, &base_graph, initial_vector_clock_id) .expect("Unable to detect conflicts and updates"); assert_eq!( @@ -905,75 +1009,214 @@ mod test { } #[test] - fn detect_conflicts_and_updates_add_unordered_child_to_ordered_container() { - let base_change_set = ChangeSet::new_local().expect("Unable to create ChangeSet"); - let active_change_set = &base_change_set; - let mut base_graph = WorkspaceSnapshotGraph::new(active_change_set) + fn detect_conflicts_and_updates_simple_with_modify_removed_item_conflict_same_vector_clocks() { + let actor_id = Ulid::new(); + let vector_clock_id = VectorClockId::new(Ulid::new(), actor_id); + let mut base_graph = WorkspaceSnapshotGraph::new(vector_clock_id) .expect("Unable to create WorkspaceSnapshotGraph"); - let active_graph = &mut base_graph; - // Create base prop node - let base_prop_id = { - let prop_id = active_change_set - .generate_ulid() - .expect("Unable to generate Ulid"); - let prop_index = active_graph - .add_ordered_node( - active_change_set, - NodeWeight::new_content( - active_change_set, - prop_id, - ContentAddress::Prop(ContentHash::new(prop_id.to_string().as_bytes())), - ) - .expect("Unable to create NodeWeight"), + let schema_id = base_graph.generate_ulid().expect("Unable to generate Ulid"); + let schema_index = base_graph + .add_node( + NodeWeight::new_content( + vector_clock_id, + schema_id, + Ulid::new(), + ContentAddress::Schema(ContentHash::from("Schema A")), ) - .expect("Unable to add prop"); - - active_graph - .add_edge( - active_graph.root_index, - EdgeWeight::new( - active_change_set.vector_clock_id(), - EdgeWeightKind::new_use(), - ) - .expect("Unable to create EdgeWeight"), - prop_index, + .expect("Unable to create NodeWeight"), + ) + .expect("Unable to add Schema A"); + let schema_variant_id = base_graph.generate_ulid().expect("Unable to generate Ulid"); + let schema_variant_index = base_graph + .add_node( + NodeWeight::new_content( + vector_clock_id, + schema_variant_id, + Ulid::new(), + ContentAddress::SchemaVariant(ContentHash::from("Schema Variant A")), ) - .expect("Unable to add sv -> prop edge"); - - prop_id - }; + .expect("Unable to create NodeWeight"), + ) + .expect("Unable to add Schema Variant A"); - active_graph.cleanup(); + base_graph + .add_edge( + base_graph.root_index, + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create EdgeWeight"), + schema_index, + ) + .expect("Unable to add root -> schema edge"); + base_graph + .add_edge( + base_graph + .get_node_index_by_id(schema_id) + .expect("Unable to get NodeIndex"), + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create EdgeWeight"), + schema_variant_index, + ) + .expect("Unable to add schema -> schema variant edge"); - // Create two prop nodes children of base prop - let ordered_prop_1_index = { - let ordered_prop_id = active_change_set - .generate_ulid() - .expect("Unable to generate Ulid"); - let ordered_prop_index = active_graph - .add_node( - NodeWeight::new_content( - active_change_set, - ordered_prop_id, - ContentAddress::Prop(ContentHash::new( - ordered_prop_id.to_string().as_bytes(), - )), - ) - .expect("Unable to create NodeWeight"), + let component_id = base_graph.generate_ulid().expect("Unable to generate Ulid"); + let component_index = base_graph + .add_node( + NodeWeight::new_content( + vector_clock_id, + component_id, + Ulid::new(), + ContentAddress::Component(ContentHash::from("Component A")), ) - .expect("Unable to add ordered prop"); - active_graph - .add_ordered_edge( - active_change_set.vector_clock_id(), - active_graph - .get_node_index_by_id(base_prop_id) - .expect("Unable to get prop NodeIndex"), - EdgeWeight::new( - active_change_set.vector_clock_id(), - EdgeWeightKind::new_use(), - ) - .expect("Unable to create uses edge weight"), + .expect("Unable to create NodeWeight"), + ) + .expect("Unable to add Component A"); + base_graph + .add_edge( + base_graph.root_index, + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create EdgeWeight"), + component_index, + ) + .expect("Unable to add root -> component edge"); + base_graph + .add_edge( + base_graph + .get_node_index_by_id(component_id) + .expect("Unable to get NodeIndex"), + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create EdgeWeight"), + base_graph + .get_node_index_by_id(schema_variant_id) + .expect("Unable to get NodeIndex"), + ) + .expect("Unable to add component -> schema variant edge"); + + base_graph.cleanup(); + base_graph.dot(); + base_graph + .mark_graph_seen(vector_clock_id) + .expect("mark graph seen"); + + let mut new_graph = base_graph.clone(); + + base_graph + .remove_edge( + vector_clock_id, + base_graph.root_index, + base_graph + .get_node_index_by_id(component_id) + .expect("Unable to get NodeIndex"), + EdgeWeightKindDiscriminants::Use, + ) + .expect("Unable to remove Component A"); + + base_graph.cleanup(); + base_graph.dot(); + base_graph + .mark_graph_seen(vector_clock_id) + .expect("mark graph seen"); + + new_graph + .update_content( + vector_clock_id, + component_id, + ContentHash::from("Updated Component A"), + ) + .expect("Unable to update Component A"); + + new_graph.cleanup(); + new_graph.dot(); + new_graph + .mark_graph_seen(vector_clock_id) + .expect("unable to mark graph seen"); + + let conflicts_and_updates = new_graph + .detect_conflicts_and_updates(vector_clock_id, &base_graph, vector_clock_id) + .expect("Unable to detect conflicts and updates"); + + // Even though we have identical vector clocks, this still produces a + // conflict, since this item has been modified in to_rebase after onto + // removed it. + assert_eq!( + vec![Conflict::ModifyRemovedItem(NodeInformation { + id: component_id.into(), + index: new_graph + .get_node_index_by_id(component_id) + .expect("Unable to get NodeIndex"), + node_weight_kind: NodeWeightDiscriminants::Content, + })], + conflicts_and_updates.conflicts + ); + assert!(conflicts_and_updates.updates.is_empty()); + } + + #[test] + fn detect_conflicts_and_updates_add_unordered_child_to_ordered_container() { + let actor_id = Ulid::new(); + let initial_vector_clock_id = VectorClockId::new(Ulid::new(), actor_id); + let mut base_graph = WorkspaceSnapshotGraph::new(initial_vector_clock_id) + .expect("Unable to create WorkspaceSnapshotGraph"); + let active_graph = &mut base_graph; + + // Create base prop node + let base_prop_id = { + let prop_id = active_graph + .generate_ulid() + .expect("Unable to generate Ulid"); + let prop_index = active_graph + .add_ordered_node( + initial_vector_clock_id, + NodeWeight::new_content( + initial_vector_clock_id, + prop_id, + Ulid::new(), + ContentAddress::Prop(ContentHash::new(prop_id.to_string().as_bytes())), + ) + .expect("Unable to create NodeWeight"), + ) + .expect("Unable to add prop"); + + active_graph + .add_edge( + active_graph.root_index, + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create EdgeWeight"), + prop_index, + ) + .expect("Unable to add sv -> prop edge"); + + prop_id + }; + + active_graph.cleanup(); + + // Create two prop nodes children of base prop + let ordered_prop_1_index = { + let ordered_prop_id = active_graph + .generate_ulid() + .expect("Unable to generate Ulid"); + let ordered_prop_index = active_graph + .add_node( + NodeWeight::new_content( + initial_vector_clock_id, + ordered_prop_id, + Ulid::new(), + ContentAddress::Prop(ContentHash::new( + ordered_prop_id.to_string().as_bytes(), + )), + ) + .expect("Unable to create NodeWeight"), + ) + .expect("Unable to add ordered prop"); + active_graph + .add_ordered_edge( + initial_vector_clock_id, + active_graph + .get_node_index_by_id(base_prop_id) + .expect("Unable to get prop NodeIndex"), + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create uses edge weight"), ordered_prop_index, ) .expect("Unable to add prop -> ordered_prop_1 edge"); @@ -984,14 +1227,15 @@ mod test { active_graph.cleanup(); let attribute_prototype_id = { - let node_id = active_change_set + let node_id = active_graph .generate_ulid() .expect("Unable to generate Ulid"); let node_index = active_graph .add_node( NodeWeight::new_content( - active_change_set, + initial_vector_clock_id, node_id, + Ulid::new(), ContentAddress::AttributePrototype(ContentHash::new( node_id.to_string().as_bytes(), )), @@ -1003,11 +1247,8 @@ mod test { active_graph .add_edge( active_graph.root_index, - EdgeWeight::new( - active_change_set.vector_clock_id(), - EdgeWeightKind::new_use(), - ) - .expect("Unable to create EdgeWeight"), + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create EdgeWeight"), node_index, ) .expect("Unable to add root -> prototype edge"); @@ -1017,54 +1258,46 @@ mod test { active_graph.cleanup(); active_graph - .mark_graph_seen(active_change_set.vector_clock_id()) + .mark_graph_seen(initial_vector_clock_id) .expect("unable to mark graph seen"); // Get new graph - let new_change_set = ChangeSet::new_local().expect("Unable to create ChangeSet"); - let active_change_set = &new_change_set; + let new_vector_clock_id = VectorClockId::new(Ulid::new(), actor_id); let mut new_graph = base_graph.clone(); - let active_graph = &mut new_graph; + let new_graph = &mut new_graph; // Connect Prototype to Prop - active_graph + new_graph .add_edge( - active_graph + new_graph .get_node_index_by_id(base_prop_id) .expect("Unable to get prop NodeIndex"), - EdgeWeight::new( - active_change_set.vector_clock_id(), - EdgeWeightKind::Prototype(None), - ) - .expect("Unable to create EdgeWeight"), - active_graph + EdgeWeight::new(new_vector_clock_id, EdgeWeightKind::Prototype(None)) + .expect("Unable to create EdgeWeight"), + new_graph .get_node_index_by_id(attribute_prototype_id) .expect("Unable to get prop NodeIndex"), ) .expect("Unable to add sv -> prop edge"); - active_graph.cleanup(); - let base_prop_node_index = active_graph + new_graph.cleanup(); + let base_prop_node_index = new_graph .get_node_index_by_id(base_prop_id) .expect("Unable to get base prop NodeIndex"); assert_eq!( vec![ordered_prop_1_index,], - active_graph + new_graph .ordered_children_for_node(base_prop_node_index) .expect("Unable to find ordered children for node") .expect("Node is not an ordered node") ); - active_graph - .mark_graph_seen(active_change_set.vector_clock_id()) + new_graph + .mark_graph_seen(new_vector_clock_id) .expect("unable to mark graph seen"); // Assert that the new edge to the prototype gets created let ConflictsAndUpdates { conflicts, updates } = base_graph - .detect_conflicts_and_updates( - base_change_set.vector_clock_id(), - &new_graph, - new_change_set.vector_clock_id(), - ) + .detect_conflicts_and_updates(initial_vector_clock_id, new_graph, new_vector_clock_id) .expect("Unable to detect conflicts and updates"); assert!(conflicts.is_empty()); @@ -1095,20 +1328,19 @@ mod test { #[test] fn detect_conflicts_and_updates_complex() { - let initial_change_set = ChangeSet::new_local().expect("Unable to create ChangeSet"); - let base_change_set = &initial_change_set; - let mut base_graph = WorkspaceSnapshotGraph::new(base_change_set) + let actor_id = Ulid::new(); + let initial_vector_clock_id = VectorClockId::new(Ulid::new(), actor_id); + let mut base_graph = WorkspaceSnapshotGraph::new(initial_vector_clock_id) .expect("Unable to create WorkspaceSnapshotGraph"); // Docker Image Schema - let docker_image_schema_id = base_change_set - .generate_ulid() - .expect("Unable to generate Ulid"); + let docker_image_schema_id = base_graph.generate_ulid().expect("Unable to generate Ulid"); let docker_image_schema_index = base_graph .add_node( NodeWeight::new_content( - base_change_set, + initial_vector_clock_id, docker_image_schema_id, + Ulid::new(), ContentAddress::Schema(ContentHash::from("first")), ) .expect("Unable to create NodeWeight"), @@ -1117,7 +1349,7 @@ mod test { base_graph .add_edge( base_graph.root_index, - EdgeWeight::new(base_change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), docker_image_schema_index, ) @@ -1126,14 +1358,14 @@ mod test { println!("Add edge from root to {} in onto", docker_image_schema_id); // Docker Image Schema Variant - let docker_image_schema_variant_id = base_change_set - .generate_ulid() - .expect("Unable to generate Ulid"); + let docker_image_schema_variant_id = + base_graph.generate_ulid().expect("Unable to generate Ulid"); let docker_image_schema_variant_index = base_graph .add_node( NodeWeight::new_content( - base_change_set, + initial_vector_clock_id, docker_image_schema_variant_id, + Ulid::new(), ContentAddress::SchemaVariant(ContentHash::from("first")), ) .expect("Unable to create NodeWeight"), @@ -1144,7 +1376,7 @@ mod test { base_graph .get_node_index_by_id(docker_image_schema_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new(base_change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), docker_image_schema_variant_index, ) @@ -1156,14 +1388,14 @@ mod test { ); // Nginx Docker Image Component - let nginx_docker_image_component_id = base_change_set - .generate_ulid() - .expect("Unable to generate Ulid"); + let nginx_docker_image_component_id = + base_graph.generate_ulid().expect("Unable to generate Ulid"); let nginx_docker_image_component_index = base_graph .add_node( NodeWeight::new_content( - base_change_set, + initial_vector_clock_id, nginx_docker_image_component_id, + Ulid::new(), ContentAddress::Component(ContentHash::from("first")), ) .expect("Unable to create NodeWeight"), @@ -1172,7 +1404,7 @@ mod test { base_graph .add_edge( base_graph.root_index, - EdgeWeight::new(base_change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), nginx_docker_image_component_index, ) @@ -1188,7 +1420,7 @@ mod test { base_graph .get_node_index_by_id(nginx_docker_image_component_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new(base_change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), base_graph .get_node_index_by_id(docker_image_schema_variant_id) @@ -1202,14 +1434,13 @@ mod test { ); // Alpine Component - let alpine_component_id = base_change_set - .generate_ulid() - .expect("Unable to generate Ulid"); + let alpine_component_id = base_graph.generate_ulid().expect("Unable to generate Ulid"); let alpine_component_index = base_graph .add_node( NodeWeight::new_content( - base_change_set, + initial_vector_clock_id, alpine_component_id, + Ulid::new(), ContentAddress::Component(ContentHash::from("first")), ) .expect("Unable to create NodeWeight"), @@ -1218,7 +1449,7 @@ mod test { base_graph .add_edge( base_graph.root_index, - EdgeWeight::new(base_change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), alpine_component_index, ) @@ -1231,7 +1462,7 @@ mod test { base_graph .get_node_index_by_id(alpine_component_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new(base_change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), base_graph .get_node_index_by_id(docker_image_schema_variant_id) @@ -1245,14 +1476,13 @@ mod test { ); // Butane Schema - let butane_schema_id = base_change_set - .generate_ulid() - .expect("Unable to generate Ulid"); + let butane_schema_id = base_graph.generate_ulid().expect("Unable to generate Ulid"); let butane_schema_index = base_graph .add_node( NodeWeight::new_content( - base_change_set, + initial_vector_clock_id, butane_schema_id, + Ulid::new(), ContentAddress::Schema(ContentHash::from("first")), ) .expect("Unable to create NodeWeight"), @@ -1261,7 +1491,7 @@ mod test { base_graph .add_edge( base_graph.root_index, - EdgeWeight::new(base_change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), butane_schema_index, ) @@ -1270,14 +1500,13 @@ mod test { println!("Add edge from root to {} in onto", butane_schema_id); // Butane Schema Variant - let butane_schema_variant_id = base_change_set - .generate_ulid() - .expect("Unable to generate Ulid"); + let butane_schema_variant_id = base_graph.generate_ulid().expect("Unable to generate Ulid"); let butane_schema_variant_index = base_graph .add_node( NodeWeight::new_content( - base_change_set, + initial_vector_clock_id, butane_schema_variant_id, + Ulid::new(), ContentAddress::SchemaVariant(ContentHash::from("first")), ) .expect("Unable to create NodeWeight"), @@ -1288,7 +1517,7 @@ mod test { base_graph .get_node_index_by_id(butane_schema_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new(base_change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), butane_schema_variant_index, ) @@ -1300,14 +1529,14 @@ mod test { ); // Nginx Butane Component - let nginx_butane_component_id = base_change_set - .generate_ulid() - .expect("Unable to generate Ulid"); + let nginx_butane_component_id = + base_graph.generate_ulid().expect("Unable to generate Ulid"); let nginx_butane_node_index = base_graph .add_node( NodeWeight::new_content( - base_change_set, + initial_vector_clock_id, nginx_butane_component_id, + Ulid::new(), ContentAddress::Component(ContentHash::from("first")), ) .expect("Unable to create NodeWeight"), @@ -1316,7 +1545,7 @@ mod test { base_graph .add_edge( base_graph.root_index, - EdgeWeight::new(base_change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), nginx_butane_node_index, ) @@ -1332,7 +1561,7 @@ mod test { base_graph .get_node_index_by_id(nginx_butane_component_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new(base_change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), base_graph .get_node_index_by_id(butane_schema_variant_id) @@ -1348,12 +1577,11 @@ mod test { base_graph.cleanup(); //base_graph.dot(); base_graph - .mark_graph_seen(base_change_set.vector_clock_id()) + .mark_graph_seen(initial_vector_clock_id) .expect("unable to mark graph seen"); // Create a new change set to cause some problems! - let new_change_set = ChangeSet::new_local().expect("Unable to create ChangeSet"); - let new_change_set = &new_change_set; + let new_vector_clock_id = VectorClockId::new(Ulid::new(), actor_id); let mut new_graph = base_graph.clone(); println!("fork onto into to_rebase"); @@ -1361,7 +1589,7 @@ mod test { // Create a modify removed item conflict. base_graph .remove_edge( - base_change_set, + initial_vector_clock_id, base_graph.root_index, base_graph .get_node_index_by_id(nginx_butane_component_id) @@ -1377,7 +1605,7 @@ mod test { new_graph .update_content( - new_change_set, + new_vector_clock_id, nginx_butane_component_id, ContentHash::from("second"), ) @@ -1391,7 +1619,7 @@ mod test { // Create a node content conflict. base_graph .update_content( - base_change_set, + initial_vector_clock_id, docker_image_schema_variant_id, ContentHash::from("oopsie"), ) @@ -1404,7 +1632,7 @@ mod test { new_graph .update_content( - new_change_set, + new_vector_clock_id, docker_image_schema_variant_id, ContentHash::from("poopsie"), ) @@ -1418,7 +1646,7 @@ mod test { // Create a pure update. base_graph .update_content( - base_change_set, + initial_vector_clock_id, docker_image_schema_id, ContentHash::from("bg3"), ) @@ -1428,22 +1656,18 @@ mod test { new_graph.cleanup(); new_graph - .mark_graph_seen(new_change_set.vector_clock_id()) + .mark_graph_seen(new_vector_clock_id) .expect("unable to mark graph seen"); base_graph.cleanup(); base_graph - .mark_graph_seen(base_change_set.vector_clock_id()) + .mark_graph_seen(initial_vector_clock_id) .expect("unable to mark graph seen"); // new_graph.tiny_dot_to_file(Some("to_rebase")); // base_graph.tiny_dot_to_file(Some("onto")); let ConflictsAndUpdates { conflicts, updates } = new_graph - .detect_conflicts_and_updates( - new_change_set.vector_clock_id(), - &base_graph, - base_change_set.vector_clock_id(), - ) + .detect_conflicts_and_updates(new_vector_clock_id, &base_graph, initial_vector_clock_id) .expect("Unable to detect conflicts and updates"); // base_graph.dot(); @@ -1502,32 +1726,34 @@ mod test { #[test] fn detect_conflicts_and_updates_simple_ordering_no_conflicts_no_updates_in_base() { - let initial_change_set = ChangeSet::new_local().expect("Unable to create ChangeSet"); - let initial_change_set = &initial_change_set; - let mut initial_graph = WorkspaceSnapshotGraph::new(initial_change_set) + let actor_id = Ulid::new(); + let initial_vector_clock_id = VectorClockId::new(Ulid::new(), actor_id); + let mut initial_graph = WorkspaceSnapshotGraph::new(initial_vector_clock_id) .expect("Unable to create WorkspaceSnapshotGraph"); - let schema_id = initial_change_set + let schema_id = initial_graph .generate_ulid() .expect("Unable to generate Ulid"); let schema_index = initial_graph .add_node( NodeWeight::new_content( - initial_change_set, + initial_vector_clock_id, schema_id, + Ulid::new(), ContentAddress::Schema(ContentHash::from("Schema A")), ) .expect("Unable to create NodeWeight"), ) .expect("Unable to add Schema A"); - let schema_variant_id = initial_change_set + let schema_variant_id = initial_graph .generate_ulid() .expect("Unable to generate Ulid"); let schema_variant_index = initial_graph .add_node( NodeWeight::new_content( - initial_change_set, + initial_vector_clock_id, schema_variant_id, + Ulid::new(), ContentAddress::SchemaVariant(ContentHash::from("Schema Variant A")), ) .expect("Unable to create NodeWeight"), @@ -1537,11 +1763,8 @@ mod test { initial_graph .add_edge( initial_graph.root_index, - EdgeWeight::new( - initial_change_set.vector_clock_id(), - EdgeWeightKind::new_use(), - ) - .expect("Unable to create EdgeWeight"), + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create EdgeWeight"), schema_index, ) .expect("Unable to add root -> schema edge"); @@ -1550,24 +1773,22 @@ mod test { initial_graph .get_node_index_by_id(schema_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new( - initial_change_set.vector_clock_id(), - EdgeWeightKind::new_use(), - ) - .expect("Unable to create EdgeWeight"), + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create EdgeWeight"), schema_variant_index, ) .expect("Unable to add schema -> schema variant edge"); - let container_prop_id = initial_change_set + let container_prop_id = initial_graph .generate_ulid() .expect("Unable to generate Ulid"); let container_prop_index = initial_graph .add_ordered_node( - initial_change_set, + initial_vector_clock_id, NodeWeight::new_content( - initial_change_set, + initial_vector_clock_id, container_prop_id, + Ulid::new(), ContentAddress::Prop(ContentHash::new( container_prop_id.to_string().as_bytes(), )), @@ -1580,23 +1801,21 @@ mod test { initial_graph .get_node_index_by_id(schema_variant_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new( - initial_change_set.vector_clock_id(), - EdgeWeightKind::new_use(), - ) - .expect("Unable to create EdgeWeight"), + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create EdgeWeight"), container_prop_index, ) .expect("Unable to add schema variant -> container prop edge"); - let ordered_prop_1_id = initial_change_set + let ordered_prop_1_id = initial_graph .generate_ulid() .expect("Unable to generate Ulid"); let ordered_prop_1_index = initial_graph .add_node( NodeWeight::new_content( - initial_change_set, + initial_vector_clock_id, ordered_prop_1_id, + Ulid::new(), ContentAddress::Prop(ContentHash::new( ordered_prop_1_id.to_string().as_bytes(), )), @@ -1606,27 +1825,25 @@ mod test { .expect("Unable to add ordered prop 1"); initial_graph .add_ordered_edge( - initial_change_set.vector_clock_id(), + initial_vector_clock_id, initial_graph .get_node_index_by_id(container_prop_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new( - initial_change_set.vector_clock_id(), - EdgeWeightKind::new_use(), - ) - .expect("Unable to create EdgeWeight"), + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create EdgeWeight"), ordered_prop_1_index, ) .expect("Unable to add container prop -> ordered prop 1 edge"); - let ordered_prop_2_id = initial_change_set + let ordered_prop_2_id = initial_graph .generate_ulid() .expect("Unable to generate Ulid"); let ordered_prop_2_index = initial_graph .add_node( NodeWeight::new_content( - initial_change_set, + initial_vector_clock_id, ordered_prop_2_id, + Ulid::new(), ContentAddress::Prop(ContentHash::new( ordered_prop_2_id.to_string().as_bytes(), )), @@ -1636,27 +1853,25 @@ mod test { .expect("Unable to add ordered prop 2"); initial_graph .add_ordered_edge( - initial_change_set.vector_clock_id(), + initial_vector_clock_id, initial_graph .get_node_index_by_id(container_prop_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new( - initial_change_set.vector_clock_id(), - EdgeWeightKind::new_use(), - ) - .expect("Unable to create EdgeWeight"), + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create EdgeWeight"), ordered_prop_2_index, ) .expect("Unable to add container prop -> ordered prop 2 edge"); - let ordered_prop_3_id = initial_change_set + let ordered_prop_3_id = initial_graph .generate_ulid() .expect("Unable to generate Ulid"); let ordered_prop_3_index = initial_graph .add_node( NodeWeight::new_content( - initial_change_set, + initial_vector_clock_id, ordered_prop_3_id, + Ulid::new(), ContentAddress::Prop(ContentHash::new( ordered_prop_3_id.to_string().as_bytes(), )), @@ -1666,27 +1881,25 @@ mod test { .expect("Unable to add ordered prop 3"); initial_graph .add_ordered_edge( - initial_change_set.vector_clock_id(), + initial_vector_clock_id, initial_graph .get_node_index_by_id(container_prop_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new( - initial_change_set.vector_clock_id(), - EdgeWeightKind::new_use(), - ) - .expect("Unable to create EdgeWeight"), + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create EdgeWeight"), ordered_prop_3_index, ) .expect("Unable to add container prop -> ordered prop 3 edge"); - let ordered_prop_4_id = initial_change_set + let ordered_prop_4_id = initial_graph .generate_ulid() .expect("Unable to generate Ulid"); let ordered_prop_4_index = initial_graph .add_node( NodeWeight::new_content( - initial_change_set, + initial_vector_clock_id, ordered_prop_4_id, + Ulid::new(), ContentAddress::Prop(ContentHash::new( ordered_prop_4_id.to_string().as_bytes(), )), @@ -1696,15 +1909,12 @@ mod test { .expect("Unable to add ordered prop 4"); initial_graph .add_ordered_edge( - initial_change_set.vector_clock_id(), + initial_vector_clock_id, initial_graph .get_node_index_by_id(container_prop_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new( - initial_change_set.vector_clock_id(), - EdgeWeightKind::new_use(), - ) - .expect("Unable to create EdgeWeight"), + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create EdgeWeight"), ordered_prop_4_index, ) .expect("Unable to add container prop -> ordered prop 4 edge"); @@ -1713,21 +1923,19 @@ mod test { initial_graph.dot(); initial_graph - .mark_graph_seen(initial_change_set.vector_clock_id()) + .mark_graph_seen(initial_vector_clock_id) .expect("unable to mark graph seen"); - let new_change_set = ChangeSet::new_local().expect("Unable to create ChangeSet"); - let new_change_set = &new_change_set; + let new_vector_clock_id = VectorClockId::new(Ulid::new(), actor_id); let mut new_graph = initial_graph.clone(); - let ordered_prop_5_id = new_change_set - .generate_ulid() - .expect("Unable to generate Ulid"); + let ordered_prop_5_id = new_graph.generate_ulid().expect("Unable to generate Ulid"); let ordered_prop_5_index = new_graph .add_node( NodeWeight::new_content( - new_change_set, + new_vector_clock_id, ordered_prop_5_id, + Ulid::new(), ContentAddress::Prop(ContentHash::new( ordered_prop_5_id.to_string().as_bytes(), )), @@ -1737,11 +1945,11 @@ mod test { .expect("Unable to add ordered prop 5"); new_graph .add_ordered_edge( - new_change_set.vector_clock_id(), + new_vector_clock_id, new_graph .get_node_index_by_id(container_prop_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new(new_change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(new_vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create EdgeWeight"), ordered_prop_5_index, ) @@ -1750,14 +1958,14 @@ mod test { new_graph.cleanup(); new_graph.dot(); new_graph - .mark_graph_seen(new_change_set.vector_clock_id()) + .mark_graph_seen(new_vector_clock_id) .expect("unable to mark graph seen"); let ConflictsAndUpdates { conflicts, updates } = new_graph .detect_conflicts_and_updates( - new_change_set.vector_clock_id(), + new_vector_clock_id, &initial_graph, - initial_change_set.vector_clock_id(), + initial_vector_clock_id, ) .expect("Unable to detect conflicts and updates"); @@ -1767,32 +1975,34 @@ mod test { #[test] fn detect_conflicts_and_updates_simple_ordering_no_conflicts_with_updates_in_base() { - let initial_change_set = ChangeSet::new_local().expect("Unable to create ChangeSet"); - let initial_change_set = &initial_change_set; - let mut initial_graph = WorkspaceSnapshotGraph::new(initial_change_set) + let actor_id = Ulid::new(); + let initial_vector_clock_id = VectorClockId::new(Ulid::new(), actor_id); + let mut initial_graph = WorkspaceSnapshotGraph::new(initial_vector_clock_id) .expect("Unable to create WorkspaceSnapshotGraph"); - let schema_id = initial_change_set + let schema_id = initial_graph .generate_ulid() .expect("Unable to generate Ulid"); let schema_index = initial_graph .add_node( NodeWeight::new_content( - initial_change_set, + initial_vector_clock_id, schema_id, + Ulid::new(), ContentAddress::Schema(ContentHash::from("Schema A")), ) .expect("Unable to create NodeWeight"), ) .expect("Unable to add Schema A"); - let schema_variant_id = initial_change_set + let schema_variant_id = initial_graph .generate_ulid() .expect("Unable to generate Ulid"); let schema_variant_index = initial_graph .add_node( NodeWeight::new_content( - initial_change_set, + initial_vector_clock_id, schema_variant_id, + Ulid::new(), ContentAddress::SchemaVariant(ContentHash::from("Schema Variant A")), ) .expect("Unable to create NodeWeight"), @@ -1802,11 +2012,8 @@ mod test { initial_graph .add_edge( initial_graph.root_index, - EdgeWeight::new( - initial_change_set.vector_clock_id(), - EdgeWeightKind::new_use(), - ) - .expect("Unable to create EdgeWeight"), + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create EdgeWeight"), schema_index, ) .expect("Unable to add root -> schema edge"); @@ -1815,24 +2022,22 @@ mod test { initial_graph .get_node_index_by_id(schema_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new( - initial_change_set.vector_clock_id(), - EdgeWeightKind::new_use(), - ) - .expect("Unable to create EdgeWeight"), + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create EdgeWeight"), schema_variant_index, ) .expect("Unable to add schema -> schema variant edge"); - let container_prop_id = initial_change_set + let container_prop_id = initial_graph .generate_ulid() .expect("Unable to generate Ulid"); let container_prop_index = initial_graph .add_ordered_node( - initial_change_set, + initial_vector_clock_id, NodeWeight::new_content( - initial_change_set, + initial_vector_clock_id, container_prop_id, + Ulid::new(), ContentAddress::Prop(ContentHash::new( container_prop_id.to_string().as_bytes(), )), @@ -1845,23 +2050,21 @@ mod test { initial_graph .get_node_index_by_id(schema_variant_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new( - initial_change_set.vector_clock_id(), - EdgeWeightKind::new_use(), - ) - .expect("Unable to create EdgeWeight"), + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create EdgeWeight"), container_prop_index, ) .expect("Unable to add schema variant -> container prop edge"); - let ordered_prop_1_id = initial_change_set + let ordered_prop_1_id = initial_graph .generate_ulid() .expect("Unable to generate Ulid"); let ordered_prop_1_index = initial_graph .add_node( NodeWeight::new_content( - initial_change_set, + initial_vector_clock_id, ordered_prop_1_id, + Ulid::new(), ContentAddress::Prop(ContentHash::new( ordered_prop_1_id.to_string().as_bytes(), )), @@ -1871,27 +2074,25 @@ mod test { .expect("Unable to add ordered prop 1"); initial_graph .add_ordered_edge( - initial_change_set.vector_clock_id(), + initial_vector_clock_id, initial_graph .get_node_index_by_id(container_prop_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new( - initial_change_set.vector_clock_id(), - EdgeWeightKind::new_use(), - ) - .expect("Unable to create EdgeWeight"), + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create EdgeWeight"), ordered_prop_1_index, ) .expect("Unable to add container prop -> ordered prop 1 edge"); - let ordered_prop_2_id = initial_change_set + let ordered_prop_2_id = initial_graph .generate_ulid() .expect("Unable to generate Ulid"); let ordered_prop_2_index = initial_graph .add_node( NodeWeight::new_content( - initial_change_set, + initial_vector_clock_id, ordered_prop_2_id, + Ulid::new(), ContentAddress::Prop(ContentHash::new( ordered_prop_2_id.to_string().as_bytes(), )), @@ -1901,27 +2102,25 @@ mod test { .expect("Unable to add ordered prop 2"); initial_graph .add_ordered_edge( - initial_change_set.vector_clock_id(), + initial_vector_clock_id, initial_graph .get_node_index_by_id(container_prop_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new( - initial_change_set.vector_clock_id(), - EdgeWeightKind::new_use(), - ) - .expect("Unable to create EdgeWeight"), + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create EdgeWeight"), ordered_prop_2_index, ) .expect("Unable to add container prop -> ordered prop 2 edge"); - let ordered_prop_3_id = initial_change_set + let ordered_prop_3_id = initial_graph .generate_ulid() .expect("Unable to generate Ulid"); let ordered_prop_3_index = initial_graph .add_node( NodeWeight::new_content( - initial_change_set, + initial_vector_clock_id, ordered_prop_3_id, + Ulid::new(), ContentAddress::Prop(ContentHash::new( ordered_prop_3_id.to_string().as_bytes(), )), @@ -1931,27 +2130,25 @@ mod test { .expect("Unable to add ordered prop 3"); initial_graph .add_ordered_edge( - initial_change_set.vector_clock_id(), + initial_vector_clock_id, initial_graph .get_node_index_by_id(container_prop_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new( - initial_change_set.vector_clock_id(), - EdgeWeightKind::new_use(), - ) - .expect("Unable to create EdgeWeight"), + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create EdgeWeight"), ordered_prop_3_index, ) .expect("Unable to add container prop -> ordered prop 3 edge"); - let ordered_prop_4_id = initial_change_set + let ordered_prop_4_id = initial_graph .generate_ulid() .expect("Unable to generate Ulid"); let ordered_prop_4_index = initial_graph .add_node( NodeWeight::new_content( - initial_change_set, + initial_vector_clock_id, ordered_prop_4_id, + Ulid::new(), ContentAddress::Prop(ContentHash::new( ordered_prop_4_id.to_string().as_bytes(), )), @@ -1961,36 +2158,33 @@ mod test { .expect("Unable to add ordered prop 4"); initial_graph .add_ordered_edge( - initial_change_set.vector_clock_id(), + initial_vector_clock_id, initial_graph .get_node_index_by_id(container_prop_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new( - initial_change_set.vector_clock_id(), - EdgeWeightKind::new_use(), - ) - .expect("Unable to create EdgeWeight"), + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create EdgeWeight"), ordered_prop_4_index, ) .expect("Unable to add container prop -> ordered prop 4 edge"); initial_graph.dot(); initial_graph - .mark_graph_seen(initial_change_set.vector_clock_id()) + .mark_graph_seen(initial_vector_clock_id) .expect("unable to mark graph seen"); - let new_change_set = ChangeSet::new_local().expect("Unable to create ChangeSet"); - let new_change_set = &new_change_set; + let new_vector_clock_id = VectorClockId::new(Ulid::new(), actor_id); let mut new_graph = initial_graph.clone(); - let ordered_prop_5_id = initial_change_set + let ordered_prop_5_id = initial_graph .generate_ulid() .expect("Unable to generate Ulid"); let ordered_prop_5_index = initial_graph .add_node( NodeWeight::new_content( - initial_change_set, + initial_vector_clock_id, ordered_prop_5_id, + Ulid::new(), ContentAddress::Prop(ContentHash::new( ordered_prop_5_id.to_string().as_bytes(), )), @@ -1998,14 +2192,11 @@ mod test { .expect("Unable to create NodeWeight"), ) .expect("Unable to add ordered prop 5"); - let new_edge_weight = EdgeWeight::new( - initial_change_set.vector_clock_id(), - EdgeWeightKind::new_use(), - ) - .expect("Unable to create EdgeWeight"); + let new_edge_weight = EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create EdgeWeight"); let (_, maybe_ordinal_edge_information) = initial_graph .add_ordered_edge( - initial_change_set.vector_clock_id(), + initial_vector_clock_id, initial_graph .get_node_index_by_id(container_prop_id) .expect("Unable to get NodeIndex"), @@ -2032,19 +2223,19 @@ mod test { .expect("could not get node weight") .id(); initial_graph - .mark_graph_seen(initial_change_set.vector_clock_id()) + .mark_graph_seen(initial_vector_clock_id) .expect("unable to mark graph seen"); new_graph - .mark_graph_seen(new_change_set.vector_clock_id()) + .mark_graph_seen(new_vector_clock_id) .expect("unable to mark graph seen"); new_graph.dot(); let ConflictsAndUpdates { conflicts, updates } = new_graph .detect_conflicts_and_updates( - new_change_set.vector_clock_id(), + new_vector_clock_id, &initial_graph, - initial_change_set.vector_clock_id(), + initial_vector_clock_id, ) .expect("Unable to detect conflicts and updates"); @@ -2129,32 +2320,34 @@ mod test { #[test] fn detect_conflicts_and_updates_simple_ordering_with_conflicting_ordering_updates() { - let initial_change_set = ChangeSet::new_local().expect("Unable to create ChangeSet"); - let initial_change_set = &initial_change_set; - let mut initial_graph = WorkspaceSnapshotGraph::new(initial_change_set) + let actor_id = Ulid::new(); + let initial_vector_clock_id = VectorClockId::new(Ulid::new(), actor_id); + let mut initial_graph = WorkspaceSnapshotGraph::new(initial_vector_clock_id) .expect("Unable to create WorkspaceSnapshotGraph"); - let schema_id = initial_change_set + let schema_id = initial_graph .generate_ulid() .expect("Unable to generate Ulid"); let schema_index = initial_graph .add_node( NodeWeight::new_content( - initial_change_set, + initial_vector_clock_id, schema_id, + Ulid::new(), ContentAddress::Schema(ContentHash::from("Schema A")), ) .expect("Unable to create NodeWeight"), ) .expect("Unable to add Schema A"); - let schema_variant_id = initial_change_set + let schema_variant_id = initial_graph .generate_ulid() .expect("Unable to generate Ulid"); let schema_variant_index = initial_graph .add_node( NodeWeight::new_content( - initial_change_set, + initial_vector_clock_id, schema_variant_id, + Ulid::new(), ContentAddress::SchemaVariant(ContentHash::from("Schema Variant A")), ) .expect("Unable to create NodeWeight"), @@ -2164,11 +2357,8 @@ mod test { initial_graph .add_edge( initial_graph.root_index, - EdgeWeight::new( - initial_change_set.vector_clock_id(), - EdgeWeightKind::new_use(), - ) - .expect("Unable to create EdgeWeight"), + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create EdgeWeight"), schema_index, ) .expect("Unable to add root -> schema edge"); @@ -2177,24 +2367,22 @@ mod test { initial_graph .get_node_index_by_id(schema_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new( - initial_change_set.vector_clock_id(), - EdgeWeightKind::new_use(), - ) - .expect("Unable to create EdgeWeight"), + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create EdgeWeight"), schema_variant_index, ) .expect("Unable to add schema -> schema variant edge"); - let container_prop_id = initial_change_set + let container_prop_id = initial_graph .generate_ulid() .expect("Unable to generate Ulid"); let container_prop_index = initial_graph .add_ordered_node( - initial_change_set, + initial_vector_clock_id, NodeWeight::new_content( - initial_change_set, + initial_vector_clock_id, container_prop_id, + Ulid::new(), ContentAddress::Prop(ContentHash::new( container_prop_id.to_string().as_bytes(), )), @@ -2207,23 +2395,21 @@ mod test { initial_graph .get_node_index_by_id(schema_variant_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new( - initial_change_set.vector_clock_id(), - EdgeWeightKind::new_use(), - ) - .expect("Unable to create EdgeWeight"), + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create EdgeWeight"), container_prop_index, ) .expect("Unable to add schema variant -> container prop edge"); - let ordered_prop_1_id = initial_change_set + let ordered_prop_1_id = initial_graph .generate_ulid() .expect("Unable to generate Ulid"); let ordered_prop_1_index = initial_graph .add_node( NodeWeight::new_content( - initial_change_set, + initial_vector_clock_id, ordered_prop_1_id, + Ulid::new(), ContentAddress::Prop(ContentHash::new( ordered_prop_1_id.to_string().as_bytes(), )), @@ -2233,27 +2419,25 @@ mod test { .expect("Unable to add ordered prop 1"); initial_graph .add_ordered_edge( - initial_change_set.vector_clock_id(), + initial_vector_clock_id, initial_graph .get_node_index_by_id(container_prop_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new( - initial_change_set.vector_clock_id(), - EdgeWeightKind::new_use(), - ) - .expect("Unable to create EdgeWeight"), + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create EdgeWeight"), ordered_prop_1_index, ) .expect("Unable to add container prop -> ordered prop 1 edge"); - let ordered_prop_2_id = initial_change_set + let ordered_prop_2_id = initial_graph .generate_ulid() .expect("Unable to generate Ulid"); let ordered_prop_2_index = initial_graph .add_node( NodeWeight::new_content( - initial_change_set, + initial_vector_clock_id, ordered_prop_2_id, + Ulid::new(), ContentAddress::Prop(ContentHash::new( ordered_prop_2_id.to_string().as_bytes(), )), @@ -2263,27 +2447,25 @@ mod test { .expect("Unable to add ordered prop 2"); initial_graph .add_ordered_edge( - initial_change_set.vector_clock_id(), + initial_vector_clock_id, initial_graph .get_node_index_by_id(container_prop_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new( - initial_change_set.vector_clock_id(), - EdgeWeightKind::new_use(), - ) - .expect("Unable to create EdgeWeight"), + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create EdgeWeight"), ordered_prop_2_index, ) .expect("Unable to add container prop -> ordered prop 2 edge"); - let ordered_prop_3_id = initial_change_set + let ordered_prop_3_id = initial_graph .generate_ulid() .expect("Unable to generate Ulid"); let ordered_prop_3_index = initial_graph .add_node( NodeWeight::new_content( - initial_change_set, + initial_vector_clock_id, ordered_prop_3_id, + Ulid::new(), ContentAddress::Prop(ContentHash::new( ordered_prop_3_id.to_string().as_bytes(), )), @@ -2293,27 +2475,25 @@ mod test { .expect("Unable to add ordered prop 3"); initial_graph .add_ordered_edge( - initial_change_set.vector_clock_id(), + initial_vector_clock_id, initial_graph .get_node_index_by_id(container_prop_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new( - initial_change_set.vector_clock_id(), - EdgeWeightKind::new_use(), - ) - .expect("Unable to create EdgeWeight"), + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create EdgeWeight"), ordered_prop_3_index, ) .expect("Unable to add container prop -> ordered prop 3 edge"); - let ordered_prop_4_id = initial_change_set + let ordered_prop_4_id = initial_graph .generate_ulid() .expect("Unable to generate Ulid"); let ordered_prop_4_index = initial_graph .add_node( NodeWeight::new_content( - initial_change_set, + initial_vector_clock_id, ordered_prop_4_id, + Ulid::new(), ContentAddress::Prop(ContentHash::new( ordered_prop_4_id.to_string().as_bytes(), )), @@ -2323,26 +2503,22 @@ mod test { .expect("Unable to add ordered prop 4"); initial_graph .add_ordered_edge( - initial_change_set.vector_clock_id(), + initial_vector_clock_id, initial_graph .get_node_index_by_id(container_prop_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new( - initial_change_set.vector_clock_id(), - EdgeWeightKind::new_use(), - ) - .expect("Unable to create EdgeWeight"), + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create EdgeWeight"), ordered_prop_4_index, ) .expect("Unable to add container prop -> ordered prop 4 edge"); initial_graph.dot(); initial_graph - .mark_graph_seen(initial_change_set.vector_clock_id()) + .mark_graph_seen(initial_vector_clock_id) .expect("unable to mark graph seen"); - let new_change_set = ChangeSet::new_local().expect("Unable to create ChangeSet"); - let new_change_set = &new_change_set; + let new_vector_clock_id = VectorClockId::new(Ulid::new(), actor_id); let mut new_graph = initial_graph.clone(); let new_order = vec![ @@ -2352,21 +2528,18 @@ mod test { ordered_prop_3_id, ]; new_graph - .update_order( - new_change_set.vector_clock_id(), - container_prop_id, - new_order, - ) + .update_order(new_vector_clock_id, container_prop_id, new_order) .expect("Unable to update order of container prop's children"); - let ordered_prop_5_id = initial_change_set + let ordered_prop_5_id = initial_graph .generate_ulid() .expect("Unable to generate Ulid"); let ordered_prop_5_index = initial_graph .add_node( NodeWeight::new_content( - initial_change_set, + initial_vector_clock_id, ordered_prop_5_id, + Ulid::new(), ContentAddress::Prop(ContentHash::new( ordered_prop_5_id.to_string().as_bytes(), )), @@ -2374,14 +2547,11 @@ mod test { .expect("Unable to create NodeWeight"), ) .expect("Unable to add ordered prop 5"); - let new_edge_weight = EdgeWeight::new( - initial_change_set.vector_clock_id(), - EdgeWeightKind::new_use(), - ) - .expect("Unable to create EdgeWeight"); + let new_edge_weight = EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create EdgeWeight"); let (_, maybe_ordinal_edge_information) = initial_graph .add_ordered_edge( - initial_change_set.vector_clock_id(), + initial_vector_clock_id, initial_graph .get_node_index_by_id(container_prop_id) .expect("Unable to get NodeIndex"), @@ -2409,20 +2579,20 @@ mod test { .id(); initial_graph - .mark_graph_seen(initial_change_set.vector_clock_id()) + .mark_graph_seen(initial_vector_clock_id) .expect("unable to mark graph seen"); new_graph.cleanup(); new_graph - .mark_graph_seen(new_change_set.vector_clock_id()) + .mark_graph_seen(new_vector_clock_id) .expect("unable to mark graph seen"); new_graph.dot(); let ConflictsAndUpdates { conflicts, updates } = new_graph .detect_conflicts_and_updates( - new_change_set.vector_clock_id(), + new_vector_clock_id, &initial_graph, - initial_change_set.vector_clock_id(), + initial_vector_clock_id, ) .expect("Unable to detect conflicts and updates"); @@ -2513,9 +2683,8 @@ mod test { #[test] fn simple_ordering_no_conflicts_same_vector_clocks() { - let change_set = ChangeSet::new_local().expect("Unable to create ChangeSet"); - let change_set = &change_set; - let mut to_rebase_graph = WorkspaceSnapshotGraph::new(change_set) + let vector_clock_id = VectorClockId::new(Ulid::new(), Ulid::new()); + let mut to_rebase_graph = WorkspaceSnapshotGraph::new(vector_clock_id) .expect("Unable to create WorkspaceSnapshotGraph"); let ordered_node = "ordered_container"; @@ -2523,10 +2692,10 @@ mod test { let onto_children = vec!["d", "e", "f"]; let mut node_id_map = - add_prop_nodes_to_graph(&mut to_rebase_graph, change_set, &[ordered_node], true); + add_prop_nodes_to_graph(&mut to_rebase_graph, vector_clock_id, &[ordered_node], true); node_id_map.extend(add_prop_nodes_to_graph( &mut to_rebase_graph, - change_set, + vector_clock_id, &initial_children, false, )); @@ -2538,7 +2707,7 @@ mod test { to_rebase_graph .add_edge( root_idx, - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("failed to make edge weight"), ordered_idx, ) @@ -2554,9 +2723,9 @@ mod test { .expect("should have a node index"); to_rebase_graph .add_ordered_edge( - change_set.vector_clock_id(), + vector_clock_id, ordered_idx, - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("failed to make edge weight"), child_idx, ) @@ -2565,7 +2734,7 @@ mod test { to_rebase_graph.cleanup(); to_rebase_graph - .mark_graph_seen(change_set.vector_clock_id()) + .mark_graph_seen(vector_clock_id) .expect("mark twain"); let mut onto_graph = to_rebase_graph.clone(); @@ -2579,7 +2748,7 @@ mod test { .expect("should have a node index"); onto_graph .remove_edge( - change_set, + vector_clock_id, ordered_idx, child_idx, EdgeWeightKindDiscriminants::Use, @@ -2589,7 +2758,7 @@ mod test { node_id_map.extend(add_prop_nodes_to_graph( &mut onto_graph, - change_set, + vector_clock_id, &onto_children, false, )); @@ -2604,9 +2773,9 @@ mod test { .expect("should have a node index"); onto_graph .add_ordered_edge( - change_set.vector_clock_id(), + vector_clock_id, ordered_idx, - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("failed to make edge weight"), child_idx, ) @@ -2615,21 +2784,17 @@ mod test { onto_graph.cleanup(); onto_graph - .mark_graph_seen(change_set.vector_clock_id()) + .mark_graph_seen(vector_clock_id) .expect("call me mark, mr seen is my father"); let conflicts_and_updates = to_rebase_graph - .detect_conflicts_and_updates( - change_set.vector_clock_id(), - &onto_graph, - change_set.vector_clock_id(), - ) + .detect_conflicts_and_updates(vector_clock_id, &onto_graph, vector_clock_id) .expect("unable to detect conflicts and updates"); assert!(conflicts_and_updates.conflicts.is_empty()); to_rebase_graph - .perform_updates(change_set, &onto_graph, &conflicts_and_updates.updates) + .perform_updates(vector_clock_id, &onto_graph, &conflicts_and_updates.updates) .expect("unable to perform updates"); to_rebase_graph.cleanup(); @@ -2679,32 +2844,34 @@ mod test { #[test] fn detect_conflicts_and_updates_simple_ordering_with_no_conflicts_add_in_onto_remove_in_to_rebase( ) { - let initial_change_set = ChangeSet::new_local().expect("Unable to create ChangeSet"); - let initial_change_set = &initial_change_set; - let mut initial_graph = WorkspaceSnapshotGraph::new(initial_change_set) + let actor_id = Ulid::new(); + let initial_vector_clock_id = VectorClockId::new(Ulid::new(), actor_id); + let mut initial_graph = WorkspaceSnapshotGraph::new(initial_vector_clock_id) .expect("Unable to create WorkspaceSnapshotGraph"); - let schema_id = initial_change_set + let schema_id = initial_graph .generate_ulid() .expect("Unable to generate Ulid"); let schema_index = initial_graph .add_node( NodeWeight::new_content( - initial_change_set, + initial_vector_clock_id, schema_id, + Ulid::new(), ContentAddress::Schema(ContentHash::from("Schema A")), ) .expect("Unable to create NodeWeight"), ) .expect("Unable to add Schema A"); - let schema_variant_id = initial_change_set + let schema_variant_id = initial_graph .generate_ulid() .expect("Unable to generate Ulid"); let schema_variant_index = initial_graph .add_node( NodeWeight::new_content( - initial_change_set, + initial_vector_clock_id, schema_variant_id, + Ulid::new(), ContentAddress::SchemaVariant(ContentHash::from("Schema Variant A")), ) .expect("Unable to create NodeWeight"), @@ -2714,11 +2881,8 @@ mod test { initial_graph .add_edge( initial_graph.root_index, - EdgeWeight::new( - initial_change_set.vector_clock_id(), - EdgeWeightKind::new_use(), - ) - .expect("Unable to create EdgeWeight"), + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create EdgeWeight"), schema_index, ) .expect("Unable to add root -> schema edge"); @@ -2727,24 +2891,22 @@ mod test { initial_graph .get_node_index_by_id(schema_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new( - initial_change_set.vector_clock_id(), - EdgeWeightKind::new_use(), - ) - .expect("Unable to create EdgeWeight"), + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create EdgeWeight"), schema_variant_index, ) .expect("Unable to add schema -> schema variant edge"); - let container_prop_id = initial_change_set + let container_prop_id = initial_graph .generate_ulid() .expect("Unable to generate Ulid"); let container_prop_index = initial_graph .add_ordered_node( - initial_change_set, + initial_vector_clock_id, NodeWeight::new_content( - initial_change_set, + initial_vector_clock_id, container_prop_id, + Ulid::new(), ContentAddress::Prop(ContentHash::new( container_prop_id.to_string().as_bytes(), )), @@ -2757,23 +2919,21 @@ mod test { initial_graph .get_node_index_by_id(schema_variant_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new( - initial_change_set.vector_clock_id(), - EdgeWeightKind::new_use(), - ) - .expect("Unable to create EdgeWeight"), + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create EdgeWeight"), container_prop_index, ) .expect("Unable to add schema variant -> container prop edge"); - let ordered_prop_1_id = initial_change_set + let ordered_prop_1_id = initial_graph .generate_ulid() .expect("Unable to generate Ulid"); let ordered_prop_1_index = initial_graph .add_node( NodeWeight::new_content( - initial_change_set, + initial_vector_clock_id, ordered_prop_1_id, + Ulid::new(), ContentAddress::Prop(ContentHash::new( ordered_prop_1_id.to_string().as_bytes(), )), @@ -2783,29 +2943,27 @@ mod test { .expect("Unable to add ordered prop 1"); initial_graph .add_ordered_edge( - initial_change_set.vector_clock_id(), + initial_vector_clock_id, initial_graph .get_node_index_by_id(container_prop_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new( - initial_change_set.vector_clock_id(), - EdgeWeightKind::new_use(), - ) - .expect("Unable to create EdgeWeight"), + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create EdgeWeight"), ordered_prop_1_index, ) .expect("Unable to add container prop -> ordered prop 1 edge"); println!("added ordered edge from {container_prop_id} to {ordered_prop_1_id} in onto"); - let ordered_prop_2_id = initial_change_set + let ordered_prop_2_id = initial_graph .generate_ulid() .expect("Unable to generate Ulid"); let ordered_prop_2_index = initial_graph .add_node( NodeWeight::new_content( - initial_change_set, + initial_vector_clock_id, ordered_prop_2_id, + Ulid::new(), ContentAddress::Prop(ContentHash::new( ordered_prop_2_id.to_string().as_bytes(), )), @@ -2815,29 +2973,27 @@ mod test { .expect("Unable to add ordered prop 2"); initial_graph .add_ordered_edge( - initial_change_set.vector_clock_id(), + initial_vector_clock_id, initial_graph .get_node_index_by_id(container_prop_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new( - initial_change_set.vector_clock_id(), - EdgeWeightKind::new_use(), - ) - .expect("Unable to create EdgeWeight"), + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create EdgeWeight"), ordered_prop_2_index, ) .expect("Unable to add container prop -> ordered prop 2 edge"); println!("added ordered edge from {container_prop_id} to {ordered_prop_2_id} in onto"); - let ordered_prop_3_id = initial_change_set + let ordered_prop_3_id = initial_graph .generate_ulid() .expect("Unable to generate Ulid"); let ordered_prop_3_index = initial_graph .add_node( NodeWeight::new_content( - initial_change_set, + initial_vector_clock_id, ordered_prop_3_id, + Ulid::new(), ContentAddress::Prop(ContentHash::new( ordered_prop_3_id.to_string().as_bytes(), )), @@ -2847,29 +3003,27 @@ mod test { .expect("Unable to add ordered prop 3"); initial_graph .add_ordered_edge( - initial_change_set.vector_clock_id(), + initial_vector_clock_id, initial_graph .get_node_index_by_id(container_prop_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new( - initial_change_set.vector_clock_id(), - EdgeWeightKind::new_use(), - ) - .expect("Unable to create EdgeWeight"), + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create EdgeWeight"), ordered_prop_3_index, ) .expect("Unable to add container prop -> ordered prop 3 edge"); println!("added ordered edge from {container_prop_id} to {ordered_prop_3_id} in onto"); - let ordered_prop_4_id = initial_change_set + let ordered_prop_4_id = initial_graph .generate_ulid() .expect("Unable to generate Ulid"); let ordered_prop_4_index = initial_graph .add_node( NodeWeight::new_content( - initial_change_set, + initial_vector_clock_id, ordered_prop_4_id, + Ulid::new(), ContentAddress::Prop(ContentHash::new( ordered_prop_4_id.to_string().as_bytes(), )), @@ -2879,15 +3033,12 @@ mod test { .expect("Unable to add ordered prop 4"); initial_graph .add_ordered_edge( - initial_change_set.vector_clock_id(), + initial_vector_clock_id, initial_graph .get_node_index_by_id(container_prop_id) .expect("Unable to get NodeIndex"), - EdgeWeight::new( - initial_change_set.vector_clock_id(), - EdgeWeightKind::new_use(), - ) - .expect("Unable to create EdgeWeight"), + EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create EdgeWeight"), ordered_prop_4_index, ) .expect("Unable to add container prop -> ordered prop 4 edge"); @@ -2896,17 +3047,17 @@ mod test { initial_graph.cleanup(); initial_graph - .mark_graph_seen(initial_change_set.vector_clock_id()) + .mark_graph_seen(initial_vector_clock_id) .expect("Unable to update recently seen information"); // initial_graph.dot(); - let new_change_set = ChangeSet::new_local().expect("Unable to create ChangeSet"); - let new_change_set = &new_change_set; + let new_vector_clock_id = VectorClockId::new(Ulid::new(), actor_id); + let mut new_graph = initial_graph.clone(); new_graph .remove_edge( - new_change_set, + new_vector_clock_id, new_graph .get_node_index_by_id(container_prop_id) .expect("Unable to get container NodeIndex"), @@ -2917,14 +3068,15 @@ mod test { println!("removed edge from {container_prop_id} to {ordered_prop_2_id} in to_rebase"); - let ordered_prop_5_id = initial_change_set + let ordered_prop_5_id = initial_graph .generate_ulid() .expect("Unable to generate Ulid"); let ordered_prop_5_index = initial_graph .add_node( NodeWeight::new_content( - initial_change_set, + initial_vector_clock_id, ordered_prop_5_id, + Ulid::new(), ContentAddress::Prop(ContentHash::new( ordered_prop_5_id.to_string().as_bytes(), )), @@ -2933,14 +3085,11 @@ mod test { ) .expect("Unable to add ordered prop 5"); - let new_edge_weight = EdgeWeight::new( - initial_change_set.vector_clock_id(), - EdgeWeightKind::new_use(), - ) - .expect("Unable to create EdgeWeight"); + let new_edge_weight = EdgeWeight::new(initial_vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create EdgeWeight"); let (_, maybe_ordinal_edge_information) = initial_graph .add_ordered_edge( - initial_change_set.vector_clock_id(), + initial_vector_clock_id, initial_graph .get_node_index_by_id(container_prop_id) .expect("Unable to get NodeIndex"), @@ -2971,13 +3120,13 @@ mod test { initial_graph.cleanup(); //initial_graph.dot(); initial_graph - .mark_graph_seen(initial_change_set.vector_clock_id()) + .mark_graph_seen(initial_vector_clock_id) .expect("unable mark graph seen"); new_graph.cleanup(); //new_graph.dot(); new_graph - .mark_graph_seen(new_change_set.vector_clock_id()) + .mark_graph_seen(new_vector_clock_id) .expect("unable to mark graph seen"); // initial_graph.tiny_dot_to_file(Some("onto")); @@ -2985,9 +3134,9 @@ mod test { let ConflictsAndUpdates { conflicts, updates } = new_graph .detect_conflicts_and_updates( - new_change_set.vector_clock_id(), + new_vector_clock_id, &initial_graph, - initial_change_set.vector_clock_id(), + initial_vector_clock_id, ) .expect("Unable to detect conflicts and updates"); @@ -3040,10 +3189,10 @@ mod test { fn detect_conflicts_and_updates_single_removal_update() { let nodes = ["a", "b", "c"]; let edges = [(None, "a"), (None, "b"), (Some("a"), "c"), (Some("c"), "b")]; + let actor_id = Ulid::new(); - let base_change_set = ChangeSet::new_local().expect("Unable to create ChangeSet"); - let base_change_set = &base_change_set; - let mut base_graph = WorkspaceSnapshotGraph::new(base_change_set) + let base_vector_clock_id = VectorClockId::new(Ulid::new(), actor_id); + let mut base_graph = WorkspaceSnapshotGraph::new(base_vector_clock_id) .expect("Unable to create WorkspaceSnapshotGraph"); // Add all nodes from the slice and store their references in a hash map. @@ -3051,12 +3200,11 @@ mod test { for node in nodes { // "props" here are just nodes that are easy to create and render the name on the dot // output. there is no domain modeling in this test. - let node_id = base_change_set - .generate_ulid() - .expect("Unable to generate Ulid"); + let node_id = base_graph.generate_ulid().expect("Unable to generate Ulid"); let prop_node_weight = NodeWeight::new_prop( - base_change_set, + base_vector_clock_id, node_id, + Ulid::new(), PropKind::Object, node, ContentHash::new(node.as_bytes()), @@ -3095,7 +3243,7 @@ mod test { base_graph .add_edge( source, - EdgeWeight::new(base_change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(base_vector_clock_id, EdgeWeightKind::new_use()) .expect("create edge weight"), target, ) @@ -3153,11 +3301,11 @@ mod test { // Prepare the graph for "forking" and fork it. Create a new change set after. base_graph - .mark_graph_seen(base_change_set.vector_clock_id()) + .mark_graph_seen(base_vector_clock_id) .expect("could not mark as seen"); let mut new_graph = base_graph.clone(); - let new_change_set = ChangeSet::new_local().expect("Unable to create ChangeSet"); - let new_change_set = &new_change_set; + + let new_vector_clock_id = VectorClockId::new(Ulid::new(), actor_id); // Remove the first edge involving "c". let a_idx = new_graph @@ -3168,7 +3316,7 @@ mod test { .expect("could not get node index by id"); new_graph .remove_edge( - new_change_set, + new_vector_clock_id, a_idx, c_idx, EdgeWeightKindDiscriminants::Use, @@ -3184,7 +3332,7 @@ mod test { .expect("could not get node index by id"); new_graph .remove_edge( - new_change_set, + new_vector_clock_id, c_idx, b_idx, EdgeWeightKindDiscriminants::Use, @@ -3197,7 +3345,7 @@ mod test { // Prepare for conflicts and updates detection new_graph - .mark_graph_seen(new_change_set.vector_clock_id()) + .mark_graph_seen(new_vector_clock_id) .expect("could not mark graph seen"); new_graph.cleanup(); @@ -3205,11 +3353,7 @@ mod test { // new_graph.tiny_dot_to_file(Some("onto")); let ConflictsAndUpdates { conflicts, updates } = base_graph - .detect_conflicts_and_updates( - base_change_set.vector_clock_id(), - &new_graph, - new_change_set.vector_clock_id(), - ) + .detect_conflicts_and_updates(base_vector_clock_id, &new_graph, new_vector_clock_id) .expect("Unable to detect conflicts and updates"); assert_eq!( @@ -3233,24 +3377,28 @@ mod test { #[test] fn detect_exclusive_edge_conflict() { - let base_change_set = ChangeSet::new_local().expect("Unable to create local change set"); - let base_change_set = &base_change_set; + let actor_id = Ulid::new(); + let base_vector_clock_id = VectorClockId::new(Ulid::new(), actor_id); let mut base_graph = - WorkspaceSnapshotGraph::new(base_change_set).expect("Unable to make base graph"); + WorkspaceSnapshotGraph::new(base_vector_clock_id).expect("Unable to make base graph"); - let av_id = base_change_set - .generate_ulid() - .expect("Unable to generate Ulid"); + let av_id = base_graph.generate_ulid().expect("Unable to generate Ulid"); base_graph .add_node( - NodeWeight::new_attribute_value(base_change_set, av_id, None, None) - .expect("Unable to create AttributeValue"), + NodeWeight::new_attribute_value( + base_vector_clock_id, + av_id, + Ulid::new(), + None, + None, + ) + .expect("Unable to create AttributeValue"), ) .expect("Unable to add AttributeValue"); base_graph .add_edge( base_graph.root_index, - EdgeWeight::new(base_change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(base_vector_clock_id, EdgeWeightKind::new_use()) .expect("Unable to create edge weight"), base_graph .get_node_index_by_id(av_id) @@ -3259,21 +3407,21 @@ mod test { .expect("Unable to add root -> AV Use edge"); base_graph.cleanup(); base_graph - .mark_graph_seen(base_change_set.vector_clock_id()) + .mark_graph_seen(base_vector_clock_id) .expect("Unable to mark base graph as seen"); - let new_change_set = ChangeSet::new_local().expect("Unable to create local change set"); - let new_change_set = &new_change_set; + let new_vector_clock_id = VectorClockId::new(Ulid::new(), actor_id); let mut new_changes_graph = base_graph.clone(); - let prototype_a_id = new_change_set + let prototype_a_id = new_changes_graph .generate_ulid() .expect("Unable to generate Ulid"); new_changes_graph .add_node( NodeWeight::new_content( - new_change_set, + new_vector_clock_id, prototype_a_id, + Ulid::new(), ContentAddress::AttributePrototype(ContentHash::new( "Prototype A".to_string().as_bytes(), )), @@ -3286,11 +3434,8 @@ mod test { new_changes_graph .get_node_index_by_id(av_id) .expect("Unable to get AV node index"), - EdgeWeight::new( - new_change_set.vector_clock_id(), - EdgeWeightKind::Prototype(None), - ) - .expect("Unable to create edge weight"), + EdgeWeight::new(new_vector_clock_id, EdgeWeightKind::Prototype(None)) + .expect("Unable to create edge weight"), new_changes_graph .get_node_index_by_id(prototype_a_id) .expect("Unable to get node index for AttributePrototype"), @@ -3298,7 +3443,7 @@ mod test { .expect("Unable to add AV -> AttributePrototype Prototype edge"); new_changes_graph.cleanup(); new_changes_graph - .mark_graph_seen(new_change_set.vector_clock_id()) + .mark_graph_seen(new_vector_clock_id) .expect("Unable to mark new changes graph as seen"); let ConflictsAndUpdates { @@ -3306,27 +3451,26 @@ mod test { updates: _, } = base_graph .detect_conflicts_and_updates( - base_change_set.vector_clock_id(), + base_vector_clock_id, &new_changes_graph, - new_change_set.vector_clock_id(), + new_vector_clock_id, ) .expect("able to detect conflicts and updates"); assert_eq!(Vec::::new(), conflicts); - let conflicting_change_set = - ChangeSet::new_local().expect("Unable to create local change set"); - let conflicting_change_set = &conflicting_change_set; + let conflicting_vector_clock_id = VectorClockId::new(Ulid::new(), actor_id); let mut conflicting_graph = new_changes_graph.clone(); - let prototype_b_id = conflicting_change_set + let prototype_b_id = conflicting_graph .generate_ulid() .expect("Unable to generate Ulid"); conflicting_graph .add_node( NodeWeight::new_content( - conflicting_change_set, + conflicting_vector_clock_id, prototype_b_id, + Ulid::new(), ContentAddress::AttributePrototype(ContentHash::new( "Prototype B".to_string().as_bytes(), )), @@ -3339,11 +3483,8 @@ mod test { conflicting_graph .get_node_index_by_id(av_id) .expect("Unable to get AV node index"), - EdgeWeight::new( - conflicting_change_set.vector_clock_id(), - EdgeWeightKind::Prototype(None), - ) - .expect("Unable to create edge weight"), + EdgeWeight::new(conflicting_vector_clock_id, EdgeWeightKind::Prototype(None)) + .expect("Unable to create edge weight"), conflicting_graph .get_node_index_by_id(prototype_b_id) .expect("Unable to get node index for AttributePrototype"), @@ -3352,7 +3493,7 @@ mod test { conflicting_graph.cleanup(); conflicting_graph - .mark_graph_seen(conflicting_change_set.vector_clock_id()) + .mark_graph_seen(conflicting_vector_clock_id) .expect("Unable to mark conflicting graph as seen"); let ConflictsAndUpdates { @@ -3360,9 +3501,9 @@ mod test { updates: _, } = new_changes_graph .detect_conflicts_and_updates( - new_change_set.vector_clock_id(), + new_vector_clock_id, &conflicting_graph, - conflicting_change_set.vector_clock_id(), + conflicting_vector_clock_id, ) .expect("able to detect conflicts and updates"); @@ -3392,9 +3533,9 @@ mod test { updates: _, } = base_graph .detect_conflicts_and_updates( - base_change_set.vector_clock_id(), + base_vector_clock_id, &conflicting_graph, - conflicting_change_set.vector_clock_id(), + conflicting_vector_clock_id, ) .expect("able to detect conflicts and updates"); @@ -3443,49 +3584,237 @@ mod test { } #[test] - fn detect_conflicts_and_updates_remove_edge_simple() { - let to_rebase_change_set = ChangeSet::new_local().expect("create cset"); - let mut to_rebase_graph = WorkspaceSnapshotGraph::new(&to_rebase_change_set) - .expect("unable to make to_rebase_graph"); - - let prototype_node_id = to_rebase_change_set.generate_ulid().expect("gen ulid"); - let prototype_node = NodeWeight::new_content( - &to_rebase_change_set, - prototype_node_id, - ContentAddress::AttributePrototype(ContentHash::from("prototype")), - ) - .expect("unable to create prototype node weight"); + fn detect_exclusive_edge_conflict_same_vector_clocks() { + let actor_id = Ulid::new(); + let vector_clock_id = VectorClockId::new(Ulid::new(), actor_id); + let mut base_graph = + WorkspaceSnapshotGraph::new(vector_clock_id).expect("Unable to make base graph"); - to_rebase_graph - .add_node(prototype_node) - .expect("unable to add node"); - to_rebase_graph - .add_edge( - to_rebase_graph.root(), - EdgeWeight::new( - to_rebase_change_set.vector_clock_id(), - EdgeWeightKind::Prototype(None), - ) - .expect("make edge weight"), - to_rebase_graph - .get_node_index_by_id(prototype_node_id) - .expect("get_node_index_by_id"), + let av_id = base_graph.generate_ulid().expect("Unable to generate Ulid"); + base_graph + .add_node( + NodeWeight::new_attribute_value(vector_clock_id, av_id, Ulid::new(), None, None) + .expect("Unable to create AttributeValue"), ) - .expect("unable to add edge"); + .expect("Unable to add AttributeValue"); + base_graph + .add_edge( + base_graph.root_index, + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) + .expect("Unable to create edge weight"), + base_graph + .get_node_index_by_id(av_id) + .expect("Unable to get node index for AttributeValue"), + ) + .expect("Unable to add root -> AV Use edge"); + base_graph.cleanup(); + base_graph + .mark_graph_seen(vector_clock_id) + .expect("Unable to mark base graph as seen"); + + let mut new_changes_graph = base_graph.clone(); + + let prototype_a_id = new_changes_graph + .generate_ulid() + .expect("Unable to generate Ulid"); + new_changes_graph + .add_node( + NodeWeight::new_content( + vector_clock_id, + prototype_a_id, + Ulid::new(), + ContentAddress::AttributePrototype(ContentHash::new( + "Prototype A".to_string().as_bytes(), + )), + ) + .expect("Unable to create content node weight"), + ) + .expect("Unable to add prototype a to graph"); + new_changes_graph + .add_edge( + new_changes_graph + .get_node_index_by_id(av_id) + .expect("Unable to get AV node index"), + EdgeWeight::new(vector_clock_id, EdgeWeightKind::Prototype(None)) + .expect("Unable to create edge weight"), + new_changes_graph + .get_node_index_by_id(prototype_a_id) + .expect("Unable to get node index for AttributePrototype"), + ) + .expect("Unable to add AV -> AttributePrototype Prototype edge"); + new_changes_graph.cleanup(); + new_changes_graph + .mark_graph_seen(vector_clock_id) + .expect("Unable to mark new changes graph as seen"); + + let ConflictsAndUpdates { + conflicts, + updates: _, + } = base_graph + .detect_conflicts_and_updates(vector_clock_id, &new_changes_graph, vector_clock_id) + .expect("able to detect conflicts and updates"); + + assert_eq!(Vec::::new(), conflicts); + + let mut conflicting_graph = new_changes_graph.clone(); + + let prototype_b_id = conflicting_graph + .generate_ulid() + .expect("Unable to generate Ulid"); + conflicting_graph + .add_node( + NodeWeight::new_content( + vector_clock_id, + prototype_b_id, + Ulid::new(), + ContentAddress::AttributePrototype(ContentHash::new( + "Prototype B".to_string().as_bytes(), + )), + ) + .expect("Unable to create content node weight"), + ) + .expect("Unable to add prototype b to graph"); + conflicting_graph + .add_edge( + conflicting_graph + .get_node_index_by_id(av_id) + .expect("Unable to get AV node index"), + EdgeWeight::new(vector_clock_id, EdgeWeightKind::Prototype(None)) + .expect("Unable to create edge weight"), + conflicting_graph + .get_node_index_by_id(prototype_b_id) + .expect("Unable to get node index for AttributePrototype"), + ) + .expect("Unable to add AV -> AttributePrototype Prototype edge"); + + conflicting_graph.cleanup(); + conflicting_graph + .mark_graph_seen(vector_clock_id) + .expect("Unable to mark conflicting graph as seen"); + + let ConflictsAndUpdates { + conflicts, + updates: _, + } = new_changes_graph + .detect_conflicts_and_updates(vector_clock_id, &conflicting_graph, vector_clock_id) + .expect("able to detect conflicts and updates"); + + assert_eq!( + vec![Conflict::ExclusiveEdgeMismatch { + source: NodeInformation { + index: new_changes_graph + .get_node_index_by_id(av_id) + .expect("Unable to get AV node index"), + node_weight_kind: NodeWeightDiscriminants::AttributeValue, + id: av_id.into(), + }, + destination: NodeInformation { + index: conflicting_graph + .get_node_index_by_id(prototype_b_id) + .expect("Unable to get Prototype B node index"), + node_weight_kind: NodeWeightDiscriminants::Content, + id: prototype_b_id.into(), + }, + edge_kind: EdgeWeightKindDiscriminants::Prototype, + }], + conflicts, + ); + + let ConflictsAndUpdates { + conflicts, + updates: _, + } = base_graph + .detect_conflicts_and_updates(vector_clock_id, &conflicting_graph, vector_clock_id) + .expect("able to detect conflicts and updates"); + + let expected_conflicts: HashSet = [ + Conflict::ExclusiveEdgeMismatch { + source: NodeInformation { + index: base_graph + .get_node_index_by_id(av_id) + .expect("Unable to get AV node index"), + node_weight_kind: NodeWeightDiscriminants::AttributeValue, + id: av_id.into(), + }, + destination: NodeInformation { + index: conflicting_graph + .get_node_index_by_id(prototype_a_id) + .expect("Unable to get Prototype A node index"), + node_weight_kind: NodeWeightDiscriminants::Content, + id: prototype_a_id.into(), + }, + edge_kind: EdgeWeightKindDiscriminants::Prototype, + }, + Conflict::ExclusiveEdgeMismatch { + source: NodeInformation { + index: base_graph + .get_node_index_by_id(av_id) + .expect("Unable to get AV node index"), + node_weight_kind: NodeWeightDiscriminants::AttributeValue, + id: av_id.into(), + }, + destination: NodeInformation { + index: conflicting_graph + .get_node_index_by_id(prototype_b_id) + .expect("Unable to get Prototype B node index"), + node_weight_kind: NodeWeightDiscriminants::Content, + id: prototype_b_id.into(), + }, + edge_kind: EdgeWeightKindDiscriminants::Prototype, + }, + ] + .iter() + .copied() + .collect(); + let actual_conflicts: HashSet = conflicts.iter().copied().collect(); + + assert_eq!(expected_conflicts, actual_conflicts); + } + + #[test] + fn detect_conflicts_and_updates_remove_edge_simple() { + let actor_id = Ulid::new(); + let to_rebase_vector_clock_id = VectorClockId::new(Ulid::new(), actor_id); + + let mut to_rebase_graph = WorkspaceSnapshotGraph::new(to_rebase_vector_clock_id) + .expect("unable to make to_rebase_graph"); + + let prototype_node_id = to_rebase_graph.generate_ulid().expect("gen ulid"); + let prototype_node = NodeWeight::new_content( + to_rebase_vector_clock_id, + prototype_node_id, + Ulid::new(), + ContentAddress::AttributePrototype(ContentHash::from("prototype")), + ) + .expect("unable to create prototype node weight"); + + to_rebase_graph + .add_node(prototype_node) + .expect("unable to add node"); + to_rebase_graph + .add_edge( + to_rebase_graph.root(), + EdgeWeight::new(to_rebase_vector_clock_id, EdgeWeightKind::Prototype(None)) + .expect("make edge weight"), + to_rebase_graph + .get_node_index_by_id(prototype_node_id) + .expect("get_node_index_by_id"), + ) + .expect("unable to add edge"); // "write" the graph to_rebase_graph.cleanup(); to_rebase_graph - .mark_graph_seen(to_rebase_change_set.vector_clock_id()) + .mark_graph_seen(to_rebase_vector_clock_id) .expect("mark_graph_seen"); // "fork" a working changeset from the current one - let onto_change_set = ChangeSet::new_local().expect("new_local"); + let onto_vector_clock_id = VectorClockId::new(Ulid::new(), actor_id); let mut onto_graph = to_rebase_graph.clone(); onto_graph .remove_edge( - &onto_change_set, + onto_vector_clock_id, onto_graph.root(), to_rebase_graph .get_node_index_by_id(prototype_node_id) @@ -3496,14 +3825,14 @@ mod test { onto_graph.cleanup(); onto_graph - .mark_graph_seen(onto_change_set.vector_clock_id()) + .mark_graph_seen(onto_vector_clock_id) .expect("mark_graph_seen"); let ConflictsAndUpdates { conflicts, updates } = to_rebase_graph .detect_conflicts_and_updates( - to_rebase_change_set.vector_clock_id(), + to_rebase_vector_clock_id, &onto_graph, - onto_change_set.vector_clock_id(), + onto_vector_clock_id, ) .expect("detect_conflicts_and_updates"); @@ -3520,14 +3849,16 @@ mod test { #[test] fn detect_conflicts_and_updates_remove_modified_item_conflict() { - let to_rebase_change_set = ChangeSet::new_local().expect("create cset"); - let mut to_rebase_graph = WorkspaceSnapshotGraph::new(&to_rebase_change_set) + let actor_id = Ulid::new(); + let to_rebase_vector_clock_id = VectorClockId::new(Ulid::new(), actor_id); + let mut to_rebase_graph = WorkspaceSnapshotGraph::new(to_rebase_vector_clock_id) .expect("unable to make to_rebase_graph"); - let prototype_node_id = to_rebase_change_set.generate_ulid().expect("gen ulid"); + let prototype_node_id = to_rebase_graph.generate_ulid().expect("gen ulid"); let prototype_node = NodeWeight::new_content( - &to_rebase_change_set, + to_rebase_vector_clock_id, prototype_node_id, + Ulid::new(), ContentAddress::AttributePrototype(ContentHash::from("prototype")), ) .expect("unable to create prototype node weight"); @@ -3538,11 +3869,8 @@ mod test { to_rebase_graph .add_edge( to_rebase_graph.root(), - EdgeWeight::new( - to_rebase_change_set.vector_clock_id(), - EdgeWeightKind::Prototype(None), - ) - .expect("make edge weight"), + EdgeWeight::new(to_rebase_vector_clock_id, EdgeWeightKind::Prototype(None)) + .expect("make edge weight"), to_rebase_graph .get_node_index_by_id(prototype_node_id) .expect("get_node_index_by_id"), @@ -3552,17 +3880,17 @@ mod test { // "write" the graph to_rebase_graph.cleanup(); to_rebase_graph - .mark_graph_seen(to_rebase_change_set.vector_clock_id()) + .mark_graph_seen(to_rebase_vector_clock_id) .expect("mark_graph_seen"); // "fork" a working changeset from the current one - let onto_change_set = ChangeSet::new_local().expect("new_local"); + let onto_vector_clock_id = VectorClockId::new(Ulid::new(), actor_id); let mut onto_graph = to_rebase_graph.clone(); // After the fork, remove the edge in to_rebase, but modify the edge in onto to_rebase_graph .remove_edge( - &onto_change_set, + onto_vector_clock_id, onto_graph.root(), to_rebase_graph .get_node_index_by_id(prototype_node_id) @@ -3572,7 +3900,7 @@ mod test { .expect("remove_edge"); to_rebase_graph.cleanup(); to_rebase_graph - .mark_graph_seen(to_rebase_change_set.vector_clock_id()) + .mark_graph_seen(to_rebase_vector_clock_id) .expect("mark_graph_seen"); let onto_content_node_idx = onto_graph @@ -3590,7 +3918,7 @@ mod test { content_node .new_content_hash(ContentHash::from("prototype_change")) .expect("update_content_hash"); - content_node.increment_vector_clocks(onto_change_set.vector_clock_id()); + content_node.increment_vector_clocks(onto_vector_clock_id); onto_graph .add_node(NodeWeight::Content(content_node)) .expect("add_node"); @@ -3599,14 +3927,14 @@ mod test { .expect("replace_references"); onto_graph.cleanup(); onto_graph - .mark_graph_seen(onto_change_set.vector_clock_id()) + .mark_graph_seen(onto_vector_clock_id) .expect("mark_graph_seen"); let ConflictsAndUpdates { conflicts, updates } = to_rebase_graph .detect_conflicts_and_updates( - to_rebase_change_set.vector_clock_id(), + to_rebase_vector_clock_id, &onto_graph, - onto_change_set.vector_clock_id(), + onto_vector_clock_id, ) .expect("detect_conflicts_and_updates"); @@ -3645,21 +3973,154 @@ mod test { ); } + #[test] + fn detect_conflicts_and_updates_remove_modified_item_conflict_same_vector_clocks() { + let actor_id = Ulid::new(); + let vector_clock_id = VectorClockId::new(Ulid::new(), actor_id); + let mut to_rebase_graph = + WorkspaceSnapshotGraph::new(vector_clock_id).expect("unable to make to_rebase_graph"); + + let prototype_node_id = to_rebase_graph.generate_ulid().expect("gen ulid"); + let prototype_node = NodeWeight::new_content( + vector_clock_id, + prototype_node_id, + Ulid::new(), + ContentAddress::AttributePrototype(ContentHash::from("prototype")), + ) + .expect("unable to create prototype node weight"); + + to_rebase_graph + .add_node(prototype_node) + .expect("unable to add node"); + to_rebase_graph + .add_edge( + to_rebase_graph.root(), + EdgeWeight::new(vector_clock_id, EdgeWeightKind::Prototype(None)) + .expect("make edge weight"), + to_rebase_graph + .get_node_index_by_id(prototype_node_id) + .expect("get_node_index_by_id"), + ) + .expect("unable to add edge"); + + // "write" the graph + to_rebase_graph.cleanup(); + to_rebase_graph + .mark_graph_seen(vector_clock_id) + .expect("mark_graph_seen"); + + // "fork" a working changeset from the current one + let mut onto_graph = to_rebase_graph.clone(); + + // After the fork, remove the edge in to_rebase, but modify the edge in onto + to_rebase_graph + .remove_edge( + vector_clock_id, + onto_graph.root(), + to_rebase_graph + .get_node_index_by_id(prototype_node_id) + .expect("get_node_index_by_id"), + EdgeWeightKindDiscriminants::Prototype, + ) + .expect("remove_edge"); + to_rebase_graph.cleanup(); + to_rebase_graph + .mark_graph_seen(vector_clock_id) + .expect("mark_graph_seen"); + + let onto_content_node_idx = onto_graph + .get_node_index_by_id(prototype_node_id) + .expect("get_node_index_by_id"); + + let mut content_node = onto_graph + .get_node_weight(onto_content_node_idx) + .expect("get_node_weight") + .get_content_node_weight_of_kind(ContentAddressDiscriminants::AttributePrototype) + .expect("get_content_node_weight_of_kind"); + + // Modifying this node in onto, after it has been removed in to_rebase + // will produce a RemoveModifiedItem conflict, even though the vector + // clocks are the same, since the same conditions still hold. + content_node + .new_content_hash(ContentHash::from("prototype_change")) + .expect("update_content_hash"); + content_node.increment_vector_clocks(vector_clock_id); + onto_graph + .add_node(NodeWeight::Content(content_node)) + .expect("add_node"); + onto_graph + .replace_references(onto_content_node_idx) + .expect("replace_references"); + onto_graph.cleanup(); + onto_graph + .mark_graph_seen(vector_clock_id) + .expect("mark_graph_seen"); + + let ConflictsAndUpdates { conflicts, updates } = to_rebase_graph + .detect_conflicts_and_updates(vector_clock_id, &onto_graph, vector_clock_id) + .expect("detect_conflicts_and_updates"); + + assert!(updates.is_empty()); + assert_eq!(1, conflicts.len()); + + let container = NodeInformation { + index: to_rebase_graph.root_index, + id: to_rebase_graph + .get_node_weight(to_rebase_graph.root()) + .expect("Unable to get root node") + .id() + .into(), + node_weight_kind: NodeWeightDiscriminants::Content, + }; + let removed_index = onto_graph + .get_node_index_by_id(prototype_node_id) + .expect("get_node_index_by_id"); + let removed_item = NodeInformation { + index: removed_index, + id: onto_graph + .get_node_weight(removed_index) + .expect("Unable to get removed item node weight") + .id() + .into(), + node_weight_kind: NodeWeightDiscriminants::Content, + }; + assert_eq!( + Conflict::RemoveModifiedItem { + container, + removed_item, + }, + conflicts[0], + ); + + // Reversing the detection order should produce the ModifyRemovedItem conflict + let ConflictsAndUpdates { conflicts, updates } = onto_graph + .detect_conflicts_and_updates(vector_clock_id, &to_rebase_graph, vector_clock_id) + .expect("detect_conflicts_and_updates"); + assert!(updates.is_empty()); + assert_eq!(Conflict::ModifyRemovedItem(removed_item), conflicts[0]); + } + #[test] fn test_merge_dependent_value_roots() { - let to_rebase_change_set = ChangeSet::new_local().expect("create cset"); - let mut to_rebase_graph = WorkspaceSnapshotGraph::new(&to_rebase_change_set) + let actor_id = Ulid::new(); + let to_rebase_vector_clock_id = VectorClockId::new(Ulid::new(), actor_id); + let mut to_rebase_graph = WorkspaceSnapshotGraph::new(to_rebase_vector_clock_id) .expect("unable to make to_rebase_graph"); to_rebase_graph - .mark_graph_seen(to_rebase_change_set.vector_clock_id()) + .mark_graph_seen(to_rebase_vector_clock_id) .expect("unable to mark graph seen"); - let onto_change_set = ChangeSet::new_local().expect("new_local"); + let onto_vector_clock_id = VectorClockId::new(Ulid::new(), actor_id); let mut onto_graph = to_rebase_graph.clone(); let cat_node_idx = to_rebase_graph - .add_category_node(&to_rebase_change_set, DependentValueRoots) + .add_category_node( + to_rebase_vector_clock_id, + Ulid::new(), + Ulid::new(), + DependentValueRoots, + ) .expect("able to add dvu root cat node"); let to_rebase_cat_node_orig_weight = to_rebase_graph .get_node_weight(cat_node_idx) @@ -3668,49 +4129,47 @@ mod test { to_rebase_graph .add_edge( to_rebase_graph.root_index, - EdgeWeight::new( - to_rebase_change_set.vector_clock_id(), - EdgeWeightKind::new_use(), - ) - .expect("unable to make edge weigh"), + EdgeWeight::new(to_rebase_vector_clock_id, EdgeWeightKind::new_use()) + .expect("unable to make edge weigh"), cat_node_idx, ) .expect("unable add edge "); let cat_node_idx = onto_graph - .add_category_node(&onto_change_set, DependentValueRoots) + .add_category_node( + onto_vector_clock_id, + Ulid::new(), + Ulid::new(), + DependentValueRoots, + ) .expect("unable to add dvu root cat node"); onto_graph .add_edge( onto_graph.root_index, - EdgeWeight::new(onto_change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(onto_vector_clock_id, EdgeWeightKind::new_use()) .expect("unable to make edge weigh"), cat_node_idx, ) .expect("unable add edge "); - let shared_value_id = to_rebase_change_set - .generate_ulid() - .expect("unable to gen ulid"); + let shared_value_id = to_rebase_graph.generate_ulid().expect("unable to gen ulid"); - let unique_to_rebase_value_id = to_rebase_change_set + let unique_to_rebase_value_id = to_rebase_graph .generate_ulid() .expect("unable to generate ulid"); - let unique_to_onto_value_id = onto_change_set - .generate_ulid() - .expect("unable to generate ulid"); + let unique_to_onto_value_id = onto_graph.generate_ulid().expect("unable to generate ulid"); let to_rebase_value_ids = [unique_to_rebase_value_id, shared_value_id]; let onto_value_ids = [unique_to_onto_value_id, shared_value_id]; - for (graph, change_set, values) in [ + for (graph, vector_clock_id, values) in [ ( &mut to_rebase_graph, - &to_rebase_change_set, + to_rebase_vector_clock_id, &to_rebase_value_ids, ), - (&mut onto_graph, &onto_change_set, &onto_value_ids), + (&mut onto_graph, onto_vector_clock_id, &onto_value_ids), ] { let (cat_id, _) = graph .get_category_node(None, DependentValueRoots) @@ -3718,15 +4177,20 @@ mod test { .expect("cat node for dvu roots not there"); for value_id in values { - let node_weight = NodeWeight::new_dependent_value_root(change_set, *value_id) - .expect("unable to make root node weight"); + let node_weight = NodeWeight::new_dependent_value_root( + vector_clock_id, + Ulid::new(), + Ulid::new(), + *value_id, + ) + .expect("unable to make root node weight"); let dvu_root_idx = graph.add_node(node_weight).expect("unable to add node"); graph .add_edge( graph .get_node_index_by_id(cat_id) .expect("unable to get node index for category"), - EdgeWeight::new(change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(vector_clock_id, EdgeWeightKind::new_use()) .expect("unable to make edge weight"), dvu_root_idx, ) @@ -3737,29 +4201,29 @@ mod test { to_rebase_graph.cleanup(); onto_graph.cleanup(); to_rebase_graph - .mark_graph_seen(to_rebase_change_set.vector_clock_id()) + .mark_graph_seen(to_rebase_vector_clock_id) .expect("unable to mark graph seen"); onto_graph - .mark_graph_seen(onto_change_set.vector_clock_id()) + .mark_graph_seen(onto_vector_clock_id) .expect("unable to mark graph seen"); let ConflictsAndUpdates { conflicts, updates } = to_rebase_graph .detect_conflicts_and_updates( - to_rebase_change_set.vector_clock_id(), + to_rebase_vector_clock_id, &onto_graph, - onto_change_set.vector_clock_id(), + onto_vector_clock_id, ) .expect("able to detect conflicts and updates"); assert!(conflicts.is_empty()); to_rebase_graph - .perform_updates(&to_rebase_change_set, &onto_graph, &updates) + .perform_updates(to_rebase_vector_clock_id, &onto_graph, &updates) .expect("unable to perform updates"); to_rebase_graph.cleanup(); to_rebase_graph - .mark_graph_seen(to_rebase_change_set.vector_clock_id()) + .mark_graph_seen(to_rebase_vector_clock_id) .expect("unable to mark graph seen"); let neighbors_of_root: Vec = to_rebase_graph diff --git a/lib/dal/src/workspace_snapshot/graph/tests/rebase.rs b/lib/dal/src/workspace_snapshot/graph/tests/rebase.rs index cb8689e7f1..dd110c1e11 100644 --- a/lib/dal/src/workspace_snapshot/graph/tests/rebase.rs +++ b/lib/dal/src/workspace_snapshot/graph/tests/rebase.rs @@ -2,9 +2,9 @@ #[cfg(test)] mod test { use pretty_assertions_sorted::assert_eq; - use si_events::ContentHash; + use si_events::ulid::Ulid; + use si_events::{ContentHash, VectorClockId}; - use crate::change_set::ChangeSet; use crate::func::FuncKind; use crate::workspace_snapshot::content_address::ContentAddress; use crate::workspace_snapshot::edge_weight::{EdgeWeight, EdgeWeightKind}; @@ -16,53 +16,55 @@ mod test { #[test] fn simulate_rebase() { - let to_rebase_change_set = ChangeSet::new_local().expect("Unable to create ChangeSet"); - let to_rebase_change_set = &to_rebase_change_set; - let mut to_rebase = WorkspaceSnapshotGraph::new(to_rebase_change_set) + let actor_id = Ulid::new(); + let to_rebase_vector_clock_id = VectorClockId::new(Ulid::new(), actor_id); + let mut to_rebase = WorkspaceSnapshotGraph::new(to_rebase_vector_clock_id) .expect("Unable to create WorkspaceSnapshotGraph"); // Set up the to rebase graph. let schema_category_node_index = to_rebase - .add_category_node(to_rebase_change_set, CategoryNodeKind::Schema) + .add_category_node( + to_rebase_vector_clock_id, + Ulid::new(), + Ulid::new(), + CategoryNodeKind::Schema, + ) .expect("could not add category node"); to_rebase .add_edge( to_rebase.root_index, - EdgeWeight::new( - to_rebase_change_set.vector_clock_id(), - EdgeWeightKind::new_use(), - ) - .expect("could not create edge weight"), + EdgeWeight::new(to_rebase_vector_clock_id, EdgeWeightKind::new_use()) + .expect("could not create edge weight"), schema_category_node_index, ) .expect("could not add edge"); let func_category_node_index = to_rebase - .add_category_node(to_rebase_change_set, CategoryNodeKind::Func) + .add_category_node( + to_rebase_vector_clock_id, + Ulid::new(), + Ulid::new(), + CategoryNodeKind::Func, + ) .expect("could not add category node"); to_rebase .add_edge( to_rebase.root_index, - EdgeWeight::new( - to_rebase_change_set.vector_clock_id(), - EdgeWeightKind::new_use(), - ) - .expect("could not create edge weight"), + EdgeWeight::new(to_rebase_vector_clock_id, EdgeWeightKind::new_use()) + .expect("could not create edge weight"), func_category_node_index, ) .expect("could not add edge"); // Create the onto graph from the to rebase graph. - let onto_change_set = ChangeSet::new_local().expect("Unable to create ChangeSet"); - let onto_change_set = &onto_change_set; + let onto_vector_clock_id = VectorClockId::new(Ulid::new(), actor_id); let mut onto = to_rebase.clone(); // FuncCategory --Use--> Func - let func_id = onto_change_set - .generate_ulid() - .expect("could not generate ulid"); + let func_id = onto.generate_ulid().expect("could not generate ulid"); let func_node_weight = FuncNodeWeight::new( - onto_change_set, + onto_vector_clock_id, func_id, + Ulid::new(), ContentAddress::Func(ContentHash::from("foo")), "foo".to_string(), FuncKind::Intrinsic, @@ -73,7 +75,7 @@ mod test { .expect("could not add node"); onto.add_edge( func_category_node_index, - EdgeWeight::new(onto_change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(onto_vector_clock_id, EdgeWeightKind::new_use()) .expect("could not create edge weight"), func_node_index, ) @@ -81,10 +83,9 @@ mod test { // SchemaCategory --Use--> Schema let schema_node_weight = ContentNodeWeight::new( - onto_change_set, - onto_change_set - .generate_ulid() - .expect("could not generate ulid"), + onto_vector_clock_id, + onto.generate_ulid().expect("could not generate ulid"), + Ulid::new(), ContentAddress::Schema(ContentHash::from("foo")), ) .expect("could not create func node weight"); @@ -93,7 +94,7 @@ mod test { .expect("could not add node"); onto.add_edge( schema_category_node_index, - EdgeWeight::new(onto_change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(onto_vector_clock_id, EdgeWeightKind::new_use()) .expect("could not create edge weight"), schema_node_index, ) @@ -101,10 +102,9 @@ mod test { // Schema --Use--> SchemaVariant let schema_variant_node_weight = ContentNodeWeight::new( - onto_change_set, - onto_change_set - .generate_ulid() - .expect("could not generate ulid"), + onto_vector_clock_id, + onto.generate_ulid().expect("could not generate ulid"), + Ulid::new(), ContentAddress::SchemaVariant(ContentHash::from("foo")), ) .expect("could not create func node weight"); @@ -113,7 +113,7 @@ mod test { .expect("could not add node"); onto.add_edge( schema_node_index, - EdgeWeight::new(onto_change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(onto_vector_clock_id, EdgeWeightKind::new_use()) .expect("could not create edge weight"), schema_variant_node_index, ) @@ -125,7 +125,7 @@ mod test { .expect("could not get node index by id"); onto.add_edge( schema_variant_node_index, - EdgeWeight::new(onto_change_set.vector_clock_id(), EdgeWeightKind::new_use()) + EdgeWeight::new(onto_vector_clock_id, EdgeWeightKind::new_use()) .expect("could not create edge weight"), func_node_index, ) @@ -136,11 +136,7 @@ mod test { conflicts: before_cleanup_conflicts, updates: before_cleanup_updates, } = to_rebase - .detect_conflicts_and_updates( - to_rebase_change_set.vector_clock_id(), - &onto, - onto_change_set.vector_clock_id(), - ) + .detect_conflicts_and_updates(to_rebase_vector_clock_id, &onto, onto_vector_clock_id) .expect("could not detect conflicts and updates"); // Cleanup and check node count. @@ -153,11 +149,7 @@ mod test { // Detect conflicts and updates. Ensure cleanup did not affect the results. let ConflictsAndUpdates { conflicts, updates } = to_rebase - .detect_conflicts_and_updates( - to_rebase_change_set.vector_clock_id(), - &onto, - onto_change_set.vector_clock_id(), - ) + .detect_conflicts_and_updates(to_rebase_vector_clock_id, &onto, onto_vector_clock_id) .expect("could not detect conflicts and updates"); assert!(conflicts.is_empty()); assert_eq!( @@ -184,7 +176,7 @@ mod test { // Perform the updates. In the future, we may want to see if the onto and resulting to // rebase graphs are logically equivalent after updates are performed. to_rebase - .perform_updates(to_rebase_change_set, &onto, &updates) + .perform_updates(to_rebase_vector_clock_id, &onto, &updates) .expect("could not perform updates"); } } diff --git a/lib/dal/src/workspace_snapshot/node_weight.rs b/lib/dal/src/workspace_snapshot/node_weight.rs index 43d4b7203a..ba8ae69115 100644 --- a/lib/dal/src/workspace_snapshot/node_weight.rs +++ b/lib/dal/src/workspace_snapshot/node_weight.rs @@ -10,7 +10,6 @@ use crate::workspace_snapshot::vector_clock::VectorClockId; use crate::EdgeWeightKindDiscriminants; use crate::{ action::prototype::ActionKind, - change_set::{ChangeSet, ChangeSetError}, workspace_snapshot::{ content_address::ContentAddress, vector_clock::{HasVectorClocks, VectorClock, VectorClockError}, @@ -59,8 +58,8 @@ pub enum NodeWeightError { CannotSetOrderOnKind, #[error("Cannot update root node's content hash")] CannotUpdateRootNodeContentHash, - #[error("ChangeSet error: {0}")] - ChangeSet(#[from] ChangeSetError), + // #[error("ChangeSet error: {0}")] + // ChangeSet(#[from] ChangeSetError), #[error("Incompatible node weights")] IncompatibleNodeWeightVariants, #[error("Invalid ContentAddress variant ({0}) for NodeWeight variant ({1})")] @@ -311,11 +310,11 @@ impl NodeWeight { pub fn set_vector_clock_recently_seen_to( &mut self, - change_set: &ChangeSet, + vector_clock_id: VectorClockId, new_clock_value: DateTime, ) { self.vector_clock_recently_seen_mut() - .inc_to(change_set.vector_clock_id(), new_clock_value); + .inc_to(vector_clock_id, new_clock_value); } pub fn remove_vector_clock_entries(&mut self, allow_list: &[VectorClockId]) { @@ -514,37 +513,45 @@ impl NodeWeight { } pub fn new_content( - change_set: &ChangeSet, - content_id: Ulid, + vector_clock_id: VectorClockId, + id: Ulid, + lineage_id: Ulid, kind: ContentAddress, ) -> NodeWeightResult { Ok(NodeWeight::Content(ContentNodeWeight::new( - change_set, content_id, kind, + vector_clock_id, + id, + lineage_id, + kind, )?)) } pub fn new_action( - change_set: &ChangeSet, + vector_clock_id: VectorClockId, originating_change_set_id: ChangeSetId, action_id: Ulid, + lineage_id: Ulid, ) -> NodeWeightResult { Ok(NodeWeight::Action(ActionNodeWeight::new( - change_set, + vector_clock_id, originating_change_set_id, action_id, + lineage_id, )?)) } pub fn new_action_prototype( - change_set: &ChangeSet, - action_id: Ulid, + vector_clock_id: VectorClockId, + action_prototype_id: Ulid, + lineage_id: Ulid, kind: ActionKind, name: String, description: Option, ) -> NodeWeightResult { Ok(NodeWeight::ActionPrototype(ActionPrototypeNodeWeight::new( - change_set, - action_id, + vector_clock_id, + action_prototype_id, + lineage_id, kind, name, description, @@ -552,50 +559,58 @@ impl NodeWeight { } pub fn new_attribute_value( - change_set: &ChangeSet, + vector_clock_id: VectorClockId, attribute_value_id: Ulid, + lineage_id: Ulid, unprocessed_value: Option, value: Option, ) -> NodeWeightResult { Ok(NodeWeight::AttributeValue(AttributeValueNodeWeight::new( - change_set, + vector_clock_id, attribute_value_id, + lineage_id, unprocessed_value, value, )?)) } pub fn new_dependent_value_root( - change_set: &ChangeSet, + vector_clock_id: VectorClockId, + id: Ulid, + lineage_id: Ulid, value_id: Ulid, ) -> NodeWeightResult { Ok(NodeWeight::DependentValueRoot( - DependentValueRootNodeWeight::new(change_set, value_id)?, + DependentValueRootNodeWeight::new(vector_clock_id, id, lineage_id, value_id)?, )) } pub fn new_component( - change_set: &ChangeSet, + vector_clock_id: VectorClockId, component_id: Ulid, + lineage_id: Ulid, content_hash: ContentHash, ) -> NodeWeightResult { Ok(NodeWeight::Component(ComponentNodeWeight::new( - change_set, + vector_clock_id, component_id, + lineage_id, ContentAddress::Component(content_hash), )?)) } pub fn new_prop( - change_set: &ChangeSet, + vector_clock_id: VectorClockId, prop_id: Ulid, + lineage_id: Ulid, prop_kind: PropKind, name: impl AsRef, content_hash: ContentHash, ) -> NodeWeightResult { Ok(NodeWeight::Prop(PropNodeWeight::new( - change_set, + vector_clock_id, prop_id, + lineage_id, ContentAddress::Prop(content_hash), prop_kind, name.as_ref().to_string(), @@ -603,15 +618,17 @@ impl NodeWeight { } pub fn new_func( - change_set: &ChangeSet, + vector_clock_id: VectorClockId, func_id: Ulid, + lineage_id: Ulid, name: impl AsRef, func_kind: FuncKind, content_hash: ContentHash, ) -> NodeWeightResult { Ok(NodeWeight::Func(FuncNodeWeight::new( - change_set, + vector_clock_id, func_id, + lineage_id, ContentAddress::Func(content_hash), name.as_ref().to_string(), func_kind, @@ -619,42 +636,48 @@ impl NodeWeight { } pub fn new_func_argument( - change_set: &ChangeSet, + vector_clock_id: VectorClockId, func_arg_id: Ulid, + lineage_id: Ulid, name: impl AsRef, content_hash: ContentHash, ) -> NodeWeightResult { Ok(NodeWeight::FuncArgument(FuncArgumentNodeWeight::new( - change_set, + vector_clock_id, func_arg_id, + lineage_id, ContentAddress::FuncArg(content_hash), name.as_ref().to_string(), )?)) } pub fn new_attribute_prototype_argument( - change_set: &ChangeSet, + vector_clock_id: VectorClockId, attribute_prototype_argument_id: Ulid, + lineage_id: Ulid, targets: Option, ) -> NodeWeightResult { Ok(NodeWeight::AttributePrototypeArgument( AttributePrototypeArgumentNodeWeight::new( - change_set, + vector_clock_id, attribute_prototype_argument_id, + lineage_id, targets, )?, )) } pub fn new_secret( - change_set: &ChangeSet, + vector_clock_id: VectorClockId, secret_id: Ulid, + lineage_id: Ulid, encrypted_secret_key: EncryptedSecretKey, content_hash: ContentHash, ) -> NodeWeightResult { Ok(NodeWeight::Secret(SecretNodeWeight::new( - change_set, + vector_clock_id, secret_id, + lineage_id, ContentAddress::Secret(content_hash), encrypted_secret_key, )?)) diff --git a/lib/dal/src/workspace_snapshot/node_weight/action_node_weight.rs b/lib/dal/src/workspace_snapshot/node_weight/action_node_weight.rs index 85ad8385bf..1394a63e2b 100644 --- a/lib/dal/src/workspace_snapshot/node_weight/action_node_weight.rs +++ b/lib/dal/src/workspace_snapshot/node_weight/action_node_weight.rs @@ -1,5 +1,5 @@ use serde::{Deserialize, Serialize}; -use si_events::{merkle_tree_hash::MerkleTreeHash, ulid::Ulid, ContentHash}; +use si_events::{merkle_tree_hash::MerkleTreeHash, ulid::Ulid, ContentHash, VectorClockId}; use crate::{ action::ActionState, @@ -8,7 +8,7 @@ use crate::{ graph::LineageId, vector_clock::{HasVectorClocks, VectorClock}, }, - ChangeSet, ChangeSetId, EdgeWeightKindDiscriminants, + ChangeSetId, EdgeWeightKindDiscriminants, }; use super::NodeWeightResult; @@ -29,18 +29,19 @@ pub struct ActionNodeWeight { impl ActionNodeWeight { pub fn new( - change_set: &ChangeSet, + vector_clock_id: VectorClockId, originating_change_set_id: ChangeSetId, id: Ulid, + lineage_id: Ulid, ) -> NodeWeightResult { - let new_vector_clock = VectorClock::new(change_set.vector_clock_id()); + let new_vector_clock = VectorClock::new(vector_clock_id); Ok(Self { id, state: ActionState::Queued, func_execution_pk: None, originating_changeset_id: originating_change_set_id, - lineage_id: change_set.generate_ulid()?, + lineage_id, merkle_tree_hash: MerkleTreeHash::default(), vector_clock_first_seen: new_vector_clock.clone(), vector_clock_recently_seen: new_vector_clock.clone(), diff --git a/lib/dal/src/workspace_snapshot/node_weight/action_prototype_node_weight.rs b/lib/dal/src/workspace_snapshot/node_weight/action_prototype_node_weight.rs index fe43b8d53f..5f03e40d4e 100644 --- a/lib/dal/src/workspace_snapshot/node_weight/action_prototype_node_weight.rs +++ b/lib/dal/src/workspace_snapshot/node_weight/action_prototype_node_weight.rs @@ -1,5 +1,5 @@ use serde::{Deserialize, Serialize}; -use si_events::{merkle_tree_hash::MerkleTreeHash, ulid::Ulid, ContentHash}; +use si_events::{merkle_tree_hash::MerkleTreeHash, ulid::Ulid, ContentHash, VectorClockId}; use crate::{ action::prototype::ActionKind, @@ -7,7 +7,7 @@ use crate::{ graph::LineageId, vector_clock::{HasVectorClocks, VectorClock}, }, - ChangeSet, EdgeWeightKindDiscriminants, + EdgeWeightKindDiscriminants, }; use super::NodeWeightResult; @@ -29,13 +29,14 @@ pub struct ActionPrototypeNodeWeight { impl ActionPrototypeNodeWeight { pub fn new( - change_set: &ChangeSet, + vector_clock_id: VectorClockId, id: Ulid, + lineage_id: Ulid, kind: ActionKind, name: impl AsRef, description: Option>, ) -> NodeWeightResult { - let new_vector_clock = VectorClock::new(change_set.vector_clock_id()); + let new_vector_clock = VectorClock::new(vector_clock_id); let name = name.as_ref().to_string(); let description = description.map(|d| d.as_ref().to_string()); @@ -44,7 +45,7 @@ impl ActionPrototypeNodeWeight { kind, name, description, - lineage_id: change_set.generate_ulid()?, + lineage_id, merkle_tree_hash: MerkleTreeHash::default(), vector_clock_first_seen: new_vector_clock.clone(), vector_clock_recently_seen: new_vector_clock.clone(), diff --git a/lib/dal/src/workspace_snapshot/node_weight/attribute_prototype_argument_node_weight.rs b/lib/dal/src/workspace_snapshot/node_weight/attribute_prototype_argument_node_weight.rs index d06f2af7dd..ade107bbf2 100644 --- a/lib/dal/src/workspace_snapshot/node_weight/attribute_prototype_argument_node_weight.rs +++ b/lib/dal/src/workspace_snapshot/node_weight/attribute_prototype_argument_node_weight.rs @@ -1,8 +1,7 @@ use serde::{Deserialize, Serialize}; -use si_events::{merkle_tree_hash::MerkleTreeHash, ulid::Ulid, ContentHash}; +use si_events::{merkle_tree_hash::MerkleTreeHash, ulid::Ulid, ContentHash, VectorClockId}; use crate::{ - change_set::ChangeSet, workspace_snapshot::{ graph::LineageId, node_weight::NodeWeightResult, @@ -33,18 +32,19 @@ pub struct AttributePrototypeArgumentNodeWeight { impl AttributePrototypeArgumentNodeWeight { pub fn new( - change_set: &ChangeSet, + vector_clock_id: VectorClockId, id: Ulid, + lineage_id: Ulid, targets: Option, ) -> NodeWeightResult { Ok(Self { id, - lineage_id: change_set.generate_ulid()?, + lineage_id, merkle_tree_hash: MerkleTreeHash::default(), targets, - vector_clock_first_seen: VectorClock::new(change_set.vector_clock_id()), - vector_clock_recently_seen: VectorClock::new(change_set.vector_clock_id()), - vector_clock_write: VectorClock::new(change_set.vector_clock_id()), + vector_clock_first_seen: VectorClock::new(vector_clock_id), + vector_clock_recently_seen: VectorClock::new(vector_clock_id), + vector_clock_write: VectorClock::new(vector_clock_id), timestamp: Timestamp::now(), }) } diff --git a/lib/dal/src/workspace_snapshot/node_weight/attribute_value_node_weight.rs b/lib/dal/src/workspace_snapshot/node_weight/attribute_value_node_weight.rs index ba5e0835d1..ded04924e5 100644 --- a/lib/dal/src/workspace_snapshot/node_weight/attribute_value_node_weight.rs +++ b/lib/dal/src/workspace_snapshot/node_weight/attribute_value_node_weight.rs @@ -1,8 +1,7 @@ use serde::{Deserialize, Serialize}; -use si_events::{merkle_tree_hash::MerkleTreeHash, ulid::Ulid, ContentHash}; +use si_events::{merkle_tree_hash::MerkleTreeHash, ulid::Ulid, ContentHash, VectorClockId}; use crate::{ - change_set::ChangeSet, func::FuncExecutionPk, workspace_snapshot::{ content_address::ContentAddress, @@ -34,18 +33,19 @@ pub struct AttributeValueNodeWeight { impl AttributeValueNodeWeight { pub fn new( - change_set: &ChangeSet, + vector_clock_id: VectorClockId, id: Ulid, + lineage_id: Ulid, unprocessed_value: Option, value: Option, ) -> NodeWeightResult { Ok(Self { id, - lineage_id: change_set.generate_ulid()?, + lineage_id, merkle_tree_hash: MerkleTreeHash::default(), - vector_clock_first_seen: VectorClock::new(change_set.vector_clock_id()), - vector_clock_recently_seen: VectorClock::new(change_set.vector_clock_id()), - vector_clock_write: VectorClock::new(change_set.vector_clock_id()), + vector_clock_first_seen: VectorClock::new(vector_clock_id), + vector_clock_recently_seen: VectorClock::new(vector_clock_id), + vector_clock_write: VectorClock::new(vector_clock_id), unprocessed_value, value, func_execution_pk: None, diff --git a/lib/dal/src/workspace_snapshot/node_weight/category_node_weight.rs b/lib/dal/src/workspace_snapshot/node_weight/category_node_weight.rs index 08d16fbf00..264b4033cb 100644 --- a/lib/dal/src/workspace_snapshot/node_weight/category_node_weight.rs +++ b/lib/dal/src/workspace_snapshot/node_weight/category_node_weight.rs @@ -1,8 +1,8 @@ use serde::{Deserialize, Serialize}; +use si_events::VectorClockId; use si_events::{merkle_tree_hash::MerkleTreeHash, ulid::Ulid, ContentHash}; use strum::{Display, EnumIter}; -use crate::change_set::ChangeSet; use crate::workspace_snapshot::vector_clock::HasVectorClocks; use crate::workspace_snapshot::{node_weight::NodeWeightResult, vector_clock::VectorClock}; use crate::EdgeWeightKindDiscriminants; @@ -67,16 +67,21 @@ impl CategoryNodeWeight { self.merkle_tree_hash = new_hash; } - pub fn new(change_set: &ChangeSet, kind: CategoryNodeKind) -> NodeWeightResult { + pub fn new( + id: Ulid, + lineage_id: Ulid, + vector_clock_id: VectorClockId, + kind: CategoryNodeKind, + ) -> NodeWeightResult { Ok(Self { - id: change_set.generate_ulid()?, - lineage_id: change_set.generate_ulid()?, + id, + lineage_id, kind, - vector_clock_write: VectorClock::new(change_set.vector_clock_id()), - vector_clock_first_seen: VectorClock::new(change_set.vector_clock_id()), + vector_clock_write: VectorClock::new(vector_clock_id), + vector_clock_first_seen: VectorClock::new(vector_clock_id), content_hash: ContentHash::from(&serde_json::json![kind]), merkle_tree_hash: Default::default(), - vector_clock_recently_seen: Default::default(), + vector_clock_recently_seen: VectorClock::new(vector_clock_id), }) } diff --git a/lib/dal/src/workspace_snapshot/node_weight/component_node_weight.rs b/lib/dal/src/workspace_snapshot/node_weight/component_node_weight.rs index 6291b5fe2e..7e1a1a19c6 100644 --- a/lib/dal/src/workspace_snapshot/node_weight/component_node_weight.rs +++ b/lib/dal/src/workspace_snapshot/node_weight/component_node_weight.rs @@ -1,8 +1,7 @@ use serde::{Deserialize, Serialize}; -use si_events::{merkle_tree_hash::MerkleTreeHash, ulid::Ulid, ContentHash}; +use si_events::{merkle_tree_hash::MerkleTreeHash, ulid::Ulid, ContentHash, VectorClockId}; use crate::{ - change_set::ChangeSet, workspace_snapshot::{ content_address::{ContentAddress, ContentAddressDiscriminants}, graph::LineageId, @@ -27,15 +26,16 @@ pub struct ComponentNodeWeight { impl ComponentNodeWeight { pub fn new( - change_set: &ChangeSet, + vector_clock_id: VectorClockId, id: Ulid, + lineage_id: Ulid, content_address: ContentAddress, ) -> NodeWeightResult { - let new_vector_clock = VectorClock::new(change_set.vector_clock_id()); + let new_vector_clock = VectorClock::new(vector_clock_id); Ok(Self { id, - lineage_id: change_set.generate_ulid()?, + lineage_id, content_address, merkle_tree_hash: MerkleTreeHash::default(), to_delete: false, diff --git a/lib/dal/src/workspace_snapshot/node_weight/content_node_weight.rs b/lib/dal/src/workspace_snapshot/node_weight/content_node_weight.rs index b360aa8f48..75bc142b60 100644 --- a/lib/dal/src/workspace_snapshot/node_weight/content_node_weight.rs +++ b/lib/dal/src/workspace_snapshot/node_weight/content_node_weight.rs @@ -1,17 +1,15 @@ use serde::{Deserialize, Serialize}; use si_events::merkle_tree_hash::MerkleTreeHash; +use si_events::VectorClockId; use si_events::{ulid::Ulid, ContentHash}; -use crate::EdgeWeightKindDiscriminants; -use crate::{ - change_set::ChangeSet, - workspace_snapshot::{ - content_address::ContentAddress, - graph::LineageId, - node_weight::{NodeWeightError, NodeWeightResult}, - vector_clock::{HasVectorClocks, VectorClock}, - }, +use crate::workspace_snapshot::{ + content_address::ContentAddress, + graph::LineageId, + node_weight::{NodeWeightError, NodeWeightResult}, + vector_clock::{HasVectorClocks, VectorClock}, }; +use crate::EdgeWeightKindDiscriminants; #[derive(Clone, Serialize, Deserialize)] pub struct ContentNodeWeight { @@ -42,18 +40,19 @@ pub struct ContentNodeWeight { impl ContentNodeWeight { pub fn new( - change_set: &ChangeSet, + vector_clock_id: VectorClockId, id: Ulid, + lineage_id: Ulid, content_address: ContentAddress, ) -> NodeWeightResult { Ok(Self { id, - lineage_id: change_set.generate_ulid()?, + lineage_id, content_address, merkle_tree_hash: MerkleTreeHash::default(), - vector_clock_first_seen: VectorClock::new(change_set.vector_clock_id()), - vector_clock_recently_seen: VectorClock::new(change_set.vector_clock_id()), - vector_clock_write: VectorClock::new(change_set.vector_clock_id()), + vector_clock_first_seen: VectorClock::new(vector_clock_id), + vector_clock_recently_seen: VectorClock::new(vector_clock_id), + vector_clock_write: VectorClock::new(vector_clock_id), to_delete: false, }) } diff --git a/lib/dal/src/workspace_snapshot/node_weight/dependent_value_root_node_weight.rs b/lib/dal/src/workspace_snapshot/node_weight/dependent_value_root_node_weight.rs index eee79c0ded..126666f4be 100644 --- a/lib/dal/src/workspace_snapshot/node_weight/dependent_value_root_node_weight.rs +++ b/lib/dal/src/workspace_snapshot/node_weight/dependent_value_root_node_weight.rs @@ -1,8 +1,9 @@ use serde::{Deserialize, Serialize}; +use si_events::VectorClockId; use si_events::{merkle_tree_hash::MerkleTreeHash, ulid::Ulid, ContentHash}; use crate::workspace_snapshot::vector_clock::{HasVectorClocks, VectorClock}; -use crate::{ChangeSet, EdgeWeightKindDiscriminants}; +use crate::EdgeWeightKindDiscriminants; use super::NodeWeightResult; @@ -39,29 +40,34 @@ impl DependentValueRootNodeWeight { self.lineage_id } - pub fn merge_clocks(&mut self, change_set: &ChangeSet, other: &Self) { + pub fn merge_clocks(&mut self, vector_clock_id: VectorClockId, other: &Self) { self.vector_clock_write - .merge(change_set.vector_clock_id(), other.vector_clock_write()); - self.vector_clock_first_seen.merge( - change_set.vector_clock_id(), - other.vector_clock_first_seen(), - ); + .merge(vector_clock_id, other.vector_clock_write()); + self.vector_clock_first_seen + .merge(vector_clock_id, other.vector_clock_first_seen()); + self.vector_clock_recently_seen + .merge(vector_clock_id, other.vector_clock_recently_seen()); } pub fn merkle_tree_hash(&self) -> MerkleTreeHash { self.merkle_tree_hash } - pub fn new(change_set: &ChangeSet, value_id: Ulid) -> NodeWeightResult { + pub fn new( + vector_clock_id: VectorClockId, + id: Ulid, + lineage_id: Ulid, + value_id: Ulid, + ) -> NodeWeightResult { Ok(Self { - id: change_set.generate_ulid()?, - lineage_id: change_set.generate_ulid()?, + id, + lineage_id, value_id, touch_count: 0, - vector_clock_write: VectorClock::new(change_set.vector_clock_id()), - vector_clock_first_seen: VectorClock::new(change_set.vector_clock_id()), + vector_clock_write: VectorClock::new(vector_clock_id), + vector_clock_first_seen: VectorClock::new(vector_clock_id), merkle_tree_hash: Default::default(), - vector_clock_recently_seen: Default::default(), + vector_clock_recently_seen: VectorClock::new(vector_clock_id), }) } diff --git a/lib/dal/src/workspace_snapshot/node_weight/func_argument_node_weight.rs b/lib/dal/src/workspace_snapshot/node_weight/func_argument_node_weight.rs index 78edc6de84..74ea2ee7b1 100644 --- a/lib/dal/src/workspace_snapshot/node_weight/func_argument_node_weight.rs +++ b/lib/dal/src/workspace_snapshot/node_weight/func_argument_node_weight.rs @@ -1,8 +1,7 @@ use serde::{Deserialize, Serialize}; -use si_events::{merkle_tree_hash::MerkleTreeHash, ulid::Ulid, ContentHash}; +use si_events::{merkle_tree_hash::MerkleTreeHash, ulid::Ulid, ContentHash, VectorClockId}; use crate::{ - change_set::ChangeSet, workspace_snapshot::{ content_address::{ContentAddress, ContentAddressDiscriminants}, graph::LineageId, @@ -27,20 +26,21 @@ pub struct FuncArgumentNodeWeight { impl FuncArgumentNodeWeight { pub fn new( - change_set: &ChangeSet, + vector_clock_id: VectorClockId, id: Ulid, + lineage_id: Ulid, content_address: ContentAddress, name: String, ) -> NodeWeightResult { Ok(Self { id, - lineage_id: change_set.generate_ulid()?, + lineage_id, content_address, merkle_tree_hash: MerkleTreeHash::default(), name, - vector_clock_first_seen: VectorClock::new(change_set.vector_clock_id()), - vector_clock_recently_seen: VectorClock::new(change_set.vector_clock_id()), - vector_clock_write: VectorClock::new(change_set.vector_clock_id()), + vector_clock_first_seen: VectorClock::new(vector_clock_id), + vector_clock_recently_seen: VectorClock::new(vector_clock_id), + vector_clock_write: VectorClock::new(vector_clock_id), }) } diff --git a/lib/dal/src/workspace_snapshot/node_weight/func_node_weight.rs b/lib/dal/src/workspace_snapshot/node_weight/func_node_weight.rs index b52dde4bf1..23a7e10c6d 100644 --- a/lib/dal/src/workspace_snapshot/node_weight/func_node_weight.rs +++ b/lib/dal/src/workspace_snapshot/node_weight/func_node_weight.rs @@ -1,19 +1,17 @@ use serde::{Deserialize, Serialize}; +use si_events::VectorClockId; use si_events::{merkle_tree_hash::MerkleTreeHash, ulid::Ulid, ContentHash}; use crate::func::FuncKind; use crate::workspace_snapshot::content_address::ContentAddressDiscriminants; use crate::workspace_snapshot::vector_clock::HasVectorClocks; -use crate::EdgeWeightKindDiscriminants; -use crate::{ - change_set::ChangeSet, - workspace_snapshot::{ - content_address::ContentAddress, - graph::LineageId, - node_weight::{NodeWeightError, NodeWeightResult}, - vector_clock::VectorClock, - }, +use crate::workspace_snapshot::{ + content_address::ContentAddress, + graph::LineageId, + node_weight::{NodeWeightError, NodeWeightResult}, + vector_clock::VectorClock, }; +use crate::EdgeWeightKindDiscriminants; #[derive(Clone, Serialize, Deserialize)] pub struct FuncNodeWeight { @@ -30,22 +28,23 @@ pub struct FuncNodeWeight { impl FuncNodeWeight { pub fn new( - change_set: &ChangeSet, + vector_clock_id: VectorClockId, id: Ulid, + lineage_id: Ulid, content_address: ContentAddress, name: String, func_kind: FuncKind, ) -> NodeWeightResult { Ok(Self { id, - lineage_id: change_set.generate_ulid()?, + lineage_id, content_address, merkle_tree_hash: MerkleTreeHash::default(), name, func_kind, - vector_clock_first_seen: VectorClock::new(change_set.vector_clock_id()), - vector_clock_recently_seen: VectorClock::new(change_set.vector_clock_id()), - vector_clock_write: VectorClock::new(change_set.vector_clock_id()), + vector_clock_first_seen: VectorClock::new(vector_clock_id), + vector_clock_recently_seen: VectorClock::new(vector_clock_id), + vector_clock_write: VectorClock::new(vector_clock_id), }) } diff --git a/lib/dal/src/workspace_snapshot/node_weight/ordering_node_weight.rs b/lib/dal/src/workspace_snapshot/node_weight/ordering_node_weight.rs index b3e46228c2..f4098a183f 100644 --- a/lib/dal/src/workspace_snapshot/node_weight/ordering_node_weight.rs +++ b/lib/dal/src/workspace_snapshot/node_weight/ordering_node_weight.rs @@ -2,7 +2,6 @@ use serde::{Deserialize, Serialize}; use si_events::{merkle_tree_hash::MerkleTreeHash, ulid::Ulid, ContentHash}; use super::NodeWeightError; -use crate::change_set::ChangeSet; use crate::workspace_snapshot::vector_clock::{HasVectorClocks, VectorClockId}; use crate::workspace_snapshot::{node_weight::NodeWeightResult, vector_clock::VectorClock}; use crate::EdgeWeightKindDiscriminants; @@ -41,12 +40,17 @@ impl OrderingNodeWeight { self.merkle_tree_hash } - pub fn new(change_set: &ChangeSet) -> NodeWeightResult { + pub fn new( + id: Ulid, + lineage_id: Ulid, + vector_clock_id: VectorClockId, + ) -> NodeWeightResult { Ok(Self { - id: change_set.generate_ulid()?, - lineage_id: change_set.generate_ulid()?, - vector_clock_write: VectorClock::new(change_set.vector_clock_id()), - vector_clock_first_seen: VectorClock::new(change_set.vector_clock_id()), + id, + lineage_id, + vector_clock_write: VectorClock::new(vector_clock_id), + vector_clock_first_seen: VectorClock::new(vector_clock_id), + vector_clock_recently_seen: VectorClock::new(vector_clock_id), ..Default::default() }) } diff --git a/lib/dal/src/workspace_snapshot/node_weight/prop_node_weight.rs b/lib/dal/src/workspace_snapshot/node_weight/prop_node_weight.rs index ad0a9132ff..5e6a8c2534 100644 --- a/lib/dal/src/workspace_snapshot/node_weight/prop_node_weight.rs +++ b/lib/dal/src/workspace_snapshot/node_weight/prop_node_weight.rs @@ -1,11 +1,11 @@ use serde::{Deserialize, Serialize}; +use si_events::VectorClockId; use si_events::{merkle_tree_hash::MerkleTreeHash, ulid::Ulid, ContentHash}; use crate::workspace_snapshot::content_address::ContentAddressDiscriminants; use crate::workspace_snapshot::vector_clock::HasVectorClocks; use crate::EdgeWeightKindDiscriminants; use crate::{ - change_set::ChangeSet, workspace_snapshot::{ content_address::ContentAddress, graph::LineageId, @@ -31,23 +31,24 @@ pub struct PropNodeWeight { impl PropNodeWeight { pub fn new( - change_set: &ChangeSet, + vector_clock_id: VectorClockId, id: Ulid, + lineage_id: Ulid, content_address: ContentAddress, kind: PropKind, name: String, ) -> NodeWeightResult { Ok(Self { id, - lineage_id: change_set.generate_ulid()?, + lineage_id, content_address, merkle_tree_hash: MerkleTreeHash::default(), kind, name, can_be_used_as_prototype_arg: false, - vector_clock_first_seen: VectorClock::new(change_set.vector_clock_id()), - vector_clock_recently_seen: VectorClock::new(change_set.vector_clock_id()), - vector_clock_write: VectorClock::new(change_set.vector_clock_id()), + vector_clock_first_seen: VectorClock::new(vector_clock_id), + vector_clock_recently_seen: VectorClock::new(vector_clock_id), + vector_clock_write: VectorClock::new(vector_clock_id), }) } diff --git a/lib/dal/src/workspace_snapshot/node_weight/secret_node_weight.rs b/lib/dal/src/workspace_snapshot/node_weight/secret_node_weight.rs index 6afd1f28a1..0401f9b8c3 100644 --- a/lib/dal/src/workspace_snapshot/node_weight/secret_node_weight.rs +++ b/lib/dal/src/workspace_snapshot/node_weight/secret_node_weight.rs @@ -1,18 +1,16 @@ use serde::{Deserialize, Serialize}; +use si_events::VectorClockId; use si_events::{merkle_tree_hash::MerkleTreeHash, ulid::Ulid, ContentHash, EncryptedSecretKey}; use crate::workspace_snapshot::content_address::ContentAddressDiscriminants; use crate::workspace_snapshot::vector_clock::HasVectorClocks; -use crate::EdgeWeightKindDiscriminants; -use crate::{ - change_set::ChangeSet, - workspace_snapshot::{ - content_address::ContentAddress, - graph::LineageId, - node_weight::{NodeWeightError, NodeWeightResult}, - vector_clock::VectorClock, - }, +use crate::workspace_snapshot::{ + content_address::ContentAddress, + graph::LineageId, + node_weight::{NodeWeightError, NodeWeightResult}, + vector_clock::VectorClock, }; +use crate::EdgeWeightKindDiscriminants; #[derive(Clone, Serialize, Deserialize)] pub struct SecretNodeWeight { @@ -28,19 +26,20 @@ pub struct SecretNodeWeight { impl SecretNodeWeight { pub fn new( - change_set: &ChangeSet, + vector_clock_id: VectorClockId, id: Ulid, + lineage_id: Ulid, content_address: ContentAddress, encrypted_secret_key: EncryptedSecretKey, ) -> NodeWeightResult { Ok(Self { id, - lineage_id: change_set.generate_ulid()?, + lineage_id, content_address, merkle_tree_hash: MerkleTreeHash::default(), - vector_clock_first_seen: VectorClock::new(change_set.vector_clock_id()), - vector_clock_recently_seen: VectorClock::new(change_set.vector_clock_id()), - vector_clock_write: VectorClock::new(change_set.vector_clock_id()), + vector_clock_first_seen: VectorClock::new(vector_clock_id), + vector_clock_recently_seen: VectorClock::new(vector_clock_id), + vector_clock_write: VectorClock::new(vector_clock_id), encrypted_secret_key, }) } diff --git a/lib/dal/src/workspace_snapshot/vector_clock.rs b/lib/dal/src/workspace_snapshot/vector_clock.rs index fbc92f0162..032dbda623 100644 --- a/lib/dal/src/workspace_snapshot/vector_clock.rs +++ b/lib/dal/src/workspace_snapshot/vector_clock.rs @@ -6,8 +6,10 @@ use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use thiserror::Error; -use crate::pk; use crate::workspace_snapshot::lamport_clock::{LamportClock, LamportClockError}; +use crate::{pk, ChangeSetId}; + +pub use si_events::{VectorClockActorId, VectorClockChangeSetId, VectorClockId}; #[derive(Debug, Error)] pub enum VectorClockError { @@ -17,7 +19,7 @@ pub enum VectorClockError { pub type VectorClockResult = Result; -pk!(VectorClockId); +pk!(DeprecatedVectorClockId); #[derive(Default, Serialize, Deserialize, PartialEq, Eq, Clone)] pub struct VectorClock { @@ -48,6 +50,18 @@ impl VectorClock { } } + pub fn max_for_change_set_id( + &self, + change_set_id: ChangeSetId, + ) -> Option<(VectorClockId, LamportClock)> { + let change_set_id = VectorClockChangeSetId::new(change_set_id.into_inner().into()); + self.entries + .iter() + .filter(|(clock_id, _)| clock_id.change_set_id() == change_set_id) + .max_by(|(_, clock_a), (_, clock_b)| (**clock_a).cmp(*clock_b)) + .map(|(clock_id, clock)| (*clock_id, *clock)) + } + pub fn entry_for(&self, vector_clock_id: VectorClockId) -> Option { self.entries.get(&vector_clock_id).copied() } diff --git a/lib/dal/tests/integration_test/component.rs b/lib/dal/tests/integration_test/component.rs index 3e70fe59c7..befeac9d6d 100644 --- a/lib/dal/tests/integration_test/component.rs +++ b/lib/dal/tests/integration_test/component.rs @@ -502,6 +502,8 @@ async fn through_the_wormholes_child_value_reactivity(ctx: &mut DalContext) { assert_eq!(possible_world_a, view); + dbg!("committing"); + ChangeSetTestHelpers::commit_and_update_snapshot_to_visibility(ctx) .await .expect("could not commit and update snapshot to visibility"); diff --git a/lib/dal/tests/integration_test/func/authoring/create_func.rs b/lib/dal/tests/integration_test/func/authoring/create_func.rs index 760fcf3dc7..b358f1ced5 100644 --- a/lib/dal/tests/integration_test/func/authoring/create_func.rs +++ b/lib/dal/tests/integration_test/func/authoring/create_func.rs @@ -294,7 +294,7 @@ async fn create_attribute_override_dynamic_func_for_prop(ctx: &mut DalContext) { .get_workspace_default_change_set_id() .await .expect("Unable to find HEAD changeset id"); - ctx.update_visibility_and_snapshot_to_visibility_no_editing_change_set(head_change_set) + ctx.update_visibility_and_snapshot_to_visibility(head_change_set) .await .expect("Unable to go back to HEAD"); let head_func = Func::find_id_by_name(ctx, func_name) @@ -364,7 +364,7 @@ async fn create_attribute_override_dynamic_func_for_output_socket(ctx: &mut DalC .get_workspace_default_change_set_id() .await .expect("Unable to find HEAD changeset id"); - ctx.update_visibility_and_snapshot_to_visibility_no_editing_change_set(head_change_set) + ctx.update_visibility_and_snapshot_to_visibility(head_change_set) .await .expect("Unable to go back to HEAD"); let head_func = Func::find_id_by_name(ctx, func_name) diff --git a/lib/rebaser-server/src/rebase.rs b/lib/rebaser-server/src/rebase.rs index 9011c455d1..5d111521bd 100644 --- a/lib/rebaser-server/src/rebase.rs +++ b/lib/rebaser-server/src/rebase.rs @@ -19,6 +19,8 @@ pub enum RebaseError { LayerDb(#[from] LayerDbError), #[error("missing change set")] MissingChangeSet(ChangeSetId), + #[error("to_rebase snapshot has no recently seen vector clock for its change set {0}")] + MissingVectorClockForChangeSet(ChangeSetId), #[error("missing workspace snapshot for change set ({0}) (the change set likely isn't pointing at a workspace snapshot)")] MissingWorkspaceSnapshotForChangeSet(ChangeSetId), #[error("serde json error: {0}")] @@ -63,10 +65,19 @@ pub async fn perform_rebase( debug!("after snapshot fetch and parse: {:?}", start.elapsed()); // Perform the conflicts and updates detection. - let onto_vector_clock_id: VectorClockId = message.payload.onto_vector_clock_id.into(); + let onto_vector_clock_id: VectorClockId = message.payload.onto_vector_clock_id; + + // Choose the most recent vector clock for the to_rebase change set for conflict detection + let to_rebase_vector_clock_id = to_rebase_workspace_snapshot + .max_recently_seen_clock_id_for_change_set(to_rebase_change_set.id) + .await? + .ok_or(RebaseError::MissingVectorClockForChangeSet( + to_rebase_change_set.id, + ))?; + let conflicts_and_updates = to_rebase_workspace_snapshot .detect_conflicts_and_updates( - to_rebase_change_set.vector_clock_id(), + to_rebase_vector_clock_id, &onto_workspace_snapshot, onto_vector_clock_id, ) @@ -83,7 +94,7 @@ pub async fn perform_rebase( let message: RebaseStatus = if conflicts_and_updates.conflicts.is_empty() { to_rebase_workspace_snapshot .perform_updates( - &to_rebase_change_set, + to_rebase_vector_clock_id, &onto_workspace_snapshot, conflicts_and_updates.updates.as_slice(), ) @@ -93,8 +104,11 @@ pub async fn perform_rebase( if !conflicts_and_updates.updates.is_empty() { // Once all updates have been performed, we can write out, mark everything as recently seen // and update the pointer. + dbg!(ctx.vector_clock_id()?); + dbg!(ctx.visibility()); + dbg!(ctx.tenancy()); to_rebase_workspace_snapshot - .write(ctx, to_rebase_change_set.vector_clock_id()) + .write(ctx, ctx.vector_clock_id()?) .await?; info!("snapshot written: {:?}", start.elapsed()); to_rebase_change_set diff --git a/lib/sdf-server/src/server/server.rs b/lib/sdf-server/src/server/server.rs index d2a088233b..faf169c0b3 100644 --- a/lib/sdf-server/src/server/server.rs +++ b/lib/sdf-server/src/server/server.rs @@ -269,24 +269,6 @@ impl Server<(), ()> { Ok(()) } - // /// Start the basic resource refresh scheduler - // pub async fn start_resource_refresh_scheduler( - // services_context: ServicesContext, - // shutdown_broadcast_rx: broadcast::Receiver<()>, - // ) { - // ResourceScheduler::new(services_context).start(shutdown_broadcast_rx); - // } - - // pub async fn start_status_updater( - // services_context: ServicesContext, - // shutdown_broadcast_rx: broadcast::Receiver<()>, - // ) -> Result<()> { - // StatusReceiver::new(services_context) - // .await? - // .start(shutdown_broadcast_rx); - // Ok(()) - // } - #[instrument(name = "sdf.init.create_pg_pool", level = "info", skip_all)] pub async fn create_pg_pool(pg_pool_config: &PgPoolConfig) -> Result { let pool = PgPool::new(pg_pool_config).await?; @@ -352,10 +334,13 @@ pub async fn migrate_builtins_from_module_index(services_context: &ServicesConte let instant = Instant::now(); let mut dal_context = services_context.clone().into_builder(true); + info!("a"); dal_context.set_no_dependent_values(); + info!("b"); dal_context.set_no_auto_migrate_snapshots(); + info!("c"); let mut ctx = dal_context.build_default().await?; - + info!("setup builtin workspace"); Workspace::setup_builtin(&mut ctx).await?; info!("migrating intrinsic functions"); diff --git a/lib/sdf-server/src/server/service/change_set/abandon_change_set.rs b/lib/sdf-server/src/server/service/change_set/abandon_change_set.rs index dca3ae9ba7..c69abc5dd2 100644 --- a/lib/sdf-server/src/server/service/change_set/abandon_change_set.rs +++ b/lib/sdf-server/src/server/service/change_set/abandon_change_set.rs @@ -36,7 +36,7 @@ pub async fn abandon_change_set( .await? .ok_or(ChangeSetError::ChangeSetNotFound)?; - ctx.update_visibility_and_snapshot_to_visibility_no_editing_change_set(change_set.id) + ctx.update_visibility_and_snapshot_to_visibility(change_set.id) .await?; change_set.abandon(&ctx).await?; diff --git a/lib/si-events-rs/src/vector_clock_id.rs b/lib/si-events-rs/src/vector_clock_id.rs index 38bf924c4c..b4fa0dcd92 100644 --- a/lib/si-events-rs/src/vector_clock_id.rs +++ b/lib/si-events-rs/src/vector_clock_id.rs @@ -5,6 +5,28 @@ use crate::ulid::Ulid; #[derive(Serialize, Deserialize, Hash, PartialEq, Eq, Clone, Copy, Debug)] pub struct VectorClockChangeSetId(Ulid); +impl VectorClockChangeSetId { + pub fn new(ulid: Ulid) -> Self { + Self(ulid) + } + + pub fn into_inner(self) -> Ulid { + self.0 + } +} + +impl From for VectorClockChangeSetId { + fn from(value: ulid::Ulid) -> Self { + Self(value.into()) + } +} + +impl From for VectorClockChangeSetId { + fn from(value: Ulid) -> Self { + Self(value) + } +} + impl std::fmt::Display for VectorClockChangeSetId { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.0) @@ -14,18 +36,91 @@ impl std::fmt::Display for VectorClockChangeSetId { #[derive(Serialize, Deserialize, Hash, PartialEq, Eq, Clone, Copy, Debug)] pub struct VectorClockActorId(Ulid); +impl VectorClockActorId { + pub fn new(ulid: Ulid) -> Self { + Self(ulid) + } + + pub fn into_inner(self) -> Ulid { + self.0 + } +} + +impl From for VectorClockActorId { + fn from(value: Ulid) -> Self { + Self(value) + } +} + +impl From for VectorClockActorId { + fn from(value: ulid::Ulid) -> Self { + Self(value.into()) + } +} + impl std::fmt::Display for VectorClockActorId { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.0) } } -#[derive(Serialize, Deserialize, Hash, PartialEq, Eq, Clone, Copy, Debug)] +#[derive(Hash, PartialEq, Eq, Clone, Copy, Debug)] pub struct VectorClockId { change_set_id: VectorClockChangeSetId, actor_id: VectorClockActorId, } +pub struct VectorClockIdStringDeserializeVisitor; + +impl<'de> serde::de::Visitor<'de> for VectorClockIdStringDeserializeVisitor { + type Value = VectorClockId; + + fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + formatter.write_str("a string reprensenting a VectorClockId") + } + + fn visit_str(self, v: &str) -> Result + where + E: serde::de::Error, + { + let (change_set_id_string, actor_id_string) = v.split_once(';').ok_or(E::custom( + format!("{v} is not a valid VectorClockId string representation."), + ))?; + + let change_set_id = Ulid::from_string(change_set_id_string).map_err(|e| { + E::custom(format!( + "VectorClock ChangeSetId \"{change_set_id_string}\" is not a valid Ulid representation: {e}" + )) + })?; + let actor_id = Ulid::from_string(actor_id_string).map_err(|e| { + E::custom(format!( + "VectorClock ActorId \"{actor_id_string}\" is not a valid Ulid representation: {e}" + )) + })?; + + Ok(VectorClockId::new(change_set_id, actor_id)) + } +} + +impl<'de> serde::Deserialize<'de> for VectorClockId { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + deserializer.deserialize_str(VectorClockIdStringDeserializeVisitor) + } +} + +impl serde::Serialize for VectorClockId { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let string_vector_clock_id = format!("{};{}", self.change_set_id, self.actor_id); + serializer.serialize_str(&string_vector_clock_id) + } +} + impl std::fmt::Display for VectorClockId { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( @@ -37,10 +132,13 @@ impl std::fmt::Display for VectorClockId { } impl VectorClockId { - pub fn new(change_set_id: VectorClockChangeSetId, actor_id: VectorClockActorId) -> Self { + pub fn new( + change_set_id: impl Into, + actor_id: impl Into, + ) -> Self { Self { - change_set_id, - actor_id, + change_set_id: change_set_id.into(), + actor_id: actor_id.into(), } } @@ -55,6 +153,8 @@ impl VectorClockId { #[cfg(test)] mod tests { + use std::collections::HashMap; + use super::*; #[test] @@ -74,4 +174,21 @@ mod tests { let display = format!("{vector_clock_id}"); assert_eq!(expected, display); } + + #[test] + fn serde_json() { + let mut vector_clock_map = HashMap::new(); + + for i in 0..10 { + let vector_clock_id = VectorClockId::new(Ulid::new(), Ulid::new()); + vector_clock_map.insert(vector_clock_id, i); + } + + let json_string = + serde_json::to_string(&vector_clock_map).expect("should serialize to string"); + let deserialized: HashMap = + serde_json::from_str(&json_string).expect("should deserialize"); + + assert_eq!(vector_clock_map, deserialized); + } } diff --git a/lib/si-layer-cache/src/activities/rebase.rs b/lib/si-layer-cache/src/activities/rebase.rs index 91721a3c82..e2703fd123 100644 --- a/lib/si-layer-cache/src/activities/rebase.rs +++ b/lib/si-layer-cache/src/activities/rebase.rs @@ -1,7 +1,7 @@ use serde::{Deserialize, Serialize}; use strum::EnumDiscriminants; -use si_events::WorkspaceSnapshotAddress; +use si_events::{VectorClockId, WorkspaceSnapshotAddress}; use telemetry::prelude::*; use telemetry::tracing::instrument; use tokio::sync::mpsc::UnboundedReceiver; @@ -24,7 +24,7 @@ pub struct RebaseRequest { /// Derived from the ephemeral or persisted change set that's either the base change set, the /// last change set before edits were made, or the change set that you are trying to rebase /// onto base. - pub onto_vector_clock_id: Ulid, + pub onto_vector_clock_id: VectorClockId, /// DEPRECATED: We have to hang on to this to ensure we can deserialize this message pub dvu_values: Option>, } @@ -33,7 +33,7 @@ impl RebaseRequest { pub fn new( to_rebase_change_set_id: Ulid, onto_workspace_snapshot_address: WorkspaceSnapshotAddress, - onto_vector_clock_id: Ulid, + onto_vector_clock_id: VectorClockId, ) -> RebaseRequest { RebaseRequest { to_rebase_change_set_id, @@ -117,7 +117,7 @@ impl<'a> ActivityRebase<'a> { &self, to_rebase_change_set_id: Ulid, onto_workspace_snapshot_address: WorkspaceSnapshotAddress, - onto_vector_clock_id: Ulid, + onto_vector_clock_id: VectorClockId, metadata: LayeredEventMetadata, ) -> LayerDbResult { let payload = RebaseRequest::new( @@ -135,7 +135,7 @@ impl<'a> ActivityRebase<'a> { &self, to_rebase_change_set_id: Ulid, onto_workspace_snapshot_address: WorkspaceSnapshotAddress, - onto_vector_clock_id: Ulid, + onto_vector_clock_id: VectorClockId, metadata: LayeredEventMetadata, ) -> LayerDbResult { let payload = RebaseRequest::new( diff --git a/lib/si-layer-cache/tests/integration_test/activities/rebase.rs b/lib/si-layer-cache/tests/integration_test/activities/rebase.rs index b4d2fbe713..fc8fe39279 100644 --- a/lib/si-layer-cache/tests/integration_test/activities/rebase.rs +++ b/lib/si-layer-cache/tests/integration_test/activities/rebase.rs @@ -3,7 +3,10 @@ use std::sync::{ Arc, }; -use si_events::{Actor, ChangeSetId, Tenancy, WorkspacePk, WorkspaceSnapshotAddress}; +use si_events::{ + Actor, ChangeSetId, Tenancy, VectorClockActorId, VectorClockChangeSetId, VectorClockId, + WorkspacePk, WorkspaceSnapshotAddress, +}; use si_layer_cache::{ activities::ActivityId, event::LayeredEventMetadata, memory_cache::MemoryCacheConfig, LayerDb, }; @@ -78,6 +81,11 @@ async fn subscribe_rebaser_requests_work_queue() { let tenancy = Tenancy::new(WorkspacePk::new(), ChangeSetId::new()); let actor = Actor::System; let metadata = LayeredEventMetadata::new(tenancy, actor); + let vector_clock_id = VectorClockId::new( + VectorClockChangeSetId::new(Ulid::new().into()), + // zackfactor - is this the system actor? + VectorClockActorId::new(tenancy.workspace_pk.into_inner().into()), + ); let rebase_request_activity = ldb_duff .activity() @@ -85,7 +93,7 @@ async fn subscribe_rebaser_requests_work_queue() { .rebase( Ulid::new(), WorkspaceSnapshotAddress::new(b"poop"), - Ulid::new(), + vector_clock_id, metadata.clone(), ) .await @@ -193,6 +201,11 @@ async fn rebase_and_wait() { let metadata = LayeredEventMetadata::new(tenancy, actor); let metadata_for_task = metadata.clone(); + let onto_vector_clock_id = VectorClockId::new( + VectorClockChangeSetId::new(Ulid::new().into()), + VectorClockActorId::new(Ulid::new().into()), + ); + let rebase_request_task = tokio::spawn(async move { ldb_slash .activity() @@ -200,7 +213,7 @@ async fn rebase_and_wait() { .rebase_and_wait( Ulid::new(), WorkspaceSnapshotAddress::new(b"poop"), - Ulid::new(), + onto_vector_clock_id, metadata_for_task, ) .await @@ -330,13 +343,17 @@ async fn rebase_requests_work_queue_stress() { tracker.spawn(async move { let mut count = 0; while count < rebase_activities { + let vector_clock_id = VectorClockId::new( + VectorClockChangeSetId::new(Ulid::new().into()), + VectorClockActorId::new(Ulid::new().into()), + ); let _rebase_request_activity = ldb_duff .activity() .rebase() .rebase( Ulid::new(), WorkspaceSnapshotAddress::new(b"poop"), - Ulid::new(), + vector_clock_id, send_meta.clone(), ) .await @@ -485,13 +502,17 @@ async fn rebase_and_wait_stress() { loop { SENT_REQUEST_COUNTER.fetch_add(1, Ordering::Relaxed); let mp = metadata_for_sender.clone(); + let onto_vector_clock_id = VectorClockId::new( + VectorClockChangeSetId::new(Ulid::new().into()), + VectorClockActorId::new(Ulid::new().into()), + ); let _response = ldb_slash_clone .activity() .rebase() .rebase_and_wait( Ulid::new(), WorkspaceSnapshotAddress::new(b"poop"), - Ulid::new(), + onto_vector_clock_id, mp, ) .await; diff --git a/lib/si-test-macros/src/expand.rs b/lib/si-test-macros/src/expand.rs index ee2c6c1d88..942274ab47 100644 --- a/lib/si-test-macros/src/expand.rs +++ b/lib/si-test-macros/src/expand.rs @@ -539,7 +539,8 @@ pub(crate) trait FnSetupExpander { .wrap_err("failed to build default dal ctx for dal_context_default")?; ctx.update_tenancy(::dal::Tenancy::new(*#nw.workspace.pk())); ::dal_test::expand_helpers::create_change_set_and_update_ctx(&mut ctx, #nw.workspace.default_change_set_id()).await; - ctx.blocking_commit() + ::dal_test::expand_helpers::setup_history_actor_ctx(&mut ctx).await; + ctx.commit_no_rebase() .await .wrap_err("failed to commit create_change_set_and_update_ctx")?; @@ -570,7 +571,8 @@ pub(crate) trait FnSetupExpander { .wrap_err("failed to build default dal ctx for dal_context_default_mut")?; ctx.update_tenancy(::dal::Tenancy::new(*#nw.workspace.pk())); ::dal_test::expand_helpers::create_change_set_and_update_ctx(&mut ctx, #nw.workspace.default_change_set_id()).await; - ctx.blocking_commit() + ::dal_test::expand_helpers::setup_history_actor_ctx(&mut ctx).await; + ctx.commit_no_rebase() .await .wrap_err("failed to commit create_change_set_and_update_ctx_mut")?;