/// <summary> /// Returns the next valid date, given the start and the interval /// </summary> /// <param name="basetime">The base time</param> /// <param name="firstdata">The first allowed date</param> /// <param name="repetition">The repetition interval</param> /// <param name="allowedDays">The days the backup is allowed to run</param> /// <returns>The next valid date, or throws an exception if no such date can be found</returns> public static DateTime GetNextValidTime(DateTime basetime, DateTime firstdate, string repetition, DayOfWeek[] allowedDays) { DateTime res = basetime; int i = 50000; while ((!IsDateAllowed(res, allowedDays) || res < firstdate) && i-- > 0) { res = Timeparser.ParseTimeInterval(repetition, res); } if (!IsDateAllowed(res, allowedDays) || res < firstdate) { StringBuilder sb = new StringBuilder(); if (allowedDays != null) { foreach (DayOfWeek w in allowedDays) { if (sb.Length != 0) { sb.Append(", "); } sb.Append(w.ToString()); } } throw new Exception(Strings.Scheduler.InvalidTimeSetupError(basetime, repetition, sb.ToString())); } return(res); }
private void BuildRecent() { Log[] logs; lock (Program.MainLock) logs = Program.DataConnection.GetObjects <Log>("EndTime > ? AND SubAction LIKE ? ORDER BY EndTime DESC", Timeparser.ParseTimeInterval(new Datamodel.ApplicationSettings(Program.DataConnection).RecentBackupDuration, DateTime.Now, true), "Primary"); try { recentBackups.BeginUpdate(); recentBackups.Items.Clear(); foreach (Log l in logs) { ListViewItem lvi = new ListViewItem(new string[] { l.EndTime.ToString("g"), l.OwnerTask == null || l.OwnerTask.Schedule == null ? "" : l.OwnerTask.Schedule.Name, l.Transfersize > 0 ? l.TransferSizeString : "" }); lvi.Tag = l; lvi.ImageIndex = imageList.Images.ContainsKey(l.ParsedStatus) ? imageList.Images.IndexOfKey(l.ParsedStatus) : imageList.Images.IndexOfKey("Warning"); recentBackups.Items.Add(lvi); if (!string.IsNullOrEmpty(l.ParsedMessage)) { lvi.ToolTipText = l.ParsedMessage; } else { switch (l.ParsedStatus) { case DuplicatiOutputParser.OKStatus: lvi.ToolTipText = Strings.ServiceStatus.BackupStatusOK; break; case DuplicatiOutputParser.ErrorStatus: lvi.ToolTipText = Strings.ServiceStatus.BackupStatusError; break; case DuplicatiOutputParser.WarningStatus: lvi.ToolTipText = Strings.ServiceStatus.BackupStatusWarning; break; case DuplicatiOutputParser.PartialStatus: lvi.ToolTipText = Strings.ServiceStatus.BackupStatusPartial; break; } } } } finally { recentBackups.EndUpdate(); } }
/// <summary> /// Returns the next valid date, given the start and the interval /// </summary> /// <param name="basetime">The base time</param> /// <param name="firstdate">The first allowed date</param> /// <param name="repetition">The repetition interval</param> /// <param name="allowedDays">The days the backup is allowed to run</param> /// <returns>The next valid date, or throws an exception if no such date can be found</returns> public static DateTime GetNextValidTime(DateTime basetime, DateTime firstdate, string repetition, DayOfWeek[] allowedDays) { var res = basetime; var i = 50000; while (res < firstdate && i-- > 0) { res = Timeparser.ParseTimeInterval(repetition, res); } // If we arived somewhere after the first allowed date if (res >= firstdate) { var ts = Timeparser.ParseTimeSpan(repetition); if (ts.TotalDays >= 1) { // We jump in days, so we pick the first valid day after firstdate for (var n = 0; n < 8; n++) { if (IsDateAllowed(res, allowedDays)) { break; } else { res = res.AddDays(1); } } } else { // We jump less than a day, so we keep adding the repetition until // we hit a valid day i = 50000; while (!IsDateAllowed(res, allowedDays) && i-- > 0) { res = Timeparser.ParseTimeInterval(repetition, res); } } } if (!IsDateAllowed(res, allowedDays) || res < firstdate) { StringBuilder sb = new StringBuilder(); if (allowedDays != null) { foreach (DayOfWeek w in allowedDays) { if (sb.Length != 0) { sb.Append(", "); } sb.Append(w.ToString()); } } throw new Exception(Strings.Scheduler.InvalidTimeSetupError(basetime, repetition, sb.ToString())); } return(res); }
/// <summary> /// The actual scheduling procedure /// </summary> private void Runner() { while (!m_terminate) { List <Schedule> reps = new List <Schedule>(); List <Schedule> tmp; lock (m_datalock) tmp = new List <Schedule>(m_connection.GetObjects <Schedule>()); //Determine schedule list foreach (Schedule sc in tmp) { if (!string.IsNullOrEmpty(sc.Repeat)) { DateTime start = sc.NextScheduledTime; try { start = GetNextValidTime(sc.NextScheduledTime, sc.Repeat, sc.AllowedWeekdays); } catch { } //TODO: Report this somehow //If time is exceeded, run it now if (start <= DateTime.Now) { //See if it is already queued List <IDuplicityTask> tmplst = m_worker.CurrentTasks; IDuplicityTask tastTemp = m_worker.CurrentTask; if (tastTemp != null) { tmplst.Add(tastTemp); } bool found = false; foreach (IDuplicityTask t in tmplst) { if (t != null && t is IncrementalBackupTask && ((IncrementalBackupTask)t).Schedule.ID == sc.ID) { found = true; break; } } //If it is not already in queue, put it there if (!found) { m_worker.AddTask(new IncrementalBackupTask(sc)); } //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.Now && i-- > 0) { try { start = GetNextValidTime(Timeparser.ParseTimeInterval(sc.Repeat, start), sc.Repeat, sc.AllowedWeekdays); } catch { //TODO: Report this somehow continue; } } if (start < DateTime.Now) { continue; } } //Add to schedule list at the new time reps.Add(sc); sc.NextScheduledTime = start; } } System.Data.LightDatamodel.QueryModel.OperationOrParameter op = System.Data.LightDatamodel.QueryModel.Parser.ParseQuery("ORDER BY When ASC"); //Sort them, lock as we assign the m_schedule variable lock (m_lock) m_schedule = op.EvaluateList <Schedule>(reps).ToArray(); //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 (m_schedule.Length > 0) { //When is the next run scheduled? TimeSpan nextrun = m_schedule[0].NextScheduledTime - DateTime.Now; 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); } }