Statistics
| Branch: | Revision:

root / trunk / Pithos.Core / Agents / BlockUpdater.cs @ 2f5fcd2f

History | View | Annotate | Download (15.8 kB)

1 796a7c29 pkanavos
#region
2 796a7c29 pkanavos
/* -----------------------------------------------------------------------
3 796a7c29 pkanavos
 * <copyright file="BlockUpdater.cs" company="GRNet">
4 796a7c29 pkanavos
 * 
5 796a7c29 pkanavos
 * Copyright 2011-2012 GRNET S.A. All rights reserved.
6 796a7c29 pkanavos
 *
7 796a7c29 pkanavos
 * Redistribution and use in source and binary forms, with or
8 796a7c29 pkanavos
 * without modification, are permitted provided that the following
9 796a7c29 pkanavos
 * conditions are met:
10 796a7c29 pkanavos
 *
11 796a7c29 pkanavos
 *   1. Redistributions of source code must retain the above
12 796a7c29 pkanavos
 *      copyright notice, this list of conditions and the following
13 796a7c29 pkanavos
 *      disclaimer.
14 796a7c29 pkanavos
 *
15 796a7c29 pkanavos
 *   2. Redistributions in binary form must reproduce the above
16 796a7c29 pkanavos
 *      copyright notice, this list of conditions and the following
17 796a7c29 pkanavos
 *      disclaimer in the documentation and/or other materials
18 796a7c29 pkanavos
 *      provided with the distribution.
19 796a7c29 pkanavos
 *
20 796a7c29 pkanavos
 *
21 796a7c29 pkanavos
 * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
22 796a7c29 pkanavos
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 796a7c29 pkanavos
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 796a7c29 pkanavos
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
25 796a7c29 pkanavos
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 796a7c29 pkanavos
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 796a7c29 pkanavos
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
28 796a7c29 pkanavos
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 796a7c29 pkanavos
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 796a7c29 pkanavos
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 796a7c29 pkanavos
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 796a7c29 pkanavos
 * POSSIBILITY OF SUCH DAMAGE.
33 796a7c29 pkanavos
 *
34 796a7c29 pkanavos
 * The views and conclusions contained in the software and
35 796a7c29 pkanavos
 * documentation are those of the authors and should not be
36 796a7c29 pkanavos
 * interpreted as representing official policies, either expressed
37 796a7c29 pkanavos
 * or implied, of GRNET S.A.
38 796a7c29 pkanavos
 * </copyright>
39 796a7c29 pkanavos
 * -----------------------------------------------------------------------
40 796a7c29 pkanavos
 */
41 796a7c29 pkanavos
#endregion
42 796a7c29 pkanavos
using System;
43 796a7c29 pkanavos
using System.Collections.Concurrent;
44 796a7c29 pkanavos
using System.Diagnostics.Contracts;
45 796a7c29 pkanavos
using System.IO;
46 796a7c29 pkanavos
using System.Linq;
47 796a7c29 pkanavos
using System.Reflection;
48 1101a72e pkanavos
using System.Threading;
49 796a7c29 pkanavos
using System.Threading.Tasks;
50 796a7c29 pkanavos
using OpenSSL.Crypto;
51 796a7c29 pkanavos
using Pithos.Network;
52 030b9baf pkanavos
using Alpha = Alphaleonis.Win32.Filesystem;
53 796a7c29 pkanavos
54 796a7c29 pkanavos
namespace Pithos.Core.Agents
55 796a7c29 pkanavos
{
56 796a7c29 pkanavos
    class BlockUpdater
57 796a7c29 pkanavos
    {
58 796a7c29 pkanavos
        //TODO: Must clean orphaned blocks from the Cache folder.
59 796a7c29 pkanavos
        //
60 796a7c29 pkanavos
        //The Cache folder may have orphaned blocks. Blocks may be left in the Cache folder because:
61 796a7c29 pkanavos
        //1. A download was in progress when the application terminated. These blocks are needed to proceed 
62 796a7c29 pkanavos
        //  with partial download
63 796a7c29 pkanavos
        //2. The application terminated abnormally before the blocks were cleared after a download
64 796a7c29 pkanavos
        //3. The server file was deleted before the download completed.
65 796a7c29 pkanavos
        //
66 796a7c29 pkanavos
        //In #1, we need to keep the blocks. We need to detect the other cases and delete orphans
67 796a7c29 pkanavos
        //
68 796a7c29 pkanavos
        //Mitigations:
69 796a7c29 pkanavos
        // - Delete blocks with no corresponding state
70 796a7c29 pkanavos
        // - Check and delete possible orphans when a Deletion is detected
71 796a7c29 pkanavos
        // - Add Advanced command "Clear Cache"
72 796a7c29 pkanavos
        //
73 796a7c29 pkanavos
        //Need a better way to differentiate between cases #2, #3 and #1
74 796a7c29 pkanavos
75 796a7c29 pkanavos
        private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
76 796a7c29 pkanavos
77 796a7c29 pkanavos
        public string FilePath { get; private set; }
78 796a7c29 pkanavos
        public string RelativePath { get; private set; }
79 796a7c29 pkanavos
80 796a7c29 pkanavos
        public string CachePath { get; private set; }
81 796a7c29 pkanavos
82 796a7c29 pkanavos
        public TreeHash ServerHash { get; private set; }
83 796a7c29 pkanavos
84 796a7c29 pkanavos
        public string TempPath { get; private set; }
85 796a7c29 pkanavos
86 796a7c29 pkanavos
        public bool HasBlocks
87 796a7c29 pkanavos
        {
88 796a7c29 pkanavos
            get { return _blocks.Count>0; }            
89 796a7c29 pkanavos
        }
90 796a7c29 pkanavos
91 796a7c29 pkanavos
        readonly ConcurrentDictionary<long, string> _blocks = new ConcurrentDictionary<long, string>();
92 796a7c29 pkanavos
        readonly ConcurrentDictionary<string, string> _orphanBlocks = new ConcurrentDictionary<string, string>();
93 796a7c29 pkanavos
94 796a7c29 pkanavos
        [ContractInvariantMethod]
95 796a7c29 pkanavos
        private void Invariants()
96 796a7c29 pkanavos
        {
97 796a7c29 pkanavos
            Contract.Invariant(Path.IsPathRooted(CachePath));
98 796a7c29 pkanavos
            Contract.Invariant(Path.IsPathRooted(FilePath));
99 796a7c29 pkanavos
            Contract.Invariant(Path.IsPathRooted(TempPath));
100 796a7c29 pkanavos
            Contract.Invariant(!Path.IsPathRooted(RelativePath));
101 796a7c29 pkanavos
            Contract.Invariant(_blocks!=null);
102 796a7c29 pkanavos
            Contract.Invariant(_orphanBlocks!=null);
103 796a7c29 pkanavos
            Contract.Invariant(ServerHash!=null);
104 796a7c29 pkanavos
        }
105 796a7c29 pkanavos
106 796a7c29 pkanavos
        public BlockUpdater(string cachePath, string filePath, string relativePath,TreeHash serverHash)
107 796a7c29 pkanavos
        {   
108 796a7c29 pkanavos
            if (String.IsNullOrWhiteSpace(cachePath))
109 796a7c29 pkanavos
                throw new ArgumentNullException("cachePath");
110 796a7c29 pkanavos
            if (!Path.IsPathRooted(cachePath))
111 796a7c29 pkanavos
                throw new ArgumentException("The cachePath must be rooted", "cachePath");
112 796a7c29 pkanavos
            
113 796a7c29 pkanavos
            if (string.IsNullOrWhiteSpace(filePath))
114 796a7c29 pkanavos
                throw new ArgumentNullException("filePath");
115 796a7c29 pkanavos
            if (!Path.IsPathRooted(filePath))
116 796a7c29 pkanavos
                throw new ArgumentException("The filePath must be rooted", "filePath");
117 796a7c29 pkanavos
            
118 796a7c29 pkanavos
            if (string.IsNullOrWhiteSpace(relativePath))
119 796a7c29 pkanavos
                throw new ArgumentNullException("relativePath");
120 796a7c29 pkanavos
            if (Path.IsPathRooted(relativePath))
121 796a7c29 pkanavos
                throw new ArgumentException("The relativePath must NOT be rooted", "relativePath");
122 796a7c29 pkanavos
123 796a7c29 pkanavos
            if (serverHash == null)
124 796a7c29 pkanavos
                throw new ArgumentNullException("serverHash");
125 796a7c29 pkanavos
            Contract.EndContractBlock();
126 796a7c29 pkanavos
127 796a7c29 pkanavos
            CachePath=cachePath;
128 796a7c29 pkanavos
            FilePath = filePath;
129 796a7c29 pkanavos
            RelativePath=relativePath;
130 796a7c29 pkanavos
            ServerHash = serverHash;
131 796a7c29 pkanavos
            //The file will be stored in a temporary location while downloading with an extension .download
132 796a7c29 pkanavos
            TempPath = Path.Combine(CachePath, RelativePath + ".download");
133 796a7c29 pkanavos
            
134 796a7c29 pkanavos
            //Need to calculate the directory path because RelativePath may include folders
135 796a7c29 pkanavos
            var directoryPath = Path.GetDirectoryName(TempPath);            
136 796a7c29 pkanavos
            //directoryPath CAN be null if TempPath is a root path
137 796a7c29 pkanavos
            if (String.IsNullOrWhiteSpace(directoryPath))
138 796a7c29 pkanavos
                throw new ArgumentException("TempPath");
139 796a7c29 pkanavos
            //CachePath was absolute so directoryPath is absolute too
140 796a7c29 pkanavos
            Contract.Assume(Path.IsPathRooted(directoryPath));
141 796a7c29 pkanavos
            
142 796a7c29 pkanavos
            if (!Directory.Exists(directoryPath))
143 796a7c29 pkanavos
                Directory.CreateDirectory(directoryPath);
144 796a7c29 pkanavos
145 796a7c29 pkanavos
            LoadOrphans(directoryPath);
146 796a7c29 pkanavos
        }
147 796a7c29 pkanavos
148 796a7c29 pkanavos
        private void LoadOrphans(string directoryPath)
149 796a7c29 pkanavos
        {
150 796a7c29 pkanavos
            if (string.IsNullOrWhiteSpace(directoryPath))
151 796a7c29 pkanavos
                throw new ArgumentNullException("directoryPath");
152 796a7c29 pkanavos
            if (!Path.IsPathRooted(directoryPath))
153 796a7c29 pkanavos
                throw new ArgumentException("The directoryPath must be rooted", "directoryPath");
154 796a7c29 pkanavos
            if (ServerHash==null)
155 796a7c29 pkanavos
                throw new InvalidOperationException("ServerHash wasn't initialized");
156 796a7c29 pkanavos
            Contract.EndContractBlock();
157 796a7c29 pkanavos
158 796a7c29 pkanavos
            var fileNamename = Path.GetFileName(FilePath);
159 796a7c29 pkanavos
            var orphans = Directory.GetFiles(directoryPath, fileNamename + ".*");
160 796a7c29 pkanavos
            foreach (var orphan in orphans)
161 796a7c29 pkanavos
            {
162 796a7c29 pkanavos
                using (var hasher = new MessageDigestContext(MessageDigest.CreateByName(ServerHash.BlockHash)))                
163 796a7c29 pkanavos
                {
164 796a7c29 pkanavos
                    hasher.Init();
165 796a7c29 pkanavos
                    var buffer=File.ReadAllBytes(orphan);
166 796a7c29 pkanavos
                    //The server truncates nulls before calculating hashes, have to do the same
167 796a7c29 pkanavos
                    //Find the last non-null byte, starting from the end
168 796a7c29 pkanavos
                    var lastByteIndex = Array.FindLastIndex(buffer, buffer.Length-1, aByte => aByte != 0);
169 796a7c29 pkanavos
                    //lastByteIndex may be -1 if the file was empty. We don't want to use that block file
170 796a7c29 pkanavos
                    if (lastByteIndex >= 0)
171 796a7c29 pkanavos
                    {
172 796a7c29 pkanavos
                        byte[] block;
173 796a7c29 pkanavos
                        if (lastByteIndex == buffer.Length - 1)
174 796a7c29 pkanavos
                            block = buffer;
175 796a7c29 pkanavos
                        else
176 796a7c29 pkanavos
                        {
177 d5617d4f pkanavos
                            block=new byte[lastByteIndex+1];
178 d5617d4f pkanavos
                            Buffer.BlockCopy(buffer,0,block,0,lastByteIndex+1);
179 796a7c29 pkanavos
                        }
180 796a7c29 pkanavos
                        var binHash = hasher.Digest(block);
181 796a7c29 pkanavos
                        var hash = binHash.ToHashString();
182 796a7c29 pkanavos
                        _orphanBlocks[hash] = orphan;
183 796a7c29 pkanavos
                    }
184 796a7c29 pkanavos
                }
185 796a7c29 pkanavos
            }
186 796a7c29 pkanavos
        }
187 796a7c29 pkanavos
188 796a7c29 pkanavos
189 796a7c29 pkanavos
        public void Commit()
190 796a7c29 pkanavos
        {
191 796a7c29 pkanavos
            if (String.IsNullOrWhiteSpace(FilePath))
192 796a7c29 pkanavos
                throw new InvalidOperationException("FilePath is empty");
193 796a7c29 pkanavos
            if (String.IsNullOrWhiteSpace(TempPath))
194 796a7c29 pkanavos
                throw new InvalidOperationException("TempPath is empty");
195 796a7c29 pkanavos
            Contract.EndContractBlock();
196 796a7c29 pkanavos
197 397b9100 pkanavos
            var info = Alpha.Volume.GetVolumeInformation(Alpha.Path.GetPathRoot(FilePath));            
198 397b9100 pkanavos
            var isNTFS = info.FileSystemName.Equals("NTFS");                
199 9a9c797a pkanavos
200 9a9c797a pkanavos
201 030b9baf pkanavos
            if (isNTFS && MS.WindowsAPICodePack.Internal.CoreHelpers.RunningOnVista)
202 9a9c797a pkanavos
            {
203 030b9baf pkanavos
                ApplyBlocksWithTransaction();
204 9a9c797a pkanavos
            }
205 9a9c797a pkanavos
            else
206 9a9c797a pkanavos
            {
207 030b9baf pkanavos
                ApplyBlocksWithCopy();
208 9a9c797a pkanavos
            }
209 9a9c797a pkanavos
            ClearBlocks();
210 9a9c797a pkanavos
        }
211 9a9c797a pkanavos
212 9a9c797a pkanavos
        private void ApplyBlocksWithTransaction()
213 9a9c797a pkanavos
        {
214 030b9baf pkanavos
            var targetFile = FilePath;
215 030b9baf pkanavos
            using (var tx = new Alpha.KernelTransaction())
216 030b9baf pkanavos
            {
217 1101a72e pkanavos
                //Retry if the file is still open
218 1101a72e pkanavos
                    using (var stream = Alpha.File.Open(tx, targetFile, 
219 1101a72e pkanavos
                        Alpha.FileMode.OpenOrCreate,Alpha.FileAccess.Write))
220 030b9baf pkanavos
                    {
221 1101a72e pkanavos
                        stream.SetLength(ServerHash.Bytes);
222 1101a72e pkanavos
                        foreach (var block in _blocks)
223 030b9baf pkanavos
                        {
224 1101a72e pkanavos
                            var blockPath = block.Value;
225 1101a72e pkanavos
                            var blockIndex = block.Key;
226 1101a72e pkanavos
                            //Retry if we can't open the block immediatelly
227 1101a72e pkanavos
                            for (int i = 0; i < 3; i++)
228 1101a72e pkanavos
                            {
229 1101a72e pkanavos
                                try
230 1101a72e pkanavos
                                {
231 1101a72e pkanavos
                                    using (var blockStream = File.OpenRead(blockPath))
232 1101a72e pkanavos
                                    {
233 1101a72e pkanavos
                                        long offset = blockIndex*ServerHash.BlockSize;
234 1101a72e pkanavos
                                        stream.Seek(offset, SeekOrigin.Begin);
235 1101a72e pkanavos
                                        blockStream.CopyTo(stream);
236 1101a72e pkanavos
                                    }
237 1101a72e pkanavos
                                    break;
238 1101a72e pkanavos
                                }
239 1101a72e pkanavos
                                catch (IOException)
240 1101a72e pkanavos
                                {
241 0e1acc13 pkanavos
                                    if (i>=2)
242 1101a72e pkanavos
                                        throw;
243 0e1acc13 pkanavos
                                    Thread.Sleep((i+1)*300);
244 1101a72e pkanavos
                                }                                
245 1101a72e pkanavos
                            }
246 030b9baf pkanavos
                        }
247 030b9baf pkanavos
                    }
248 030b9baf pkanavos
                tx.Commit();
249 030b9baf pkanavos
            }
250 030b9baf pkanavos
251 9a9c797a pkanavos
        }
252 9a9c797a pkanavos
253 9a9c797a pkanavos
        private void ApplyBlocksWithCopy()
254 9a9c797a pkanavos
        {
255 796a7c29 pkanavos
            //Copy the file to a temporary location. Changes will be made to the
256 796a7c29 pkanavos
            //temporary file, then it will replace the original file
257 796a7c29 pkanavos
            if (File.Exists(FilePath))
258 796a7c29 pkanavos
                File.Copy(FilePath, TempPath, true);
259 796a7c29 pkanavos
260 796a7c29 pkanavos
            //Set the size of the file to the size specified in the treehash
261 796a7c29 pkanavos
            //This will also create an empty file if the file doesn't exist                        
262 9a9c797a pkanavos
263 9a9c797a pkanavos
            ApplyBlocks(TempPath);
264 9a9c797a pkanavos
            SwapFiles();
265 9a9c797a pkanavos
        }
266 9a9c797a pkanavos
267 9a9c797a pkanavos
        private void ApplyBlocks(string targetFile)
268 9a9c797a pkanavos
        {
269 9a9c797a pkanavos
            SetFileSize(targetFile, ServerHash.Bytes);
270 796a7c29 pkanavos
271 796a7c29 pkanavos
            //Update the temporary file with the data from the blocks
272 9a9c797a pkanavos
            using (var stream = File.OpenWrite(targetFile))
273 796a7c29 pkanavos
            {
274 796a7c29 pkanavos
                foreach (var block in _blocks)
275 796a7c29 pkanavos
                {
276 796a7c29 pkanavos
                    var blockPath = block.Value;
277 796a7c29 pkanavos
                    var blockIndex = block.Key;
278 796a7c29 pkanavos
                    using (var blockStream = File.OpenRead(blockPath))
279 9a9c797a pkanavos
                    {
280 796a7c29 pkanavos
                        long offset = blockIndex*ServerHash.BlockSize;
281 796a7c29 pkanavos
                        stream.Seek(offset, SeekOrigin.Begin);
282 796a7c29 pkanavos
                        blockStream.CopyTo(stream);
283 796a7c29 pkanavos
                    }
284 796a7c29 pkanavos
                }
285 796a7c29 pkanavos
            }
286 796a7c29 pkanavos
        }
287 796a7c29 pkanavos
288 796a7c29 pkanavos
        private void SwapFiles()
289 796a7c29 pkanavos
        {
290 796a7c29 pkanavos
            if (String.IsNullOrWhiteSpace(FilePath))
291 796a7c29 pkanavos
                throw new InvalidOperationException("FilePath is empty");
292 796a7c29 pkanavos
            if (String.IsNullOrWhiteSpace(TempPath))
293 796a7c29 pkanavos
                throw new InvalidOperationException("TempPath is empty");            
294 796a7c29 pkanavos
            Contract.EndContractBlock();
295 796a7c29 pkanavos
296 796a7c29 pkanavos
            if (File.Exists(FilePath))
297 796a7c29 pkanavos
                File.Replace(TempPath, FilePath, null, true);
298 796a7c29 pkanavos
            else
299 796a7c29 pkanavos
            {
300 796a7c29 pkanavos
                var targetDirectory = Path.GetDirectoryName(FilePath);
301 796a7c29 pkanavos
                if (!Directory.Exists(targetDirectory))
302 796a7c29 pkanavos
                    Directory.CreateDirectory(targetDirectory);
303 796a7c29 pkanavos
                File.Move(TempPath, FilePath);
304 796a7c29 pkanavos
            }
305 796a7c29 pkanavos
        }
306 796a7c29 pkanavos
307 796a7c29 pkanavos
        private void ClearBlocks()
308 796a7c29 pkanavos
        {
309 796a7c29 pkanavos
            if (Log.IsDebugEnabled)
310 796a7c29 pkanavos
                Log.DebugFormat("Clearing blocks for {0}",this.FilePath);
311 796a7c29 pkanavos
            //Get all the the block paths, orphan or not
312 796a7c29 pkanavos
            var paths= _blocks.Select(pair => pair.Value)
313 796a7c29 pkanavos
                          .Union(_orphanBlocks.Select(pair => pair.Value));
314 796a7c29 pkanavos
            foreach (var filePath in paths)
315 796a7c29 pkanavos
            {
316 796a7c29 pkanavos
                File.Delete(filePath);
317 796a7c29 pkanavos
            }
318 796a7c29 pkanavos
319 796a7c29 pkanavos
            File.Delete(TempPath);
320 796a7c29 pkanavos
            _blocks.Clear();
321 796a7c29 pkanavos
            _orphanBlocks.Clear();
322 796a7c29 pkanavos
        }
323 796a7c29 pkanavos
324 796a7c29 pkanavos
        //Change the file's size, possibly truncating or adding to it
325 796a7c29 pkanavos
        private  void SetFileSize(string filePath, long fileSize)
326 796a7c29 pkanavos
        {
327 796a7c29 pkanavos
            if (String.IsNullOrWhiteSpace(filePath))
328 796a7c29 pkanavos
                throw new ArgumentNullException("filePath");
329 796a7c29 pkanavos
            if (!Path.IsPathRooted(filePath))
330 796a7c29 pkanavos
                throw new ArgumentException("The filePath must be rooted", "filePath");
331 796a7c29 pkanavos
            if (fileSize < 0)
332 796a7c29 pkanavos
                throw new ArgumentOutOfRangeException("fileSize");
333 796a7c29 pkanavos
            Contract.EndContractBlock();
334 796a7c29 pkanavos
335 796a7c29 pkanavos
            using (var stream = File.Open(filePath, FileMode.OpenOrCreate, FileAccess.Write))
336 796a7c29 pkanavos
            {
337 796a7c29 pkanavos
                stream.SetLength(fileSize);
338 796a7c29 pkanavos
            }
339 796a7c29 pkanavos
        }
340 796a7c29 pkanavos
341 796a7c29 pkanavos
       /* //Check whether we should copy the local file to a temp path        
342 796a7c29 pkanavos
        private  bool ShouldCopy(string localPath, string tempPath)
343 796a7c29 pkanavos
        {
344 796a7c29 pkanavos
            //No need to copy if there is no file
345 796a7c29 pkanavos
            if (!File.Exists(localPath))
346 796a7c29 pkanavos
                return false;
347 796a7c29 pkanavos
348 796a7c29 pkanavos
            //If there is no temp file, go ahead and copy
349 796a7c29 pkanavos
            if (!File.Exists(tempPath))
350 796a7c29 pkanavos
                return true;
351 796a7c29 pkanavos
352 796a7c29 pkanavos
            //If there is a temp file and is newer than the actual file, don't copy
353 796a7c29 pkanavos
            var localLastWrite = File.GetLastWriteTime(localPath);
354 796a7c29 pkanavos
            var tempLastWrite = File.GetLastWriteTime(tempPath);
355 796a7c29 pkanavos
356 796a7c29 pkanavos
            //This could mean there is an interrupted download in progress
357 796a7c29 pkanavos
            return (tempLastWrite < localLastWrite);
358 796a7c29 pkanavos
        }*/
359 796a7c29 pkanavos
360 796a7c29 pkanavos
361 796a7c29 pkanavos
        public bool UseOrphan(long blockIndex, string blockHash)
362 796a7c29 pkanavos
        {
363 796a7c29 pkanavos
            string blockPath=null;
364 796a7c29 pkanavos
            if (_orphanBlocks.TryGetValue(blockHash,out blockPath))
365 796a7c29 pkanavos
            {
366 796a7c29 pkanavos
                _blocks[blockIndex] = blockPath;
367 796a7c29 pkanavos
                return true;
368 796a7c29 pkanavos
            }
369 796a7c29 pkanavos
            return false;
370 796a7c29 pkanavos
        }
371 796a7c29 pkanavos
372 796a7c29 pkanavos
        public Task StoreBlock(long blockIndex,byte[] buffer)
373 796a7c29 pkanavos
        {
374 796a7c29 pkanavos
            var blockPath = String.Format("{0}.{1:000000}", TempPath, blockIndex);
375 796a7c29 pkanavos
            _blocks[blockIndex] = blockPath;
376 796a7c29 pkanavos
            //Remove any orphan files
377 796a7c29 pkanavos
            if (File.Exists(blockPath))
378 796a7c29 pkanavos
                File.Delete(blockPath);
379 796a7c29 pkanavos
380 796a7c29 pkanavos
            return FileAsync.WriteAllBytes(blockPath, buffer);
381 796a7c29 pkanavos
        }
382 796a7c29 pkanavos
383 796a7c29 pkanavos
       
384 796a7c29 pkanavos
385 796a7c29 pkanavos
    }
386 796a7c29 pkanavos
}