Lease.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ FX-1434 / FX-1434 / 1.0 / untmp / whidbey / REDBITS / ndp / clr / src / BCL / System / Runtime / Remoting / Lease.cs / 2 / Lease.cs

                            // ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 
//+----------------------------------------------------------------------------
// 
// Microsoft Windows 
// File:        Lease.cs
// 
// Contents:    Lease class
//
// History:     1/5/00   [....]        Created
// 
//+---------------------------------------------------------------------------
 
namespace System.Runtime.Remoting.Lifetime 
{
    using System; 
    using System.Security;
    using System.Security.Permissions;
    using System.Collections;
    using System.Threading; 
    using System.Runtime.Remoting.Messaging;
    using System.Runtime.Remoting.Proxies; 
    using System.Globalization; 

    internal class Lease : MarshalByRefObject, ILease 
    {
        internal int id = 0;

        // Lease Time 
        internal DateTime leaseTime;
        internal TimeSpan initialLeaseTime; 
 
        // Renewal Policies
        internal TimeSpan renewOnCallTime; 
        internal TimeSpan sponsorshipTimeout;
        internal Boolean isInfinite = false;

        // Sponsors 
        internal Hashtable sponsorTable;
        internal int sponsorCallThread; 
 
        // Links to leasemanager and managed object
        internal LeaseManager leaseManager; 
        internal MarshalByRefObject managedObject;

        // State
        internal LeaseState state; 

        internal static int nextId = 0; 
 

        internal Lease(TimeSpan initialLeaseTime, 
                       TimeSpan renewOnCallTime,
                       TimeSpan sponsorshipTimeout,
                       MarshalByRefObject managedObject
                      ) 
        {
            id = nextId++; 
            BCLDebug.Trace("REMOTE", "Lease Constructor ",managedObject," initialLeaseTime "+initialLeaseTime+" renewOnCall "+renewOnCallTime+" sponsorshipTimeout ",sponsorshipTimeout); 

            // Set Policy 
            this.renewOnCallTime = renewOnCallTime;
            this.sponsorshipTimeout = sponsorshipTimeout;
            this.initialLeaseTime = initialLeaseTime;
            this.managedObject = managedObject; 

            //Add lease to leaseManager 
            leaseManager = LeaseManager.GetLeaseManager(); 

            // Initialize tables 
            sponsorTable = new Hashtable(10);
            state = LeaseState.Initial;
        }
 
        internal void ActivateLease()
        { 
            // Set leaseTime 
            leaseTime = DateTime.UtcNow.Add(initialLeaseTime);
            state = LeaseState.Active; 
            leaseManager.ActivateLease(this);
        }

        // Override MarshalByRefObject InitializeLifetimeService 
        // Don't want a lease on a lease therefore returns null
        public override Object InitializeLifetimeService() 
        { 
            BCLDebug.Trace("REMOTE", "Lease ",id," InitializeLifetimeService, lease Marshalled");
            return null; 
        }

        // ILease Property and Methods
 
        public TimeSpan RenewOnCallTime
        { 
            get { return renewOnCallTime; } 
            [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.RemotingConfiguration)]
            set 
            {
                if (state == LeaseState.Initial)
                {
                    renewOnCallTime = value; 
                    BCLDebug.Trace("REMOTE", "Lease Set RenewOnCallProperty ",managedObject," "+renewOnCallTime);
                } 
                else 
                    throw new RemotingException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Remoting_Lifetime_InitialStateRenewOnCall"), ((Enum)state).ToString()));
            } 
        }

        public TimeSpan SponsorshipTimeout
        { 
            get { return sponsorshipTimeout; }
            [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.RemotingConfiguration)] 
            set 
            {
                if (state == LeaseState.Initial) 
                {
                    sponsorshipTimeout = value;
                    BCLDebug.Trace("REMOTE", "Lease Set SponsorshipTimeout Property ",managedObject," "+sponsorshipTimeout);
                } 
                else
                    throw new RemotingException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Remoting_Lifetime_InitialStateSponsorshipTimeout"), ((Enum)state).ToString())); 
            } 
        }
 
        public TimeSpan InitialLeaseTime
        {
            get { return initialLeaseTime; }
 
            [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.RemotingConfiguration)]
            set 
            { 
                if (state == LeaseState.Initial)
                { 
                    initialLeaseTime = value;
                    if (TimeSpan.Zero.CompareTo(value) >= 0)
                        state = LeaseState.Null;
                    BCLDebug.Trace("REMOTE", "Lease Set InitialLeaseTime Property ",managedObject,"  "+InitialLeaseTime+", current state "+((Enum)state).ToString()); 
                }
                else 
                    throw new RemotingException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Remoting_Lifetime_InitialStateInitialLeaseTime"), ((Enum)state).ToString())); 
            }
        } 

        public TimeSpan CurrentLeaseTime
        {
            get { return leaseTime.Subtract(DateTime.UtcNow); } 
        }
 
        public LeaseState CurrentState 
        {
            get { return state;} 
        }


        [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.RemotingConfiguration)] 
        public void Register(ISponsor obj)
        { 
            Register(obj, TimeSpan.Zero); 
        }
 
        [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.RemotingConfiguration)]
        public void Register(ISponsor obj, TimeSpan renewalTime)
        {
            lock(this) 
            {
                BCLDebug.Trace("REMOTE", "Lease "+id+" Register Sponsor  renewalTime ",renewalTime," state ",((Enum)state).ToString()); 
                if (state == LeaseState.Expired || sponsorshipTimeout == TimeSpan.Zero) 
                    return;
 
                Object sponsorId = GetSponsorId(obj);
                lock(sponsorTable)
                {
                    if (renewalTime > TimeSpan.Zero) 
                        AddTime(renewalTime);
                    if (!sponsorTable.ContainsKey(sponsorId)) 
                    { 
                        // Place in tables
                        sponsorTable[sponsorId] = new SponsorStateInfo(renewalTime, SponsorState.Initial); 
                    }
                }
            }
        } 

        [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.RemotingConfiguration)] 
        public void Unregister(ISponsor sponsor) 
        {
            lock(this) 
            {
                BCLDebug.Trace("REMOTE", "Lease",id," Unregister  state ",((Enum)state).ToString());
                if (state == LeaseState.Expired)
                    return; 

                Object sponsorId = GetSponsorId(sponsor); 
                lock(sponsorTable) 
                {
                    if (sponsorId != null) 
                    {
                        leaseManager.DeleteSponsor(sponsorId);
                        SponsorStateInfo sponsorStateInfo = (SponsorStateInfo)sponsorTable[sponsorId];
                        sponsorTable.Remove(sponsorId); 
                    }
                } 
            } 
        }
 
        // Get the local representative of the sponsor to prevent a remote access when placing
        // in a hash table.
        private Object GetSponsorId(ISponsor obj)
        { 
            Object sponsorId = null;
            if (obj != null) 
            { 
                if (RemotingServices.IsTransparentProxy(obj))
                    sponsorId = RemotingServices.GetRealProxy(obj); 
                else
                    sponsorId = obj;
            }
            return sponsorId; 
        }
 
        // Convert from the local representative of the sponsor to either the MarshalByRefObject or local object 
        private ISponsor GetSponsorFromId(Object sponsorId)
        { 
            Object sponsor = null;
            RealProxy rp = sponsorId as RealProxy;
            if (null != rp)
                sponsor = rp.GetTransparentProxy(); 
            else
                sponsor = sponsorId; 
            return (ISponsor)sponsor; 
        }
 
        [SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.RemotingConfiguration)]
        public TimeSpan Renew(TimeSpan renewalTime)
        {
            return RenewInternal(renewalTime); 
        }
 
        // We will call this internally within the server domain 
        internal TimeSpan RenewInternal(TimeSpan renewalTime)
        { 
            lock(this)
            {
                BCLDebug.Trace("REMOTE","Lease ",id," Renew ",renewalTime," state ",((Enum)state).ToString());
                if (state == LeaseState.Expired) 
                    return TimeSpan.Zero;
                AddTime(renewalTime); 
                return leaseTime.Subtract(DateTime.UtcNow); 
            }
        } 

        // Used for a lease which has been created, but will not be used
        internal void Remove()
        { 
            BCLDebug.Trace("REMOTE","Lease ",id," Remove state ",((Enum)state).ToString());
            if (state == LeaseState.Expired) 
                return; 
            state = LeaseState.Expired;
            leaseManager.DeleteLease(this); 
        }

        internal void Cancel()
        { 
            lock(this)
            { 
                BCLDebug.Trace("REMOTE","Lease ",id," Cancel Managed Object ",managedObject," state ",((Enum)state).ToString()); 

                if (state == LeaseState.Expired) 
                    return;

                Remove();
                // Disconnect the object ... 
                // We use the internal version of Disconnect passing "false"
                // for the bResetURI flag. This allows the object to keep its 
                // old URI in case its lease gets reactivated later. 
                RemotingServices.Disconnect(managedObject, false);
 
                // Disconnect the lease for the object.
                RemotingServices.Disconnect(this);
            }
        } 

 
 
#if _DEBUG
        ~Lease() 
        {
            BCLDebug.Trace("REMOTE","Lease ",id," Finalize");
        }
#endif 

        internal void RenewOnCall() 
        { 
            lock(this)
            { 
                //BCLDebug.Trace("REMOTE","Lease ",id," RenewOnCall state ",((Enum)state).ToString());
                if (state == LeaseState.Initial || state == LeaseState.Expired)
                    return;
                AddTime(renewOnCallTime); 
            }
        } 
 
        internal void LeaseExpired(DateTime now)
        { 
            lock(this)
            {
                BCLDebug.Trace("REMOTE","Lease ",id," LeaseExpired state ",((Enum)state).ToString());
                if (state == LeaseState.Expired) 
                    return;
 
                // There is a small window between the time the leaseManager 
                // thread examines all the leases and tests for expiry and
                // when an indivisual lease is locked for expiry. The object 
                // could get marshal-ed in this time which would reset its lease
                // Therefore we check again to see if we should indeed proceed
                // with the expire code (using the same value of 'now' as used
                // by the leaseManager thread) 
                if (leaseTime.CompareTo(now) < 0)
                    ProcessNextSponsor(); 
            } 
        }
 
        internal delegate TimeSpan AsyncRenewal(ILease lease);

        internal void SponsorCall(ISponsor sponsor)
        { 
            BCLDebug.Trace("REMOTE","Lease ",id," SponsorCall state ",((Enum)state).ToString());
            bool exceptionOccurred = false; 
            if (state == LeaseState.Expired) 
                return;
 
            lock(sponsorTable)
            {
                try
                { 
                    Object sponsorId = GetSponsorId(sponsor);
                    sponsorCallThread = Thread.CurrentThread.GetHashCode(); 
                    AsyncRenewal ar = new AsyncRenewal(sponsor.Renewal); 
                    SponsorStateInfo sponsorStateInfo = (SponsorStateInfo)sponsorTable[sponsorId];
                    sponsorStateInfo.sponsorState = SponsorState.Waiting; 

                    // The first parameter should be the lease we are trying to renew.
                    IAsyncResult iar = ar.BeginInvoke(this, new AsyncCallback(this.SponsorCallback), null);
                    if ((sponsorStateInfo.sponsorState == SponsorState.Waiting) && (state != LeaseState.Expired)) 
                    {
                        //   Even if we get here, the operation could still complete before 
                        //   we call the the line below. This seems to be a race. 

                        // Sponsor could have completed before statement is reached, so only execute 
                        // if the sponsor state is still waiting
                        leaseManager.RegisterSponsorCall(this, sponsorId, sponsorshipTimeout);
                    }
                    sponsorCallThread = 0; 
                }catch(Exception)
                { 
                    // Sponsor not avaiable 
                    exceptionOccurred = true;
 
                    sponsorCallThread = 0;
                }
            }
 
            if (exceptionOccurred)
            { 
                BCLDebug.Trace("REMOTE","Lease ",id," SponsorCall Sponsor Exception "); 
                Unregister(sponsor);
                ProcessNextSponsor(); 
            }
        }

        internal void SponsorTimeout(Object sponsorId) 
        {
            lock (this) 
            { 
                if (!sponsorTable.ContainsKey(sponsorId))
                    return; 
                lock(sponsorTable)
                {
                    SponsorStateInfo sponsorStateInfo = (SponsorStateInfo)sponsorTable[sponsorId];
                    BCLDebug.Trace("REMOTE","Lease ",id," SponsorTimeout  sponsorState ",((Enum)sponsorStateInfo.sponsorState).ToString()); 
                    if (sponsorStateInfo.sponsorState == SponsorState.Waiting)
                    { 
                        Unregister(GetSponsorFromId(sponsorId)); 
                        ProcessNextSponsor();
                    } 
                }
            }
        }
 
        private void ProcessNextSponsor()
        { 
            BCLDebug.Trace("REMOTE","Lease ",id," ProcessNextSponsor"); 

            Object largestSponsor = null; 
            TimeSpan largestRenewalTime = TimeSpan.Zero;


            lock(sponsorTable) 
            {
                IDictionaryEnumerator e = sponsorTable.GetEnumerator(); 
                // Find sponsor with largest previous renewal value 
                while(e.MoveNext())
                { 
                    Object sponsorId = e.Key;
                    SponsorStateInfo sponsorStateInfo = (SponsorStateInfo)e.Value;
                    if ((sponsorStateInfo.sponsorState == SponsorState.Initial) && (largestRenewalTime == TimeSpan.Zero))
                    { 
                        largestRenewalTime = sponsorStateInfo.renewalTime;
                        largestSponsor = sponsorId; 
                    } 
                    else if (sponsorStateInfo.renewalTime > largestRenewalTime)
                    { 
                        largestRenewalTime = sponsorStateInfo.renewalTime;
                        largestSponsor = sponsorId;
                    }
                } 
            }
 
            if (largestSponsor != null) 
                SponsorCall(GetSponsorFromId(largestSponsor));
            else 
            {
                // No more sponsors to try, Cancel
                BCLDebug.Trace("REMOTE","Lease ",id," ProcessNextSponsor no more sponsors");
                Cancel(); 
            }
        } 
 

        // This gets called when we explicitly transfer the call back from the 
        // called function to a threadpool thread.
        internal void SponsorCallback(Object obj)
        {
            SponsorCallback((IAsyncResult)obj); 
        }
 
        // On another thread 
        internal void SponsorCallback(IAsyncResult iar)
        { 
            BCLDebug.Trace("REMOTE","Lease ",id," SponsorCallback IAsyncResult ",iar," state ",((Enum)state).ToString());
            if (state == LeaseState.Expired)
            {
                return; 
            }
 
            int thisThread = Thread.CurrentThread.GetHashCode(); 
            if (thisThread == sponsorCallThread)
            { 
                // Looks like something went wrong and the thread that
                // did the AsyncRenewal::BeginInvoke is executing the callback
                // We will queue the work to the thread pool (otherwise there
                // is a possibility of stack overflow if all sponsors are down) 
                WaitCallback threadFunc = new WaitCallback(this.SponsorCallback);
                ThreadPool.QueueUserWorkItem(threadFunc, iar); 
                return; 
            }
 
            AsyncResult asyncResult = (AsyncResult)iar;
            AsyncRenewal ar = (AsyncRenewal)asyncResult.AsyncDelegate;
            ISponsor sponsor = (ISponsor)ar.Target;
            SponsorStateInfo sponsorStateInfo = null; 
            if (iar.IsCompleted)
            { 
                // Sponsor came back with renewal 
                BCLDebug.Trace("REMOTE","Lease ",id," SponsorCallback sponsor completed");
                bool exceptionOccurred = false; 
                TimeSpan renewalTime = TimeSpan.Zero;
                try
                {
                    renewalTime = (TimeSpan)ar.EndInvoke(iar); 
                }catch(Exception)
                { 
                    // Sponsor not avaiable 
                    exceptionOccurred = true;
                } 
                if (exceptionOccurred)
                {
                    BCLDebug.Trace("REMOTE","Lease ",id," SponsorCallback Sponsor Exception ");
                    Unregister(sponsor); 
                    ProcessNextSponsor();
                } 
                else 
                {
                    Object sponsorId = GetSponsorId(sponsor); 
                    lock(sponsorTable)
                    {
                        if (sponsorTable.ContainsKey(sponsorId))
                        { 
                            sponsorStateInfo = (SponsorStateInfo)sponsorTable[sponsorId];
                            sponsorStateInfo.sponsorState = SponsorState.Completed; 
                            sponsorStateInfo.renewalTime = renewalTime; 
                        }
                        else 
                        {
                            // Sponsor was deleted, possibly from a sponsor time out
                        }
                    } 

                    if (sponsorStateInfo == null) 
                    { 
                        // Sponsor was deleted
                        ProcessNextSponsor(); 
                    }
                    else if (sponsorStateInfo.renewalTime == TimeSpan.Zero)
                    {
                        BCLDebug.Trace("REMOTE","Lease ",id," SponsorCallback sponsor did not renew "); 
                        Unregister(sponsor);
                        ProcessNextSponsor(); 
                    } 
                    else
                        RenewInternal(sponsorStateInfo.renewalTime); 
                }
            }
            else
            { 
                // Sponsor timed out
                // Note time outs should be handled by the LeaseManager 
                BCLDebug.Trace("REMOTE","Lease ",id," SponsorCallback sponsor did not complete, timed out"); 
                Unregister(sponsor);
                ProcessNextSponsor(); 
            }
        }

 

        private void AddTime(TimeSpan renewalSpan) 
        { 
            if (state == LeaseState.Expired)
                return; 

            DateTime now = DateTime.UtcNow;
            DateTime oldLeaseTime = leaseTime;
            DateTime renewTime = now.Add(renewalSpan); 
            if (leaseTime.CompareTo(renewTime) < 0)
            { 
                leaseManager.ChangedLeaseTime(this, renewTime); 
                leaseTime = renewTime;
                state = LeaseState.Active; 
            }
            //BCLDebug.Trace("REMOTE","Lease ",id," AddTime renewalSpan ",renewalSpan," current Time ",now," old leaseTime ",oldLeaseTime," new leaseTime ",leaseTime," state ",((Enum)state).ToString());
        }
 

 
        [Serializable] 
        internal enum SponsorState
        { 
            Initial = 0,
            Waiting = 1,
            Completed = 2
        } 

        internal sealed class SponsorStateInfo 
        { 
            internal TimeSpan renewalTime;
            internal SponsorState sponsorState; 

            internal SponsorStateInfo(TimeSpan renewalTime, SponsorState sponsorState)
            {
                this.renewalTime = renewalTime; 
                this.sponsorState = sponsorState;
            } 
        } 
    }
 
    internal class LeaseSink : IMessageSink
    {
        Lease lease = null;
        IMessageSink nextSink = null; 

        public LeaseSink(Lease lease, IMessageSink nextSink) 
        { 
            this.lease = lease;
            this.nextSink = nextSink; 
        }

        //IMessageSink methods
        public IMessage SyncProcessMessage(IMessage msg) 
        {
            //BCLDebug.Trace("REMOTE","Lease ",id," SyncProcessMessage"); 
            lease.RenewOnCall(); 
            return nextSink.SyncProcessMessage(msg);
        } 

        public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink)
        {
            //BCLDebug.Trace("REMOTE","Lease ",id," AsyncProcessMessage"); 
            lease.RenewOnCall();
            return nextSink.AsyncProcessMessage(msg, replySink); 
        } 

        public IMessageSink NextSink 
        {
            get
            {
                //BCLDebug.Trace("REMOTE","Lease ",id," NextSink"); 
                return nextSink;
            } 
        } 
    }
} 


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK