Replaced object load and update with direct HQL execution to resolve database locks...
authorPanagiotis Kanavos <pkanavos@gmail.com>
Thu, 5 Jan 2012 18:08:09 +0000 (20:08 +0200)
committerPanagiotis Kanavos <pkanavos@gmail.com>
Thu, 5 Jan 2012 18:08:09 +0000 (20:08 +0200)
Removed dead code in StatusAgent.cs

1  2 
trunk/Pithos.Core/Agents/FileAgent.cs
trunk/Pithos.Core/Agents/NetworkAgent.cs
trunk/Pithos.Core/Agents/StatusAgent.cs
trunk/Pithos.Core/Agents/WorkflowAgent.cs
trunk/Pithos.Core/FileState.cs
trunk/Pithos.Core/NativeMethods.cs
trunk/Pithos.Interfaces/ObjectInfo.cs
trunk/Pithos.Network/CloudFilesClient.cs

@@@ -52,77 -102,9 +52,68 @@@ namespace Pithos.Core.Agent
              _watcher.Deleted += OnFileEvent;
              _watcher.Renamed += OnRenameEvent;
              _watcher.EnableRaisingEvents = true;
 -           
 +
 +
 +            _agent = Agent<WorkflowState>.Start(inbox =>
 +            {
 +                Action loop = null;
 +                loop = () =>
 +                {
 +                    var message = inbox.Receive();
 +                    var process=message.Then(Process,inbox.CancellationToken);
 +
 +                    inbox.LoopAsync(process,loop,ex=>
 +                        Log.ErrorFormat("[ERROR] File Event Processing:\r{0}", ex));
 +                };
 +                loop();
 +            });
 +        }
 +
 +        private Task<object> Process(WorkflowState state)
 +        {
 +            if (state==null)
 +                throw new ArgumentNullException("state");
 +            Contract.EndContractBlock();
 +
 +            Debug.Assert(!Ignore(state.Path));
 +
 +            var networkState = NetworkGate.GetNetworkState(state.Path);
 +            //Skip if the file is already being downloaded or uploaded and 
 +            //the change is create or modify
 +            if (networkState != NetworkOperation.None &&
 +                (
 +                    state.TriggeringChange == WatcherChangeTypes.Created ||
 +                    state.TriggeringChange == WatcherChangeTypes.Changed
 +                ))
 +                return CompletedTask<object>.Default;
 +
 +            try
 +            {
 +                UpdateFileStatus(state);
 +                UpdateOverlayStatus(state);
 +                UpdateFileChecksum(state);
 +                WorkflowAgent.Post(state);
 +            }
 +            catch (IOException exc)
 +            {
 +                if (File.Exists(state.Path))
 +                {
 +                    Log.WarnFormat("File access error occured, retrying {0}\n{1}", state.Path, exc);
 +                    _agent.Post(state);
 +                }
 +                else
 +                {
 +                    Log.WarnFormat("File {0} does not exist. Will be ignored\n{1}", state.Path, exc);
 +                }
 +            }
 +            catch (Exception exc)
 +            {
 +                Log.WarnFormat("Error occured while indexing{0}. The file will be skipped\n{1}",
 +                               state.Path, exc);
 +            }
 +            return CompletedTask<object>.Default;
          }
  
- /*
-         private Task Process(Task<WorkflowState> action)
-         {
-             return action.ContinueWith(t => Process(t.Result));
-         }
- */
          public bool Pause
          {
              get { return _watcher == null || !_watcher.EnableRaisingEvents; }
              //Ignore events that affect the cache folder
              var filePath = e.FullPath;
              if (Ignore(filePath)) 
--                return;           
--            
++                return;
++            if (Directory.Exists(filePath))
++                return;            
              _agent.Post(new WorkflowState{AccountInfo=AccountInfo, Path = filePath, FileName = e.Name, TriggeringChange = e.ChangeType });
          }
  
@@@ -95,7 -95,7 +95,7 @@@ namespace Pithos.Core.Agent
                              break;
                          case CloudActionType.DownloadUnconditional:
  
--                            await DownloadCloudFile(accountInfo,  cloudFile,downloadPath);
++                            await DownloadCloudFile(accountInfo, cloudFile, downloadPath);
                              break;
                          case CloudActionType.DeleteCloud:
                              DeleteCloudFile(accountInfo, cloudFile);
                          case CloudActionType.MustSynch:
  
                              if (!File.Exists(downloadPath))
--                            {                                
++                            {
                                  await DownloadCloudFile(accountInfo, cloudFile, downloadPath);
                              }
                              else
                      Log.InfoFormat("[ACTION] End Processing {0}:{1}->{2}", action.Action, action.LocalFile,
                                             action.CloudFile.Name);
                  }
++                catch (WebException exc)
++                {
++                    Log.ErrorFormat("[WEB ERROR] {0} : {1} -> {2} due to exception\r\n{3}", action.Action, action.LocalFile, action.CloudFile, exc);                    
++                }
                  catch (OperationCanceledException)
                  {
                      throw;
                      if (task.IsFaulted)
                      {
                          //ListObjects failed at this point, need to reschedule
--                        Log.ErrorFormat("[FAIL] ListObjects for{0} in ProcessRemoteFiles with {0}", accountInfo.UserName,task.Exception);
++                        Log.ErrorFormat("[FAIL] ListObjects for{0} in ProcessRemoteFiles with {1}", accountInfo.UserName,task.Exception);
                          return;
                      }
                      using (log4net.ThreadContext.Stacks["SCHEDULE"].Push("Process Results"))
                          //Items with the same name, hash may be both in the container and the trash
                          //Don't delete items that exist in the container
                          var realTrash = from trash in trashObjects
--                                        where !remoteObjects.Any(info => info.Hash == trash.Hash)
++                                        where !remoteObjects.Any(info => info.Name == trash.Name &&  info.Hash == trash.Hash)
                                          select trash;
                          ProcessDeletedFiles(accountInfo,realTrash);                        
  
@@@ -1,6 -1,6 +1,7 @@@
  using System;
  using System.Collections.Generic;
  using System.ComponentModel.Composition;
++using System.Data.SQLite;
  using System.Diagnostics;
  using System.Diagnostics.Contracts;
  using System.IO;
@@@ -12,9 -13,9 +13,6 @@@ using Castle.ActiveRecord.Framework.Con
  using Pithos.Interfaces;
  using Pithos.Network;
  using log4net;
--using log4net.Appender;
--using log4net.Config;
--using log4net.Layout;
  
  namespace Pithos.Core.Agents
  {
  
          public void StartProcessing(CancellationToken token)
          {
 -            _persistenceAgent = new ActionBlock<Action>(async action=>
 +            _persistenceAgent = Agent<Action>.Start(queue =>
              {
 -                    try
 -                    {
 -                        await TaskEx.Run(action);
 -                    }
 -                    catch (Exception ex)
 +                Action loop = null;
 +                loop = () =>
 +                {
 +                    var job = queue.Receive();
 +                    job.ContinueWith(t =>
                      {
 -                        Log.ErrorFormat("[ERROR] STATE \n{0}",ex);
 -                    }
 +                        var action = job.Result;
 +                        try
 +                        {
 +                            action();
 +                        }
++                        catch (SQLiteException ex)
++                        {
++                            Log.ErrorFormat("[ERROR] SQL \n{0}", ex);
++                        }
 +                        catch (Exception ex)
 +                        {
-                             Log.ErrorFormat("[ERROR] STATE \n{0}",ex);
++                            Log.ErrorFormat("[ERROR] STATE \n{0}", ex);
 +                        }
++// ReSharper disable AccessToModifiedClosure
 +                        queue.DoAsync(loop);
++// ReSharper restore AccessToModifiedClosure
 +                    });
 +                };
 +                loop();
              });
              
          }
                  {
                      //This is a new file
                      var fullPath = pair.File.FullName.ToLower();
--                    var createState = FileState.CreateForAsync(fullPath, this.BlockSize, this.BlockHash);
++                    var createState = FileState.CreateForAsync(fullPath, BlockSize, BlockHash);
                      createState.ContinueWith(state => _persistenceAgent.Post(state.Result.Create));
                  }                
                  else if (file == null)
          }
  
  
--        private string _pithosDataPath;
-         public T GetStatus<T>(string path,Func<FileState,T> getter,T defaultValue )
-         {
-             if (String.IsNullOrWhiteSpace(path))
-                 throw new ArgumentNullException("path");
-             if (!Path.IsPathRooted(path))
-                 throw new ArgumentException("path must be a rooted path", "path");
-             if (getter == null)
-                 throw new ArgumentNullException("getter");
-             Contract.EndContractBlock();
-             try
-             {                
-                 var state = FileState.FindByFilePath(path);
-                 return state == null ? defaultValue : getter(state);
-             }
-             catch (Exception exc)
-             {
-                 Log.ErrorFormat(exc.ToString());
-                 return defaultValue;
-             }
-         }
-         /// <summary>
-         /// Sets the status of a file, creating a new FileState entry if one doesn't already exist.
-         /// </summary>
-         /// <param name="path"></param>
-         /// <param name="setter"></param>
-         public void SetStatus(string path,Action<FileState> setter)
-         {
-             if (String.IsNullOrWhiteSpace(path))
-                 throw new ArgumentNullException("path", "path can't be empty");
-             if (setter==null)
-                 throw new ArgumentNullException("setter", "setter can't be empty");
-             Contract.EndContractBlock();
 -       
++        private readonly string _pithosDataPath;
 +
-             _persistenceAgent.Post(() =>
-             {
-                 using (new SessionScope())
-                 {
-                     var filePath = path.ToLower();
-                     var state = FileState.FindByFilePath(filePath);
-                     if (state != null)
-                     {
-                         setter(state);
-                         state.Save();
-                     }
-                     else
-                     {
-                         state = new FileState {FilePath = filePath,Id=Guid.NewGuid()};
-                         setter(state);
-                         state.Save();
-                     }                    
-                 }
-             });
-         }
-         /// <summary>
-         /// Sets the status of a file only if the file already exists
-         /// </summary>
-         /// <param name="path"></param>
-         /// <param name="setter"></param>
-         private void UpdateStatus(string path, Action<FileState> setter)
-         {
-             if (String.IsNullOrWhiteSpace(path))
-                 throw new ArgumentNullException("path");
-             if (!Path.IsPathRooted(path))
-                 throw new ArgumentException("The path must be rooted", "path");
-             if (setter == null)
-                 throw new ArgumentNullException("setter");
-             Contract.EndContractBlock();
-             Debug.Assert(!path.Contains(FolderConstants.CacheFolder));
-             Debug.Assert(!path.EndsWith(".ignore"));
-             if (String.IsNullOrWhiteSpace(path))
-                 throw new ArgumentNullException("path", "path can't be empty");
-             if (setter == null)
-                 throw new ArgumentNullException("setter", "setter can't be empty");
-             _persistenceAgent.Post(() =>
-             {
-                 using (new SessionScope())
-                 {
-                     var filePath = path.ToLower();
-                     var state = FileState.FindByFilePath(filePath);
-                     if (state == null)
-                     {
-                         Log.WarnFormat("[NOFILE] Unable to set status for {0}.", filePath);
-                         state = new FileState { FilePath = path, Id = Guid.NewGuid() };
-                         state.Create();                        
-                     }
-                     setter(state);
-                     state.Save();
-                 }
-                 
-             });
-         }
-         
-         /// <summary>
-         /// Sets the status of a specific state
-         /// </summary>
-         /// <param name="path"></param>
-         /// <param name="setter"></param>
-         private void UpdateStatus(Guid stateID, Action<FileState> setter)
-         {
-             if (setter == null)
-                 throw new ArgumentNullException("setter");
-             Contract.EndContractBlock();
-             _persistenceAgent.Post(() =>
-             {
-                 using (new SessionScope())
-                 {
-                     var state = FileState.Find(stateID);
-                     if (state == null)
-                     {
-                         Log.WarnFormat("[NOFILE] Unable to set status for {0}.", stateID);
-                         return;
-                     }
-                     setter(state);
-                     state.Save();
-                 }
-                 
-             });
-         }
  
          public FileOverlayStatus GetFileOverlayStatus(string path)
          {
  
              try
              {
 +
-                 //var state = FileState.FindByFilePath(path);
-                 var st=from state in FileState.Queryable
-                        where state.FilePath == path.ToLower()
-                        select state.OverlayStatus; ;                
-                 return st.FirstOrDefault(); // state == null ? FileOverlayStatus.Unversioned : state.OverlayStatus;
+                 var status = from state in  FileState.Queryable 
+                                  where state.FilePath ==path.ToLower()
+                                  select state.OverlayStatus;
+                 return status.Any()? status.First():FileOverlayStatus.Unversioned;
              }
              catch (Exception exc)
              {
                  throw new ArgumentException("The path must be rooted","path");
              Contract.EndContractBlock();
  
-             SetStatus(path.ToLower(),s=>s.OverlayStatus=overlayStatus);
-         }
-         /*public void RemoveFileOverlayStatus(string path)
-         {
-             if (String.IsNullOrWhiteSpace(path))
-                 throw new ArgumentNullException("path");
-             if (!Path.IsPathRooted(path))
-                 throw new ArgumentException("The path must be rooted", "path");
-             Contract.EndContractBlock();
-             _persistenceAgent.Post(() =>
-                 InnerRemoveFileOverlayStatus(path));
-         }
-         private static void InnerRemoveFileOverlayStatus(string path)
-         {
-             if (String.IsNullOrWhiteSpace(path))
-                 throw new ArgumentNullException("path");
-             if (!Path.IsPathRooted(path))
-                 throw new ArgumentException("The path must be rooted", "path");
-             Contract.EndContractBlock();
-             FileState.DeleteByFilePath(path);            
-         }*/
-         public void RenameFileOverlayStatus(string oldPath, string newPath)
-         {
-             if (String.IsNullOrWhiteSpace(oldPath))
-                 throw new ArgumentNullException("oldPath");
-             if (!Path.IsPathRooted(oldPath))
-                 throw new ArgumentException("The oldPath must be rooted", "oldPath");
-             if (String.IsNullOrWhiteSpace(newPath))
-                 throw new ArgumentNullException("newPath");
-             if (!Path.IsPathRooted(newPath))
-                 throw new ArgumentException("The newPath must be rooted", "newPath");
-             Contract.EndContractBlock();
-             _persistenceAgent.Post(() =>
-                 InnerRenameFileOverlayStatus(oldPath, newPath));
+             _persistenceAgent.Post(() => FileState.StoreOverlayStatus(path.ToLower(),overlayStatus));
          }
  
-         private static void InnerRenameFileOverlayStatus(string oldPath, string newPath)
 -        /*public void RemoveFileOverlayStatus(string path)
 -        {
 -            if (String.IsNullOrWhiteSpace(path))
 -                throw new ArgumentNullException("path");
 -            if (!Path.IsPathRooted(path))
 -                throw new ArgumentException("The path must be rooted", "path");
 -            Contract.EndContractBlock();
 -
 -            _persistenceAgent.Post(() =>
 -                InnerRemoveFileOverlayStatus(path));
 -        }
 -
 -        private static void InnerRemoveFileOverlayStatus(string path)
 -        {
 -            if (String.IsNullOrWhiteSpace(path))
 -                throw new ArgumentNullException("path");
 -            if (!Path.IsPathRooted(path))
 -                throw new ArgumentException("The path must be rooted", "path");
 -            Contract.EndContractBlock();
 -
 -            FileState.DeleteByFilePath(path);            
 -        }*/
 -
 -        public void RenameFileOverlayStatus(string oldPath, string newPath)
++       /* public void RenameFileOverlayStatus(string oldPath, string newPath)
          {
              if (String.IsNullOrWhiteSpace(oldPath))
                  throw new ArgumentNullException("oldPath");
                  throw new ArgumentException("The newPath must be rooted", "newPath");
              Contract.EndContractBlock();
  
-             var state = FileState.FindByFilePath(oldPath);
-             if (state == null)
-             {
-                 Log.WarnFormat("[NOFILE] Unable to set status for {0}.", oldPath);
-                 return;
-             }
-             //NOTE: This will cause problems if path is used as a key in relationships
-             state.FilePath = newPath;
-             state.Update();
-         }
+             _persistenceAgent.Post(() =>FileState.RenameState(oldPath, newPath));
 -        }
++        }*/
  
          public void SetFileState(string path, FileStatus fileStatus, FileOverlayStatus overlayStatus)
          {
                      state.FileStatus = FileStatus.Unchanged;
                      state.OverlayStatus = FileOverlayStatus.Normal;
                      
--                    //Create a list of tags from the ObjectInfo's tag dictionary
--                    //Make sure to bind each tag to its parent state so we don't have to save each tag separately
--                    //state.Tags = (from pair in objectInfo.Tags
--                    //                select
--                    //                    new FileTag
--                    //                        {
--                    //                            FileState = state,
--                    //                            Name = pair.Key,
--                    //                            Value = pair.Value
--                    //                        }
--                    //            ).ToList();
--
++                  
                      //Do the save
                      state.Save();
                  }
              if (!Path.IsPathRooted(path))
                  throw new ArgumentException("The path must be rooted", "path");
              Contract.EndContractBlock();
--
--            //TODO:SHOULDN'T need both clear file status and remove overlay status
--            _persistenceAgent.Post(() =>
--            {
--                using (new SessionScope())
--                {
--                    FileState.DeleteByFilePath(path);
--                }
--            });   
++            
++            _persistenceAgent.Post(() => FileState.DeleteByFilePath(path));   
          }
  
          public void UpdateFileChecksum(string path, string checksum)
@@@ -48,48 -68,45 +48,59 @@@ namespace Pithos.Core.Agent
              var accountInfo = state.AccountInfo;
              using (log4net.ThreadContext.Stacks["Workflow"].Push("Process"))
              {
--                if (Log.IsDebugEnabled) Log.DebugFormat("State {0} {1} {2}", state.FileName,state.Status,state.TriggeringChange);
--
--                if (state.Skip)
 -                {
 -                    if (Log.IsDebugEnabled) Log.DebugFormat("Skipping {0}",state.FileName);
 -                    
 -                    return null;
 -                }
 -                string path = state.Path.ToLower();
 -
 -                //Bypass deleted files, unless the status is Deleted
 -                if (!File.Exists(path) && state.Status != FileStatus.Deleted)
++                try
                  {
-                     if (Log.IsDebugEnabled) Log.DebugFormat("Skipping {0}",state.FileName);
-                     
-                     return CompletedTask<object>.Default;
-                 }
-                 string path = state.Path.ToLower();
 -                    state.Skip = true;
 -                    this.StatusKeeper.ClearFileStatus(path);
 -                    
 -                    if (Log.IsDebugEnabled) Log.DebugFormat("Skipped missing {0}", state.FileName);
  
-                 //Bypass deleted files, unless the status is Deleted
-                 if (!File.Exists(path) && state.Status != FileStatus.Deleted)
-                 {
-                     state.Skip = true;
-                     this.StatusKeeper.ClearFileStatus(path);
-                     
-                     if (Log.IsDebugEnabled) Log.DebugFormat("Skipped missing {0}", state.FileName);
 -                    return null;
++                    if (Log.IsDebugEnabled)
++                        Log.DebugFormat("State {0} {1} {2}", state.FileName, state.Status, state.TriggeringChange);
++
++                    if (state.Skip)
++                    {
++                        if (Log.IsDebugEnabled) Log.DebugFormat("Skipping {0}", state.FileName);
++
++                        return CompletedTask<object>.Default;
++                    }
++                    string path = state.Path.ToLower();
++
++                    //Bypass deleted files, unless the status is Deleted
++                    if (!File.Exists(path) && state.Status != FileStatus.Deleted)
++                    {
++                        state.Skip = true;
++                        this.StatusKeeper.ClearFileStatus(path);
++
++                        if (Log.IsDebugEnabled) Log.DebugFormat("Skipped missing {0}", state.FileName);
++
++                        return CompletedTask<object>.Default;
++                    }
++
++                    var fileState = FileState.FindByFilePath(path);
++                    var info = new FileInfo(path);
++
++
++                    switch (state.Status)
++                    {
++                        case FileStatus.Created:
++                        case FileStatus.Modified:
++                            NetworkAgent.Post(new CloudUploadAction(accountInfo, info, fileState, accountInfo.BlockSize,
++                                                                    accountInfo.BlockHash));
++                            break;
++                        case FileStatus.Deleted:
++                            NetworkAgent.Post(new CloudDeleteAction(accountInfo, info, fileState));
++                            break;
++                        case FileStatus.Renamed:
++                            NetworkAgent.Post(new CloudMoveAction(accountInfo, CloudActionType.RenameCloud,
++                                                                  new FileInfo(state.OldPath),
++                                                                  new FileInfo(state.Path)));
++                            break;
++                    }
 +
 +                    return CompletedTask<object>.Default;
                  }
--
--                var fileState = FileState.FindByFilePath(path);
--                var info = new FileInfo(path);
--
--
--                switch (state.Status)
++                catch (Exception ex)
                  {
--                    case FileStatus.Created:
--                    case FileStatus.Modified:
-                         NetworkAgent.Post(new CloudUploadAction(accountInfo,info, fileState, accountInfo.BlockSize,
-                             accountInfo.BlockHash));
-                         break;
-                     case FileStatus.Deleted:                       
-                         NetworkAgent.Post(new CloudDeleteAction(accountInfo,info, fileState));
-                         break;
-                     case FileStatus.Renamed:
-                         NetworkAgent.Post(new CloudMoveAction(accountInfo,CloudActionType.RenameCloud, new FileInfo(state.OldPath),
-                                                               new FileInfo(state.Path)));
-                         break;
 -                        return new CloudUploadAction(accountInfo,info, fileState, accountInfo.BlockSize,
 -                            accountInfo.BlockHash);
 -                    case FileStatus.Deleted:                       
 -                        return new CloudDeleteAction(accountInfo,info, fileState);
 -                    case FileStatus.Renamed:
 -                        return new CloudMoveAction(accountInfo,CloudActionType.RenameCloud, 
 -                            new FileInfo(state.OldPath),
 -                            new FileInfo(state.Path));
++                    Log.Error(ex.ToString());
++                    throw;
                  }
-                 return CompletedTask<object>.Default;
 -                return null;
              }
          }
  
                                       where state.FileStatus != FileStatus.Unchanged &&
                                             !state.FilePath.StartsWith(cachePath) &&
                                             !state.FilePath.EndsWith(".ignore") &&
 -                                           state.FilePath.StartsWith(accountInfo.AccountPath)
 +                                           state.FilePath.StartsWith(account.AccountPath)
                                       select state;
 +                var pendingStates = new List<WorkflowState>();
 +                foreach (var state in pendingEntries)
 +                {
-                     pendingStates.Add(new WorkflowState(account, state));
++                    if (!Directory.Exists(state.FilePath))
++                        pendingStates.Add(new WorkflowState(account, state));
 +                }
                  if (Log.IsDebugEnabled)
 -                    Log.DebugFormat("Found {0} interrupted files",pendingEntries.Count());
 -
 -                var validEntries = from state in pendingEntries
 -                                   select new WorkflowState
 -                                              {
 -                                                  AccountInfo=accountInfo,
 -                                                  Path = state.FilePath.ToLower(),
 -                                                  FileName = Path.GetFileName(state.FilePath).ToLower(),
 -                                                  Hash = state.Checksum,
 -                                                  Status = state.OverlayStatus == FileOverlayStatus.Unversioned
 -                                                               ? FileStatus.Created
 -                                                               : state.FileStatus,
 -                                                  TriggeringChange =
 -                                                      state.OverlayStatus == FileOverlayStatus.Unversioned
 -                                                          ? WatcherChangeTypes.Created
 -                                                          : WatcherChangeTypes.Changed
 -                                              };
 -                foreach (var entry in validEntries)
 -                {                    
 -                    Post(entry);
 +                    Log.DebugFormat("Found {0} interrupted files", pendingStates.Count);
 +
 +
 +                foreach (var entry in pendingStates)
 +                {
 +                    //Remove invalid state            
 +                    if (Directory.Exists(entry.Path))
 +                    {
 +                        Debug.Assert(false, "State has path instead of file", entry.Path);
 +                        StatusKeeper.ClearFileStatus(entry.Path);
 +                        return;
 +                    }
 +                    else
 +                        Post(entry);
                  }
              }
 -        }       
 +        }
 +
  
 -       
  
          public void Post(WorkflowState workflowState)
          {
@@@ -9,19 -9,18 +9,15 @@@ using System.IO
  using System.Threading.Tasks;
  using Castle.ActiveRecord;
  using Castle.ActiveRecord.Framework;
--using Castle.ActiveRecord.Queries;
--using NHibernate.Engine;
  using Pithos.Core.Agents;
  using Pithos.Interfaces;
--using Pithos.Network;
 +using log4net;
  
  namespace Pithos.Core
  {
      using System;
      using System.Collections.Generic;
      using System.Linq;
--    using System.Text;
  
      /// <summary>
      /// TODO: Update summary.
          [Property]
          public string Checksum { get; set; }
  
--/*
--        [Property]
--        public string TopHash { get; set; }
--*/
  
          [Property]
          public long? Version { get; set; }
              set { _tags=value;}
          }
  
--//        [HasMany(Cascade = ManyRelationCascadeEnum.AllDeleteOrphan, Lazy = true)]
--//        public IList<FileHash> Hashes { get; set; }
--
--//        [Property]
--//        public byte[] HashmapHash { get; set; }
--       
++   
          public static FileState FindByFilePath(string absolutePath)
          {
              if (string.IsNullOrWhiteSpace(absolutePath))
                  throw new ArgumentNullException("absolutePath");
              Contract.EndContractBlock();
              
--            FileState.Execute((session, instance) =>
++            Execute((session, instance) =>
                               {
                                   const string hqlDelete = "delete FileState where FilePath = :path";                                 
                                   var deletedEntities = session.CreateQuery(hqlDelete)
                                           .SetString("path", absolutePath.ToLower())
                                           .ExecuteUpdate();
--                                 return null;
++                                 return deletedEntities;
                               },null);
              
          }
  
+         public static void StoreFileStatus(string absolutePath, FileStatus newStatus)
+         {
+             if (string.IsNullOrWhiteSpace(absolutePath))
+                 throw new ArgumentNullException("absolutePath");
+             Contract.EndContractBlock();
+             Execute((session, instance) =>
+             {
+                 const string hqlUpdate = "update FileState set FileStatus= :status where FilePath = :path  ";
+                 var updatedEntities = session.CreateQuery(hqlUpdate)
+                         .SetString("path", absolutePath.ToLower())
+                         .SetEnum("status", newStatus)
+                         .ExecuteUpdate();
+                 if (updatedEntities == 0)
+                 {
+                     var newState = new FileState { FilePath = absolutePath, Id = Guid.NewGuid(), FileStatus = newStatus };
+                     newState.CreateAndFlush();
+                 }
+                 return null;
+             }, null);
+         }
+         public static void StoreOverlayStatus(string absolutePath, FileOverlayStatus newStatus)
+         {
+             if (string.IsNullOrWhiteSpace(absolutePath))
+                 throw new ArgumentNullException("absolutePath");
+             Contract.EndContractBlock();
+             Execute((session, instance) =>
+             {
+                 const string hqlUpdate = "update FileState set OverlayStatus= :status where FilePath = :path  ";
+                 var updatedEntities = session.CreateQuery(hqlUpdate)
+                         .SetString("path", absolutePath.ToLower())
+                         .SetEnum("status", newStatus)
+                         .ExecuteUpdate();
+                 if (updatedEntities == 0)
+                 {
+                     var newState = new FileState { FilePath = absolutePath, Id = Guid.NewGuid(), OverlayStatus = newStatus };
+                     newState.CreateAndFlush();
+                 }
+                 return null;
+             }, null);
+         }
+         public static void UpdateStatus(string absolutePath, FileStatus fileStatus, FileOverlayStatus overlayStatus)
+         {
+             if (string.IsNullOrWhiteSpace(absolutePath))
+                 throw new ArgumentNullException("absolutePath");
+             Contract.EndContractBlock();
+             Execute((session, instance) =>
+             {
+                 const string hqlUpdate = "update FileState set OverlayStatus= :overlayStatus, FileStatus= :fileStatus where FilePath = :path  ";
+                 var updatedEntities = session.CreateQuery(hqlUpdate)
+                         .SetString("path", absolutePath.ToLower())
+                         .SetEnum("fileStatus", fileStatus)
+                         .SetEnum("overlayStatus", overlayStatus)
+                         .ExecuteUpdate();
 -                return null;
++                return updatedEntities;
+             }, null);
+         }
+         public static void UpdateStatus(string absolutePath, FileStatus fileStatus)
+         {
+             if (string.IsNullOrWhiteSpace(absolutePath))
+                 throw new ArgumentNullException("absolutePath");
+             Contract.EndContractBlock();
+             Execute((session, instance) =>
+             {
+                 const string hqlUpdate = "update FileState set FileStatus= :fileStatus where FilePath = :path  ";
+                 var updatedEntities = session.CreateQuery(hqlUpdate)
+                         .SetString("path", absolutePath.ToLower())
+                         .SetEnum("fileStatus", fileStatus)                        
+                         .ExecuteUpdate();
+                 return updatedEntities;
+             }, null);
+         }
+         public static void RenameState(string oldPath, string newPath)
+         {
+             if (string.IsNullOrWhiteSpace(oldPath))
+                 throw new ArgumentNullException("oldPath");
+             Contract.EndContractBlock();
+             Execute((session, instance) =>
+             {
+                 const string hqlUpdate = "update FileState set FilePath= :newPath where FilePath = :oldPath  ";
+                 var updatedEntities = session.CreateQuery(hqlUpdate)
+                         .SetString("oldPath", oldPath.ToLower())
+                         .SetString("newPath", newPath.ToLower())                                          
+                         .ExecuteUpdate();
+                 return updatedEntities;
+             }, null);
+         }
+         public static void UpdateStatus(Guid id, FileStatus fileStatus)
+         {
+             Contract.EndContractBlock();
+             Execute((session, instance) =>
+             {
+                 const string hqlUpdate = "update FileState set FileStatus= :fileStatus where Id = :id  ";
+                 var updatedEntities = session.CreateQuery(hqlUpdate)
+                         .SetGuid("id", id)
+                         .SetEnum("fileStatus", fileStatus)                        
+                         .ExecuteUpdate();
 -                return null;
++                return updatedEntities;
+             }, null);
+         }
+         public static void UpdateChecksum(string absolutePath, string checksum)
+         {
+             if (string.IsNullOrWhiteSpace(absolutePath))
+                 throw new ArgumentNullException("absolutePath");
+             Contract.EndContractBlock();
+             Execute((session, instance) =>
+             {
+                 const string hqlUpdate = "update FileState set Checksum= :checksum where FilePath = :path  ";
+                 var updatedEntities = session.CreateQuery(hqlUpdate)
+                         .SetString("path", absolutePath.ToLower())
+                         .SetString("checksum", checksum)                        
+                         .ExecuteUpdate();
 -                return null;
++                return updatedEntities;
+             }, null);
+         }
          public static void ChangeRootPath(string oldPath,string newPath)
          {
              if (String.IsNullOrWhiteSpace(oldPath))
                              {
                                  const string hqlUpdate =
                                      "update FileState set FilePath = replace(FilePath,:oldPath,:newPath) where FilePath like :oldPath || '%' ";
--                                var result=session.CreateQuery(hqlUpdate)
++                                var renames=session.CreateQuery(hqlUpdate)
                                      .SetString("oldPath", oldPath.ToLower())
                                      .SetString("newPath", newPath.ToLower())
                                      .ExecuteUpdate();
--                                return null;
++                                return renames;
                              }, null);
              }
          }
          public FileState FileState { get; set; }
  
      }
--    
--  /*  [ActiveRecord("hashes")]
--    public class FileHash : ActiveRecordLinqBase<FileHash>
--    {
--        [PrimaryKey]
--        public int Id { get; set; }
--
--        [Property]
--        public int Order { get; set; }
--
--        [Property]
--        public byte[] Value { get; set; }        
--
--        [BelongsTo("FileStateID")]
--        public FileState FileState { get; set; }
--
--    }*/
--
--
++   
  }
@@@ -283,7 -283,7 +283,7 @@@ namespace Pithos.Cor
                  throw new ArgumentNullException("path", "The path parameter must not be emtpy");
  
              if (!Directory.Exists(path) && !File.Exists(path))
--                throw new FileNotFoundException("The specified file or path does not exist", path);
++                return;
  
  
              IntPtr pathPointer = Marshal.StringToCoTaskMemAuto(path);
@@@ -1,5 -1,5 +1,6 @@@
  using System;
  using System.Collections.Generic;
++using System.Diagnostics;
  using System.Diagnostics.Contracts;
  using System.Dynamic;
  using System.Globalization;
@@@ -10,6 -10,6 +11,7 @@@ using Newtonsoft.Json
  
  namespace Pithos.Interfaces
  {
++    [DebuggerDisplay("Name {Name}")]
      public class ObjectInfo:DynamicObject 
      {
          private readonly List<string> _knownContainers= new List<string>{"trash"};
              _extensions.TryGetValue(name, out value);
              return value ;                        
          }
--
++        
          private long? GetLong(string name)
          {
              string version;
@@@ -1110,7 -1109,7 +1110,7 @@@ namespace Pithos.Networ
          }
  
  
--        public Task<TreeHash> GetHashMap(string account, string container, string objectName)
++        public async Task<TreeHash> GetHashMap(string account, string container, string objectName)
          {
              if (String.IsNullOrWhiteSpace(container))
                  throw new ArgumentNullException("container");
                  //object to avoid concurrency errors.
                  //
                  //Download operations take a long time therefore they have no timeout.
--                //TODO: Do we really? this is a hashmap operation, not a download
--                var client = new RestClient(_baseClient) { Timeout = 0 };
--                if (!String.IsNullOrWhiteSpace(account))
--                    client.BaseAddress = GetAccountUrl(account);
--
--
--                //The container and objectName are relative names. They are joined with the client's
--                //BaseAddress to create the object's absolute address
--                var builder = client.GetAddressBuilder(container, objectName);
--                builder.Query = "format=json&hashmap";
--                var uri = builder.Uri;
++                //TODO: Do they really? this is a hashmap operation, not a download
                  
                  //Start downloading the object asynchronously
--                var downloadTask = client.DownloadStringTask(uri);
--                
--                //Once the download completes
--                return downloadTask.ContinueWith(download =>
++                using (var client = new RestClient(_baseClient) { Timeout = 0 })
                  {
--                    //Delete the local client object
--                    client.Dispose();
--                    //And report failure or completion
--                    if (download.IsFaulted)
--                    {
--                        Log.ErrorFormat("[GET HASH] FAIL for {0} with \r{1}", objectName,
--                                        download.Exception);
--                        throw download.Exception;
--                    }
--                                          
--                    //The server will return an empty string if the file is empty
--                    var json = download.Result;
++                    if (!String.IsNullOrWhiteSpace(account))
++                        client.BaseAddress = GetAccountUrl(account);
++
++                    //The container and objectName are relative names. They are joined with the client's
++                    //BaseAddress to create the object's absolute address
++                    var builder = client.GetAddressBuilder(container, objectName);
++                    builder.Query = "format=json&hashmap";
++                    var uri = builder.Uri;
++
++
++                    var json = await client.DownloadStringTaskAsync(uri);
                      var treeHash = TreeHash.Parse(json);
--                    Log.InfoFormat("[GET HASH] END {0}", objectName);                                             
++                    Log.InfoFormat("[GET HASH] END {0}", objectName);
                      return treeHash;
--                });
++                }
              }
              catch (Exception exc)
              {
                  throw;
              }
  
--
--
          }