Revision 4f6d51d4 trunk/Pithos.Core/Agents/NetworkAgent.cs

b/trunk/Pithos.Core/Agents/NetworkAgent.cs
1 1
using System;
2
using System.Collections.Concurrent;
2 3
using System.Collections.Generic;
3 4
using System.ComponentModel.Composition;
4 5
using System.Diagnostics;
......
26 27

  
27 28
        private static readonly ILog Log = LogManager.GetLogger("NetworkAgent");
28 29

  
29
        private readonly List<AccountInfo> _accounts=new List<AccountInfo>();
30
        private readonly ConcurrentBag<AccountInfo> _accounts = new ConcurrentBag<AccountInfo>();
30 31

  
31 32
        public void Start()
32 33
        {
......
81 82
                            RenameCloudFile(accountInfo, moveAction);
82 83
                            break;
83 84
                        case CloudActionType.MustSynch:
84

  
85
                            if (!File.Exists(downloadPath))
85
                            if (!File.Exists(downloadPath) && !Directory.Exists(downloadPath))
86 86
                            {
87 87
                                await DownloadCloudFile(accountInfo, cloudFile, downloadPath);
88 88
                            }
......
221 221
            Contract.EndContractBlock();
222 222
            
223 223
            //If the action targets a local file, add a treehash calculation
224
            if (cloudAction.LocalFile != null)
224
            if (cloudAction.LocalFile as FileInfo != null)
225 225
            {
226 226
                var accountInfo = cloudAction.AccountInfo;
227
                if (!Directory.Exists(cloudAction.LocalFile.FullName))
227
                var localFile = (FileInfo) cloudAction.LocalFile;
228
                if (localFile.Length > accountInfo.BlockSize)
229
                    cloudAction.TopHash =
230
                        new Lazy<string>(() => Signature.CalculateTreeHashAsync(localFile,
231
                                                                                accountInfo.BlockSize,
232
                                                                                accountInfo.BlockHash).Result
233
                                                    .TopHash.ToHashString());
234
                else
228 235
                {
229
                    if (cloudAction.LocalFile.Length > accountInfo.BlockSize)
230
                        cloudAction.TopHash =
231
                            new Lazy<string>(() => Signature.CalculateTreeHashAsync(cloudAction.LocalFile,
232
                                                                                    accountInfo.BlockSize,
233
                                                                                    accountInfo.BlockHash).Result
234
                                                       .TopHash.ToHashString());
235
                    else
236
                    {
237
                        cloudAction.TopHash = new Lazy<string>(() => cloudAction.LocalHash.Value);
238
                    }
236
                    cloudAction.TopHash = new Lazy<string>(() => cloudAction.LocalHash.Value);
239 237
                }
240

  
238
            }
239
            else
240
            {
241
                //The hash for a directory is the empty string
242
                cloudAction.TopHash = new Lazy<string>(() => String.Empty);
241 243
            }
242 244
            _agent.Post(cloudAction);
243 245
        }
......
274 276
                    var tasks = from accountInfo in _accounts
275 277
                                select ProcessAccountFiles(accountInfo, since);
276 278

  
277
                    await TaskEx.WhenAll(tasks);
279
                    await TaskEx.WhenAll(tasks.ToList());
278 280

  
279 281
                    ProcessRemoteFiles(nextSince);
280 282
                }
......
377 379
            }
378 380
        }
379 381

  
380
        private static void CreateContainerFolders(AccountInfo accountInfo, IList<ContainerInfo> containers)
382
        private static void CreateContainerFolders(AccountInfo accountInfo, IEnumerable<ContainerInfo> containers)
381 383
        {
382 384
            var containerPaths = from container in containers
383 385
                                 let containerPath = Path.Combine(accountInfo.AccountPath, container.Name)
......
407 409
                
408 410
                if (fileAgent.Exists(relativePath))
409 411
                {
412
                    //If a directory object already exists, we don't need to perform any other action                    
410 413
                    var localFile = fileAgent.GetFileInfo(relativePath);
414
                    if (objectInfo.Content_Type == @"application/directory" && localFile is DirectoryInfo)
415
                        continue;
411 416
                    var state = FileState.FindByFilePath(localFile.FullName);
412 417
                    //Common files should be checked on a per-case basis to detect differences, which is newer
413 418

  
......
756 761
                    var cloudFile = action.CloudFile;
757 762
                    var account = cloudFile.Account ?? accountInfo.UserName;
758 763

  
759
                    var client = new CloudFilesClient(accountInfo);
764
                    var client = new CloudFilesClient(accountInfo);                    
760 765
                    //Even if GetObjectInfo times out, we can proceed with the upload            
761 766
                    var info = client.GetObjectInfo(account, cloudFile.Container, cloudFile.Name);
762
                    var cloudHash = info.Hash.ToLower();
763 767

  
764
                    var hash = action.LocalHash.Value;
765
                    var topHash = action.TopHash.Value;
768
                    //If this is a read-only file, do not upload changes
769
                    if (info.AllowedTo == "read")
770
                        return;
766 771

  
767
                    //If the file hashes match, abort the upload
768
                    if (hash == cloudHash || topHash == cloudHash)
772
                    //WRONG: If this is a directory, there is no hash to check. ????
773
                    //TODO: Check how a directory hash is calculated
774
                    if (fileInfo is DirectoryInfo)
769 775
                    {
770
                        //but store any metadata changes 
771
                        StatusKeeper.StoreInfo(fullFileName, info);
772
                        Log.InfoFormat("Skip upload of {0}, hashes match", fullFileName);
773
                        return;
776
                        //If the directory doesn't exist the Hash property will be empty
777
                        if (String.IsNullOrWhiteSpace(info.Hash))
778
                            //Go on and create the directory
779
                            client.PutObject(account, cloudFile.Container, cloudFile.Name, fileInfo.FullName, String.Empty, "application/directory");
774 780
                    }
781
                    else
782
                    {
775 783

  
776
                    if (info.AllowedTo == "read")
777
                        return;
784
                        var cloudHash = info.Hash.ToLower();
778 785

  
779
                    //Mark the file as modified while we upload it
780
                    StatusKeeper.SetFileOverlayStatus(fullFileName, FileOverlayStatus.Modified);
781
                    //And then upload it
786
                        var hash = action.LocalHash.Value;
787
                        var topHash = action.TopHash.Value;
788

  
789
                        //If the file hashes match, abort the upload
790
                        if (hash == cloudHash || topHash == cloudHash)
791
                        {
792
                            //but store any metadata changes 
793
                            StatusKeeper.StoreInfo(fullFileName, info);
794
                            Log.InfoFormat("Skip upload of {0}, hashes match", fullFileName);
795
                            return;
796
                        }
782 797

  
783
                    //Upload even small files using the Hashmap. The server may already containt
784
                    //the relevant folder
785 798

  
786
                    //First, calculate the tree hash
787
                    var treeHash = await Signature.CalculateTreeHashAsync(fileInfo.FullName, accountInfo.BlockSize,
788
                        accountInfo.BlockHash);
799
                        //Mark the file as modified while we upload it
800
                        StatusKeeper.SetFileOverlayStatus(fullFileName, FileOverlayStatus.Modified);
801
                        //And then upload it
789 802

  
790
                    await UploadWithHashMap(accountInfo, cloudFile, fileInfo, cloudFile.Name, treeHash);
803
                        //Upload even small files using the Hashmap. The server may already contain
804
                        //the relevant block
791 805

  
806
                        //First, calculate the tree hash
807
                        var treeHash = await Signature.CalculateTreeHashAsync(fileInfo.FullName, accountInfo.BlockSize,
808
                                                                              accountInfo.BlockHash);
809

  
810
                        await UploadWithHashMap(accountInfo, cloudFile, fileInfo as FileInfo, cloudFile.Name, treeHash);
811
                    }
792 812
                    //If everything succeeds, change the file and overlay status to normal
793 813
                    StatusKeeper.SetFileState(fullFileName, FileStatus.Unchanged, FileOverlayStatus.Normal);
794 814
                }

Also available in: Unified diff