/// <summary>
        /// Process study migration candidates retrieved from the <see cref="Model.FilesystemQueue"/> table
        /// </summary>
        /// <param name="candidateList">The list of candidate studies for deleting.</param>
		private void ProcessStudyMigrateCandidates(IList<FilesystemQueue> candidateList)
        {
        	Platform.CheckForNullReference(candidateList, "candidateList");

        	if (candidateList.Count > 0)
        		Platform.Log(LogLevel.Debug, "Scheduling tier-migration for {0} eligible studies...", candidateList.Count);

			FilesystemProcessStatistics summaryStats = new FilesystemProcessStatistics("FilesystemTierMigrateInsert");
        	foreach (FilesystemQueue queueItem in candidateList)
        	{
				if (_bytesToRemove < 0 || CancelPending)
        		{
                    Platform.Log(LogLevel.Debug, "Estimated disk space has been reached.");
                    break;
        		}
				StudyProcessStatistics stats = new StudyProcessStatistics("TierMigrateStudy");
				stats.TotalTime.Start();

				stats.StudyStorageTime.Start();
        		// First, get the StudyStorage locations for the study, and calculate the disk usage.
				StudyStorageLocation location;
				if (!FilesystemMonitor.Instance.GetWritableStudyStorageLocation(queueItem.StudyStorageKey, out location))
					continue;
				stats.StudyStorageTime.End();

				stats.CalculateDirectorySizeTime.Start();
				// Get the disk usage
				float studySize = EstimateFolderSizeFromStudyXml(location);
				stats.CalculateDirectorySizeTime.End();
        		stats.DirectorySize = (ulong) studySize;

				stats.DbUpdateTime.Start();
        		using (
        			IUpdateContext update =
        				PersistentStoreRegistry.GetDefaultStore().OpenUpdateContext(UpdateContextSyncMode.Flush))
        		{
					ILockStudy lockstudy = update.GetBroker<ILockStudy>();
					LockStudyParameters lockParms = new LockStudyParameters
					                                	{
					                                		StudyStorageKey = location.Key,
					                                		QueueStudyStateEnum = QueueStudyStateEnum.MigrationScheduled
					                                	};
        			if (!lockstudy.Execute(lockParms) || !lockParms.Successful)
					{
						Platform.Log(LogLevel.Warn, "Unable to lock study for inserting Tier Migration. Reason:{0}. Skipping study ({1})",
                                     lockParms.FailureReason, location.StudyInstanceUid);
						continue;
					}

					IInsertWorkQueueFromFilesystemQueue broker = update.GetBroker<IInsertWorkQueueFromFilesystemQueue>();

					InsertWorkQueueFromFilesystemQueueParameters insertParms = new InsertWorkQueueFromFilesystemQueueParameters
                                                       	{
                                                       		StudyStorageKey = location.GetKey(),
                                                       		ServerPartitionKey = location.ServerPartitionKey,
                                                       		ScheduledTime = _scheduledTime,
                                                       		DeleteFilesystemQueue = true,
                                                       		WorkQueueTypeEnum = WorkQueueTypeEnum.MigrateStudy,
                                                       		FilesystemQueueTypeEnum =
                                                       			FilesystemQueueTypeEnum.TierMigrate
                                                       	};

        			Platform.Log(LogLevel.Debug, "Scheduling tier-migration for study {0} from {1} at {2}...",
        			             location.StudyInstanceUid, location.FilesystemTierEnum, _scheduledTime);
        			WorkQueue insertItem = broker.FindOne(insertParms);
					if (insertItem == null)
        			{
        				Platform.Log(LogLevel.Error,
        				             "Unexpected problem inserting 'MigrateStudy' record into WorkQueue for Study {0}",
        				             location.StudyInstanceUid);
        			}
        			else
        			{
        				update.Commit();
        				_bytesToRemove -= studySize;
        				_studiesMigrated++;

        				// spread out the scheduled migration entries based on the size
        				// assuming that the larger the study the longer it will take to migrate
        				// The assumed migration speed is arbitarily chosen.
        				double migrationSpeed = ServiceLockSettings.Default.TierMigrationSpeed*1024*1024; // MB / sec
        				TimeSpan estMigrateTime = TimeSpan.FromSeconds(studySize/migrationSpeed);
        				_scheduledTime = _scheduledTime.Add(estMigrateTime);
        			}
        		}
				stats.DbUpdateTime.End();
				stats.TotalTime.End();

        		summaryStats.AddSubStats(stats);
				StatisticsLogger.Log(LogLevel.Debug, stats);
			}

			summaryStats.CalculateAverage();
    		StatisticsLogger.Log(LogLevel.Info, false, summaryStats);
        }
		/// <summary>
		/// Process StudyDelete Candidates retrieved from the <see cref="Model.FilesystemQueue"/> table
		/// </summary>
		/// <param name="candidateList">The list of candidate studies for deleting.</param>
		/// <param name="type">The type of compress.</param>
		private void ProcessCompressCandidates(IEnumerable<FilesystemQueue> candidateList, FilesystemQueueTypeEnum type)
		{
			DateTime scheduledTime = Platform.Time.AddSeconds(10);

			foreach (FilesystemQueue queueItem in candidateList)
			{
				// Check for Shutdown/Cancel
				if (CancelPending) break;

				// First, get the StudyStorage locations for the study, and calculate the disk usage.
				StudyStorageLocation location;
				if (!FilesystemMonitor.Instance.GetWritableStudyStorageLocation(queueItem.StudyStorageKey, out location))
					continue;

				// Get the disk usage
				StudyXml studyXml = LoadStudyXml(location);

				using (IUpdateContext update = PersistentStoreRegistry.GetDefaultStore().OpenUpdateContext(UpdateContextSyncMode.Flush))
				{
					ILockStudy lockstudy = update.GetBroker<ILockStudy>();
					LockStudyParameters lockParms = new LockStudyParameters();
					lockParms.StudyStorageKey = location.Key;
					lockParms.QueueStudyStateEnum = QueueStudyStateEnum.CompressScheduled;
					if (!lockstudy.Execute(lockParms) || !lockParms.Successful)
					{
						Platform.Log(LogLevel.Warn, "Unable to lock study for inserting Lossy Compress, skipping study ({0}",
									 location.StudyInstanceUid);
						continue;
					}

					scheduledTime = scheduledTime.AddSeconds(3);

					IInsertWorkQueueFromFilesystemQueue workQueueInsert = update.GetBroker<IInsertWorkQueueFromFilesystemQueue>();

					InsertWorkQueueFromFilesystemQueueParameters insertParms = new InsertWorkQueueFromFilesystemQueueParameters();
				    insertParms.WorkQueueTypeEnum = WorkQueueTypeEnum.CompressStudy;
					insertParms.FilesystemQueueTypeEnum = FilesystemQueueTypeEnum.LossyCompress;
					insertParms.StudyStorageKey = location.GetKey();
					insertParms.ServerPartitionKey = location.ServerPartitionKey;
					DateTime expirationTime = scheduledTime;
					insertParms.ScheduledTime = expirationTime;
					insertParms.DeleteFilesystemQueue = true;
					insertParms.Data = queueItem.QueueXml;
					insertParms.WorkQueueTypeEnum = WorkQueueTypeEnum.CompressStudy;
					insertParms.FilesystemQueueTypeEnum = type;
					
					try
					{
						WorkQueue entry = workQueueInsert.FindOne(insertParms);

						InsertWorkQueueUidFromStudyXml(studyXml,update,entry.GetKey());

						update.Commit();
						_studiesInserted++;
					}
					catch(Exception e) 
					{
						Platform.Log(LogLevel.Error, e, "Unexpected problem inserting 'CompressStudy' record into WorkQueue for Study {0}", location.StudyInstanceUid);
						// throw; -- would cause abort of inserts, go ahead and try everything
					}
				}
			}
		}
		/// <summary>
		/// Process StudyPurge <see cref="FilesystemQueue"/> entries.
		/// </summary>
		/// <param name="candidateList">The list of candidates for purging</param>
		private void ProcessStudyPurgeCandidates(IList<FilesystemQueue> candidateList)
		{
			if (candidateList.Count > 0)
				Platform.Log(LogLevel.Debug, "Scheduling purge study for {0} eligible studies...", candidateList.Count);

			FilesystemProcessStatistics summaryStats = new FilesystemProcessStatistics("FilesystemPurgeInsert");

			foreach (FilesystemQueue queueItem in candidateList)
			{
				if (_bytesToRemove < 0 || CancelPending)
					break;

				StudyProcessStatistics stats = new StudyProcessStatistics("PurgeStudy");
				stats.TotalTime.Start();

				stats.StudyStorageTime.Start();
				// First, get the StudyStorage locations for the study, and calculate the disk usage.
				StudyStorageLocation location;
				if (!FilesystemMonitor.Instance.GetWritableStudyStorageLocation(queueItem.StudyStorageKey, out location))
					continue;
				stats.StudyStorageTime.End();

				stats.CalculateDirectorySizeTime.Start();
				// Get the disk usage
				float studySize = EstimateFolderSizeFromStudyXml(location);
				stats.CalculateDirectorySizeTime.End();
				stats.DirectorySize = (ulong) studySize;

				stats.DbUpdateTime.Start();
				// Update the DB
				using (
					IUpdateContext update = PersistentStoreRegistry.GetDefaultStore().OpenUpdateContext(UpdateContextSyncMode.Flush))
				{
					ILockStudy lockstudy = update.GetBroker<ILockStudy>();
					LockStudyParameters lockParms = new LockStudyParameters();
					lockParms.StudyStorageKey = location.Key;
					lockParms.QueueStudyStateEnum = QueueStudyStateEnum.PurgeScheduled;
					if (!lockstudy.Execute(lockParms) || !lockParms.Successful)
					{
						Platform.Log(LogLevel.Warn, "Unable to lock study for inserting Study Purge, skipping study ({0}",
						             location.StudyInstanceUid);
						continue;
					}

                    IInsertWorkQueueFromFilesystemQueue insertBroker = update.GetBroker<IInsertWorkQueueFromFilesystemQueue>();

					InsertWorkQueueFromFilesystemQueueParameters insertParms = new InsertWorkQueueFromFilesystemQueueParameters();
					insertParms.StudyStorageKey = location.GetKey();
					insertParms.ServerPartitionKey = location.ServerPartitionKey;
					insertParms.ScheduledTime = _scheduledTime;
					insertParms.DeleteFilesystemQueue = true;
					insertParms.WorkQueueTypeEnum = WorkQueueTypeEnum.PurgeStudy;
					insertParms.FilesystemQueueTypeEnum = FilesystemQueueTypeEnum.PurgeStudy;
					
                    WorkQueue insertItem = insertBroker.FindOne(insertParms);
					if (insertItem == null)
					{
						Platform.Log(LogLevel.Error, "Unexpected problem inserting 'PurgeStudy' record into WorkQueue for Study {0}",
						             location.StudyInstanceUid);
					}
					else
					{
						update.Commit();
						_bytesToRemove -= studySize;
						_studiesPurged++;
						_scheduledTime = _scheduledTime.AddSeconds(2);
					}
					
				}
				stats.DbUpdateTime.End();
				stats.TotalTime.End();

				summaryStats.AddSubStats(stats);
				StatisticsLogger.Log(LogLevel.Debug, stats);
			}
			summaryStats.CalculateAverage();
			StatisticsLogger.Log(LogLevel.Info, false, summaryStats);
		}