private readonly ConcurrentBag<AccountInfo> _accounts = new ConcurrentBag<AccountInfo>();
+ [System.ComponentModel.Composition.Import]
+ public IPithosSettings Settings { get; set; }
private bool _firstPoll = true;
+ private TaskCompletionSource<bool> _tcs;
+
public void Start()
{
_firstPoll = true;
}
}*/
-
+ public void SynchNow()
+ {
+ if (_tcs!=null)
+ _tcs.SetResult(true);
+ else
+ {
+ //TODO: This may be OK for testing purposes, but we have no guarantee that it will
+ //work properly in production
+ PollRemoteFiles(repeat:false);
+ }
+ }
//Remote files are polled periodically. Any changes are processed
- public async Task ProcessRemoteFiles(DateTime? since = null)
- {
- await TaskEx.Delay(TimeSpan.FromSeconds(10),_agent.CancellationToken);
+ public async Task PollRemoteFiles(DateTime? since = null,bool repeat=true)
+ {
+
+ _tcs = new TaskCompletionSource<bool>();
+ var wait = TaskEx.Delay(TimeSpan.FromSeconds(Settings.PollingInterval), _agent.CancellationToken);
+ var signaledTask=await TaskEx.WhenAny(_tcs.Task,wait);
+ //If polling is signalled by SynchNow, ignore the since tag
+ if (signaledTask is Task<bool>)
+ since = null;
using (log4net.ThreadContext.Stacks["Retrieve Remote"].Push("All accounts"))
{
await TaskEx.WhenAll(tasks.ToList());
_firstPoll = false;
- ProcessRemoteFiles(nextSince);
+ if (repeat)
+ PollRemoteFiles(nextSince);
}
catch (Exception ex)
{
Log.ErrorFormat("Error while processing accounts\r\n{0}",ex);
//In case of failure retry with the same parameter
- ProcessRemoteFiles(since);
+ PollRemoteFiles(since);
}
ProcessTrashedFiles(accountInfo, realTrash);
- var cleanRemotes = from info in remoteObjects
+ var cleanRemotes = (from info in remoteObjects
//.Union(sharedObjects)
let name = info.Name
where !name.EndsWith(".ignore", StringComparison.InvariantCultureIgnoreCase) &&
!name.StartsWith(FolderConstants.CacheFolder + "/",
StringComparison.InvariantCultureIgnoreCase)
- select info;
+ select info).ToList();
-
+ ProcessDeletedFiles(accountInfo, cleanRemotes, pollTime);
//Create a list of actions from the remote files
var allActions = ObjectsToActions(accountInfo, cleanRemotes);
- ProcessDeletedFiles(accountInfo, cleanRemotes, pollTime);
+
//var relativePath = objectInfo.RelativeUrlToFilePath(accountInfo.UserName);
//And remove those that are already being processed by the agent
throw new ArgumentNullException("cloudFiles");
Contract.EndContractBlock();
- if (_firstPoll) return;
-
- var deleteCandidates = from state in FileState.Queryable
- let stateUrl = FileInfoExtensions.FromPath(state.FilePath)
- .AsRelativeUrlTo(accountInfo.AccountPath)
- where state.Modified <= pollTime &&
- !cloudFiles.Any(r => r.Name == stateUrl)
- select state;
-
- foreach (var deleteCandidate in deleteCandidates)
+ //Check the Modified date to ensure that were just created and haven't been uploaded yet
+ //NOTE: The NHibernate LINQ provider doesn't support custom functions so we need to break the query
+ //in two steps
+ //NOTE: DON'T return files that are already in conflict. The first poll would mark them as
+ //"In Conflict" but subsequent polls would delete them
+ var deleteCandidates = (from state in FileState.Queryable
+ where
+ state.Modified <= pollTime
+ && state.FilePath.StartsWith(accountInfo.AccountPath)
+ && state.FileStatus != FileStatus.Conflict
+ select state).ToList();
+
+ var filesToDelete = (from deleteCandidate in deleteCandidates
+ let localFile = FileInfoExtensions.FromPath(deleteCandidate.FilePath)
+ let relativeFilePath = localFile.AsRelativeTo(accountInfo.AccountPath)
+ where !cloudFiles.Any(r => Path.Combine(r.Container, r.Name) == relativeFilePath)
+ select localFile).ToList();
+
+ //On the first run
+ if (_firstPoll)
+ {
+ //Set the status of missing files to Conflict
+ foreach (var item in filesToDelete)
+ {
+ StatusKeeper.SetFileState(item.FullName, FileStatus.Conflict, FileOverlayStatus.Deleted);
+ }
+ StatusNotification.NotifyConflicts(filesToDelete, String.Format("{0} local files are missing from Pithos, possibly because they were deleted",filesToDelete.Count));
+ }
+ else
{
- File.Delete(deleteCandidate.FilePath);
- StatusKeeper.ClearFileStatus(deleteCandidate.FilePath);
+ foreach (var item in filesToDelete)
+ {
+ item.Delete();
+ StatusKeeper.ClearFileStatus(item.FullName);
+ }
+ StatusNotification.NotifyForFiles(filesToDelete, String.Format("{0} files were deleted",filesToDelete.Count),TraceLevel.Info);
}
+
}
private static void CreateContainerFolders(AccountInfo accountInfo, IEnumerable<ContainerInfo> containers)