// ----------------------------------------------------------------------- // // 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. // // ----------------------------------------------------------------------- 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) //And reset the operation state for the file SetNetworkState(FilePath,NetworkOperation.None); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected void Dispose(bool disposing) { if (disposing) { Release(); } } } }