Пример #1
0
        /// <summary>
        /// Associates the service handler with a message router by registering
        /// the necessary application message handlers.
        /// </summary>
        /// <param name="router">The message router.</param>
        /// <param name="keyPrefix">The configuration key prefix or (null to use <b>LillTek.Datacenter.AppStore</b>).</param>
        /// <param name="perfCounters">The application's performance counter set (or <c>null</c>).</param>
        /// <param name="perfPrefix">The string to prefix any performance counter names (or <c>null</c>).</param>
        /// <remarks>
        /// <para>
        /// Applications that expose performance counters will pass a non-<c>null</c> <b>perfCounters</b>
        /// instance.  The service handler should add any counters it implements to this set.
        /// If <paramref name="perfPrefix" /> is not <c>null</c> then any counters added should prefix their
        /// names with this parameter.
        /// </para>
        /// </remarks>
        public void Start(MsgRouter router, string keyPrefix, PerfCounterSet perfCounters, string perfPrefix)
        {
            var config = new Config(keyPrefix != null ? keyPrefix : ConfigPrefix);

            // Make sure the syncLock is set early.

            this.syncLock = router.SyncRoot;

            // Make sure that the LillTek.Datacenter message types have been
            // registered with the LillTek.Messaging subsystem.

            LillTek.Datacenter.Global.RegisterMsgTypes();

            // Verify the router parameter

            if (router == null)
            {
                throw new ArgumentNullException("router", "Router cannot be null.");
            }

            if (this.router != null)
            {
                throw new InvalidOperationException("This handler has already been started.");
            }

            // General initialization

            mode                = config.Get <AppStoreMode>("Mode", AppStoreMode.Primary);
            primaryBroadcast    = config.Get("PrimaryBroadcast", true);
            packageScanInterval = config.Get("PackageScanInterval", TimeSpan.FromMinutes(5));
            primaryPollInterval = config.Get("PrimaryPollInterval", TimeSpan.FromMinutes(15));
            primaryPollTime     = SysTime.Now;
            onTransfer          = new AsyncCallback(OnTransfer);
            downloads           = new Dictionary <AppRef, PendingDownload>();
            forceSync           = false;
            cDownloads          = 0;
            netFail             = false;

            // Initialize the package folder

            packageFolder              = new AppPackageFolder(syncLock, config.Get("PackageFolder", "Packages"));
            packageFolder.ChangeEvent += new MethodArg1Invoker(OnPackageFolderChange);
            packageScanTime            = SysTime.Now;

            // Initialize the performance counters

            startTime = DateTime.UtcNow;
            perf      = new Perf(perfCounters, perfPrefix);

            // Crank up the background task timer.

            bkTimer = new GatedTimer(new TimerCallback(OnBkTimer), null, config.Get("BkTaskInterval", TimeSpan.FromSeconds(1)));

            try
            {
                // Initialize the router

                this.router = router;

                // Join the cluster, initializing this instance's state.

                cluster         = new ClusterMember(router, ClusterMemberSettings.LoadConfig(config.KeyPrefix + "Cluster"));
                cluster["Mode"] = this.mode.ToString();

                cluster.ClusterStatusUpdate += new ClusterMemberEventHandler(OnClusterStatusUpdate);
                cluster.Start();

                // Rather than calling cluster.JoinWait() which could take a really long
                // time, I'm going to sleep for two seconds.  There are three scenarios:
                //
                //      1. This is the first Application Store instance.
                //
                //      2. Other instances are running but they haven't
                //         organized into a cluster.
                //
                //      3. A cluster is already running.
                //
                // If #1 is the current situation, then it will take a very long time
                // for JoinWait() to return because we have to go through the entire
                // missed master broadcast and election periods.  Since we're the only
                // instance, we could have started serving content well before this.
                //
                // #2 won't be very common but if it is the case, the worst thing
                // that will happen is that it will take a while to discover the
                // primary store.
                //
                // If #3 is the case, then two seconds should be long enough for the
                // master to send the instance a cluster update.

                Thread.Sleep(2000);

                // Register the message handlers via the cluster member
                // so that the endpoint used will be the member's instanceEP.

                cluster.AddTarget(this, AppStoreHandler.DynamicScope);
            }
            catch
            {
                if (packageFolder != null)
                {
                    packageFolder.Dispose();
                    packageFolder = null;
                }

                if (bkTimer != null)
                {
                    bkTimer.Dispose();
                    bkTimer = null;
                }

                router.Dispatcher.RemoveTarget(this);

                if (cluster != null)
                {
                    cluster.Stop();
                    cluster = null;
                }

                throw;
            }
        }