activemq-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Hiram Chirino" <hi...@hiramchirino.com>
Subject Re: ActiveMQ.Net: Client does not include timestamp when calculating expiration
Date Thu, 30 Aug 2007 21:51:37 GMT
Hi,

Awesome work.  If you open and attach a patch to our issue tracker
then we could start working on merging your change into the main line.

The issue tracker is here:
https://issues.apache.org/activemq/browse/AMQNET
And this page describes how to create patches:
http://activemq.apache.org/contributing.html

Regards,
Hiram

On 8/30/07, semog <e.semog@gmail.com> 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#a12412240
> Sent from the ActiveMQ - Dev mailing list archive at Nabble.com.
>
>


-- 
Regards,
Hiram

Blog: http://hiramchirino.com

Mime
View raw message