From 1d412cf0d555fc1896070089e7403626ec3bb2d9 Mon Sep 17 00:00:00 2001 From: Lucien Greathouse Date: Wed, 16 Jan 2019 17:59:57 -0800 Subject: [PATCH] Begin the metadata merge trek --- server/src/path_map.rs | 24 +++++++++++++ server/src/rbx_session.rs | 59 +++++++++++++++++++------------ server/src/rbx_snapshot.rs | 13 +++++-- server/src/snapshot_reconciler.rs | 32 ++++++++++------- server/src/web.rs | 4 +-- 5 files changed, 92 insertions(+), 40 deletions(-) diff --git a/server/src/path_map.rs b/server/src/path_map.rs index cc9265c4..138d4c40 100644 --- a/server/src/path_map.rs +++ b/server/src/path_map.rs @@ -1,4 +1,5 @@ use std::{ + collections::hash_map, path::{self, Path, PathBuf}, collections::{HashMap, HashSet}, }; @@ -31,6 +32,16 @@ impl PathMap { self.nodes.get(path).map(|v| &v.value) } + pub fn get_mut(&mut self, path: &Path) -> Option<&mut T> { + self.nodes.get_mut(path).map(|v| &mut v.value) + } + + pub fn entry<'a>(&'a mut self, path: PathBuf) -> Entry<'a, T> { + Entry { + internal: self.nodes.entry(path), + } + } + pub fn insert(&mut self, path: PathBuf, value: T) { if let Some(parent_path) = path.parent() { if let Some(parent) = self.nodes.get_mut(parent_path) { @@ -105,4 +116,17 @@ impl PathMap { current_path } +} + +pub struct Entry<'a, T> { + internal: hash_map::Entry<'a, PathBuf, PathMapNode>, +} + +impl<'a, T> Entry<'a, T> { + pub fn or_insert(self, value: T) -> &'a mut T { + &mut self.internal.or_insert(PathMapNode { + value, + children: HashSet::new(), + }).value + } } \ No newline at end of file diff --git a/server/src/rbx_session.rs b/server/src/rbx_session.rs index 052d2c1e..61768a81 100644 --- a/server/src/rbx_session.rs +++ b/server/src/rbx_session.rs @@ -6,6 +6,7 @@ use std::{ sync::{Arc, Mutex}, }; +use serde_derive::{Serialize, Deserialize}; use log::{info, trace}; use rbx_tree::{RbxTree, RbxId}; @@ -22,11 +23,22 @@ const INIT_SCRIPT: &str = "init.lua"; const INIT_SERVER_SCRIPT: &str = "init.server.lua"; const INIT_CLIENT_SCRIPT: &str = "init.client.lua"; +#[derive(Debug, Serialize, Deserialize)] +pub struct MetadataPerPath { + pub instance_id: RbxId, + pub instance_name: Option, +} + pub struct RbxSession { tree: RbxTree, - path_map: PathMap, + + // TODO(#105): Change metadata_per_path to PathMap> for + // path aliasing. + metadata_per_path: PathMap, + + // TODO: Track map from RbxId to PathBuf to support two-way sync + instance_metadata_map: HashMap, - sync_point_names: HashMap, message_queue: Arc>, imfs: Arc>, } @@ -37,20 +49,18 @@ impl RbxSession { imfs: Arc>, message_queue: Arc>, ) -> RbxSession { - let mut sync_point_names = HashMap::new(); - let mut path_map = PathMap::new(); + let mut metadata_per_path = PathMap::new(); let mut instance_metadata_map = HashMap::new(); let tree = { let temp_imfs = imfs.lock().unwrap(); - reify_initial_tree(&project, &temp_imfs, &mut path_map, &mut instance_metadata_map, &mut sync_point_names) + reify_initial_tree(&project, &temp_imfs, &mut metadata_per_path, &mut instance_metadata_map) }; RbxSession { tree, - path_map, + metadata_per_path, instance_metadata_map, - sync_point_names, message_queue, imfs, } @@ -67,8 +77,7 @@ impl RbxSession { .expect("Path was outside in-memory filesystem roots"); // Find the closest instance in the tree that currently exists - let mut path_to_snapshot = self.path_map.descend(root_path, path); - let &instance_id = self.path_map.get(&path_to_snapshot).unwrap(); + let mut path_to_snapshot = self.metadata_per_path.descend(root_path, path); // If this is a file that might affect its parent if modified, we // should snapshot its parent instead. @@ -81,10 +90,16 @@ impl RbxSession { trace!("Snapshotting path {}", path_to_snapshot.display()); - let instance_name = self.sync_point_names.get(&path_to_snapshot) + let path_metadata = self.metadata_per_path.get(&path_to_snapshot).unwrap(); + let instance_id = path_metadata.instance_id; + + // If this instance is a sync point, pull its name out of our + // per-path metadata store. + let instance_name = path_metadata.instance_name.as_ref() .map(|value| Cow::Owned(value.to_owned())); + let mut snapshot_meta = SnapshotMetadata { - sync_point_names: &mut self.sync_point_names, + metadata_per_path: &mut self.metadata_per_path, }; let maybe_snapshot = snapshot_imfs_path(&imfs, &mut snapshot_meta, &path_to_snapshot, instance_name) .unwrap_or_else(|_| panic!("Could not generate instance snapshot for path {}", path_to_snapshot.display())); @@ -103,7 +118,7 @@ impl RbxSession { &mut self.tree, instance_id, &snapshot, - &mut self.path_map, + &mut self.metadata_per_path, &mut self.instance_metadata_map, &mut changes, ); @@ -144,13 +159,13 @@ impl RbxSession { pub fn path_removed(&mut self, path: &Path) { info!("Path removed: {}", path.display()); - self.path_map.remove(path); + self.metadata_per_path.remove(path); self.path_created_or_updated(path); } pub fn path_renamed(&mut self, from_path: &Path, to_path: &Path) { info!("Path renamed from {} to {}", from_path.display(), to_path.display()); - self.path_map.remove(from_path); + self.metadata_per_path.remove(from_path); self.path_created_or_updated(from_path); self.path_created_or_updated(to_path); } @@ -163,34 +178,32 @@ impl RbxSession { self.instance_metadata_map.get(&id) } - pub fn debug_get_path_map(&self) -> &PathMap { - &self.path_map + pub fn debug_get_metadata_per_path(&self) -> &PathMap { + &self.metadata_per_path } } pub fn construct_oneoff_tree(project: &Project, imfs: &Imfs) -> RbxTree { - let mut path_map = PathMap::new(); + let mut metadata_per_path = PathMap::new(); let mut instance_metadata_map = HashMap::new(); - let mut sync_point_names = HashMap::new(); - reify_initial_tree(project, imfs, &mut path_map, &mut instance_metadata_map, &mut sync_point_names) + reify_initial_tree(project, imfs, &mut metadata_per_path, &mut instance_metadata_map) } fn reify_initial_tree( project: &Project, imfs: &Imfs, - path_map: &mut PathMap, + metadata_per_path: &mut PathMap, instance_metadata_map: &mut HashMap, - sync_point_names: &mut HashMap, ) -> RbxTree { let mut meta = SnapshotMetadata { - sync_point_names, + metadata_per_path, }; let snapshot = snapshot_project_tree(imfs, &mut meta, project) .expect("Could not snapshot project tree") .expect("Project did not produce any instances"); let mut changes = InstanceChanges::default(); - let tree = reify_root(&snapshot, path_map, instance_metadata_map, &mut changes); + let tree = reify_root(&snapshot, metadata_per_path, instance_metadata_map, &mut changes); tree } \ No newline at end of file diff --git a/server/src/rbx_snapshot.rs b/server/src/rbx_snapshot.rs index 3979ce91..7eda3725 100644 --- a/server/src/rbx_snapshot.rs +++ b/server/src/rbx_snapshot.rs @@ -8,7 +8,7 @@ use std::{ use serde_derive::{Serialize, Deserialize}; use maplit::hashmap; -use rbx_tree::{RbxTree, RbxValue, RbxInstanceProperties}; +use rbx_tree::{RbxId, RbxTree, RbxValue, RbxInstanceProperties}; use failure::Fail; use crate::{ @@ -28,6 +28,9 @@ use crate::{ RbxSnapshotInstance, snapshot_from_tree, }, + path_map::PathMap, + // TODO: Move MetadataPerPath into this module? + rbx_session::MetadataPerPath, }; const INIT_MODULE_NAME: &str = "init.lua"; @@ -37,7 +40,7 @@ const INIT_CLIENT_NAME: &str = "init.client.lua"; pub type SnapshotResult<'a> = Result>, SnapshotError>; pub struct SnapshotMetadata<'meta> { - pub sync_point_names: &'meta mut HashMap, + pub metadata_per_path: &'meta mut PathMap, } #[derive(Debug, Fail)] @@ -138,7 +141,11 @@ fn snapshot_sync_point_node<'source>( }; // Otherwise, we can log the name of the sync point we just snapshotted. - metadata.sync_point_names.insert(node.path.to_owned(), snapshot.name.clone().into_owned()); + // TODO: Use entry API + metadata.metadata_per_path.insert(node.path.to_owned(), MetadataPerPath { + instance_id: RbxId::new(), + instance_name: Some(snapshot.name.clone().into_owned()), + }); Ok(Some(snapshot)) } diff --git a/server/src/snapshot_reconciler.rs b/server/src/snapshot_reconciler.rs index 64c702c3..749e5f05 100644 --- a/server/src/snapshot_reconciler.rs +++ b/server/src/snapshot_reconciler.rs @@ -11,6 +11,7 @@ use serde_derive::{Serialize, Deserialize}; use crate::{ path_map::PathMap, + rbx_session::MetadataPerPath, project::InstanceProjectNodeMetadata, }; @@ -86,7 +87,7 @@ pub fn snapshot_from_tree(tree: &RbxTree, id: RbxId) -> Option, + metadata_per_path: &mut PathMap, instance_metadata_map: &mut HashMap, changes: &mut InstanceChanges, ) -> RbxTree { @@ -95,7 +96,12 @@ pub fn reify_root( let root_id = tree.get_root_id(); if let Some(source_path) = &snapshot.source_path { - path_map.insert(source_path.clone(), root_id); + // TODO: Use entry API instead? + // metadata_per_path.entry() + metadata_per_path.insert(source_path.clone(), MetadataPerPath { + instance_id: root_id, + instance_name: None, + }); } if let Some(metadata) = &snapshot.metadata { @@ -105,7 +111,7 @@ pub fn reify_root( changes.added.insert(root_id); for child in &snapshot.children { - reify_subtree(child, &mut tree, root_id, path_map, instance_metadata_map, changes); + reify_subtree(child, &mut tree, root_id, metadata_per_path, instance_metadata_map, changes); } tree @@ -115,7 +121,7 @@ pub fn reify_subtree( snapshot: &RbxSnapshotInstance, tree: &mut RbxTree, parent_id: RbxId, - path_map: &mut PathMap, + metadata_per_path: &mut PathMap, instance_metadata_map: &mut HashMap, changes: &mut InstanceChanges, ) { @@ -123,7 +129,8 @@ pub fn reify_subtree( let id = tree.insert_instance(instance, parent_id); if let Some(source_path) = &snapshot.source_path { - path_map.insert(source_path.clone(), id); + // TODO: use entry API + // metadata_per_path.insert(source_path.clone(), id); } if let Some(metadata) = &snapshot.metadata { @@ -133,7 +140,7 @@ pub fn reify_subtree( changes.added.insert(id); for child in &snapshot.children { - reify_subtree(child, tree, id, path_map, instance_metadata_map, changes); + reify_subtree(child, tree, id, metadata_per_path, instance_metadata_map, changes); } } @@ -141,12 +148,13 @@ pub fn reconcile_subtree( tree: &mut RbxTree, id: RbxId, snapshot: &RbxSnapshotInstance, - path_map: &mut PathMap, + metadata_per_path: &mut PathMap, instance_metadata_map: &mut HashMap, changes: &mut InstanceChanges, ) { if let Some(source_path) = &snapshot.source_path { - path_map.insert(source_path.clone(), id); + // TODO: use entry API + // metadata_per_path.insert(source_path.clone(), id); } if let Some(metadata) = &snapshot.metadata { @@ -157,7 +165,7 @@ pub fn reconcile_subtree( changes.updated.insert(id); } - reconcile_instance_children(tree, id, snapshot, path_map, instance_metadata_map, changes); + reconcile_instance_children(tree, id, snapshot, metadata_per_path, instance_metadata_map, changes); } fn reify_core(snapshot: &RbxSnapshotInstance) -> RbxInstanceProperties { @@ -237,7 +245,7 @@ fn reconcile_instance_children( tree: &mut RbxTree, id: RbxId, snapshot: &RbxSnapshotInstance, - path_map: &mut PathMap, + metadata_per_path: &mut PathMap, instance_metadata_map: &mut HashMap, changes: &mut InstanceChanges, ) { @@ -290,7 +298,7 @@ fn reconcile_instance_children( } for child_snapshot in &children_to_add { - reify_subtree(child_snapshot, tree, id, path_map, instance_metadata_map, changes); + reify_subtree(child_snapshot, tree, id, metadata_per_path, instance_metadata_map, changes); } for child_id in &children_to_remove { @@ -303,6 +311,6 @@ fn reconcile_instance_children( } for (child_id, child_snapshot) in &children_to_update { - reconcile_subtree(tree, *child_id, child_snapshot, path_map, instance_metadata_map, changes); + reconcile_subtree(tree, *child_id, child_snapshot, metadata_per_path, instance_metadata_map, changes); } } \ No newline at end of file diff --git a/server/src/web.rs b/server/src/web.rs index c992e8ad..2ff1a92c 100644 --- a/server/src/web.rs +++ b/server/src/web.rs @@ -205,10 +205,10 @@ impl Server { Response::svg(graphviz_to_svg(&dot_source)) }, - (GET) (/visualize/path_map) => { + (GET) (/visualize/path_metadata) => { let rbx_session = self.session.rbx_session.lock().unwrap(); - Response::json(&rbx_session.debug_get_path_map()) + Response::json(&rbx_session.debug_get_metadata_per_path()) }, _ => Response::empty_404()