Modified "Cancel Current Operation" to immediatelly cancel the upload of the current block
Enalbed build optimization for all projects
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
- <Optimize>false</Optimize>
+ <Optimize>true</Optimize>
<OutputPath>bin\Debug\Net\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
- <Optimize>false</Optimize>
+ <Optimize>true</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
- <Optimize>false</Optimize>
+ <Optimize>true</Optimize>
<OutputPath>Debug\lib\net40-full\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
- <Optimize>false</Optimize>
+ <Optimize>true</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
let account = accounts.First(acc => conflict.FilePath.StartsWith(acc.AccountPath, StringComparison.InvariantCultureIgnoreCase))
let info = FileInfoExtensions.FromPath(conflict.FilePath)
select new CloudUploadAction(account, info, conflict.State,
- account.BlockSize, account.BlockHash,"Resolver");
+ account.BlockSize, account.BlockHash,"Resolver",false);
actions.Apply(action => StatusAgent.SetFileState(action.FileState.FilePath, FileStatus.Modified, FileOverlayStatus.Normal, "Resolve by downloading"));
actions.Apply(NetworkAgent.Post);
<PlatformTarget>x86</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
- <Optimize>false</Optimize>
+ <Optimize>true</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
public class CloudUploadAction:CloudAction
{
- public CloudUploadAction(AccountInfo accountInfo, FileSystemInfo fileInfo, FileState state, int blockSize, string algorithm,object originator)
- : base(accountInfo, CloudActionType.UploadUnconditional,fileInfo,CreateObjectInfoFor(accountInfo,fileInfo),state,blockSize,algorithm,originator)
+
+ public bool IsCreation { get; set; }
+
+ public CloudUploadAction(AccountInfo accountInfo, FileSystemInfo fileInfo, FileState state, int blockSize, string algorithm,object originator,bool isCreation)
+ : base(accountInfo, CloudActionType.UploadUnconditional,fileInfo,CreateObjectInfoFor(accountInfo,fileInfo),state,blockSize,algorithm,originator)
{
+ IsCreation = isCreation;
}
[ContractInvariantMethod]
var info = fileAgent.GetFileSystemInfo(fileName);
var fullPath = info.FullName.ToLower();
- StatusKeeper.SetFileOverlayStatus(fullPath, FileOverlayStatus.Modified);
+ StatusKeeper.SetFileOverlayStatus(fullPath, FileOverlayStatus.Modified).Wait();
var account = cloudFile.Account ?? accountInfo.UserName;
var container = cloudFile.Container;//?? FolderConstants.PithosContainer;
private void ProcessBatchedEvents(Dictionary<string, FileSystemEventArgs[]> fileEvents)
{
StatusNotification.SetPithosStatus(PithosStatus.LocalSyncing,String.Format("Uploading {0} files",fileEvents.Count));
- foreach (var fileEvent in fileEvents)
+ //Start with events that do not originate in one of the ignored folders
+ var initialEvents = from evt in fileEvents
+ where !IgnorePaths(evt.Key)
+ select evt;
+
+ IEnumerable<KeyValuePair<string, FileSystemEventArgs[]>> cleanEvents;
+
+
+ var selectiveEnabled = Selectives.IsSelectiveEnabled(AccountInfo.AccountKey);
+ //When selective sync is enabled,
+ if (selectiveEnabled)
+ {
+ //Include all selected items
+ var selectedEvents = from evt in initialEvents
+ where Selectives.IsSelected(AccountInfo, evt.Key)
+ select evt;
+ //And all folder creations in the unselected folders
+ var folderCreations = from evt in initialEvents
+ let folderPath=evt.Key
+ //The original folder may not exist due to renames. Just make sure that the path is not a file
+ where !File.Exists(folderPath)
+ //We only want unselected items
+ && !Selectives.IsSelected(AccountInfo, folderPath)
+ //Is there any creation event related to the folder?
+ && evt.Value.Any(arg => arg.ChangeType == WatcherChangeTypes.Created)
+ select evt;
+ cleanEvents = selectedEvents.Union(folderCreations).ToList();
+ }
+ //If selective is disabled, only exclude the shared folders
+ else
{
- var filePath = fileEvent.Key;
+ cleanEvents = (from evt in initialEvents
+ where !evt.Key.IsSharedTo(AccountInfo)
+ select evt).ToList();
+ }
+
+
+ foreach (var fileEvent in cleanEvents)
+ {
+ //var filePath = fileEvent.Key;
var changes = fileEvent.Value;
-
- if (Ignore(filePath)) continue;
-
+
+ var isNotFile = !File.Exists(fileEvent.Key);
foreach (var change in changes)
{
if (change.ChangeType == WatcherChangeTypes.Renamed)
});
}
else
+ {
+ var isCreation = selectiveEnabled && isNotFile && change.ChangeType == WatcherChangeTypes.Created;
_agent.Post(new WorkflowState(change)
- {
- AccountInfo = AccountInfo,
- Path = change.FullPath,
- FileName = Path.GetFileName(change.Name),
- TriggeringChange = change.ChangeType
- });
+ {
+ AccountInfo = AccountInfo,
+ Path = change.FullPath,
+ FileName = Path.GetFileName(change.Name),
+ TriggeringChange = change.ChangeType,
+ IsCreation=isCreation
+ });
+ }
}
}
StatusNotification.SetPithosStatus(PithosStatus.LocalComplete);
//Ignore anything happening in the cache path
if (filePath.StartsWith(CachePath))
return true;
- if (_ignoreFiles.ContainsKey(filePath.ToLower()))
- return true;
- //If selective sync is enabled, propagate folder events
- if (Selectives.IsSelectiveEnabled(AccountInfo.AccountKey) && Directory.Exists(filePath))
- return false;
- //Ignore if selective synchronization is defined,
- //And the target file is not below any of the selective paths
- return !Selectives.IsSelected(AccountInfo, filePath);
+ //Finally, ignore events about one of the ignored files
+ return _ignoreFiles.ContainsKey(filePath.ToLower());
}
/* private static bool FoundInRoot(string filePath, string rootPath)
switch (state.Status)
{
case FileStatus.Created:
- this.StatusKeeper.SetFileOverlayStatus(state.Path, FileOverlayStatus.Modified,state.ShortHash);
+ this.StatusKeeper.SetFileOverlayStatus(state.Path, FileOverlayStatus.Modified,state.ShortHash).Wait();
break;
case FileStatus.Modified:
- this.StatusKeeper.SetFileOverlayStatus(state.Path, FileOverlayStatus.Modified,state.ShortHash);
+ this.StatusKeeper.SetFileOverlayStatus(state.Path, FileOverlayStatus.Modified, state.ShortHash).Wait();
break;
case FileStatus.Deleted:
//this.StatusAgent.RemoveFileOverlayStatus(state.Path);
break;
case FileStatus.Renamed:
this.StatusKeeper.ClearFileStatus(state.OldPath);
- this.StatusKeeper.SetFileOverlayStatus(state.Path, FileOverlayStatus.Modified,state.ShortHash);
+ this.StatusKeeper.SetFileOverlayStatus(state.Path, FileOverlayStatus.Modified, state.ShortHash).Wait();
break;
case FileStatus.Unchanged:
- this.StatusKeeper.SetFileOverlayStatus(state.Path, FileOverlayStatus.Normal,state.ShortHash);
+ this.StatusKeeper.SetFileOverlayStatus(state.Path, FileOverlayStatus.Normal, state.ShortHash).Wait();
break;
}
{
case CloudActionType.UploadUnconditional:
//Abort if the file was deleted before we reached this point
- await Uploader.UploadCloudFile(action,CurrentOperationCancelToken);
+ var uploadAction = (CloudUploadAction) action;
+ ProcessChildUploads(uploadAction);
+ await Uploader.UploadCloudFile(uploadAction ,CurrentOperationCancelToken);
break;
case CloudActionType.DownloadUnconditional:
await Downloader.DownloadCloudFile(accountInfo, cloudFile, downloadPath, CurrentOperationCancelToken);
}
}
+ private void ProcessChildUploads(CloudUploadAction uploadAction)
+ {
+ if (!uploadAction.IsCreation || !(uploadAction.LocalFile is DirectoryInfo))
+ return;
+
+ var dirInfo = uploadAction.LocalFile as DirectoryInfo;
+
+ var account = uploadAction.AccountInfo;
+ var actions = from file in dirInfo.EnumerateFiles("*", SearchOption.AllDirectories)
+ select
+ new CloudUploadAction(account, file, null, account.BlockSize, account.BlockHash,
+ uploadAction, true);
+ foreach (var action in actions)
+ {
+ var state=StatusKeeper.GetStateByFilePath(action.LocalFile.FullName);
+ if (state!=null)
+ state.Delete();
+ //StatusKeeper.SetFileState(action.LocalFile.FullName,FileStatus.Created,FileOverlayStatus.Normal,String.Empty);
+ state=FileState.CreateFor(action.LocalFile);
+ //StatusKeeper.SetFileStatus();
+ state.FileStatus = FileStatus.Created;
+ state.OverlayStatus=FileOverlayStatus.Normal;
+ state.Create();
+ action.FileState = state;
+ Post(action);
+ }
+ }
+
private CancellationToken CurrentOperationCancelToken
{
get { return _currentOperationCancellation.Token; }
//The local file is already renamed
- StatusKeeper.SetFileOverlayStatus(newFilePath, FileOverlayStatus.Modified);
+ StatusKeeper.SetFileOverlayStatus(newFilePath, FileOverlayStatus.Modified).Wait();
var account = action.CloudFile.Account ?? accountInfo.UserName;
client.MoveObject(account, container, action.OldCloudFile.Name, container, action.CloudFile.Name);
StatusKeeper.SetFileStatus(newFilePath, FileStatus.Unchanged);
- StatusKeeper.SetFileOverlayStatus(newFilePath, FileOverlayStatus.Normal);
+ StatusKeeper.SetFileOverlayStatus(newFilePath, FileOverlayStatus.Normal).Wait();
NativeMethods.RaiseChangeNotification(newFilePath);
}
}
\r
public bool IsSelected(AccountInfo account, string fullPath)\r
{\r
- if (Directory.Exists(fullPath))\r
- return true;\r
-\r
//Shared folders should NOT be synced if selective syncing is disabled\r
var isShared = fullPath.IsSharedTo(account);\r
var selectiveEnabled = IsSelectiveEnabled(account.AccountKey);\r
_cts.Cancel();\r
}*/\r
\r
- public async Task UploadCloudFile(CloudAction action,CancellationToken cancellationToken)\r
+ public async Task UploadCloudFile(CloudUploadAction action,CancellationToken cancellationToken)\r
{\r
if (action == null)\r
throw new ArgumentNullException("action");\r
if (fileInfo.Extension.Equals("ignore", StringComparison.InvariantCultureIgnoreCase))\r
return;\r
\r
- if (!Selectives.IsSelected(action.AccountInfo, fileInfo))\r
+ if (!Selectives.IsSelected(action.AccountInfo, fileInfo) && !action.IsCreation)\r
return;\r
\r
//Try to load the action's local state, if it is empty\r
\r
\r
//Mark the file as modified while we upload it\r
- StatusKeeper.SetFileOverlayStatus(fullFileName, FileOverlayStatus.Modified);\r
+ await StatusKeeper.SetFileOverlayStatus(fullFileName, FileOverlayStatus.Modified);\r
//And then upload it\r
\r
//Upload even small files using the Hashmap. The server may already contain\r
try\r
{\r
//And upload the block \r
- await client.PostBlock(account, container, buffer, 0, read);\r
+ await client.PostBlock(account, container, buffer, 0, read, token);\r
Log.InfoFormat("[BLOCK] Block {0} of {1} uploaded", blockIndex, fullFileName);\r
}\r
+ catch (TaskCanceledException exc)\r
+ {\r
+ throw new OperationCanceledException(token);\r
+ }\r
catch (Exception exc)\r
{\r
Log.Error(String.Format("Uploading block {0} of {1}", blockIndex, fullFileName), exc);\r
case FileStatus.Modified:
NetworkAgent.Post(new CloudUploadAction(accountInfo, info, fileState,
accountInfo.BlockSize,
- accountInfo.BlockHash,state));
+ accountInfo.BlockHash,state,state.IsCreation));
break;
case FileStatus.Deleted:
DeleteChildObjects(state, fileState);
if (!Selectives.IsSelected(workflowState.AccountInfo, workflowState.Path))
{
- Log.InfoFormat("File skipped, not under a selected folder [{0}] ", workflowState.Path);
- return;
+ if (!workflowState.IsCreation || File.Exists(workflowState.Path))
+ {
+ Log.InfoFormat("File skipped, not under a selected folder [{0}] ", workflowState.Path);
+ return;
+ }
}
Debug.Assert(workflowState.Path.StartsWith(workflowState.AccountInfo.AccountPath, StringComparison.InvariantCultureIgnoreCase), "File from wrong account posted");
<CodeContractsRuntimeCheckingLevel>Full</CodeContractsRuntimeCheckingLevel>
<CodeContractsReferenceAssembly>Build</CodeContractsReferenceAssembly>
<CodeContractsAnalysisWarningLevel>0</CodeContractsAnalysisWarningLevel>
+ <Optimize>true</Optimize>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
{
public class WorkflowState
{
+ public bool IsCreation { get; set; }
public object Originator { get; set; }
public AccountInfo AccountInfo { get; set; }
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
- <Optimize>false</Optimize>
+ <Optimize>true</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
}
- public async Task PostBlock(string account, string container, byte[] block, int offset, int count)
+ public async Task PostBlock(string account, string container, byte[] block, int offset, int count,CancellationToken token)
{
if (String.IsNullOrWhiteSpace(container))
throw new ArgumentNullException("container");
try
{
- //Don't use a timeout because putting the hashmap may be a long process
+ //Don't use a timeout because putting the hashmap may be a long process
using (var client = new RestClient(_baseClient) { Timeout = 0 })
- {
+ {
if (!String.IsNullOrWhiteSpace(account))
client.BaseAddress = GetAccountUrl(account);
+ token.Register(client.CancelAsync);
+
var builder = client.GetAddressBuilder(container, "");
//We are doing an update
builder.Query = "update";
var buffer = new byte[count];
Buffer.BlockCopy(block, offset, buffer, 0, count);
//Send the block
- await client.UploadDataTaskAsync(uri, "POST", buffer);
+ await client.UploadDataTaskAsync(uri, "POST", buffer);
Log.InfoFormat("[BLOCK POST] END");
}
}
+ catch (TaskCanceledException )
+ {
+ Log.Info("Aborting block");
+ throw;
+ }
catch (Exception exc)
{
- Log.ErrorFormat("[BLOCK POST] FAIL with \r{0}", exc);
+ Log.ErrorFormat("[BLOCK POST] FAIL with \r{0}", exc);
throw;
}
}
#region Hashmap operations
Task<TreeHash> GetHashMap(string account, string container, string objectName);
Task<IList<string>> PutHashMap(string account, string container, string objectName, TreeHash hash);
- Task PostBlock(string account, string container, byte[] block, int offset, int count);
+ Task PostBlock(string account, string container, byte[] block, int offset, int count,CancellationToken token);
Task<byte[]> GetBlock(string account, string container, Uri relativeUrl, long start, long? end,CancellationToken cancellationToken);
#endregion
return default(Task<IList<string>>);
}
- public Task PostBlock(string account, string container, byte[] block, int offset, int count)
+ public Task PostBlock(string account, string container, byte[] block, int offset, int count,CancellationToken token)
{
Contract.Requires(!String.IsNullOrWhiteSpace(Token));
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
- <Optimize>false</Optimize>
+ <Optimize>true</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisIgnoreBuiltInRuleSets>true</CodeAnalysisIgnoreBuiltInRuleSets>
<CodeAnalysisRuleDirectories>;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules</CodeAnalysisRuleDirectories>
<CodeAnalysisIgnoreBuiltInRules>true</CodeAnalysisIgnoreBuiltInRules>
+ <Optimize>true</Optimize>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>