Statistics
| Branch: | Revision:

root / trunk / Pithos.Network / BlockHashAlgorithms.cs @ 6bcdd8e2

History | View | Annotate | Download (9.3 kB)

1 255f5f86 Panagiotis Kanavos
#region
2 255f5f86 Panagiotis Kanavos
/* -----------------------------------------------------------------------
3 255f5f86 Panagiotis Kanavos
 * <copyright file="BlockHashAlgorithms.cs" company="GRNet">
4 255f5f86 Panagiotis Kanavos
 * 
5 255f5f86 Panagiotis Kanavos
 * Copyright 2011-2012 GRNET S.A. All rights reserved.
6 255f5f86 Panagiotis Kanavos
 *
7 255f5f86 Panagiotis Kanavos
 * Redistribution and use in source and binary forms, with or
8 255f5f86 Panagiotis Kanavos
 * without modification, are permitted provided that the following
9 255f5f86 Panagiotis Kanavos
 * conditions are met:
10 255f5f86 Panagiotis Kanavos
 *
11 255f5f86 Panagiotis Kanavos
 *   1. Redistributions of source code must retain the above
12 255f5f86 Panagiotis Kanavos
 *      copyright notice, this list of conditions and the following
13 255f5f86 Panagiotis Kanavos
 *      disclaimer.
14 255f5f86 Panagiotis Kanavos
 *
15 255f5f86 Panagiotis Kanavos
 *   2. Redistributions in binary form must reproduce the above
16 255f5f86 Panagiotis Kanavos
 *      copyright notice, this list of conditions and the following
17 255f5f86 Panagiotis Kanavos
 *      disclaimer in the documentation and/or other materials
18 255f5f86 Panagiotis Kanavos
 *      provided with the distribution.
19 255f5f86 Panagiotis Kanavos
 *
20 255f5f86 Panagiotis Kanavos
 *
21 255f5f86 Panagiotis Kanavos
 * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
22 255f5f86 Panagiotis Kanavos
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 255f5f86 Panagiotis Kanavos
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 255f5f86 Panagiotis Kanavos
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
25 255f5f86 Panagiotis Kanavos
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 255f5f86 Panagiotis Kanavos
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 255f5f86 Panagiotis Kanavos
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
28 255f5f86 Panagiotis Kanavos
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 255f5f86 Panagiotis Kanavos
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 255f5f86 Panagiotis Kanavos
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 255f5f86 Panagiotis Kanavos
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 255f5f86 Panagiotis Kanavos
 * POSSIBILITY OF SUCH DAMAGE.
33 255f5f86 Panagiotis Kanavos
 *
34 255f5f86 Panagiotis Kanavos
 * The views and conclusions contained in the software and
35 255f5f86 Panagiotis Kanavos
 * documentation are those of the authors and should not be
36 255f5f86 Panagiotis Kanavos
 * interpreted as representing official policies, either expressed
37 255f5f86 Panagiotis Kanavos
 * or implied, of GRNET S.A.
38 255f5f86 Panagiotis Kanavos
 * </copyright>
39 255f5f86 Panagiotis Kanavos
 * -----------------------------------------------------------------------
40 255f5f86 Panagiotis Kanavos
 */
41 255f5f86 Panagiotis Kanavos
#endregion
42 422c9598 Panagiotis Kanavos
using System.Collections.Concurrent;
43 422c9598 Panagiotis Kanavos
using System.Diagnostics.Contracts;
44 422c9598 Panagiotis Kanavos
using System.IO;
45 6bcdd8e2 Panagiotis Kanavos
using System.Reflection;
46 422c9598 Panagiotis Kanavos
using System.Security.Cryptography;
47 422c9598 Panagiotis Kanavos
using System.Threading.Tasks;
48 422c9598 Panagiotis Kanavos
using System.Threading.Tasks.Dataflow;
49 422c9598 Panagiotis Kanavos
50 422c9598 Panagiotis Kanavos
namespace Pithos.Network
51 422c9598 Panagiotis Kanavos
{
52 422c9598 Panagiotis Kanavos
    using System;
53 422c9598 Panagiotis Kanavos
    using System.Collections.Generic;
54 422c9598 Panagiotis Kanavos
    using System.Linq;
55 422c9598 Panagiotis Kanavos
    using System.Text;
56 422c9598 Panagiotis Kanavos
57 422c9598 Panagiotis Kanavos
    /// <summary>
58 422c9598 Panagiotis Kanavos
    /// TODO: Update summary.
59 422c9598 Panagiotis Kanavos
    /// </summary>
60 422c9598 Panagiotis Kanavos
    public static class BlockHashAlgorithms
61 422c9598 Panagiotis Kanavos
    {
62 6bcdd8e2 Panagiotis Kanavos
        private static readonly log4net.ILog Log = log4net.LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
63 6bcdd8e2 Panagiotis Kanavos
64 422c9598 Panagiotis Kanavos
        public static Func<FileStream, int, string, ConcurrentDictionary<int, byte[]>, int, Task<ConcurrentDictionary<int, byte[]>>> CalculateBlockHash;
65 422c9598 Panagiotis Kanavos
66 422c9598 Panagiotis Kanavos
        public static Task<ConcurrentDictionary<int, byte[]>> CalculateBlockHashesRecursiveAsync(FileStream stream, int blockSize, string algorithm, ConcurrentDictionary<int, byte[]> hashes = null, int index = 0)
67 422c9598 Panagiotis Kanavos
        {
68 422c9598 Panagiotis Kanavos
            if (stream == null)
69 422c9598 Panagiotis Kanavos
                throw new ArgumentNullException("stream");
70 422c9598 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(algorithm))
71 422c9598 Panagiotis Kanavos
                throw new ArgumentNullException("algorithm");
72 422c9598 Panagiotis Kanavos
            if (blockSize <= 0)
73 422c9598 Panagiotis Kanavos
                throw new ArgumentOutOfRangeException("blockSize", "blockSize must be a value greater than zero ");
74 422c9598 Panagiotis Kanavos
            if (index < 0)
75 422c9598 Panagiotis Kanavos
                throw new ArgumentOutOfRangeException("index", "index must be a non-negative value");
76 422c9598 Panagiotis Kanavos
            Contract.EndContractBlock();
77 422c9598 Panagiotis Kanavos
78 422c9598 Panagiotis Kanavos
79 422c9598 Panagiotis Kanavos
            if (hashes == null)
80 422c9598 Panagiotis Kanavos
                hashes = new ConcurrentDictionary<int, byte[]>();
81 422c9598 Panagiotis Kanavos
82 422c9598 Panagiotis Kanavos
            var buffer = new byte[blockSize];
83 422c9598 Panagiotis Kanavos
            return stream.ReadAsync(buffer, 0, blockSize).ContinueWith(t =>
84 422c9598 Panagiotis Kanavos
            {
85 422c9598 Panagiotis Kanavos
                var read = t.Result;
86 422c9598 Panagiotis Kanavos
87 422c9598 Panagiotis Kanavos
                var nextTask = read == blockSize
88 422c9598 Panagiotis Kanavos
                                    ? CalculateBlockHashesRecursiveAsync(stream, blockSize, algorithm, hashes, index + 1)
89 422c9598 Panagiotis Kanavos
                                    : Task.Factory.StartNew(() => hashes);
90 422c9598 Panagiotis Kanavos
                if (read > 0)
91 422c9598 Panagiotis Kanavos
                    using (var hasher = HashAlgorithm.Create(algorithm))
92 422c9598 Panagiotis Kanavos
                    {
93 422c9598 Panagiotis Kanavos
                        //This code was added for compatibility with the way Pithos calculates the last hash
94 422c9598 Panagiotis Kanavos
                        //We calculate the hash only up to the last non-null byte
95 422c9598 Panagiotis Kanavos
                        var lastByteIndex = Array.FindLastIndex(buffer, read - 1, aByte => aByte != 0);
96 422c9598 Panagiotis Kanavos
97 422c9598 Panagiotis Kanavos
                        var hash = hasher.ComputeHash(buffer, 0, lastByteIndex + 1);
98 422c9598 Panagiotis Kanavos
                        hashes[index] = hash;
99 422c9598 Panagiotis Kanavos
                    }
100 422c9598 Panagiotis Kanavos
                return nextTask;
101 422c9598 Panagiotis Kanavos
            }).Unwrap();
102 422c9598 Panagiotis Kanavos
        }
103 422c9598 Panagiotis Kanavos
        public static async Task<ConcurrentDictionary<int, byte[]>> CalculateBlockHashesAsync(FileStream stream, int blockSize, string algorithm, ConcurrentDictionary<int, byte[]> hashes = null, int index = 0)
104 422c9598 Panagiotis Kanavos
        {
105 422c9598 Panagiotis Kanavos
            if (stream == null)
106 422c9598 Panagiotis Kanavos
                throw new ArgumentNullException("stream");
107 422c9598 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(algorithm))
108 422c9598 Panagiotis Kanavos
                throw new ArgumentNullException("algorithm");
109 422c9598 Panagiotis Kanavos
            if (blockSize <= 0)
110 422c9598 Panagiotis Kanavos
                throw new ArgumentOutOfRangeException("blockSize", "blockSize must be a value greater than zero ");
111 422c9598 Panagiotis Kanavos
            Contract.EndContractBlock();
112 422c9598 Panagiotis Kanavos
113 422c9598 Panagiotis Kanavos
114 422c9598 Panagiotis Kanavos
            if (hashes == null)
115 422c9598 Panagiotis Kanavos
                hashes = new ConcurrentDictionary<int, byte[]>();
116 422c9598 Panagiotis Kanavos
117 422c9598 Panagiotis Kanavos
            var buffer = new byte[blockSize];
118 422c9598 Panagiotis Kanavos
            int read;
119 422c9598 Panagiotis Kanavos
            while ((read = await stream.ReadAsync(buffer, 0, blockSize)) > 0)
120 422c9598 Panagiotis Kanavos
            {
121 422c9598 Panagiotis Kanavos
                //TODO: identify the value of index
122 422c9598 Panagiotis Kanavos
123 422c9598 Panagiotis Kanavos
                using (var hasher = HashAlgorithm.Create(algorithm))
124 422c9598 Panagiotis Kanavos
                {
125 422c9598 Panagiotis Kanavos
                    //This code was added for compatibility with the way Pithos calculates the last hash
126 422c9598 Panagiotis Kanavos
                    //We calculate the hash only up to the last non-null byte
127 422c9598 Panagiotis Kanavos
                    var lastByteIndex = Array.FindLastIndex(buffer, read - 1, aByte => aByte != 0);
128 422c9598 Panagiotis Kanavos
129 422c9598 Panagiotis Kanavos
                    var hash = hasher.ComputeHash(buffer, 0, lastByteIndex + 1);
130 422c9598 Panagiotis Kanavos
                    hashes[index] = hash;
131 422c9598 Panagiotis Kanavos
                }
132 422c9598 Panagiotis Kanavos
                index += read;
133 422c9598 Panagiotis Kanavos
            };
134 422c9598 Panagiotis Kanavos
            return hashes;
135 422c9598 Panagiotis Kanavos
        }
136 422c9598 Panagiotis Kanavos
        
137 422c9598 Panagiotis Kanavos
        public static async Task<ConcurrentDictionary<int, byte[]>> CalculateBlockHashesAgentAsync(FileStream stream, int blockSize, string algorithm, int parallelism)
138 422c9598 Panagiotis Kanavos
        {
139 422c9598 Panagiotis Kanavos
            if (stream == null)
140 422c9598 Panagiotis Kanavos
                throw new ArgumentNullException("stream");
141 422c9598 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(algorithm))
142 422c9598 Panagiotis Kanavos
                throw new ArgumentNullException("algorithm");
143 422c9598 Panagiotis Kanavos
            if (blockSize <= 0)
144 422c9598 Panagiotis Kanavos
                throw new ArgumentOutOfRangeException("blockSize", "blockSize must be a value greater than zero ");
145 422c9598 Panagiotis Kanavos
            Contract.EndContractBlock();
146 422c9598 Panagiotis Kanavos
147 422c9598 Panagiotis Kanavos
            var hashes = new ConcurrentDictionary<int, byte[]>();
148 422c9598 Panagiotis Kanavos
149 6bcdd8e2 Panagiotis Kanavos
            var path = stream.Name;
150 6bcdd8e2 Panagiotis Kanavos
            var size = stream.Length;
151 6bcdd8e2 Panagiotis Kanavos
            Log.DebugFormat("Hashing [{0}] size [{1}]",path,size);
152 6bcdd8e2 Panagiotis Kanavos
            
153 6bcdd8e2 Panagiotis Kanavos
/*
154 422c9598 Panagiotis Kanavos
            var options = new ExecutionDataflowBlockOptions {BoundedCapacity = parallelism,MaxDegreeOfParallelism=parallelism};
155 422c9598 Panagiotis Kanavos
            var hashBlock=new ActionBlock<Tuple<int,byte[]>>(input=>
156 422c9598 Panagiotis Kanavos
                              {
157 422c9598 Panagiotis Kanavos
                                  int idx = input.Item1;
158 422c9598 Panagiotis Kanavos
                                  byte[] block = input.Item2;
159 422c9598 Panagiotis Kanavos
                                  using (var hasher = HashAlgorithm.Create(algorithm))
160 422c9598 Panagiotis Kanavos
                                  {
161 422c9598 Panagiotis Kanavos
                                      //This code was added for compatibility with the way Pithos calculates the last hash
162 422c9598 Panagiotis Kanavos
                                      //We calculate the hash only up to the last non-null byte
163 422c9598 Panagiotis Kanavos
                                      var lastByteIndex = Array.FindLastIndex(block, block.Length-1, aByte => aByte != 0);
164 422c9598 Panagiotis Kanavos
165 422c9598 Panagiotis Kanavos
                                      var hash = hasher.ComputeHash(block, 0, lastByteIndex + 1);
166 422c9598 Panagiotis Kanavos
                                      hashes[idx] = hash;
167 422c9598 Panagiotis Kanavos
                                  }                                  
168 422c9598 Panagiotis Kanavos
                              },options);
169 6bcdd8e2 Panagiotis Kanavos
*/
170 422c9598 Panagiotis Kanavos
171 422c9598 Panagiotis Kanavos
            var buffer = new byte[blockSize];
172 422c9598 Panagiotis Kanavos
            int read;
173 422c9598 Panagiotis Kanavos
            int index = 0;
174 6bcdd8e2 Panagiotis Kanavos
            using (var hasher = HashAlgorithm.Create(algorithm))
175 422c9598 Panagiotis Kanavos
            {
176 6bcdd8e2 Panagiotis Kanavos
                while ((read = await stream.ReadAsync(buffer, 0, blockSize)) > 0)
177 6bcdd8e2 Panagiotis Kanavos
                {
178 6bcdd8e2 Panagiotis Kanavos
                    //                var block = new byte[read];
179 6bcdd8e2 Panagiotis Kanavos
180 6bcdd8e2 Panagiotis Kanavos
                    //This code was added for compatibility with the way Pithos calculates the last hash
181 6bcdd8e2 Panagiotis Kanavos
                    //We calculate the hash only up to the last non-null byte
182 6bcdd8e2 Panagiotis Kanavos
                    var lastByteIndex = Array.FindLastIndex(buffer, read - 1, aByte => aByte != 0);
183 6bcdd8e2 Panagiotis Kanavos
184 6bcdd8e2 Panagiotis Kanavos
                    var hash = hasher.ComputeHash(buffer, 0, lastByteIndex + 1);
185 6bcdd8e2 Panagiotis Kanavos
                    Log.DebugFormat("Hashed [{0}] [{1}/{2}] [{3:p}]", path, index,size,(double)index/size);
186 6bcdd8e2 Panagiotis Kanavos
                    hashes[index] = hash;
187 6bcdd8e2 Panagiotis Kanavos
                    index += read;
188 6bcdd8e2 Panagiotis Kanavos
                }
189 6bcdd8e2 Panagiotis Kanavos
190 6bcdd8e2 Panagiotis Kanavos
                /*
191 6bcdd8e2 Panagiotis Kanavos
                                Buffer.BlockCopy(buffer,0,block,0,read);
192 6bcdd8e2 Panagiotis Kanavos
                                await hashBlock.SendAsync(Tuple.Create(index, block));
193 6bcdd8e2 Panagiotis Kanavos
                */
194 6bcdd8e2 Panagiotis Kanavos
                
195 6bcdd8e2 Panagiotis Kanavos
            }
196 6bcdd8e2 Panagiotis Kanavos
            
197 422c9598 Panagiotis Kanavos
198 6bcdd8e2 Panagiotis Kanavos
/*
199 422c9598 Panagiotis Kanavos
            hashBlock.Complete();
200 422c9598 Panagiotis Kanavos
            await hashBlock.Completion;
201 6bcdd8e2 Panagiotis Kanavos
*/
202 422c9598 Panagiotis Kanavos
203 422c9598 Panagiotis Kanavos
            return hashes;
204 422c9598 Panagiotis Kanavos
        }
205 422c9598 Panagiotis Kanavos
206 422c9598 Panagiotis Kanavos
        static BlockHashAlgorithms()
207 422c9598 Panagiotis Kanavos
        {
208 422c9598 Panagiotis Kanavos
            CalculateBlockHash = CalculateBlockHashesRecursiveAsync;
209 422c9598 Panagiotis Kanavos
        }
210 422c9598 Panagiotis Kanavos
    }
211 422c9598 Panagiotis Kanavos
}