/// <summary> /// Initializes a new instance of the <see cref="PathGroup"/> class. /// </summary> /// <param name="pathTable">The table of items in the group.</param> /// <param name="groupParentPath">The specified parent path.</param> public PathGroup(IReadOnlyDictionary <ITreeNodePath, IPathConnection> pathTable, IFolderPath groupParentPath) { if (groupParentPath == null) { throw new ArgumentNullException(nameof(groupParentPath)); } if (pathTable == null) { throw new ArgumentNullException(nameof(pathTable)); } Debug.Assert(HasNullCommonParent(pathTable)); Dictionary <ITreeNodePath, IPathConnection> PathTable = new Dictionary <ITreeNodePath, IPathConnection>(); foreach (KeyValuePair <ITreeNodePath, IPathConnection> Entry in pathTable) { ITreeNodePath Path = Entry.Key; IPathConnection PathConnection = Entry.Value; IFolderPath? ParentPath = PathConnection.ParentPath; ITreeNodeProperties Properties = PathConnection.Properties; bool IsExpanded = PathConnection.IsExpanded; if (ParentPath == null) { ParentPath = GroupParentPath; } PathTable.Add(Path, new PathConnection(ParentPath, Properties, IsExpanded)); } this.PathTable = PathTable; GroupParentPath = groupParentPath; }
public PathGroup(IReadOnlyDictionary <ITreeNodePath, IPathConnection> pathTable, IFolderPath groupParentPath) { Assert.ValidateReference(pathTable); Assert.ValidateReference(groupParentPath); Assert.CheckCondition(HasNullCommonParent(pathTable)); Dictionary <ITreeNodePath, IPathConnection> PathTable = new Dictionary <ITreeNodePath, IPathConnection>(); foreach (KeyValuePair <ITreeNodePath, IPathConnection> Entry in pathTable) { ITreeNodePath Path = Entry.Key; IPathConnection PathConnection = Entry.Value; IFolderPath ParentPath = PathConnection.ParentPath; ITreeNodeProperties Properties = PathConnection.Properties; bool IsExpanded = PathConnection.IsExpanded; if (ParentPath == null) { ParentPath = GroupParentPath; } PathTable.Add(Path, new PathConnection(ParentPath, Properties, IsExpanded)); } this.PathTable = PathTable; this.GroupParentPath = GroupParentPath; }
public void Init(IPathConnection connection) { // Get the current root, DataAddress currentRoot = connection.GetSnapshot(); // Turn it into a transaction ITransaction transaction = connection.CreateTransaction(currentRoot); // Initialize the magic property set, etc IDataFile df = transaction.GetFile(DbTransaction.MagicKey, FileAccess.ReadWrite); StringDictionary magicSet = new StringDictionary(df); magicSet.SetValue("ob_type", "Deveel.Data.CloudBase"); magicSet.SetValue("version", "1.0"); // Flush and publish the change DataAddress finalRoot = connection.CommitTransaction(transaction); connection.Publish(finalRoot); }
public static bool HasNullCommonParent(IReadOnlyDictionary <ITreeNodePath, IPathConnection> pathTable) { Assert.ValidateReference(pathTable); foreach (KeyValuePair <ITreeNodePath, IPathConnection> Entry in pathTable) { IPathConnection PathConnection = Entry.Value; IFolderPath ParentPath = PathConnection.ParentPath; if (ParentPath != null && !pathTable.ContainsKey(ParentPath)) { return(false); } } return(true); }
/// <summary> /// Checks whether paths in a table have a common parent. /// </summary> /// <param name="pathTable">The table of items.</param> /// <returns>True if items have a common parent; otherwise, false.</returns> public static bool HasCommonParent(IReadOnlyDictionary <ITreeNodePath, IPathConnection> pathTable) { if (pathTable == null) { throw new ArgumentNullException(nameof(pathTable)); } IFolderPath?GroupParentPath = null; bool? IsNullParent = null; foreach (KeyValuePair <ITreeNodePath, IPathConnection> Entry in pathTable) { IPathConnection PathConnection = Entry.Value; IFolderPath? ParentPath = PathConnection.ParentPath; if (ParentPath != null && pathTable.ContainsKey(ParentPath)) { continue; } if (!IsNullParent.HasValue) { IsNullParent = ParentPath == null; } else if (IsNullParent.Value != (ParentPath == null)) { return(false); } if (ParentPath != null) { if (GroupParentPath == null) { GroupParentPath = ParentPath; } else if (GroupParentPath != ParentPath) { return(false); } } } return(true); }
public static bool HasCommonParent(IReadOnlyDictionary <ITreeNodePath, IPathConnection> pathTable) { Assert.ValidateReference(pathTable); IFolderPath GroupParentPath = null; bool? IsNullParent = null; foreach (KeyValuePair <ITreeNodePath, IPathConnection> Entry in pathTable) { IPathConnection PathConnection = Entry.Value; IFolderPath ParentPath = PathConnection.ParentPath; if (ParentPath != null && pathTable.ContainsKey(ParentPath)) { continue; } if (!IsNullParent.HasValue) { IsNullParent = (ParentPath == null); } else if (IsNullParent.Value != (ParentPath == null)) { return(false); } if (ParentPath != null) { if (GroupParentPath == null) { GroupParentPath = ParentPath; } else if (GroupParentPath != ParentPath) { return(false); } } } return(true); }
/// <summary> /// Removes a table of paths. /// </summary> /// <param name="pathTable">The table of paths.</param> protected virtual void Remove(IReadOnlyDictionary <ITreeNodePath, IPathConnection> pathTable) { if (pathTable == null) { throw new ArgumentNullException(nameof(pathTable)); } IReadOnlyDictionary <IFolderPath, ISolutionFolder> FlatFolderTable = Root.FlatFolderChildren; List <ISolutionTreeNodeCollection> ModifiedCollectionList = new List <ISolutionTreeNodeCollection>(); foreach (KeyValuePair <ITreeNodePath, IPathConnection> Entry in pathTable) { ITreeNodePath Path = Entry.Key; IPathConnection Connection = Entry.Value; IFolderPath? ParentPath = Connection.ParentPath; if (ParentPath != null) { ISolutionFolder ParentFolder = FlatFolderTable[ParentPath]; ISolutionTreeNodeCollection ChildrenCollection = (ISolutionTreeNodeCollection)ParentFolder.Children; foreach (ISolutionTreeNode Child in (IEnumerable <ISolutionTreeNode>)ChildrenCollection) { if (Child.Path.IsEqual(Path)) { ChildrenCollection.Remove(Child); break; } } if (!ModifiedCollectionList.Contains(ChildrenCollection)) { ModifiedCollectionList.Add(ChildrenCollection); } } } foreach (ISolutionTreeNodeCollection ChildrenCollection in ModifiedCollectionList) { ChildrenCollection.Sort(); } }
/// <summary> /// Checks whether paths in a table have no parents. /// </summary> /// <param name="pathTable">The table of items.</param> /// <returns>True if items don't have any parent; otherwise, false.</returns> public static bool HasNullCommonParent(IReadOnlyDictionary <ITreeNodePath, IPathConnection> pathTable) { if (pathTable == null) { throw new ArgumentNullException(nameof(pathTable)); } foreach (KeyValuePair <ITreeNodePath, IPathConnection> Entry in pathTable) { IPathConnection PathConnection = Entry.Value; IFolderPath? ParentPath = PathConnection.ParentPath; if (ParentPath != null && !pathTable.ContainsKey(ParentPath)) { return(false); } } return(true); }
protected virtual void Remove(IReadOnlyDictionary <ITreeNodePath, IPathConnection> pathTable) { Assert.ValidateReference(pathTable); IReadOnlyDictionary <IFolderPath, ISolutionFolder> FlatFolderTable = Root.FlatFolderChildren; List <ISolutionTreeNodeCollection> ModifiedCollectionList = new List <ISolutionTreeNodeCollection>(); foreach (KeyValuePair <ITreeNodePath, IPathConnection> Entry in pathTable) { ITreeNodePath Path = Entry.Key; IPathConnection Connection = Entry.Value; IFolderPath ParentPath = Connection.ParentPath; ISolutionFolder ParentFolder = FlatFolderTable[ParentPath]; ISolutionTreeNodeCollection ChildrenCollection = (ISolutionTreeNodeCollection)ParentFolder.Children; foreach (ISolutionTreeNode Child in ChildrenCollection) { if (Child.Path.IsEqual(Path)) { ChildrenCollection.Remove(Child); break; } } if (!ModifiedCollectionList.Contains(ChildrenCollection)) { ModifiedCollectionList.Add(ChildrenCollection); } } foreach (ISolutionTreeNodeCollection ChildrenCollection in ModifiedCollectionList) { ChildrenCollection.Sort(); } }
public DataAddress Commit(IPathConnection connection, DataAddress rootNode) { // Turn the proposal into a proposed_transaction, ITransaction t = connection.CreateTransaction(rootNode); DbTransaction proposedTransaction = new DbTransaction(null, rootNode, t); try { // Fetch the base root from the proposed_transaction log, TextReader reader = proposedTransaction.GetLogReader(); string baseRootStr = reader.ReadLine(); // If 'base_root_str' is "no base root" then it means we are commiting // an introduced transaction that is not an iteration of previous // snapshots. if (baseRootStr.Equals("no base root")) { // In which case, we publish the proposed snapshot unconditionally // and return. connection.Publish(rootNode); return(rootNode); } DataAddress baseRoot = DataAddress.Parse(baseRootStr); // Find all the entries since this base DataAddress[] roots = connection.GetSnapshots(baseRoot); // If there are no roots, we can publish the proposed_transaction // unconditionally if (roots.Length == 0) { connection.Publish(rootNode); return(rootNode); } // Check historical log for clashes, and if none, replay the commands // in the log. // For each previous root, we build a structure that can answer the // following questions; // * Is file [name] created, deleted or changed in this root? // * Is table [name] created or deleted in this root? // * Is table [name] structurally changed in this root? // * Has row [rowid] been deleted in table [name] in this root? RootEvents[] rootEventSet = new RootEvents[roots.Length]; int i = 0; // TODO: RootEvents is pre-computed information which we could // store in a local cache for some speed improvements, so we don't // need to walk through through the same data multiple times. foreach (DataAddress root in roots) { RootEvents rootEvents = new RootEvents(); rootEventSet[i] = rootEvents; ++i; // Create a transaction object for this root ITransaction rootT = connection.CreateTransaction(root); DbTransaction rootTransaction = new DbTransaction(null, root, rootT); // Make a reader object for the log, TextReader rootReader = rootTransaction.GetLogReader(); // Read the base root from this transaction, String baseRootParent = rootReader.ReadLine(); // If 'bast_root_parent' is 'no base root' then it means a version // has been introduced that is not an iteration of previous // snapshots. In this case, it is not possible to merge updates // therefore we generate a commit fault. if (baseRootParent.Equals("no base root")) { throw new CommitFaultException("Transaction history contains introduced version."); } // Go through each log entry and determine if there's a clash, string rootLine = rootReader.ReadLine(); while (rootLine != null) { String mfile = rootLine.Substring(2); // This represents a file modification, bool unknownCommand = false; if (rootLine.StartsWith("F")) { rootEvents.SetFileChange(mfile); } // This is a table modification, else if (rootLine.StartsWith("T")) { char c = rootLine[1]; // If this is a table create or delete event, if (c == 'C' || c == 'D') { rootEvents.SetTableCreateOrDelete(mfile); } // This is a table structural change, else if (c == 'S') { rootEvents.SetTableStructuralChange(mfile); } // This is a table data change event, else if (c == 'M') { DbTable table = rootTransaction.GetTable(mfile); rootEvents.SetTableDataChange(mfile, table); } else { unknownCommand = true; } } else { unknownCommand = true; } if (unknownCommand) { throw new ApplicationException("Unknown transaction command: " + rootLine); } // Read the next log entry, rootLine = rootReader.ReadLine(); } } // Now we have a set of RootEvents objects that describe what // happens in each previous root. // Now replay the events in the proposal transaction in the latest // transaction. // A transaction representing the current state, DataAddress currentRoot = connection.GetSnapshot(); ITransaction currentT = connection.CreateTransaction(currentRoot); DbTransaction currentTransaction = new DbTransaction(null, currentRoot, currentT); String entry = reader.ReadLine(); while (entry != null) { String mfile = entry.Substring(2); // If it's a file entry, we need to check the file hasn't been // changed in any way in any roots if (entry.StartsWith("F")) { foreach (RootEvents events in rootEventSet) { events.CheckFileChange(mfile); } // All checks passed, so perform the operation currentTransaction.ReplayFileLogEntry(entry, proposedTransaction); } // If it's a table entry, else if (entry.StartsWith("T")) { // Check that a table with this name hasn't been created, deleted // or modified, foreach (RootEvents events in rootEventSet) { // This fails on any event on this table, except a data change // (insert or delete) events.CheckTableMetaChange(mfile); } // The type of operation, char c = entry[1]; // Is it a table structural change? if (c == 'S') { // A structural change can only happen if all the roots leave the // table untouched, foreach (RootEvents events in rootEventSet) { // This fails if it finds a delete event for this rowid events.CheckTableDataChange(mfile); } } // Is it a table modification command? else if (c == 'M') { // This is a table modification, we need to check the rowid // logs and look for possible clashes, // The delete set from the proposed transaction, DbTable proposedTable = proposedTransaction.GetTable(mfile); SortedIndex deleteSet = proposedTable.Deletes; IIndexCursor dsi = deleteSet.GetCursor(); while (dsi.MoveNext()) { long rowid = dsi.Current; foreach (RootEvents events in rootEventSet) { // This fails if it finds a delete event for this rowid events.CheckTableDataDelete(mfile, rowid); } } } // Go through each root, if the data in the table was changed // by any of the roots, we set 'has_data_changes' to true; bool hasDataChanges = false; foreach (RootEvents events in rootEventSet) { if (events.HasTableDataChanges(mfile)) { hasDataChanges = true; } } // Ok, checks passed, so reply all the data changes on the table currentTransaction.ReplayTableLogEntry(entry, proposedTransaction, hasDataChanges); } else { throw new ApplicationException("Unknown transaction command: " + entry); } // Read the next log entry, entry = reader.ReadLine(); } // Refresh the transaction log currentTransaction.RefreshTransactionLog(); // Flush and publish the change DataAddress finalRoot = connection.CommitTransaction(currentT); connection.Publish(finalRoot); // Done. return(finalRoot); } catch (IOException e) { throw new ApplicationException("IO Error: " + e.Message); } }
public string GetStats(IPathConnection connection, DataAddress snapshot) { throw new NotImplementedException(); }
protected virtual void Add(IReadOnlyDictionary <ITreeNodePath, IPathConnection> pathTable) { Assert.ValidateReference(pathTable); ClearExpandedFolders(); List <ISolutionTreeNodeCollection> ModifiedCollectionList = new List <ISolutionTreeNodeCollection>(); List <ITreeNodePath> PathList = new List <ITreeNodePath>(); foreach (KeyValuePair <ITreeNodePath, IPathConnection> Entry in pathTable) { PathList.Add(Entry.Key); } while (PathList.Count > 0) { IReadOnlyDictionary <IFolderPath, ISolutionFolder> FlatFolderTable = Root.FlatFolderChildren; int i = 0; while (i < PathList.Count) { ITreeNodePath Path = PathList[i]; IPathConnection Connection = pathTable[Path]; IFolderPath ParentPath = Connection.ParentPath; if (FlatFolderTable.ContainsKey(ParentPath)) { PathList.RemoveAt(i); ISolutionFolder ParentFolder = FlatFolderTable[ParentPath]; ISolutionTreeNodeCollection ChildrenCollection = (ISolutionTreeNodeCollection)ParentFolder.Children; IFolderPath AsFolderPath; IItemPath AsItemPath; if ((AsFolderPath = Path as IFolderPath) != null) { IFolderProperties Properties = (IFolderProperties)Connection.Properties; ISolutionFolder NewFolder = CreateSolutionFolder(ParentFolder, AsFolderPath, Properties); ChildrenCollection.Add(NewFolder); if (Connection.IsExpanded) { AddExpandedFolder(NewFolder); } } else if ((AsItemPath = Path as IItemPath) != null) { IItemProperties Properties = (IItemProperties)Connection.Properties; ISolutionItem NewItem = CreateSolutionItem(ParentFolder, AsItemPath, Properties); ChildrenCollection.Add(NewItem); } else { Assert.InvalidExecutionPath(); } if (!ModifiedCollectionList.Contains(ChildrenCollection)) { ModifiedCollectionList.Add(ChildrenCollection); } } else { i++; } } } foreach (ISolutionTreeNodeCollection ChildrenCollection in ModifiedCollectionList) { ChildrenCollection.Sort(); } }
/// <summary> /// Adds a table of path. /// </summary> /// <param name="pathTable">The table to add.</param> protected virtual void Add(IReadOnlyDictionary <ITreeNodePath, IPathConnection> pathTable) { if (pathTable == null) { throw new ArgumentNullException(nameof(pathTable)); } ClearExpandedFolders(); List <ISolutionTreeNodeCollection> ModifiedCollectionList = new List <ISolutionTreeNodeCollection>(); List <ITreeNodePath> PathList = new List <ITreeNodePath>(); foreach (KeyValuePair <ITreeNodePath, IPathConnection> Entry in pathTable) { PathList.Add(Entry.Key); } while (PathList.Count > 0) { IReadOnlyDictionary <IFolderPath, ISolutionFolder> FlatFolderTable = Root.FlatFolderChildren; int i = 0; while (i < PathList.Count) { ITreeNodePath Path = PathList[i]; IPathConnection Connection = pathTable[Path]; IFolderPath? ParentPath = Connection.ParentPath; if (ParentPath != null && FlatFolderTable.ContainsKey(ParentPath)) { PathList.RemoveAt(i); ISolutionFolder ParentFolder = FlatFolderTable[ParentPath]; ISolutionTreeNodeCollection ChildrenCollection = (ISolutionTreeNodeCollection)ParentFolder.Children; bool IsHandled = false; switch (Path) { case IFolderPath AsFolderPath: IFolderProperties FolderProperties = (IFolderProperties)Connection.Properties; ISolutionFolder NewFolder = CreateSolutionFolder(ParentFolder, AsFolderPath, FolderProperties); ChildrenCollection.Add(NewFolder); if (Connection.IsExpanded) { AddExpandedFolder(NewFolder); } IsHandled = true; break; case IItemPath AsItemPath: IItemProperties ItemProperties = (IItemProperties)Connection.Properties; ISolutionItem NewItem = CreateSolutionItem(ParentFolder, AsItemPath, ItemProperties); ChildrenCollection.Add(NewItem); IsHandled = true; break; } Debug.Assert(IsHandled); if (!ModifiedCollectionList.Contains(ChildrenCollection)) { ModifiedCollectionList.Add(ChildrenCollection); } } else { i++; } } } foreach (ISolutionTreeNodeCollection ChildrenCollection in ModifiedCollectionList) { ChildrenCollection.Sort(); } }