root / trunk / Pithos.Core / NetworkGate.cs @ b9f5b594
History | View | Annotate | Download (6.4 kB)
1 |
// ----------------------------------------------------------------------- |
---|---|
2 |
// <copyright file="NetworkGate.cs" company="GRNET"> |
3 |
// Copyright 2011 GRNET S.A. All rights reserved. |
4 |
// |
5 |
// Redistribution and use in source and binary forms, with or |
6 |
// without modification, are permitted provided that the following |
7 |
// conditions are met: |
8 |
// |
9 |
// 1. Redistributions of source code must retain the above |
10 |
// copyright notice, this list of conditions and the following |
11 |
// disclaimer. |
12 |
// |
13 |
// 2. Redistributions in binary form must reproduce the above |
14 |
// copyright notice, this list of conditions and the following |
15 |
// disclaimer in the documentation and/or other materials |
16 |
// provided with the distribution. |
17 |
// |
18 |
// THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS |
19 |
// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
20 |
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
21 |
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR |
22 |
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
23 |
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
24 |
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
25 |
// USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
26 |
// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
27 |
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
28 |
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 |
// POSSIBILITY OF SUCH DAMAGE. |
30 |
// |
31 |
// The views and conclusions contained in the software and |
32 |
// documentation are those of the authors and should not be |
33 |
// interpreted as representing official policies, either expressed |
34 |
// or implied, of GRNET S.A. |
35 |
// </copyright> |
36 |
// ----------------------------------------------------------------------- |
37 |
|
38 |
using System; |
39 |
using System.Collections.Concurrent; |
40 |
using System.Collections.Generic; |
41 |
using System.Diagnostics.Contracts; |
42 |
using System.IO; |
43 |
|
44 |
namespace Pithos.Core |
45 |
{ |
46 |
public enum NetworkOperation |
47 |
{ |
48 |
None, |
49 |
Uploading, |
50 |
Downloading, |
51 |
Deleting, |
52 |
Renaming |
53 |
} |
54 |
|
55 |
//The NetworkGate prevents starting download/uploads for files that are already in the process of downloading, |
56 |
//uploading. |
57 |
public class NetworkGate:IDisposable |
58 |
{ |
59 |
public string FilePath { get; private set; } |
60 |
public NetworkOperation Operation { get; private set; } |
61 |
|
62 |
[ContractInvariantMethod] |
63 |
private void Invariants() |
64 |
{ |
65 |
Contract.Invariant(!String.IsNullOrWhiteSpace(FilePath)); |
66 |
Contract.Invariant(Path.IsPathRooted(FilePath)); |
67 |
} |
68 |
|
69 |
//The state of each file is stored in a thread-safe dictionary |
70 |
static readonly ConcurrentDictionary<string, NetworkOperation> NetworkState = new ConcurrentDictionary<string, NetworkOperation>(); |
71 |
|
72 |
public static NetworkOperation GetNetworkState(string path) |
73 |
{ |
74 |
if (String.IsNullOrWhiteSpace(path)) |
75 |
throw new ArgumentNullException("path"); |
76 |
if (!Path.IsPathRooted(path)) |
77 |
throw new ArgumentException("path must be a rooted path", "path"); |
78 |
Contract.EndContractBlock(); |
79 |
|
80 |
NetworkOperation operation; |
81 |
var lower = path.ToLower(); |
82 |
if (NetworkState.TryGetValue(lower, out operation)) |
83 |
return operation; |
84 |
return NetworkOperation.None; |
85 |
} |
86 |
|
87 |
//Store a network operation for the specified path |
88 |
public static void SetNetworkState(string path, NetworkOperation operation) |
89 |
{ |
90 |
if (String.IsNullOrWhiteSpace(path)) |
91 |
throw new ArgumentNullException("path"); |
92 |
if (!Path.IsPathRooted(path)) |
93 |
throw new ArgumentException("path must be a rooted path", "path"); |
94 |
Contract.EndContractBlock(); |
95 |
|
96 |
var lower = path.ToLower(); |
97 |
NetworkState[lower] = operation; |
98 |
//By default, None values don't need to be stored. They are stored anyway |
99 |
//because TryRemove may fail. |
100 |
if (operation == NetworkOperation.None) |
101 |
{ |
102 |
NetworkOperation oldOperation; |
103 |
NetworkState.TryRemove(lower, out oldOperation); |
104 |
} |
105 |
} |
106 |
|
107 |
//Clients should acquire a NetworkGate before starting any network operation. |
108 |
//If Acquire fails, another network operation is already in progress |
109 |
public static NetworkGate Acquire(string path, NetworkOperation operation) |
110 |
{ |
111 |
if (String.IsNullOrWhiteSpace(path)) |
112 |
throw new ArgumentNullException("path"); |
113 |
if (!Path.IsPathRooted(path)) |
114 |
throw new ArgumentException("path must be a rooted path", "path"); |
115 |
Contract.EndContractBlock(); |
116 |
|
117 |
var lower = path.ToLower(); |
118 |
var state = GetNetworkState(lower); |
119 |
//If no operation is in progress, return a NetworkGate |
120 |
return (state == NetworkOperation.None) |
121 |
? new NetworkGate(lower, operation) |
122 |
//otherwise return a gate with Fail flagged |
123 |
: new NetworkGate(lower, NetworkOperation.None); |
124 |
} |
125 |
|
126 |
|
127 |
|
128 |
|
129 |
|
130 |
|
131 |
private NetworkGate(string path,NetworkOperation operation) |
132 |
{ |
133 |
if (String.IsNullOrWhiteSpace(path)) |
134 |
throw new ArgumentNullException("path"); |
135 |
if (!Path.IsPathRooted(path)) |
136 |
throw new ArgumentException("path must be rooted","path"); |
137 |
Contract.EndContractBlock(); |
138 |
|
139 |
Operation = operation; |
140 |
FilePath = path.ToLower(); |
141 |
|
142 |
//Skip dummy operations (those with Operation == None) |
143 |
if (Operation != NetworkOperation.None) |
144 |
//and store the file's operation |
145 |
SetNetworkState(FilePath, operation); |
146 |
} |
147 |
|
148 |
//A NetworkGate has Failed if its operation is None |
149 |
public bool Failed { get { return Operation == NetworkOperation.None; } } |
150 |
|
151 |
//Release a gate by setting the NetworkOperation to None |
152 |
public void Release() |
153 |
{ |
154 |
//Skip Failed flags |
155 |
if (!Failed) |
156 |
//And reset the operation state for the file |
157 |
SetNetworkState(FilePath,NetworkOperation.None); |
158 |
} |
159 |
|
160 |
|
161 |
public void Dispose() |
162 |
{ |
163 |
Dispose(true); |
164 |
GC.SuppressFinalize(this); |
165 |
} |
166 |
|
167 |
protected void Dispose(bool disposing) |
168 |
{ |
169 |
if (disposing) |
170 |
{ |
171 |
Release(); |
172 |
} |
173 |
} |
174 |
|
175 |
} |
176 |
} |