private void SharedLoadWorkflow(InstancePersistenceContext context, Guid instanceId) { if (instanceId != Guid.Empty) { IDictionary <XName, InstanceValue> instanceData; IDictionary <XName, InstanceValue> instanceMetadata; _dataStore.LoadInstance(instanceId, out instanceData, out instanceMetadata); if (context.InstanceView.InstanceId == Guid.Empty) { context.BindInstance(instanceId); } context.LoadedInstance(InstanceState.Initialized, instanceData, instanceMetadata, null, null); } else { throw new InstanceNotReadyException( String.Format(ErrorResource.UnableToLoadInstance, instanceId)); } }
private long ProcessLoadByKeyCommand(InstancePersistenceContext context, LoadWorkflowByInstanceKeyCommand command) { Owner owner = CheckOwner(context, command.Name); Key key = PersistenceItemManager.Load <Key>(command.LookupInstanceKey); Instance instance; if (key == null) { if (context.InstanceView.IsBoundToLock && context.InstanceView.InstanceId != command.AssociateInstanceKeyToInstanceId) { // This happens in the bind reclaimed lock case. context.InstanceHandle.Free(); throw new InstanceLockLostException(command.Name, context.InstanceView.InstanceId); } if (command.AssociateInstanceKeyToInstanceId == Guid.Empty) { throw new InstanceKeyNotReadyException(command.Name, new InstanceKey(command.LookupInstanceKey)); } key = new Key() { Id = command.LookupInstanceKey, TargetInstanceId = command.AssociateInstanceKeyToInstanceId, Metadata = new PropertyBag() }; instance = PersistenceItemManager.Load <Instance>(command.AssociateInstanceKeyToInstanceId); if (instance == null) { // Checking instance.Owner is like an InstanceLockQueryResult. context.QueriedInstanceStore(new InstanceLockQueryResult(command.AssociateInstanceKeyToInstanceId, Guid.Empty)); if (context.InstanceView.IsBoundToLock) { // This happens in the bind reclaimed lock case. context.InstanceHandle.Free(); throw new InstanceLockLostException(command.Name, context.InstanceView.InstanceId); } context.BindInstance(command.AssociateInstanceKeyToInstanceId); if (command.AcceptUninitializedInstance) { instance = new Instance() { Id = command.AssociateInstanceKeyToInstanceId, Version = 1, Metadata = new PropertyBag(), Owner = context.InstanceView.InstanceOwner.InstanceOwnerId }; PersistenceItemManager.SaveToFile <Instance>(instance); } else { throw new Exception("Could not create new Instance"); } context.BindAcquiredLock(1); } else { // Checking instance.Owner is like an InstanceLockQueryResult. context.QueriedInstanceStore(new InstanceLockQueryResult(command.AssociateInstanceKeyToInstanceId, instance.Owner)); if (context.InstanceView.IsBoundToLock) { if (instance.Version != context.InstanceVersion || instance.Owner != context.InstanceView.InstanceOwner.InstanceOwnerId) { if (context.InstanceVersion > instance.Version) { throw new InvalidProgramException("This is a bug, the context should never be bound higher than the lock."); } context.InstanceHandle.Free(); throw new InstanceLockLostException(command.Name, context.InstanceView.InstanceId); } } if (instance.Data != null) { // LoadByInstanceKeyCommand only allows auto-association to an uninitialized instance. throw new InstanceCollisionException(command.Name, command.AssociateInstanceKeyToInstanceId); } if (!context.InstanceView.IsBoundToLock) { if (instance.Owner == Guid.Empty) { context.BindInstance(command.AssociateInstanceKeyToInstanceId); instance.Version++; instance.Owner = context.InstanceView.InstanceOwner.InstanceOwnerId; PersistenceItemManager.SaveToFile <Instance>(instance); context.BindAcquiredLock(instance.Version); } else if (instance.Owner == context.InstanceView.InstanceOwner.InstanceOwnerId) { // This is a pretty weird case - maybe it's a retry? context.BindInstance(command.AssociateInstanceKeyToInstanceId); return(instance.Version); } else { throw new InstanceLockedException(command.Name, instance.Owner); } } } if (command.InstanceKeysToAssociate.TryGetValue(command.LookupInstanceKey, out IDictionary <XName, InstanceValue> lookupKeyMetadata)) { key.Metadata = new PropertyBag(lookupKeyMetadata); } else { key.Metadata = new PropertyBag(); } key.Id = command.LookupInstanceKey; key.TargetInstanceId = command.AssociateInstanceKeyToInstanceId; PersistenceItemManager.SaveToFile <Key>(key); context.AssociatedInstanceKey(command.LookupInstanceKey); if (lookupKeyMetadata != null) { foreach (KeyValuePair <XName, InstanceValue> property in lookupKeyMetadata) { context.WroteInstanceKeyMetadataValue(command.LookupInstanceKey, property.Key, property.Value); } } } else { if (context.InstanceView.IsBoundToLock && (key.State == InstanceKeyState.Completed || key.TargetInstanceId != context.InstanceView.InstanceId)) { // This happens in the bind reclaimed lock case. context.InstanceHandle.Free(); throw new InstanceLockLostException(command.Name, context.InstanceView.InstanceId); } if (key.State == InstanceKeyState.Completed) { throw new InstanceKeyCompleteException(command.Name, new InstanceKey(command.LookupInstanceKey)); } instance = PersistenceItemManager.Load <Instance>(key.TargetInstanceId); // Checking instance.Owner is like an InstanceLockQueryResult. context.QueriedInstanceStore(new InstanceLockQueryResult(key.TargetInstanceId, instance.Owner)); if (context.InstanceView.IsBoundToLock) { if (instance.Version != context.InstanceVersion || instance.Owner != context.InstanceView.InstanceOwner.InstanceOwnerId) { if (context.InstanceVersion > instance.Version) { throw new InvalidProgramException("This is a bug, the context should never be bound higher than the lock."); } context.InstanceHandle.Free(); throw new InstanceLockLostException(command.Name, context.InstanceView.InstanceId); } } if (instance.Data == null && !command.AcceptUninitializedInstance) { throw new InstanceNotReadyException(command.Name, key.TargetInstanceId); } if (!context.InstanceView.IsBoundToLock) { if (instance.Owner == Guid.Empty) { context.BindInstance(key.TargetInstanceId); instance.Version++; instance.Owner = context.InstanceView.InstanceOwner.InstanceOwnerId; PersistenceItemManager.SaveToFile <Instance>(instance); context.BindAcquiredLock(instance.Version); } else if (instance.Owner == context.InstanceView.InstanceOwner.InstanceOwnerId) { // This is the very interesting parallel-convoy conflicting handle race resolution case. Two handles // can get bound to the same lock, which is necessary to allow parallel convoy to succeed without preventing // zombied locked instances from being reclaimed. context.BindInstance(key.TargetInstanceId); return(instance.Version); } else { throw new InstanceLockedException(command.Name, instance.Owner); } } } Key newKey; Exception exception = null; foreach (KeyValuePair <Guid, IDictionary <XName, InstanceValue> > keyEntry in command.InstanceKeysToAssociate) { newKey = PersistenceItemManager.Load <Key>(keyEntry.Key); if (newKey == null) { newKey = new Key() { Id = keyEntry.Key, TargetInstanceId = key.TargetInstanceId, Metadata = new PropertyBag(keyEntry.Value) }; PersistenceItemManager.AddKeyToInstance(key.TargetInstanceId, newKey); context.AssociatedInstanceKey(keyEntry.Key); if (keyEntry.Value != null) { foreach (KeyValuePair <XName, InstanceValue> property in keyEntry.Value) { context.WroteInstanceKeyMetadataValue(keyEntry.Key, property.Key, property.Value); } } } else { if (newKey.TargetInstanceId != key.TargetInstanceId && exception == null) { exception = new InstanceKeyCollisionException(command.Name, key.TargetInstanceId, new InstanceKey(keyEntry.Key), newKey.TargetInstanceId); } } } if (exception != null) { throw exception; } Dictionary <Guid, IDictionary <XName, InstanceValue> > associatedKeys = new Dictionary <Guid, IDictionary <XName, InstanceValue> >(); Dictionary <Guid, IDictionary <XName, InstanceValue> > completedKeys = new Dictionary <Guid, IDictionary <XName, InstanceValue> >(); foreach (Guid keyId in instance.RelatedKeys) { key = PersistenceItemManager.Load <Key>(keyId); if (key.TargetInstanceId == context.InstanceView.InstanceId) { if (key.State == InstanceKeyState.Completed) { completedKeys.Add(key.Id, ExcludeWriteOnlyPropertyBagItems(key.Metadata)); } else { associatedKeys.Add(key.Id, ExcludeWriteOnlyPropertyBagItems(key.Metadata)); } } } instance.State = instance.Data == null ? InstanceState.Uninitialized : InstanceState.Initialized; PersistenceItemManager.SaveToFile <Instance>(instance); context.LoadedInstance(instance.State, ExcludeWriteOnlyPropertyBagItems(instance.Data), ExcludeWriteOnlyPropertyBagItems(instance.Metadata), associatedKeys, completedKeys); return(0); }