/// <summary> /// Handles a Destination Order entering the error state. /// </summary> private static void SetErrorAction(Object[] key, params Object[] parameters) { // A middle tier context is also required for a transacted update. DataModelTransaction dataModelTransaction = DataModelTransaction.Current; // It is possible that the Working Order that is the object of this status update operation may have been deleted since the action was // created. This is not an error condition. If there is no Working Order to update, then the operation is just terminated prematurely. WorkingOrderRow workingOrderRow = DataModel.WorkingOrder.WorkingOrderKey.Find(key); if (workingOrderRow == null) { return; } workingOrderRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout); dataModelTransaction.AddLock(workingOrderRow); if (workingOrderRow.RowState == DataRowState.Detached) { return; } // The Working Order reflects an 'Error' Status if any of its Destination Orders have an error. if (workingOrderRow.StatusId != StatusMap.FromCode(Status.Error)) { UpdateWorkingOrderStatus(workingOrderRow, Status.Error); } }
/// <summary> /// Changes the state of the Working Order to reflect a filledly filled state. /// </summary> private static void OnFilledAction(Object[] key, params Object[] parameters) { // A middle tier context is also required for a transacted update. DataModelTransaction dataModelTransaction = DataModelTransaction.Current; // It is possible that the Working Order that is the object of this status update operation may have been deleted since the action was // created. This is not an error condition. If there is no Working Order to update, then the operation is just terminated prematurely. WorkingOrderRow workingOrderRow = DataModel.WorkingOrder.WorkingOrderKey.Find(key); if (workingOrderRow == null) { return; } workingOrderRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout); dataModelTransaction.AddLock(workingOrderRow); if (workingOrderRow.RowState == DataRowState.Detached) { return; } // The error status on a Working Order cannot be cleared with a fill. if (workingOrderRow.StatusId != StatusMap.FromCode(Status.Error)) { // The Working Order is 'Filled' when the quantity executed is the same as the quantity ordered. Decimal quantityOrdered = WorkingOrder.GetSourceOrderQuantity(dataModelTransaction, workingOrderRow); Decimal quantityExecuted = WorkingOrder.GetExecutionQuantity(dataModelTransaction, workingOrderRow); if (quantityOrdered == quantityExecuted) { UpdateWorkingOrderStatus(workingOrderRow, Status.Filled); } } }
/// <summary> /// Changes the state of the Working Order to reflect a partially filled status. /// </summary> private static void OnPartialAction(Object[] key, params Object[] parameters) { // A middle tier context is also required for a transacted update. DataModelTransaction dataModelTransaction = DataModelTransaction.Current; // It is possible that the Working Order that is the object of this status update operation may have been deleted since the action was // created. This is not an error condition. If there is no Working Order to update, then the operation is just terminated prematurely. WorkingOrderRow workingOrderRow = DataModel.WorkingOrder.WorkingOrderKey.Find(key); if (workingOrderRow == null) { return; } workingOrderRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout); dataModelTransaction.AddLock(workingOrderRow); if (workingOrderRow.RowState == DataRowState.Detached) { return; } // The error status on a Working Order cannot be cleared with a partial fill. Otherwise, a partial fill on any of the Destination Orders is // reflected in the status of the parent Working Order. if (workingOrderRow.StatusId != StatusMap.FromCode(Status.Error)) { if (workingOrderRow.StatusId != StatusMap.FromCode(Status.PartiallyFilled)) { UpdateWorkingOrderStatus(workingOrderRow, Status.PartiallyFilled); } } }
/// <summary> /// Changes the state of the Working Order to reflect a filledly filled state. /// </summary> private static void ClearErrorAction(Object[] key, params Object[] parameters) { // A middle tier context is also required for a transacted update. DataModelTransaction dataModelTransaction = DataModelTransaction.Current; // It is possible that the Working Order that is the object of this status update operation may have been deleted since the action was // created. This is not an error condition. If there is no Working Order to update, then the operation is just terminated prematurely. WorkingOrderRow workingOrderRow = DataModel.WorkingOrder.WorkingOrderKey.Find(key); if (workingOrderRow == null) { return; } workingOrderRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout); dataModelTransaction.AddLock(workingOrderRow); if (workingOrderRow.RowState == DataRowState.Detached) { return; } // The 'Error' status is only cleared when all the Destination Orders are valid. Boolean isErrorStatus = false; foreach (DestinationOrderRow siblingOrderRow in workingOrderRow.GetDestinationOrderRows()) { siblingOrderRow.AcquireReaderLock(dataModelTransaction); if (siblingOrderRow.StatusId == StatusMap.FromCode(Status.Error)) { isErrorStatus = true; break; } } // The proper Working Order status must be evaluated when the error status is cleared. if (!isErrorStatus) { // The aggregates will determine the new state of the Working Order. Decimal quantityExecuted = WorkingOrder.GetExecutionQuantity(dataModelTransaction, workingOrderRow); Decimal quantityOrdered = WorkingOrder.GetSourceOrderQuantity(dataModelTransaction, workingOrderRow); // This restores the 'New' status when the canceled Destination Order was the only order with any fills. if (quantityExecuted == 0.0M && workingOrderRow.StatusId != StatusMap.FromCode(Status.New)) { UpdateWorkingOrderStatus(workingOrderRow, Status.New); } // This restores the 'Partially Filled' status when other executions remain. if (0.0M < quantityExecuted && quantityExecuted < quantityOrdered && workingOrderRow.StatusId != StatusMap.FromCode(Status.PartiallyFilled)) { UpdateWorkingOrderStatus(workingOrderRow, Status.PartiallyFilled); } // This restores the 'Filled' status when the quantity executed is the same as the quantity ordered. if (quantityExecuted == quantityOrdered && workingOrderRow.StatusId != StatusMap.FromCode(Status.Filled)) { UpdateWorkingOrderStatus(workingOrderRow, Status.Filled); } } }
/// <summary> /// Delete a WorkingOrderRow. /// </summary> /// <param name="dataModel">The data model.</param> /// <param name="transaction">The current transaction.</param> /// <param name="workingOrderRow">The working order row to delete.</param> /// <returns>Error code of any failure, or Success.</returns> public ErrorCode DeleteRow(DataModel dataModel, DataModelTransaction transaction, WorkingOrderRow workingOrderRow) { SecurityRow securityRow = null; EntityRow securityEntityRow = null; MatchRow[] matchRows; ConsumerDebtRow[] consumerDebtRows; ConsumerTrustRow[] consumerTrustRows; CreditCardRow creditCardRow = null; ConsumerRow consumerRow = null; Guid blotterId; Guid securityEntityId = Guid.Empty; Int64 securityEntityRowVersion = 0; Guid consumerId = Guid.Empty; Int64 consumerRowVersion = 0; Guid creditCardId = Guid.Empty; Int64 creditCardRowVersion = 0; Boolean consumerStillInUse = false; workingOrderRow.AcquireWriterLock(transaction.TransactionId, DataModel.LockTimeout); if (workingOrderRow.RowState == DataRowState.Deleted || workingOrderRow.RowState == DataRowState.Detached) { workingOrderRow.ReleaseLock(transaction.TransactionId); return(ErrorCode.RecordNotFound); } else { transaction.AddLock(workingOrderRow); } blotterId = workingOrderRow.BlotterId; securityRow = workingOrderRow.SecurityRowByFK_Security_WorkingOrder_SecurityId; matchRows = workingOrderRow.GetMatchRows(); if (matchRows != null) { foreach (MatchRow matchRow in matchRows) { if (IsSettled(transaction, matchRow)) { return(ErrorCode.RecordExists); } } } if (!DataModelFilters.HasAccess(transaction, TradingSupport.UserId, blotterId, AccessRight.Write)) { workingOrderRow.ReleaseLock(transaction.TransactionId); return(ErrorCode.AccessDenied); } securityRow.AcquireWriterLock(transaction.TransactionId, DataModel.LockTimeout); if (securityRow.RowState == DataRowState.Deleted || securityRow.RowState == DataRowState.Detached) { workingOrderRow.ReleaseLock(transaction.TransactionId); securityRow.ReleaseWriterLock(transaction.TransactionId); return(ErrorCode.RecordNotFound); } securityEntityRow = securityRow.EntityRow; consumerDebtRows = securityRow.GetConsumerDebtRows(); consumerTrustRows = securityRow.GetConsumerTrustRows(); securityRow.ReleaseWriterLock(transaction.TransactionId); securityEntityRow.AcquireWriterLock(transaction); if (securityEntityRow.RowState == DataRowState.Deleted || securityEntityRow.RowState == DataRowState.Detached) { workingOrderRow.ReleaseLock(transaction.TransactionId); securityEntityRow.ReleaseLock(transaction.TransactionId); return(ErrorCode.RecordNotFound); } securityEntityId = securityEntityRow.EntityId; securityEntityRowVersion = securityEntityRow.RowVersion; securityEntityRow.ReleaseLock(transaction.TransactionId); if (consumerTrustRows.Length > 0 && consumerDebtRows.Length > 0) { EventLog.Warning("Deleting a working order associated with both ConsumerDebt and ConsumerTrust rows"); } else if (consumerDebtRows.Length > 1) { EventLog.Warning("Deleting a working order associated with more than one ConsumerDebt row"); } else if (consumerTrustRows.Length > 1) { EventLog.Warning("Deleting a working order associated with more than one ConsumerTrust row"); } if (consumerDebtRows.Length == 1) { ConsumerDebtRow consumerDebtRow = consumerDebtRows[0]; consumerDebtRow.AcquireWriterLock(transaction); if (consumerDebtRow.RowState == DataRowState.Deleted || consumerDebtRow.RowState == DataRowState.Detached) { } else { creditCardRow = consumerDebtRow.CreditCardRow; consumerRow = consumerDebtRow.ConsumerRow; } consumerDebtRow.ReleaseLock(transaction.TransactionId); } else if (consumerTrustRows.Length == 1) { ConsumerTrustRow consumerTrustRow = consumerTrustRows[0]; consumerTrustRow.AcquireWriterLock(transaction); if (consumerTrustRow.RowState == DataRowState.Deleted || consumerTrustRow.RowState == DataRowState.Detached) { } else { consumerRow = consumerTrustRow.ConsumerRow; } consumerTrustRow.ReleaseLock(transaction.TransactionId); } if (consumerRow != null) { consumerRow.AcquireWriterLock(transaction); if (consumerRow.RowState == DataRowState.Deleted || consumerRow.RowState == DataRowState.Detached) { consumerRow = null; } else { consumerStillInUse = consumerRow.GetConsumerDebtRows().Length > 1; consumerId = consumerRow.ConsumerId; consumerRowVersion = consumerRow.RowVersion; } consumerRow.ReleaseLock(transaction.TransactionId); } if (creditCardRow != null) { creditCardRow.AcquireWriterLock(transaction); if (creditCardRow.RowState == DataRowState.Deleted || creditCardRow.RowState == DataRowState.Detached) { creditCardRow = null; } else { creditCardId = creditCardRow.ConsumerId; creditCardRowVersion = creditCardRow.RowVersion; } creditCardRow.ReleaseLock(transaction.TransactionId); } //gonna get the lock on the workingOrder and let the txn commit/rollback get rid of it //this will basically wrap the delete row //action in a critical section because the first //reader lock in the method is on the workingOrder row //workingOrderRow.AcquireWriterLock(transaction.TransactionId, DataModel.LockTimeout); if (workingOrderRow.RowState == DataRowState.Deleted || workingOrderRow.RowState == DataRowState.Detached) { workingOrderRow.ReleaseLock(transaction.TransactionId); return(ErrorCode.RecordNotFound); } //securityRow.AcquireWriterLock(transaction.TransactionId, DataModel.LockTimeout); //if(securityRow.RowState == DataRowState.Deleted || // securityRow.RowState == DataRowState.Detached) //{ // workingOrderRow.ReleaseLock(transaction.TransactionId); // return ErrorCode.RecordNotFound; //} if (creditCardRow != null && consumerStillInUse) { dataModel.DestroyCreditCard(new object[] { creditCardId }, creditCardRowVersion); } if (consumerRow != null && !consumerStillInUse) { dataModel.DestroyConsumer(new object[] { consumerId }, consumerRowVersion); } dataModel.DestroyEntity(new object[] { securityEntityId }, securityEntityRowVersion); return(ErrorCode.Success); }
internal static void ClearDestinationOrders() { int batchCounter = 0; int batchSize = 1000; DataModel dataModel = new DataModel(); try { DataModel.DataLock.EnterReadLock(); // This context is used to keep track of the locks aquired for the ancillary data. TransactionScope transactionScope = new TransactionScope(); DataModelTransaction dataModelTransaction = DataModelTransaction.Current; List <ExecutionRow> executionRows = new List <ExecutionRow>(); foreach (ExecutionRow executionRow in DataModel.Execution.Rows) { executionRows.Add(executionRow); } // Destroy all the executions. foreach (ExecutionRow executionRow in executionRows) { executionRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout); dataModelTransaction.AddLock(executionRow); dataModel.DestroyExecution(new object[] { executionRow.ExecutionId }, executionRow.RowVersion); if (batchCounter++ == batchSize) { batchCounter = 0; transactionScope.Complete(); transactionScope.Dispose(); transactionScope = new TransactionScope(); dataModelTransaction = DataModelTransaction.Current; } } List <DestinationOrderRow> destinationOrderRows = new List <DestinationOrderRow>(); foreach (DestinationOrderRow destinationOrderRow in DataModel.DestinationOrder.Rows) { destinationOrderRows.Add(destinationOrderRow); } // Destroy all the Destination Orders. foreach (DestinationOrderRow destinationOrderRow in destinationOrderRows) { destinationOrderRow.AcquireReaderLock(dataModelTransaction.TransactionId, DataModel.LockTimeout); dataModelTransaction.AddLock(destinationOrderRow); dataModel.DestroyDestinationOrder(new object[] { destinationOrderRow.DestinationOrderId }, destinationOrderRow.RowVersion); if (batchCounter++ == batchSize) { batchCounter = 0; transactionScope.Complete(); transactionScope.Dispose(); transactionScope = new TransactionScope(); dataModelTransaction = DataModelTransaction.Current; } } transactionScope.Complete(); transactionScope.Dispose(); } finally { DataModel.DataLock.ExitReadLock(); } }