Modified selective sync to propagate the creation of new local directories and their...
authorpkanavos <pkanavos@gmail.com>
Mon, 21 May 2012 23:24:21 +0000 (02:24 +0300)
committerpkanavos <pkanavos@gmail.com>
Mon, 21 May 2012 23:24:21 +0000 (02:24 +0300)
Modified "Cancel Current Operation" to immediatelly cancel the upload of the current block
Enalbed build optimization for all projects

20 files changed:
trunk/Libraries/Json40r2/Source/Src/Newtonsoft.Json/Newtonsoft.Json.csproj
trunk/Libraries/ParallelExtensionsExtras/ParallelExtensionsExtras.csproj
trunk/NetSparkle/NetSparkle2010.csproj
trunk/NotifyIconWpf/NotifyIconWpf.csproj
trunk/Pithos.Client.WPF/FileProperties/ConflictResolver.cs
trunk/Pithos.Client.WPF/Pithos.Client.WPF.csproj
trunk/Pithos.Core/Agents/CloudTransferAction.cs
trunk/Pithos.Core/Agents/DeleteAgent.cs
trunk/Pithos.Core/Agents/FileAgent.cs
trunk/Pithos.Core/Agents/NetworkAgent.cs
trunk/Pithos.Core/Agents/SelectiveUris.cs
trunk/Pithos.Core/Agents/Uploader.cs
trunk/Pithos.Core/Agents/WorkflowAgent.cs
trunk/Pithos.Core/Pithos.Core.csproj
trunk/Pithos.Core/WorkflowState.cs
trunk/Pithos.Interfaces/Pithos.Interfaces.csproj
trunk/Pithos.Network/CloudFilesClient.cs
trunk/Pithos.Network/ICloudClient.cs
trunk/Pithos.Network/Pithos.Network.csproj
trunk/Pithos.ShellExtensions/Pithos.ShellExtensions.csproj

index 4b8bf9f..d62ca6d 100644 (file)
@@ -47,7 +47,7 @@
   <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>
index 951f952..9c4adaf 100644 (file)
@@ -18,7 +18,7 @@
   <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>
index 3503aa8..f375f78 100644 (file)
@@ -44,7 +44,7 @@
   <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>
index 01869ea..67e2a9b 100644 (file)
@@ -39,7 +39,7 @@
   <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>
index fe1095f..12424b8 100644 (file)
@@ -94,7 +94,7 @@ namespace Pithos.Client.WPF.FileProperties
                           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);
index 465d212..5323b86 100644 (file)
@@ -36,7 +36,7 @@
     <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>
index 88ca6d5..9f24195 100644 (file)
@@ -227,9 +227,13 @@ namespace Pithos.Core.Agents
 
     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]
index 6659b8a..f7ce256 100644 (file)
@@ -220,7 +220,7 @@ namespace Pithos.Core.Agents
                 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;
index 65c0579..dbbacb4 100644 (file)
@@ -82,13 +82,49 @@ namespace Pithos.Core.Agents
         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)
@@ -105,13 +141,17 @@ namespace Pithos.Core.Agents
                                         });
                     }
                     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);
@@ -322,15 +362,9 @@ namespace Pithos.Core.Agents
             //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)
@@ -476,20 +510,20 @@ namespace Pithos.Core.Agents
             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;
             }
 
index e1b9b16..6431ffe 100644 (file)
@@ -219,7 +219,9 @@ namespace Pithos.Core.Agents
                         {
                             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);
@@ -295,6 +297,34 @@ namespace Pithos.Core.Agents
             }
         }
 
+        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; }
@@ -527,7 +557,7 @@ namespace Pithos.Core.Agents
 
 
                 //The local file is already renamed
-                StatusKeeper.SetFileOverlayStatus(newFilePath, FileOverlayStatus.Modified);
+                StatusKeeper.SetFileOverlayStatus(newFilePath, FileOverlayStatus.Modified).Wait();
 
 
                 var account = action.CloudFile.Account ?? accountInfo.UserName;
@@ -538,7 +568,7 @@ namespace Pithos.Core.Agents
                 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);
             }
         }
index 827f2c5..db60ced 100644 (file)
@@ -86,9 +86,6 @@ namespace Pithos.Core.Agents
 \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
index 1506dad..59ddf66 100644 (file)
@@ -34,7 +34,7 @@ namespace Pithos.Core.Agents
             _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
@@ -51,7 +51,7 @@ namespace Pithos.Core.Agents
                     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
@@ -164,7 +164,7 @@ namespace Pithos.Core.Agents
 \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
@@ -307,9 +307,13 @@ namespace Pithos.Core.Agents
                         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
index b2c3b51..acc5560 100644 (file)
@@ -134,7 +134,7 @@ namespace Pithos.Core.Agents
                             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);
@@ -272,8 +272,11 @@ namespace Pithos.Core.Agents
 
             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");
index 613b632..7542e01 100644 (file)
     <CodeContractsRuntimeCheckingLevel>Full</CodeContractsRuntimeCheckingLevel>
     <CodeContractsReferenceAssembly>Build</CodeContractsReferenceAssembly>
     <CodeContractsAnalysisWarningLevel>0</CodeContractsAnalysisWarningLevel>
+    <Optimize>true</Optimize>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
     <OutputPath>bin\x86\Release\</OutputPath>
index 99943aa..4c7ef36 100644 (file)
@@ -52,6 +52,7 @@ namespace Pithos.Core
 {
     public class WorkflowState
     {
+        public bool IsCreation { get; set; }
         public object Originator { get; set; }
         public AccountInfo AccountInfo { get; set; }
 
index a450690..c6d8d77 100644 (file)
@@ -18,7 +18,7 @@
   <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>
index c4496c9..2f5fed0 100644 (file)
@@ -1124,7 +1124,7 @@ namespace Pithos.Network
         }
 
 
-        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");
@@ -1144,12 +1144,14 @@ namespace Pithos.Network
             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";
@@ -1169,13 +1171,18 @@ namespace Pithos.Network
                     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;
             }
         }
index 0496e36..b4dab54 100644 (file)
@@ -91,7 +91,7 @@ namespace Pithos.Network
         #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
 
@@ -346,7 +346,7 @@ namespace Pithos.Network
             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));
index 02abe61..3db3267 100644 (file)
@@ -18,7 +18,7 @@
   <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>
index 1cb0cb3..6d4ac94 100644 (file)
     <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>