Skip to content
This repository was archived by the owner on Dec 5, 2024. It is now read-only.

Cache refresh fixes for 1.0rc/master #627

Merged
merged 15 commits into from
Mar 18, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions src/GitHub.Api/Application/ApplicationManagerBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ public void Run(bool firstRun)
{
Logger.Trace("Run - CurrentDirectory {0}", NPath.CurrentDirectory);

isBusy = true;

var gitExecutablePath = SystemSettings.Get(Constants.GitInstallPathKey)?.ToNPath();
if (gitExecutablePath.HasValue && gitExecutablePath.Value.FileExists()) // we have a git path
{
Expand All @@ -65,7 +67,6 @@ public void Run(bool firstRun)
{
Logger.Trace("No git path found in settings");

isBusy = true;
var initEnvironmentTask = new ActionTask<NPath>(CancellationToken,
(b, path) => InitializeEnvironment(path)) { Affinity = TaskAffinity.UI };
var findExecTask = new FindExecTask("git", CancellationToken)
Expand All @@ -81,7 +82,6 @@ public void Run(bool firstRun)
//Logger.Warning("FindExecTask Failure");
Logger.Error("Git not found");
}
isBusy = false;
});

var gitInstaller = new GitInstaller(Environment, CancellationToken);
Expand All @@ -91,7 +91,7 @@ public void Run(bool firstRun)
setupTask.Progress(progressReporter.UpdateProgress);
setupTask.OnEnd += (thisTask, result, success, exception) =>
{
if (success && result != null)
if (success && result.IsInitialized)
thisTask.Then(initEnvironmentTask);
else
thisTask.Then(findExecTask);
Expand Down Expand Up @@ -248,7 +248,7 @@ public void Dispose()
public ISettings SystemSettings { get; protected set; }
public ISettings UserSettings { get; protected set; }
public IUsageTracker UsageTracker { get; protected set; }
public bool IsBusy { get { return isBusy || (RepositoryManager?.IsBusy ?? false); } }
public bool IsBusy { get { return isBusy; } }
protected TaskScheduler UIScheduler { get; private set; }
protected SynchronizationContext SynchronizationContext { get; private set; }
protected IRepositoryManager RepositoryManager { get { return repositoryManager; } }
Expand Down
93 changes: 90 additions & 3 deletions src/GitHub.Api/Cache/CacheContainer.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using GitHub.Logging;

namespace GitHub.Unity
Expand Down Expand Up @@ -47,10 +48,11 @@ public IManagedCache GetCache(CacheType cacheType)
return caches[cacheType].Value;
}

public void CheckAndRaiseEventsIfCacheNewer(CacheUpdateEvent cacheUpdateEvent)
public void CheckAndRaiseEventsIfCacheNewer(CacheType cacheType, CacheUpdateEvent cacheUpdateEvent)
{
var cache = GetCache(cacheUpdateEvent.cacheType);
if (cache.LastUpdatedAt != cacheUpdateEvent.UpdatedTime)
var cache = GetCache(cacheType);
var needsInvalidation = cache.ValidateData();
if (!cacheUpdateEvent.IsInitialized || !needsInvalidation || cache.LastUpdatedAt != cacheUpdateEvent.UpdatedTime)
{
OnCacheUpdated(cache.CacheType, cache.LastUpdatedAt);
}
Expand Down Expand Up @@ -98,4 +100,89 @@ public void Dispose()
public IGitUserCache GitUserCache { get { return (IGitUserCache)caches[CacheType.GitUser].Value; } }
public IRepositoryInfoCache RepositoryInfoCache { get { return (IRepositoryInfoCache)caches[CacheType.RepositoryInfo].Value; } }
}

[Serializable]
public struct CacheUpdateEvent
{
[NonSerialized] private DateTimeOffset? updatedTimeValue;
public string updatedTimeString;
public CacheType cacheType;

public CacheUpdateEvent(CacheType type, DateTimeOffset when)
{
if (type == CacheType.None) throw new ArgumentOutOfRangeException(nameof(type));

cacheType = type;
updatedTimeValue = when;
updatedTimeString = when.ToString(Constants.Iso8601Format);
}

public override int GetHashCode()
{
int hash = 17;
hash = hash * 23 + cacheType.GetHashCode();
hash = hash * 23 + (updatedTimeString?.GetHashCode() ?? 0);
return hash;
}

public override bool Equals(object other)
{
if (other is CacheUpdateEvent)
return Equals((CacheUpdateEvent)other);
return false;
}

public bool Equals(CacheUpdateEvent other)
{
return
cacheType == other.cacheType &&
String.Equals(updatedTimeString, other.updatedTimeString)
;
}

public static bool operator ==(CacheUpdateEvent lhs, CacheUpdateEvent rhs)
{
// If both are null, or both are same instance, return true.
if (ReferenceEquals(lhs, rhs))
return true;

// If one is null, but not both, return false.
if (((object)lhs == null) || ((object)rhs == null))
return false;

// Return true if the fields match:
return lhs.Equals(rhs);
}

public static bool operator !=(CacheUpdateEvent lhs, CacheUpdateEvent rhs)
{
return !(lhs == rhs);
}

public DateTimeOffset UpdatedTime
{
get
{
if (!updatedTimeValue.HasValue)
{
DateTimeOffset result;
if (DateTimeOffset.TryParseExact(updatedTimeString, Constants.Iso8601Format, CultureInfo.InvariantCulture, DateTimeStyles.None, out result))
{
updatedTimeValue = result;
}
else
{
updatedTimeValue = DateTimeOffset.MinValue;
updatedTimeString = updatedTimeValue.Value.ToString(Constants.Iso8601Format);
}
}

return updatedTimeValue.Value;
}
}

public bool IsInitialized => cacheType != CacheType.None;

public string UpdatedTimeString => updatedTimeString;
}
}
3 changes: 2 additions & 1 deletion src/GitHub.Api/Cache/CacheInterfaces.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ namespace GitHub.Unity
{
public enum CacheType
{
None,
RepositoryInfo,
Branches,
GitLog,
Expand All @@ -29,7 +30,7 @@ public interface ICacheContainer : IDisposable
void ValidateAll();
void InvalidateAll();
IManagedCache GetCache(CacheType cacheType);
void CheckAndRaiseEventsIfCacheNewer(CacheUpdateEvent cacheUpdateEvent);
void CheckAndRaiseEventsIfCacheNewer(CacheType cacheType, CacheUpdateEvent cacheUpdateEvent);
}

public interface IManagedCache
Expand Down
3 changes: 2 additions & 1 deletion src/GitHub.Api/Git/IRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public interface IRepository : IEquatable<IRepository>, IDisposable
ITask RequestLock(string file);
ITask ReleaseLock(string file, bool force);
ITask DiscardChanges(GitStatusEntry[] discardEntries);
void CheckAndRaiseEventsIfCacheNewer(CacheUpdateEvent cacheUpdateEvent);
void CheckAndRaiseEventsIfCacheNewer(CacheType cacheType, CacheUpdateEvent cacheUpdateEvent);

/// <summary>
/// Gets the name of the repository.
Expand Down Expand Up @@ -60,6 +60,7 @@ public interface IRepository : IEquatable<IRepository>, IDisposable
List<GitLock> CurrentLocks { get; }
string CurrentBranchName { get; }
List<GitLogEntry> CurrentLog { get; }
bool IsBusy { get; }

event Action<CacheUpdateEvent> LogChanged;
event Action<CacheUpdateEvent> TrackingStatusChanged;
Expand Down
126 changes: 19 additions & 107 deletions src/GitHub.Api/Git/Repository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,10 @@ public Repository(NPath localPath, ICacheContainer container)
RemoteBranchListChanged?.Invoke(cacheUpdateEvent);
LocalAndRemoteBranchListChanged?.Invoke(cacheUpdateEvent);
}},
{ CacheType.GitAheadBehind, TrackingStatusChanged.SafeInvoke },
{ CacheType.GitLocks, LocksChanged.SafeInvoke },
{ CacheType.GitLog, LogChanged.SafeInvoke },
{ CacheType.GitStatus, StatusEntriesChanged.SafeInvoke },
{ CacheType.GitAheadBehind, c => TrackingStatusChanged?.Invoke(c) },
{ CacheType.GitLocks, c => LocksChanged?.Invoke(c) },
{ CacheType.GitLog, c => LogChanged?.Invoke(c) },
{ CacheType.GitStatus, c => StatusEntriesChanged?.Invoke(c) },
{ CacheType.GitUser, cacheUpdateEvent => { } },
{ CacheType.RepositoryInfo, cacheUpdateEvent => {
CurrentBranchChanged?.Invoke(cacheUpdateEvent);
Expand All @@ -64,7 +64,10 @@ public Repository(NPath localPath, ICacheContainer container)

cacheContainer = container;
cacheContainer.CacheInvalidated += CacheHasBeenInvalidated;
cacheContainer.CacheUpdated += (cacheType, offset) => cacheUpdateEvents[cacheType](new CacheUpdateEvent(cacheType, offset));
cacheContainer.CacheUpdated += (cacheType, offset) =>
{
cacheUpdateEvents[cacheType](new CacheUpdateEvent(cacheType, offset));
};
}

public void Initialize(IRepositoryManager repositoryManager, ITaskManager taskManager)
Expand Down Expand Up @@ -117,7 +120,7 @@ public ITask SetupRemote(string remote, string remoteUrl)
public ITask ReleaseLock(string file, bool force) => repositoryManager.UnlockFile(file, force);
public ITask DiscardChanges(GitStatusEntry[] gitStatusEntry) => repositoryManager.DiscardChanges(gitStatusEntry);

public void CheckAndRaiseEventsIfCacheNewer(CacheUpdateEvent cacheUpdateEvent) => cacheContainer.CheckAndRaiseEventsIfCacheNewer(cacheUpdateEvent);
public void CheckAndRaiseEventsIfCacheNewer(CacheType cacheType, CacheUpdateEvent cacheUpdateEvent) => cacheContainer.CheckAndRaiseEventsIfCacheNewer(cacheType, cacheUpdateEvent);


/// <summary>
Expand Down Expand Up @@ -154,11 +157,14 @@ public bool Equals(IRepository other)

private void RefreshCache(CacheType cacheType)
{
var cache = cacheContainer.GetCache(cacheType);
// if the cache has valid data, we need to force an invalidation to refresh it
// if it doesn't have valid data, it will trigger an invalidation automatically
if (cache.ValidateData())
cache.InvalidateData();
taskManager.RunInUI(() =>
{
var cache = cacheContainer.GetCache(cacheType);
// if the cache has valid data, we need to force an invalidation to refresh it
// if it doesn't have valid data, it will trigger an invalidation automatically
if (cache.ValidateData())
cache.InvalidateData();
});
}

private void CacheHasBeenInvalidated(CacheType cacheType)
Expand Down Expand Up @@ -362,6 +368,7 @@ public string Name
public NPath LocalPath { get; private set; }
public string Owner => CloneUrl?.Owner ?? null;
public bool IsGitHub => HostAddress.IsGitHubDotCom(CloneUrl);
public bool IsBusy => repositoryManager?.IsBusy ?? false;

internal string DebuggerDisplay => String.Format(CultureInfo.InvariantCulture,
"{0} Owner: {1} Name: {2} CloneUrl: {3} LocalPath: {4} Branch: {5} Remote: {6}", GetHashCode(), Owner, Name,
Expand Down Expand Up @@ -398,17 +405,7 @@ public User(ICacheContainer cacheContainer)
cacheContainer.CacheUpdated += (type, dt) => { if (type == CacheType.GitUser) CacheHasBeenUpdated(dt); };
}

public void CheckUserChangedEvent(CacheUpdateEvent cacheUpdateEvent)
{
var managedCache = cacheContainer.GitUserCache;
var raiseEvent = managedCache.LastUpdatedAt != cacheUpdateEvent.UpdatedTime;

Logger.Trace("Check GitUserCache CacheUpdateEvent Current:{0} Check:{1} Result:{2}", managedCache.LastUpdatedAt,
cacheUpdateEvent.UpdatedTime, raiseEvent);

if (raiseEvent)
CacheHasBeenUpdated(managedCache.LastUpdatedAt);
}
public void CheckUserChangedEvent(CacheUpdateEvent cacheUpdateEvent) => cacheContainer.CheckAndRaiseEventsIfCacheNewer(CacheType.GitUser, cacheUpdateEvent);

public void Initialize(IGitClient client)
{
Expand Down Expand Up @@ -486,89 +483,4 @@ public string Email

protected static ILogging Logger { get; } = LogHelper.GetLogger<User>();
}

[Serializable]
public struct CacheUpdateEvent
{
[NonSerialized] private DateTimeOffset? updatedTimeValue;
public string updatedTimeString;
public CacheType cacheType;

public CacheUpdateEvent(CacheType type, DateTimeOffset when)
{
cacheType = type;
updatedTimeValue = when;
updatedTimeString = when.ToString(Constants.Iso8601Format);
}

public override int GetHashCode()
{
int hash = 17;
hash = hash * 23 + cacheType.GetHashCode();
hash = hash * 23 + (updatedTimeString?.GetHashCode() ?? 0);
return hash;
}

public override bool Equals(object other)
{
if (other is CacheUpdateEvent)
return Equals((CacheUpdateEvent)other);
return false;
}

public bool Equals(CacheUpdateEvent other)
{
return
cacheType == other.cacheType &&
String.Equals(updatedTimeString, other.updatedTimeString)
;
}

public static bool operator ==(CacheUpdateEvent lhs, CacheUpdateEvent rhs)
{
// If both are null, or both are same instance, return true.
if (ReferenceEquals(lhs, rhs))
return true;

// If one is null, but not both, return false.
if (((object)lhs == null) || ((object)rhs == null))
return false;

// Return true if the fields match:
return lhs.Equals(rhs);
}

public static bool operator !=(CacheUpdateEvent lhs, CacheUpdateEvent rhs)
{
return !(lhs == rhs);
}

public DateTimeOffset UpdatedTime
{
get
{
if (!updatedTimeValue.HasValue)
{
DateTimeOffset result;
if (DateTimeOffset.TryParseExact(updatedTimeString, Constants.Iso8601Format, CultureInfo.InvariantCulture, DateTimeStyles.None, out result))
{
updatedTimeValue = result;
}
else
{
UpdatedTime = DateTimeOffset.MinValue;
}
}

return updatedTimeValue.Value;
}
set
{
updatedTimeValue = value;
updatedTimeString = value.ToString(Constants.Iso8601Format);
}
}

public string UpdatedTimeString => updatedTimeString;
}
}
Loading