示例#1
0
        /// <summary>
        /// The actual scheduling procedure
        /// </summary>
        private void Runner()
        {
            var scheduled = new Dictionary <long, DateTime>();

            while (!m_terminate)
            {
                //TODO: As this is executed repeatedly we should cache it
                // to avoid frequent db lookups

                //Determine schedule list
                var lst = Program.DataConnection.Schedules;
                foreach (var sc in lst)
                {
                    if (!string.IsNullOrEmpty(sc.Repeat))
                    {
                        DateTime start;
                        DateTime last = new DateTime(0, DateTimeKind.Utc);
                        if (!scheduled.TryGetValue(sc.ID, out start))
                        {
                            start = new DateTime(sc.Time.Ticks, DateTimeKind.Utc);
                            last  = sc.LastRun;
                        }

                        try
                        {
                            start = GetNextValidTime(start, last, sc.Repeat, sc.AllowedDays);
                        }
                        catch (Exception ex)
                        {
                            Program.DataConnection.LogError(sc.ID.ToString(), "Scheduler failed to find next date", ex);
                        }

                        //If time is exceeded, run it now
                        if (start <= DateTime.UtcNow)
                        {
                            var jobsToRun = new List <Server.Runner.IRunnerData>();
                            //TODO: Cache this to avoid frequent lookups
                            foreach (var id in Program.DataConnection.GetBackupIDsForTags(sc.Tags).Distinct().Select(x => x.ToString()))
                            {
                                //See if it is already queued
                                var tmplst = from n in m_worker.CurrentTasks
                                             where n.Operation == Duplicati.Server.Serialization.DuplicatiOperation.Backup
                                             select n.Backup;
                                var tastTemp = m_worker.CurrentTask;
                                if (tastTemp != null && tastTemp.Operation == Duplicati.Server.Serialization.DuplicatiOperation.Backup)
                                {
                                    tmplst.Union(new [] { tastTemp.Backup });
                                }

                                //If it is not already in queue, put it there
                                if (!tmplst.Any(x => x.ID == id))
                                {
                                    var entry = Program.DataConnection.GetBackup(id);
                                    if (entry != null)
                                    {
                                        jobsToRun.Add(Server.Runner.CreateTask(Duplicati.Server.Serialization.DuplicatiOperation.Backup, entry));
                                    }
                                }
                            }

                            //Caluclate next time, by adding the interval to the start until we have
                            // passed the current date and time
                            //TODO: Make this more efficient
                            int i = 50000;
                            while (start <= DateTime.UtcNow && i-- > 0)
                            {
                                try
                                {
                                    start = GetNextValidTime(start, start.AddSeconds(1), sc.Repeat, sc.AllowedDays);
                                }
                                catch (Exception ex)
                                {
                                    Program.DataConnection.LogError(sc.ID.ToString(), "Scheduler failed to find next date", ex);
                                    continue;
                                }
                            }

                            Server.Runner.IRunnerData lastJob = jobsToRun.LastOrDefault();
                            if (lastJob != null && lastJob != null)
                            {
                                lock (m_lock)
                                    m_updateTasks[lastJob] = new Tuple <ISchedule, DateTime, DateTime>(sc, start, DateTime.UtcNow);
                            }

                            foreach (var job in jobsToRun)
                            {
                                m_worker.AddTask(job);
                            }

                            if (start < DateTime.UtcNow)
                            {
                                //TODO: Report this somehow
                                continue;
                            }
                        }

                        scheduled[sc.ID] = start;
                    }
                }

                var existing = lst.ToDictionary(x => x.ID);
                //Sort them, lock as we assign the m_schedule variable
                lock (m_lock)
                    m_schedule = (from n in scheduled
                                  where existing.ContainsKey(n.Key)
                                  orderby n.Value
                                  select new KeyValuePair <DateTime, ISchedule>(n.Value, existing[n.Key])).ToArray();

                // Remove unused entries
                foreach (var c in (from n in scheduled where !existing.ContainsKey(n.Key) select n.Key).ToArray())
                {
                    scheduled.Remove(c);
                }

                //Raise event if needed
                if (NewSchedule != null)
                {
                    NewSchedule(this, null);
                }

                int waittime = 0;

                //Figure out a sensible amount of time to sleep the thread
                if (scheduled.Count > 0)
                {
                    //When is the next run scheduled?
                    TimeSpan nextrun = scheduled.Min((x) => x.Value) - DateTime.UtcNow;
                    if (nextrun.TotalMilliseconds < 0)
                    {
                        continue;
                    }

                    //Don't sleep for more than 5 minutes
                    waittime = (int)Math.Min(nextrun.TotalMilliseconds, 60 * 1000 * 5);
                }
                else
                {
                    //No tasks, check back later
                    waittime = 60 * 1000;
                }

                //Waiting on the event, enables a wakeup call from termination
                // never use waittime = 0
                m_event.WaitOne(Math.Max(100, waittime), false);
            }
        }
示例#2
0
        /// <summary>
        /// The actual scheduling procedure
        /// </summary>
        private void Runner()
        {
            var scheduled = new Dictionary <long, KeyValuePair <long, DateTime> >();

            while (!m_terminate)
            {
                //TODO: As this is executed repeatedly we should cache it
                // to avoid frequent db lookups

                //Determine schedule list
                var lst = Program.DataConnection.Schedules;
                foreach (var sc in lst)
                {
                    if (!string.IsNullOrEmpty(sc.Repeat))
                    {
                        KeyValuePair <long, DateTime> startkey;

                        DateTime last = new DateTime(0, DateTimeKind.Utc);
                        DateTime start;
                        var      scticks = sc.Time.Ticks;

                        if (!scheduled.TryGetValue(sc.ID, out startkey) || startkey.Key != scticks)
                        {
                            start = new DateTime(scticks, DateTimeKind.Utc);
                            last  = sc.LastRun;
                        }
                        else
                        {
                            start = startkey.Value;
                        }

                        try
                        {
                            // Recover from timedrift issues by overriding the dates if the last run date is in the future.
                            if (last > DateTime.UtcNow)
                            {
                                start = DateTime.UtcNow;
                                last  = DateTime.UtcNow;
                            }
                            start = GetNextValidTime(start, last, sc.Repeat, sc.AllowedDays);
                        }
                        catch (Exception ex)
                        {
                            Program.DataConnection.LogError(sc.ID.ToString(), "Scheduler failed to find next date", ex);
                        }

                        //If time is exceeded, run it now
                        if (start <= DateTime.UtcNow)
                        {
                            var jobsToRun = new List <Server.Runner.IRunnerData>();
                            //TODO: Cache this to avoid frequent lookups
                            foreach (var id in Program.DataConnection.GetBackupIDsForTags(sc.Tags).Distinct().Select(x => x.ToString()))
                            {
                                //See if it is already queued
                                var tmplst = from n in m_worker.CurrentTasks
                                             where n.Operation == Duplicati.Server.Serialization.DuplicatiOperation.Backup
                                             select n.Backup;
                                var tastTemp = m_worker.CurrentTask;
                                if (tastTemp != null && tastTemp.Operation == Duplicati.Server.Serialization.DuplicatiOperation.Backup)
                                {
                                    tmplst.Union(new [] { tastTemp.Backup });
                                }

                                //If it is not already in queue, put it there
                                if (!tmplst.Any(x => x.ID == id))
                                {
                                    var entry = Program.DataConnection.GetBackup(id);
                                    if (entry != null)
                                    {
                                        Dictionary <string, string> options = Duplicati.Server.Runner.GetCommonOptions(entry, Duplicati.Server.Serialization.DuplicatiOperation.Backup);
                                        Duplicati.Server.Runner.ApplyOptions(entry, Duplicati.Server.Serialization.DuplicatiOperation.Backup, options);
                                        if ((new Duplicati.Library.Main.Options(options)).DisableOnBattery && (Duplicati.Library.Utility.Power.PowerSupply.GetSource() == Duplicati.Library.Utility.Power.PowerSupply.Source.Battery))
                                        {
                                            Duplicati.Library.Logging.Log.WriteInformationMessage(LOGTAG, "BackupDisabledOnBattery", "Scheduled backup disabled while on battery power.");
                                        }
                                        else
                                        {
                                            jobsToRun.Add(Server.Runner.CreateTask(Duplicati.Server.Serialization.DuplicatiOperation.Backup, entry));
                                        }
                                    }
                                }
                            }

                            //Caluclate next time, by finding the first entry later than now
                            try
                            {
                                start = GetNextValidTime(start, new DateTime(Math.Max(DateTime.UtcNow.AddSeconds(1).Ticks, start.AddSeconds(1).Ticks), DateTimeKind.Utc), sc.Repeat, sc.AllowedDays);
                            }
                            catch (Exception ex)
                            {
                                Program.DataConnection.LogError(sc.ID.ToString(), "Scheduler failed to find next date", ex);
                                continue;
                            }

                            Server.Runner.IRunnerData lastJob = jobsToRun.LastOrDefault();
                            if (lastJob != null && lastJob != null)
                            {
                                lock (m_lock)
                                    m_updateTasks[lastJob] = new Tuple <ISchedule, DateTime, DateTime>(sc, start, DateTime.UtcNow);
                            }

                            foreach (var job in jobsToRun)
                            {
                                m_worker.AddTask(job);
                            }

                            if (start < DateTime.UtcNow)
                            {
                                //TODO: Report this somehow
                                continue;
                            }
                        }

                        scheduled[sc.ID] = new KeyValuePair <long, DateTime>(scticks, start);
                    }
                }

                var existing = lst.ToDictionary(x => x.ID);
                //Sort them, lock as we assign the m_schedule variable
                lock (m_lock)
                    m_schedule = (from n in scheduled
                                  where existing.ContainsKey(n.Key)
                                  orderby n.Value.Value
                                  select new KeyValuePair <DateTime, ISchedule>(n.Value.Value, existing[n.Key])).ToArray();

                // Remove unused entries
                foreach (var c in (from n in scheduled where !existing.ContainsKey(n.Key) select n.Key).ToArray())
                {
                    scheduled.Remove(c);
                }

                //Raise event if needed
                if (NewSchedule != null)
                {
                    NewSchedule(this, null);
                }

                int waittime = 0;

                //Figure out a sensible amount of time to sleep the thread
                if (scheduled.Count > 0)
                {
                    //When is the next run scheduled?
                    TimeSpan nextrun = scheduled.Values.Min((x) => x.Value) - DateTime.UtcNow;
                    if (nextrun.TotalMilliseconds < 0)
                    {
                        continue;
                    }

                    //Don't sleep for more than 5 minutes
                    waittime = (int)Math.Min(nextrun.TotalMilliseconds, 60 * 1000 * 5);
                }
                else
                {
                    //No tasks, check back later
                    waittime = 60 * 1000;
                }

                //Waiting on the event, enables a wakeup call from termination
                // never use waittime = 0
                m_event.WaitOne(Math.Max(100, waittime), false);
            }
        }