_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 });
}
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);
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
++using System.Data.SQLite;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.IO;
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)
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)
{
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; }
--
-- }*/
--
--
++
}
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);
using System;
using System.Collections.Generic;
++using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Dynamic;
using System.Globalization;
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;
}
-- 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;
}
--
--
}