// -----------------------------------------------------------------------
-// <copyright file="FileState.cs" company="Microsoft">
-// TODO: Update copyright text.
+// <copyright file="FileState.cs" company="GRNet">
+// Copyright 2011 GRNET S.A. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or
+// without modification, are permitted provided that the following
+// conditions are met:
+//
+// 1. Redistributions of source code must retain the above
+// copyright notice, this list of conditions and the following
+// disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials
+// provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
+// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
+// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+// USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// The views and conclusions contained in the software and
+// documentation are those of the authors and should not be
+// interpreted as representing official policies, either expressed
+// or implied, of GRNET S.A.
// </copyright>
// -----------------------------------------------------------------------
+using System.Data.SQLite;
using System.Diagnostics.Contracts;
using System.IO;
using System.Threading.Tasks;
using Castle.ActiveRecord;
using Castle.ActiveRecord.Framework;
-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.
/// </summary>
[ActiveRecord]
- public class FileState:ActiveRecordLinqBase<FileState>
+ public class FileState : ActiveRecordLinqBase<FileState>
{
+ private static readonly ILog Log = LogManager.GetLogger("FileState");
+
private string _filePath;
- private IList<FileTag> _tags=new List<FileTag>();
+ private IList<FileTag> _tags = new List<FileTag>();
[PrimaryKey(PrimaryKeyType.Guid)]
public Guid Id { get; set; }
- [Property(Unique=true,UniqueKey="IX_FileState_FilePath")]
+ [Property(Unique = true, UniqueKey = "IX_FileState_FilePath")]
public string FilePath
{
get { return _filePath; }
[Property]
public string Checksum { get; set; }
-/*
- [Property]
- public string TopHash { get; set; }
-*/
[Property]
public long? Version { get; set; }
[Property]
public DateTime? VersionTimeStamp { get; set; }
-
- [HasMany(Cascade = ManyRelationCascadeEnum.AllDeleteOrphan, Lazy = true,Inverse=true)]
+
+ [Property]
+ public bool IsShared { get; set; }
+
+ [Property]
+ public string SharedBy { get; set; }
+
+ [Property]
+ public bool ShareWrite { get; set; }
+
+
+ [HasMany(Cascade = ManyRelationCascadeEnum.AllDeleteOrphan, Lazy = true, Inverse = true)]
public IList<FileTag> Tags
{
- get { return _tags; }
- set { _tags=value;}
+ get { return _tags; }
+ 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();
- return Queryable.FirstOrDefault(s => s.FilePath == absolutePath.ToLower());
+ try
+ {
+
+
+
+ return Queryable.FirstOrDefault(s => s.FilePath == absolutePath.ToLower());
+ }
+ catch (Exception ex)
+ {
+ Log.Error(ex.ToString());
+ throw;
+ }
+
+
+ }
+
+ /* public static void DeleteByFilePath(string absolutePath)
+ {
+ if (string.IsNullOrWhiteSpace(absolutePath))
+ throw new ArgumentNullException("absolutePath");
+ Contract.EndContractBlock();
+
+ ExecuteWithRetry((session, instance) =>
+ {
+ const string hqlDelete = "delete FileState where FilePath = :path";
+ var deletedEntities = session.CreateQuery(hqlDelete)
+ .SetString("path", absolutePath.ToLower())
+ .ExecuteUpdate();
+ return deletedEntities;
+ }, null);
+
+ }*/
+
+ public static void StoreFileStatus(string absolutePath, FileStatus newStatus)
+ {
+ if (string.IsNullOrWhiteSpace(absolutePath))
+ throw new ArgumentNullException("absolutePath");
+ Contract.EndContractBlock();
+
+ ExecuteWithRetry((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.ToLower(),
+ Id = Guid.NewGuid(),
+ FileStatus = newStatus
+ };
+ newState.CreateAndFlush();
+ }
+ return null;
+ }, null);
+
}
- public static void DeleteByFilePath(string absolutePath)
+ public static void StoreOverlayStatus(string absolutePath, FileOverlayStatus newStatus)
{
- if(string.IsNullOrWhiteSpace(absolutePath))
+ if (string.IsNullOrWhiteSpace(absolutePath))
throw new ArgumentNullException("absolutePath");
Contract.EndContractBlock();
-
- var stateKeys = from state in FileState.Queryable
- where state.FilePath == absolutePath.ToLower()
- select state.Id;
- DeleteAll(stateKeys);
+
+ ExecuteWithRetry((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 Task<FileState> CreateForAsync(string filePath,int blockSize,string algorithm)
+/*
+ public static void UpdateStatus(string absolutePath, FileStatus fileStatus, FileOverlayStatus overlayStatus)
+ {
+ if (string.IsNullOrWhiteSpace(absolutePath))
+ throw new ArgumentNullException("absolutePath");
+ Contract.EndContractBlock();
+
+ ExecuteWithRetry((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 updatedEntities;
+ }, null);
+
+ }
+*/
+
+/*
+ public static void UpdateStatus(string absolutePath, FileStatus fileStatus)
+ {
+ if (string.IsNullOrWhiteSpace(absolutePath))
+ throw new ArgumentNullException("absolutePath");
+ Contract.EndContractBlock();
+
+ ExecuteWithRetry((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();
+
+ ExecuteWithRetry((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)
+ {
+
+ ExecuteWithRetry((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 updatedEntities;
+ }, null);
+ }*/
+
+ public static void UpdateChecksum(string absolutePath, string checksum)
+ {
+ if (string.IsNullOrWhiteSpace(absolutePath))
+ throw new ArgumentNullException("absolutePath");
+ Contract.EndContractBlock();
+
+ ExecuteWithRetry((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 updatedEntities;
+ }, null);
+
+ }
+
+ public static void ChangeRootPath(string oldPath, string newPath)
+ {
+ if (String.IsNullOrWhiteSpace(oldPath))
+ throw new ArgumentNullException("oldPath");
+ if (!Path.IsPathRooted(oldPath))
+ throw new ArgumentException("oldPath must be an absolute path", "oldPath");
+ if (string.IsNullOrWhiteSpace(newPath))
+ throw new ArgumentNullException("newPath");
+ if (!Path.IsPathRooted(newPath))
+ throw new ArgumentException("newPath must be an absolute path", "newPath");
+ Contract.EndContractBlock();
+
+ //Ensure the paths end with the same character
+ if (!oldPath.EndsWith("\\"))
+ oldPath = oldPath + "\\";
+ if (!newPath.EndsWith("\\"))
+ newPath = newPath + "\\";
+
+ ExecuteWithRetry((session, instance) =>
+ {
+ const string hqlUpdate =
+ "update FileState set FilePath = replace(FilePath,:oldPath,:newPath) where FilePath like :oldPath || '%' ";
+ var renames = session.CreateQuery(hqlUpdate)
+ .SetString("oldPath", oldPath.ToLower())
+ .SetString("newPath", newPath.ToLower())
+ .ExecuteUpdate();
+ return renames;
+ }, null);
+ }
+
+ public static Task<FileState> CreateForAsync(string filePath, int blockSize, string algorithm)
{
if (blockSize <= 0)
throw new ArgumentOutOfRangeException("blockSize");
var fileState = new FileState
{
- FilePath = filePath,
- OverlayStatus = FileOverlayStatus.Unversioned,
+ FilePath = filePath.ToLower(),
+ OverlayStatus = FileOverlayStatus.Unversioned,
FileStatus = FileStatus.Created,
- Id=Guid.NewGuid()
+ Id = Guid.NewGuid()
};
- return fileState.UpdateHashesAsync(blockSize,algorithm);
+ return fileState.UpdateHashesAsync(blockSize, algorithm);
}
- public Task<FileState> UpdateHashesAsync(int blockSize,string algorithm)
+ public async Task<FileState> UpdateHashesAsync(int blockSize, string algorithm)
{
- if (blockSize<=0)
+ if (blockSize <= 0)
throw new ArgumentOutOfRangeException("blockSize");
if (String.IsNullOrWhiteSpace(algorithm))
throw new ArgumentNullException("algorithm");
Contract.EndContractBlock();
-
+
//Skip updating the hash for folders
if (Directory.Exists(FilePath))
- return Task.Factory.FromResult(this);
+ return this;
- var results = Task.Factory.StartNew(() =>
- {
- var info = new FileInfo(FilePath);
- return info.CalculateHash(blockSize, algorithm);
- });
+ var hash = await TaskEx.Run(() =>
+ {
+ var info = new FileInfo(FilePath);
+ return info.CalculateHash(blockSize, algorithm);
+ });
+
+ Checksum = hash;
+
+ return this;
+ }
+
+ private static void ExecuteWithRetry(NHibernateDelegate call, object state)
+ {
+ int retries = 3;
+ while (retries > 0)
+ try
+ {
+ using (new SessionScope())
+ {
+ Execute(call, state);
+ }
+ }
+ catch (ActiveRecordException exc)
+ {
+ retries--;
+ if (retries <= 0)
+ throw;
+ }
+ catch (Exception exc)
+ {
+ throw;
+ }
- var state=results.Then(hash =>
- {
- Checksum = hash;
- return Task.Factory.FromResult(this);
- });
-
- return state;
}
}
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; }
-
- }*/
-
-
+
}