#region /* ----------------------------------------------------------------------- * * * Copyright 2011-2012 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. * * ----------------------------------------------------------------------- */ #endregion using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics.Contracts; using System.IO; namespace Pithos.Core { public enum NetworkOperation { None, Uploading, Downloading, Deleting, Renaming } //The NetworkGate prevents starting download/uploads for files that are already in the process of downloading, //uploading. public class NetworkGate:IDisposable { public string FilePath { get; private set; } public NetworkOperation Operation { get; private set; } [ContractInvariantMethod] private void Invariants() { Contract.Invariant(!String.IsNullOrWhiteSpace(FilePath)); Contract.Invariant(Path.IsPathRooted(FilePath)); } //The state of each file is stored in a thread-safe dictionary static readonly ConcurrentDictionary NetworkState = new ConcurrentDictionary(); public static NetworkOperation GetNetworkState(string path) { if (String.IsNullOrWhiteSpace(path)) throw new ArgumentNullException("path"); if (!Path.IsPathRooted(path)) throw new ArgumentException("path must be a rooted path", "path"); Contract.EndContractBlock(); NetworkOperation operation; var lower = path.ToLower(); if (NetworkState.TryGetValue(lower, out operation)) return operation; return NetworkOperation.None; } //Store a network operation for the specified path public static void SetNetworkState(string path, NetworkOperation operation) { if (String.IsNullOrWhiteSpace(path)) throw new ArgumentNullException("path"); if (!Path.IsPathRooted(path)) throw new ArgumentException("path must be a rooted path", "path"); Contract.EndContractBlock(); var lower = path.ToLower(); NetworkState[lower] = operation; //By default, None values don't need to be stored. They are stored anyway //because TryRemove may fail. if (operation == NetworkOperation.None) { NetworkOperation oldOperation; NetworkState.TryRemove(lower, out oldOperation); } } //Clients should acquire a NetworkGate before starting any network operation. //If Acquire fails, another network operation is already in progress public static NetworkGate Acquire(string path, NetworkOperation operation) { if (String.IsNullOrWhiteSpace(path)) throw new ArgumentNullException("path"); if (!Path.IsPathRooted(path)) throw new ArgumentException("path must be a rooted path", "path"); Contract.EndContractBlock(); var lower = path.ToLower(); var state = GetNetworkState(lower); //If no operation is in progress, return a NetworkGate return (state == NetworkOperation.None) ? new NetworkGate(lower, operation) //otherwise return a gate with Fail flagged : new NetworkGate(lower, NetworkOperation.None); } private NetworkGate(string path,NetworkOperation operation) { if (String.IsNullOrWhiteSpace(path)) throw new ArgumentNullException("path"); if (!Path.IsPathRooted(path)) throw new ArgumentException("path must be rooted","path"); Contract.EndContractBlock(); Operation = operation; FilePath = path.ToLower(); //Skip dummy operations (those with Operation == None) if (Operation != NetworkOperation.None) //and store the file's operation SetNetworkState(FilePath, operation); } //A NetworkGate has Failed if its operation is None public bool Failed { get { return Operation == NetworkOperation.None; } } //Release a gate by setting the NetworkOperation to None public void Release() { //Skip Failed flags if (!Failed) SetNetworkState(FilePath,NetworkOperation.None); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected void Dispose(bool disposing) { if (disposing) { Release(); } } } }