activemq-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From StefanL <stefan_...@yahoo.se>
Subject Re: ActiveMQ.Net: Client does not include timestamp when calculating expiration
Date Tue, 04 Sep 2007 06:06:02 GMT

Hi Jim,

Thanks for your fix which I am about to use. Just a note on the type
initializer in DateUtils,
    static DateUtils() 
    { 
        epochDiff = (javaEpoch.ToFileTime() - windowsEpoch.ToFileTime())  /
TimeSpan.TicksPerMillisecond; 
    } 

This fails here in GMT+1 land when the 'windowsEpoch.ToFileTime()' is called
with ArgumentException.
If I instead do 'new DateTime(1601, 1, 1, 1, 0, 0, 0).ToFileTime()' this
gives 0/zero.
Note the 1 hour specified to the DateTime ctor.

Anyway, I would suggest that the row would be 
epochDiff = (javaEpoch.ToFileTimeUtc() - windowsEpoch.ToFileTimeUtc())  /
TimeSpan.TicksPerMillisecond;

Which runs without exceptions, hopefully it runs correct also..
Regards
 Stefan


semog wrote:
> 
> Hi Peter,
> 
> I have just spent the last week diagnosing and fixing this very problem in
> the .NET client.  It took me a long time to figure out exactly where the
> problem was.  There seems to be a disconnect between the concept of "time
> to live" and "expiration".  "Time to live" is a relative timespan, while
> "expiration" is an absolute date/time.  In addition, there is a bug in the
> DateUtils class when converting between .NET DateTime and Java dates. 
> Here is the fix that I have come up with.  Basically, I fixed the date
> utility conversion functions.  I then made the concept of "time to live"
> transparent to the client API.  ActiveMQ seems to require an absolute
> "expiration" time, so I hid the translation of that inside the
> ActiveMQMessage class.  Following are the gist of my changes.  I will show
> the key parts that you can add, but you may have to change some
> supplementary files to make the change complete, but those supplementary
> changes should be very obvious (i.e., adding a declaration, or changing
> the NMSExpiration to NMSTimeToLive).  Try these changes and see if they
> work for you:
> 
> Here is my new implementation of the DateUtils class.  This is a complete
> drop-in replacement.  The key fix here was the old implementation mixed
> calculating ticks with millisecends.  Ticks are defined as 100-nanosecond
> increments, a calculation error factor of 10,000:
> 
> 	internal class DateUtils
> 	{
> 		/// <summary>
> 		/// The start of the Windows epoch
> 		/// </summary>
> 		public static readonly DateTime windowsEpoch = new DateTime(1601, 1, 1,
> 0, 0, 0, 0);
> 		/// <summary>
> 		/// The start of the Java epoch
> 		/// </summary>
> 		public static readonly DateTime javaEpoch = new DateTime(1970, 1, 1, 0,
> 0, 0, 0);
> 		
> 		/// <summary>
> 		/// The difference between the Windows epoch and the Java epoch
> 		/// in milliseconds.
> 		/// </summary>
> 		public static readonly long epochDiff; /* = 1164447360000L; */
> 
> 		static DateUtils()
> 		{
> 			epochDiff = (javaEpoch.ToFileTime() - windowsEpoch.ToFileTime())
> 							/ TimeSpan.TicksPerMillisecond;
> 		}
> 
> 		public static long ToJavaTime(DateTime dateTime)
> 		{
> 			return (dateTime.ToFileTime() / TimeSpan.TicksPerMillisecond) -
> epochDiff;
> 		}
> 
> 		public static DateTime ToDateTime(long javaTime)
> 		{
> 			return DateTime.FromFileTime((javaTime + epochDiff) *
> TimeSpan.TicksPerMillisecond);
> 		}
> 	}
> 
> In IMessage.cs, change the interface declaration name for NMSExpiration to
> NMSTimeToLive.  In the ActiveMQMessage.cs file, add the following member
> variable to ActiveMQMessage:
> 
> 		protected DateTime expirationBaseTime;
> 
> In the same ActiveMQMessage.cs file, change the definition for
> NMSExpiration into the following definition for NMSTimeToLive (renaming
> the property field at the same time):
> 
>         /// <summary>
>         /// The time in milliseconds that this message should expire in
>         /// </summary>
> 		public TimeSpan NMSTimeToLive
> 		{
> 			get {
> 				if(0 != Expiration)
> 				{
> 					DateTime expirationTime = DateUtils.ToDateTime(Expiration);
> 					return expirationTime - expirationBaseTime;
> 				}
> 				else
> 				{
> 					return TimeSpan.FromMilliseconds(0);
> 				}
> 			}
> 			set {
> 				expirationBaseTime = DateTime.UtcNow;
> 				Expiration = DateUtils.ToJavaTime(expirationBaseTime + value);
> 			}
> 		}
> 
> I also changed the NMSTimeStamp property as follows.  I added a setter
> property, which makes things much easier on the client side:
> 
>         /// <summary>
>         /// The timestamp the broker added to the message
>         /// </summary>
>         public DateTime NMSTimestamp
>         {
>             get {
>                 return DateUtils.ToDateTime(Timestamp);
>             }
>             set {
>                 Timestamp = DateUtils.ToJavaTime(value);
>             }
>         }
> 
> Now, in the ActiveMQ MessageProducer.cs file, change the Send(...)
> function as follows:
> 
> 		protected void Send(IDestination destination, IMessage message, bool
> persistent, byte priority, TimeSpan timeToLive, bool specifiedTimeToLive)
> 		{
> 			ActiveMQMessage activeMessage = (ActiveMQMessage)message;
> 
> 			if (!disableMessageID)
> 			{
> 				MessageId id = new MessageId();
> 				id.ProducerId = info.ProducerId;
> 				lock (this)
> 				{
> 					id.ProducerSequenceId = ++messageCounter;
> 				}
> 
> 				activeMessage.MessageId = id;
> 			}
> 
> 			activeMessage.ProducerId = info.ProducerId;
> 			activeMessage.FromDestination = destination;
> 			activeMessage.NMSPersistent = persistent;
> 			activeMessage.NMSPriority = priority;
> 
> 			if (session.Transacted)
> 			{
> 				session.DoStartTransaction();
> 				activeMessage.TransactionId =
> session.TransactionContext.TransactionId;
> 			}
> 
> 			if (specifiedTimeToLive)
> 			{
> 				activeMessage.NMSTimeToLive = timeToLive;
> 			}
> 
> 			if (!disableMessageTimestamp)
> 			{
> 				activeMessage.NMSTimestamp = DateTime.UtcNow;
> 			}
> 
> 			session.DoSend(activeMessage);
> 		}
> 
> Notice that the setting of the NMSTimestamp property does not require
> conversion to Java time from .NET time format, as this is taken care of
> inside the new setter property.  At any level above this where you may
> have explicitly set the NMSExpiration property of the message, will need
> to be changed to NMSTimeToLive.  The NMSTimeToLive property is now
> correctly and consistently a timespan, instead of an absolute date/time. 
> These changes are much more logical to me, and I will continue with my
> version of the client.  These changes allow my .NET clients to deal
> compleletly in .NET date/time format and the conversion to/from Java
> date/time format is hidden.
> 
> Like I mentioned, you will need to make some trivial changes to MSMQ
> implementation and one or two test cases, but those are simple renames.  I
> hope that this can save you some time.  Since I am new to this list, I
> haven't found the directions on how to submit these changes back for
> possible commit into the actual source code.  Perhaps this is the first
> step in that process.
> 
> Thanks.  Please let me know if you have any questions or need further
> assistance in this area.
> 
> - Jim Gomes
> 
> 
> 
> PeterNilsson wrote:
>> 
>> Hi,
>> 
>> We have just started setting timeToLive when sending messages with the
>> ActiveMQ.Net client. However we get an exception when sending:
>> 
>> mscorlib.dll!System.DateTime.ToFileTimeUtc() + 0xad bytes	
>> mscorlib.dll!System.DateTime.ToFileTime() + 0x1c bytes	
>> NMS.ActiveMQ.DLL!ActiveMQ.Util.DateUtils.ToJavaTime(System.DateTime
>> dateTime = {0001-01-01 00:00:05}) Line 46 + 0x8 bytes	C#
>> NMS.ActiveMQ.DLL!ActiveMQ.Util.DateUtils.ToJavaTime(System.TimeSpan
>> timeToLive = {00:00:05}) Line 41 + 0x35 bytes	C#
>> NMS.ActiveMQ.DLL!ActiveMQ.MessageProducer.Send(NMS.IDestination
>> destination = {queue://test}, NMS.IMessage message =
>> {ActiveMQBytesMessage[ ProducerId= Destination= TransactionId=
>> OriginalDestination= MessageId=MessageId[ ProducerId=ProducerId[
>> ConnectionId=a5e10bc2-46ce-4b5b-be85-d1ed6e0c7575 Value=1 SessionId=1 ]
>> ProducerSequenceId=1 BrokerSequenceId=0 ] OriginalTransactionId= GroupID=
>> GroupSequence=0 CorrelationId=0 Persistent=False Expiration=0 Priority=0
>> ReplyTo=temp-queue://a5e10bc2-46ce-4b5b-be85-d1ed6e0c7575:1
>> Timestamp=128310953802143903 Type= Content=System.Byte[]
>> MarshalledProperties= DataStructure= TargetConsumerId= Compressed=False
>> RedeliveryCounter=0 BrokerPath= Arrival=0 UserID=
>> RecievedByDFBridge=False Droppable=False ]}, bool persistent = false,
>> byte priority = 5, System.TimeSpan timeToLive = {00:00:05}, bool
>> specifiedTimeToLive = true) Line 88 + 0x17 bytes	C#
>> NMS.ActiveMQ.DLL!ActiveMQ.MessageProducer.Send(NMS.IDestination
>> destination = {queue://test}, NMS.IMessage message =
>> {ActiveMQBytesMessage[ ProducerId= Destination= TransactionId=
>> OriginalDestination= MessageId=MessageId[ ProducerId=ProducerId[
>> ConnectionId=a5e10bc2-46ce-4b5b-be85-d1ed6e0c7575 Value=1 SessionId=1 ]
>> ProducerSequenceId=1 BrokerSequenceId=0 ] OriginalTransactionId= GroupID=
>> GroupSequence=0 CorrelationId=0 Persistent=False Expiration=0 Priority=0
>> ReplyTo=temp-queue://a5e10bc2-46ce-4b5b-be85-d1ed6e0c7575:1
>> Timestamp=128310953802143903 Type= Content=System.Byte[]
>> MarshalledProperties= DataStructure= TargetConsumerId= Compressed=False
>> RedeliveryCounter=0 BrokerPath= Arrival=0 UserID=
>> RecievedByDFBridge=False Droppable=False ]}, bool persistent = false,
>> byte priority = 5, System.TimeSpan timeToLive = {00:00:05}) Line 62 +
>> 0x27 bytes	C#
>>  	
>> When looking at the code for MessageProducer it looks like timestamp has
>> been omitted from the calculation of expiration: 
>> 
>> if (specifiedTimeToLive) {
>>   activeMessage.Expiration =
>> ActiveMQ.Util.DateUtils.ToJavaTime(timeToLive);
>> }
>> 
>> It looks like a bug to me, do you agree? 
>> 
>>    Peter
>> 
>> 
> 
> 

-- 
View this message in context: http://www.nabble.com/ActiveMQ.Net%3A-Client-does-not-include-timestamp-when-calculating-expiration-tf4312287s2354.html#a12472360
Sent from the ActiveMQ - Dev mailing list archive at Nabble.com.


Mime
View raw message