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); }
public static Exception GetError(XName commandName, CommandResult result, SqlDataReader reader) { Exception returnValue = null; if (result != CommandResult.Success) { switch (result) { case CommandResult.InstanceAlreadyExists: returnValue = new InstanceCollisionException(commandName, reader.GetGuid(1)); break; case CommandResult.InstanceLockNotAcquired: returnValue = new InstanceLockedException(commandName, reader.GetGuid(1), reader.GetGuid(2), ReadLockOwnerMetadata(reader)); break; case CommandResult.InstanceNotFound: returnValue = new InstanceNotReadyException(commandName, reader.GetGuid(1)); break; case CommandResult.KeyAlreadyExists: returnValue = new InstanceKeyCollisionException(commandName, Guid.Empty, new InstanceKey(reader.GetGuid(1)), Guid.Empty); break; case CommandResult.KeyNotFound: returnValue = new InstanceKeyNotReadyException(commandName, new InstanceKey(reader.GetGuid(1))); break; case CommandResult.InstanceLockLost: returnValue = new InstanceLockLostException(commandName, reader.GetGuid(1)); break; case CommandResult.InstanceCompleted: returnValue = new InstanceCompleteException(commandName, reader.GetGuid(1)); break; case CommandResult.KeyDisassociated: returnValue = new InstanceKeyCompleteException(commandName, new InstanceKey(reader.GetGuid(1))); break; case CommandResult.StaleInstanceVersion: returnValue = new InstanceLockLostException(commandName, reader.GetGuid(1)); break; case CommandResult.HostLockExpired: returnValue = new InstancePersistenceException(SR.HostLockExpired); break; case CommandResult.HostLockNotFound: returnValue = new InstancePersistenceException(SR.HostLockNotFound); break; case CommandResult.CleanupInProgress: returnValue = new InstancePersistenceCommandException(SR.CleanupInProgress); break; case CommandResult.InstanceAlreadyLockedToOwner: returnValue = new InstanceAlreadyLockedToOwnerException(commandName, reader.GetGuid(1), reader.GetInt64(2)); break; default: returnValue = new InstancePersistenceCommandException(SR.UnknownSprocResult(result)); break; } } return(returnValue); }