repo: update sync algorithm. fewer threads, less complexity
This commit is contained in:
parent
95122e44fd
commit
a483759760
|
@ -161,30 +161,6 @@ namespace SparkleLib.Git {
|
||||||
File.WriteAllText (size_file_path, size.ToString ());
|
File.WriteAllText (size_file_path, size.ToString ());
|
||||||
File.WriteAllText (history_size_file_path, history_size.ToString ());
|
File.WriteAllText (history_size_file_path, history_size.ToString ());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public override string [] UnsyncedFilePaths {
|
|
||||||
get {
|
|
||||||
List<string> file_paths = new List<string> ();
|
|
||||||
SparkleGit git = new SparkleGit (LocalPath, "status --porcelain");
|
|
||||||
string output = git.StartAndReadStandardOutput ();
|
|
||||||
string [] lines = output.Split ("\n".ToCharArray ());
|
|
||||||
|
|
||||||
foreach (string line in lines) {
|
|
||||||
if (line [1].ToString ().Equals ("M") ||
|
|
||||||
line [1].ToString ().Equals ("?") ||
|
|
||||||
line [1].ToString ().Equals ("A")) {
|
|
||||||
|
|
||||||
string path = line.Substring (3);
|
|
||||||
path = path.Trim ("\"".ToCharArray ());
|
|
||||||
|
|
||||||
file_paths.Add (path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return file_paths.ToArray ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public override string CurrentRevision {
|
public override string CurrentRevision {
|
||||||
|
|
|
@ -45,20 +45,25 @@ namespace SparkleLib {
|
||||||
|
|
||||||
public abstract class SparkleRepoBase {
|
public abstract class SparkleRepoBase {
|
||||||
|
|
||||||
public static bool UseCustomWatcher = false;
|
|
||||||
|
public abstract bool SyncUp ();
|
||||||
|
public abstract bool SyncDown ();
|
||||||
|
public abstract void RestoreFile (string path, string revision, string target_file_path);
|
||||||
|
public abstract bool HasUnsyncedChanges { get; set; }
|
||||||
|
public abstract bool HasLocalChanges { get; }
|
||||||
|
public abstract bool HasRemoteChanges { get; }
|
||||||
|
|
||||||
public abstract string CurrentRevision { get; }
|
public abstract string CurrentRevision { get; }
|
||||||
public abstract double Size { get; }
|
public abstract double Size { get; }
|
||||||
public abstract double HistorySize { get; }
|
public abstract double HistorySize { get; }
|
||||||
|
|
||||||
public abstract List<string> ExcludePaths { get; }
|
public abstract List<string> ExcludePaths { get; }
|
||||||
public abstract bool HasUnsyncedChanges { get; set; }
|
|
||||||
public abstract bool HasLocalChanges { get; }
|
|
||||||
public abstract bool HasRemoteChanges { get; }
|
|
||||||
public abstract bool SyncUp ();
|
|
||||||
public abstract bool SyncDown ();
|
|
||||||
public abstract List<SparkleChangeSet> GetChangeSets ();
|
public abstract List<SparkleChangeSet> GetChangeSets ();
|
||||||
public abstract List<SparkleChangeSet> GetChangeSets (string path);
|
public abstract List<SparkleChangeSet> GetChangeSets (string path);
|
||||||
public abstract void RestoreFile (string path, string revision, string target_file_path);
|
|
||||||
|
|
||||||
|
public static bool UseCustomWatcher = false;
|
||||||
|
|
||||||
|
|
||||||
public event SyncStatusChangedEventHandler SyncStatusChanged = delegate { };
|
public event SyncStatusChangedEventHandler SyncStatusChanged = delegate { };
|
||||||
public delegate void SyncStatusChangedEventHandler (SyncStatus new_status);
|
public delegate void SyncStatusChangedEventHandler (SyncStatus new_status);
|
||||||
|
@ -114,12 +119,6 @@ namespace SparkleLib {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual string [] UnsyncedFilePaths {
|
|
||||||
get {
|
|
||||||
return new string [0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
protected SparkleConfig local_config;
|
protected SparkleConfig local_config;
|
||||||
|
|
||||||
|
@ -127,16 +126,13 @@ namespace SparkleLib {
|
||||||
private string identifier;
|
private string identifier;
|
||||||
private SparkleListenerBase listener;
|
private SparkleListenerBase listener;
|
||||||
private SparkleWatcher watcher;
|
private SparkleWatcher watcher;
|
||||||
private TimeSpan poll_interval = PollInterval.Short;
|
private TimeSpan poll_interval = PollInterval.Short;
|
||||||
private DateTime last_poll = DateTime.Now;
|
private DateTime last_poll = DateTime.Now;
|
||||||
private DateTime progress_last_change = DateTime.Now;
|
private DateTime progress_last_change = DateTime.Now;
|
||||||
private TimeSpan progress_change_interval = new TimeSpan (0, 0, 0, 1);
|
private Timers.Timer remote_timer = new Timers.Timer () { Interval = 5000 };
|
||||||
private Timers.Timer remote_timer = new Timers.Timer () { Interval = 5000 };
|
|
||||||
|
|
||||||
private bool is_syncing {
|
private bool is_syncing {
|
||||||
get {
|
get { return (Status == SyncStatus.SyncUp || Status == SyncStatus.SyncDown || IsBuffering); }
|
||||||
return (Status == SyncStatus.SyncUp || Status == SyncStatus.SyncDown || IsBuffering);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class PollInterval {
|
private static class PollInterval {
|
||||||
|
@ -162,9 +158,7 @@ namespace SparkleLib {
|
||||||
string identifier_file_path = Path.Combine (LocalPath, ".sparkleshare");
|
string identifier_file_path = Path.Combine (LocalPath, ".sparkleshare");
|
||||||
File.SetAttributes (identifier_file_path, FileAttributes.Hidden);
|
File.SetAttributes (identifier_file_path, FileAttributes.Hidden);
|
||||||
|
|
||||||
SyncStatusChanged += delegate (SyncStatus status) {
|
SyncStatusChanged += delegate (SyncStatus status) { Status = status; };
|
||||||
Status = status;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!UseCustomWatcher)
|
if (!UseCustomWatcher)
|
||||||
this.watcher = new SparkleWatcher (LocalPath);
|
this.watcher = new SparkleWatcher (LocalPath);
|
||||||
|
@ -176,20 +170,23 @@ namespace SparkleLib {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int time_comparison = DateTime.Compare (this.last_poll, DateTime.Now.Subtract (this.poll_interval));
|
int time_comparison = DateTime.Compare (this.last_poll, DateTime.Now.Subtract (this.poll_interval));
|
||||||
bool time_to_poll = (time_comparison < 0);
|
|
||||||
|
|
||||||
if (time_to_poll && !is_syncing) {
|
if (time_comparison < 0) {
|
||||||
|
if (HasUnsyncedChanges && !this.is_syncing)
|
||||||
|
SyncUpBase ();
|
||||||
|
|
||||||
this.last_poll = DateTime.Now;
|
this.last_poll = DateTime.Now;
|
||||||
|
|
||||||
if (HasRemoteChanges) {
|
if (HasRemoteChanges && !this.is_syncing)
|
||||||
this.poll_interval = PollInterval.Long;
|
|
||||||
SyncDownBase ();
|
SyncDownBase ();
|
||||||
}
|
|
||||||
|
if (this.listener.IsConnected)
|
||||||
|
this.poll_interval = PollInterval.Long;
|
||||||
}
|
}
|
||||||
|
|
||||||
// In the unlikely case that we haven't synced up our
|
// In the unlikely case that we haven't synced up our
|
||||||
// changes or the server was down, sync up again
|
// changes or the server was down, sync up again
|
||||||
if (HasUnsyncedChanges && !is_syncing && Error == ErrorStatus.None)
|
if (HasUnsyncedChanges && !this.is_syncing && Error == ErrorStatus.None)
|
||||||
SyncUpBase ();
|
SyncUpBase ();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -197,18 +194,20 @@ namespace SparkleLib {
|
||||||
|
|
||||||
public void Initialize ()
|
public void Initialize ()
|
||||||
{
|
{
|
||||||
if (!UseCustomWatcher)
|
// Sync up everything that changed since we've been offline
|
||||||
this.watcher.ChangeEvent += OnFileActivity;
|
|
||||||
|
|
||||||
// Sync up everything that changed
|
|
||||||
// since we've been offline
|
|
||||||
new Thread (() => {
|
new Thread (() => {
|
||||||
if (!this.is_syncing && (HasUnsyncedChanges || HasLocalChanges)) {
|
if (HasRemoteChanges)
|
||||||
|
SyncDownBase ();
|
||||||
|
|
||||||
|
if (HasUnsyncedChanges || HasLocalChanges) {
|
||||||
do {
|
do {
|
||||||
SyncUpBase ();
|
SyncUpBase ();
|
||||||
|
|
||||||
} while (!this.is_syncing && HasLocalChanges);
|
} while (HasLocalChanges);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!UseCustomWatcher)
|
||||||
|
this.watcher.ChangeEvent += OnFileActivity;
|
||||||
|
|
||||||
this.remote_timer.Start ();
|
this.remote_timer.Start ();
|
||||||
|
|
||||||
|
@ -306,7 +305,7 @@ namespace SparkleLib {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Only trigger the ProgressChanged event once per second
|
// Only trigger the ProgressChanged event once per second
|
||||||
if (DateTime.Compare (this.progress_last_change, DateTime.Now.Subtract (this.progress_change_interval)) >= 0)
|
if (DateTime.Compare (this.progress_last_change, DateTime.Now.Subtract (new TimeSpan (0, 0, 0, 1))) >= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (progress_percentage == 100.0)
|
if (progress_percentage == 100.0)
|
||||||
|
@ -350,8 +349,8 @@ namespace SparkleLib {
|
||||||
if (Error == ErrorStatus.None && SyncUp ()) {
|
if (Error == ErrorStatus.None && SyncUp ()) {
|
||||||
HasUnsyncedChanges = false;
|
HasUnsyncedChanges = false;
|
||||||
|
|
||||||
SyncStatusChanged (SyncStatus.Idle);
|
|
||||||
this.listener.Announce (new SparkleAnnouncement (Identifier, CurrentRevision));
|
this.listener.Announce (new SparkleAnnouncement (Identifier, CurrentRevision));
|
||||||
|
SyncStatusChanged (SyncStatus.Idle);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
this.poll_interval = PollInterval.Short;
|
this.poll_interval = PollInterval.Short;
|
||||||
|
@ -409,8 +408,8 @@ namespace SparkleLib {
|
||||||
if (HasUnsyncedChanges) {
|
if (HasUnsyncedChanges) {
|
||||||
SyncStatusChanged (SyncStatus.SyncUp);
|
SyncStatusChanged (SyncStatus.SyncUp);
|
||||||
|
|
||||||
SyncUp ();
|
if (SyncUp ())
|
||||||
HasUnsyncedChanges = false;
|
HasUnsyncedChanges = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
SyncStatusChanged (SyncStatus.Idle);
|
SyncStatusChanged (SyncStatus.Idle);
|
||||||
|
@ -425,10 +424,10 @@ namespace SparkleLib {
|
||||||
ProgressPercentage = 0.0;
|
ProgressPercentage = 0.0;
|
||||||
ProgressSpeed = 0.0;
|
ProgressSpeed = 0.0;
|
||||||
|
|
||||||
|
SyncStatusChanged (SyncStatus.Idle);
|
||||||
|
|
||||||
if (!UseCustomWatcher)
|
if (!UseCustomWatcher)
|
||||||
this.watcher.Enable ();
|
this.watcher.Enable ();
|
||||||
|
|
||||||
SyncStatusChanged (SyncStatus.Idle);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -436,69 +435,38 @@ namespace SparkleLib {
|
||||||
{
|
{
|
||||||
this.listener = SparkleListenerFactory.CreateListener (Name, Identifier);
|
this.listener = SparkleListenerFactory.CreateListener (Name, Identifier);
|
||||||
|
|
||||||
if (this.listener.IsConnected) {
|
if (this.listener.IsConnected)
|
||||||
this.poll_interval = PollInterval.Long;
|
this.poll_interval = PollInterval.Long;
|
||||||
|
|
||||||
new Thread (() => {
|
|
||||||
if (!this.is_syncing && !HasLocalChanges && HasRemoteChanges)
|
|
||||||
SyncDownBase ();
|
|
||||||
|
|
||||||
}).Start ();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.listener.Connected += ListenerConnectedDelegate;
|
|
||||||
this.listener.Disconnected += ListenerDisconnectedDelegate;
|
this.listener.Disconnected += ListenerDisconnectedDelegate;
|
||||||
this.listener.AnnouncementReceived += ListenerAnnouncementReceivedDelegate;
|
this.listener.AnnouncementReceived += ListenerAnnouncementReceivedDelegate;
|
||||||
|
|
||||||
// Start listening
|
|
||||||
if (!this.listener.IsConnected && !this.listener.IsConnecting)
|
if (!this.listener.IsConnected && !this.listener.IsConnecting)
|
||||||
this.listener.Connect ();
|
this.listener.Connect ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Stop polling when the connection to the irc channel is succesful
|
|
||||||
private void ListenerConnectedDelegate ()
|
|
||||||
{
|
|
||||||
this.poll_interval = PollInterval.Long;
|
|
||||||
this.last_poll = DateTime.Now;
|
|
||||||
|
|
||||||
if (!this.is_syncing) {
|
|
||||||
// Check for changes manually one more time
|
|
||||||
if (HasRemoteChanges)
|
|
||||||
SyncDownBase ();
|
|
||||||
|
|
||||||
// Push changes that were made since the last disconnect
|
|
||||||
if (HasUnsyncedChanges)
|
|
||||||
SyncUpBase ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Start polling when the connection to the channel is lost
|
|
||||||
private void ListenerDisconnectedDelegate ()
|
private void ListenerDisconnectedDelegate ()
|
||||||
{
|
{
|
||||||
this.poll_interval = PollInterval.Short;
|
this.poll_interval = PollInterval.Short;
|
||||||
SparkleLogger.LogInfo (Name, "Falling back to polling");
|
SparkleLogger.LogInfo (Name, "Falling back to regular polling");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Fetch changes when there is an announcement
|
|
||||||
private void ListenerAnnouncementReceivedDelegate (SparkleAnnouncement announcement)
|
private void ListenerAnnouncementReceivedDelegate (SparkleAnnouncement announcement)
|
||||||
{
|
{
|
||||||
string identifier = Identifier;
|
string identifier = Identifier;
|
||||||
|
|
||||||
if (announcement.FolderIdentifier.Equals (identifier) &&
|
if (!announcement.FolderIdentifier.Equals (identifier))
|
||||||
!announcement.Message.Equals (CurrentRevision)) {
|
return;
|
||||||
|
|
||||||
|
if (!announcement.Message.Equals (CurrentRevision)) {
|
||||||
while (this.is_syncing)
|
while (this.is_syncing)
|
||||||
Thread.Sleep (100);
|
Thread.Sleep (100);
|
||||||
|
|
||||||
SparkleLogger.LogInfo (Name, "Syncing due to announcement");
|
SparkleLogger.LogInfo (Name, "Syncing due to announcement");
|
||||||
SyncDownBase ();
|
SyncDownBase ();
|
||||||
|
|
||||||
} else {
|
|
||||||
if (announcement.FolderIdentifier.Equals (identifier))
|
|
||||||
SparkleLogger.LogInfo (Name, "Not syncing, message is for current revision");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -531,7 +499,6 @@ namespace SparkleLib {
|
||||||
this.remote_timer.Stop ();
|
this.remote_timer.Stop ();
|
||||||
this.remote_timer.Dispose ();
|
this.remote_timer.Dispose ();
|
||||||
|
|
||||||
this.listener.Connected -= ListenerConnectedDelegate;
|
|
||||||
this.listener.Disconnected -= ListenerDisconnectedDelegate;
|
this.listener.Disconnected -= ListenerDisconnectedDelegate;
|
||||||
this.listener.AnnouncementReceived -= ListenerAnnouncementReceivedDelegate;
|
this.listener.AnnouncementReceived -= ListenerAnnouncementReceivedDelegate;
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,6 @@ namespace SparkleShare {
|
||||||
|
|
||||||
public static class SparkleUIHelpers {
|
public static class SparkleUIHelpers {
|
||||||
|
|
||||||
// Looks up an icon from the system's theme
|
|
||||||
public static Gdk.Pixbuf GetIcon (string name, int size)
|
public static Gdk.Pixbuf GetIcon (string name, int size)
|
||||||
{
|
{
|
||||||
IconTheme icon_theme = new IconTheme ();
|
IconTheme icon_theme = new IconTheme ();
|
||||||
|
@ -36,7 +35,6 @@ namespace SparkleShare {
|
||||||
icon_theme.AppendSearchPath ("/usr/share/icons");
|
icon_theme.AppendSearchPath ("/usr/share/icons");
|
||||||
icon_theme.AppendSearchPath ("/usr/local/share/icons");
|
icon_theme.AppendSearchPath ("/usr/local/share/icons");
|
||||||
icon_theme.AppendSearchPath ("/opt/local/share/icons");
|
icon_theme.AppendSearchPath ("/opt/local/share/icons");
|
||||||
|
|
||||||
icon_theme.AppendSearchPath (Path.Combine (SparkleUI.AssetsPath, "icons"));
|
icon_theme.AppendSearchPath (Path.Combine (SparkleUI.AssetsPath, "icons"));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
Loading…
Reference in a new issue