public void DeleteMessage(MsmqReceiveContext receiveContext, TimeSpan timeout) { TimeoutHelper helper = new TimeoutHelper(timeout); long lookupId = receiveContext.LookupId; lock (this.internalStateLock) { if (!this.messageExpiryMap.ContainsKey(lookupId)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MsmqException(System.ServiceModel.SR.GetString("MessageValidityExpired", new object[] { lookupId }))); } MsmqReceiveContext item = this.messageExpiryMap[lookupId]; if (DateTime.UtcNow > item.ExpiryTime) { item.MarkContextExpired(); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MsmqException(System.ServiceModel.SR.GetString("MessageValidityExpired", new object[] { lookupId }))); } ((ILockingQueue)this.queue).DeleteMessage(lookupId, helper.RemainingTime()); if (Transaction.Current != null) { List <MsmqReceiveContext> list; if (!this.transMessages.TryGetValue(Transaction.Current.TransactionInformation.DistributedIdentifier, out list)) { list = new List <MsmqReceiveContext>(); this.transMessages.Add(Transaction.Current.TransactionInformation.DistributedIdentifier, list); Transaction.Current.TransactionCompleted += this.transactionCompletedHandler; } list.Add(item); } else { this.messageExpiryMap.Remove(lookupId); } } }
// tx aborts can ---- with DeleteMessage but this ---- is harmless because // - internal state changes are protected via the internalStateLock // - we do not have an ordering requirement between DeleteMessage and a tx abort // // tx commits cannot ---- with DeleteMessage as the ReceiveContext state machine does not allow // DeleteMessage calls if the tx holding this lock committed public void DeleteMessage(MsmqReceiveContext receiveContext, TimeSpan timeout) { TimeoutHelper helper = new TimeoutHelper(timeout); long lookupId = receiveContext.LookupId; lock (this.internalStateLock) { // Expiry map is first checked before calling ReceiveContextExists as we need to throw // validity expired exception if the lookup id is not in the map. if (this.messageExpiryMap.ContainsKey(lookupId)) { Fx.Assert(ReceiveContextExists(receiveContext), "Mismatch between the receive context object stored in the map and the object passed to the method"); MsmqReceiveContext entry = this.messageExpiryMap[lookupId]; if (DateTime.UtcNow > entry.ExpiryTime) { entry.MarkContextExpired(); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MsmqException(SR.GetString(SR.MessageValidityExpired, lookupId))); } else { ((ILockingQueue)this.queue).DeleteMessage(lookupId, helper.RemainingTime()); if (Transaction.Current != null) { List <MsmqReceiveContext> transMsgs; if (!this.transMessages.TryGetValue(Transaction.Current.TransactionInformation.DistributedIdentifier, out transMsgs)) { transMsgs = new List <MsmqReceiveContext>(); this.transMessages.Add(Transaction.Current.TransactionInformation.DistributedIdentifier, transMsgs); // only need to attach the tx complete handler once per transaction Transaction.Current.TransactionCompleted += this.transactionCompletedHandler; } transMsgs.Add(entry); } else { this.messageExpiryMap.Remove(lookupId); } } } else { // it was cleaned up by the expiry timer throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MsmqException(SR.GetString(SR.MessageValidityExpired, lookupId))); } } }