/// <summary> /// This operation moves workspace to given snapshot ID. /// All uncommited changes which are made in the workspace are going to be preserved. /// In case that conflicting changes were made, ConcurrentModificationException will be thrown and workspace will remain not updated. /// </summary> /// <param name="newSnapshotId">Snapshot Id to be loaded, must be in sequence after the current snapshot ID</param> public void Update(Guid newSnapshotId) { CheckThread(); var mapping = workspaceFacade.ChangesBetween(snapshotId, newSnapshotId); if (isolatedProvider != null) { foreach (Guid changedNodeId in isolatedProvider.EnumerateChanges()) { if (mapping.ContainsKey(changedNodeId)) { Guid typeId = Guid.Empty; try { typeId = typesService.GetInstanceTypeId(changedNodeId); } catch { throw new ConcurrentModificationException(); } throw new ConcurrentModificationException(typesService.GetTypeFromId(typeId).Name); } } } mutableProxyMap.UpgradeProxies(mapping); snapshotId = newSnapshotId; workspaceFacade.UpdateWorkspace(workspaceId, snapshotId); }
private void Initialize() { foreach (var typeId in typesService.GetRegisteredTypes()) { if (!typesService.IsScalarType(typeId)) { var type = typesService.GetTypeFromId(typeId); var rule = new TypeMergeRule(); Type collectionType = null; Type dictionaryType = null; if (!Utils.IsCollectionType(type, ref collectionType) && !Utils.IsDictionaryType(type, ref dictionaryType)) { var attributes = type.GetCustomAttributes(typeof(ConcurrentAttribute), true); if (attributes.Length == 1) { rule.IsConcurrent = true; rule.IsStaticConcurrency = ((ConcurrentAttribute)attributes[0]).Behavior == ConcurrentBehavior.Static; if (!rule.IsStaticConcurrency) { rule.DynamicResolverType = ((ConcurrentAttribute)attributes[0]).Resolver; } else { foreach (var edge in typesService.GetTypeEdges(typeId)) { if (edge.Data.Semantic == Graph.EdgeType.Property) { var memberId = edge.ToNodeId; //var memberTypeId = typesService.GetMemberTypeId(memberId); var memberName = typesService.GetMemberName(typeId, memberId); PropertyInfo propertyInfo = FindPropertyInfo(type, memberName); bool isOverride = propertyInfo.GetCustomAttributes(typeof(OverrideAttribute), false).Length == 1; rule.IsMemberOverride.Add(memberId, isOverride); } } } } } else { rule.IsConcurrent = true; rule.IsStaticConcurrency = true; } // Add rule for the type in cache typeMergeRules.Add(typeId, rule); } } }
public void MergeObjects(Guid nodeId, Node <Guid, object, EdgeData> originalNode, Node <Guid, object, EdgeData> changedNode, Node <Guid, object, EdgeData> node, MergeRecursiveDelegate mergeRecursive, InsertRecursiveDelegate insertRecursive, RecursiveResolutionParameters parameters) { Guid typeId = typesService.GetInstanceTypeId(originalNode); if (!objectAttributeProvider.IsConcurrent(typeId)) { var instanceType = typesService.GetTypeFromId(typesService.GetInstanceTypeId(nodeId)); throw new ConcurrentModificationException("Concurrent modification not allowed for entity type:" + instanceType.ToString()); } if (objectAttributeProvider.IsStaticConcurrency(typeId)) { MergeObjectsStatic(nodeId, typeId, originalNode, changedNode, node, mergeRecursive, insertRecursive, parameters); } else { throw new NotImplementedException("Dynamic concurrency not implemented"); } }
private static void LogCollection(Guid nodeId, Node <Guid, object, EdgeData> node, INodeProvider <Guid, object, EdgeData> nodes, INodeProvider <Guid, object, EdgeData> changes, int tabLevel, Hashtable visited, TypesService typesService) { Edge <Guid, EdgeData> typeEdge = null; BPlusTreeOperations.TryFindEdge(nodes, nodeId, new EdgeData(EdgeType.OfType, null), out typeEdge); var typeId = typeEdge.ToNodeId; var typeName = typesService.GetTypeFromId(typeId).Name; Debug.WriteLine(LogTabs(tabLevel) + nodeId + "(" + typeName + ")"); Debug.WriteLine(LogTabs(tabLevel) + "Previous=" + node.Previous); using (var enumeration = BPlusTreeOperations.GetEnumerator(nodes, nodeId, EdgeType.ListItem)) { while (enumeration.MoveNext()) { Debug.WriteLine(LogTabs(tabLevel) + enumeration.Current.Data + "="); LogNodesRecursive(enumeration.Current.ToNodeId, nodes, changes, tabLevel + 1, visited, typesService); } } }
private static void LogObject(Guid nodeId, Node <Guid, object, EdgeData> node, INodeProvider <Guid, object, EdgeData> nodes, INodeProvider <Guid, object, EdgeData> changes, int tabLevel, Hashtable visited, TypesService typesService) { var typeId = typesService.GetInstanceTypeId(node); var typeName = typesService.GetTypeFromId(typeId).Name; Debug.WriteLine(LogTabs(tabLevel) + nodeId + "(" + typeName + ")"); Debug.WriteLine(LogTabs(tabLevel) + "Previous=" + node.Previous); foreach (var value in node.Values) { Debug.WriteLine(LogTabs(tabLevel) + typesService.GetMemberName(typeId, value.Key) + "=" + value.Value); } foreach (var edge in node.Edges) { if (edge.Value.Data.Semantic == EdgeType.Property) { Debug.WriteLine(LogTabs(tabLevel) + typesService.GetMemberName(typeId, (Guid)edge.Value.Data.Data) + "="); LogNodesRecursive(edge.Value.ToNodeId, nodes, changes, tabLevel + 1, visited, typesService); } } }
/// <summary> /// Creates subscription to object changes for specific property /// </summary> /// <param name="workspaceId">Workspace identifier which is making a subscription</param> /// <param name="instanceId">Instance Id which changes are going to be notified</param> /// <param name="propertyName">Property name which changes are going to be notified</param> /// <param name="notifyChangesFromSameWorkspace">Defines if changes from same workspace should be notified</param> /// <param name="del">Delegate to be called</param> /// <returns>Subscription object</returns> public Subscription Create(Guid workspaceId, Guid instanceId, string propertyName, bool notifyChangesFromSameWorkspace, EventHandler <ObjectChangedEventArgs> del) { lock (subscriptions) { var id = Guid.NewGuid(); var typeId = typesService.GetInstanceTypeId(instanceId); var memberId = typesService.GetTypeMemberId(typeId, propertyName); if (memberId.Equals(Guid.Empty)) { throw new ArgumentException("Property " + propertyName + " not found in type " + typesService.GetTypeFromId(typeId)); } var res = new SubscriptionElement(id, workspaceId, instanceId, memberId, notifyChangesFromSameWorkspace, del); subscriptions.Add(id, res); return(new Subscription(id, workspaceId)); } }