Revision 0c02aa65 trunk/Pithos.Core/Signature.cs

b/trunk/Pithos.Core/Signature.cs
1
using System;
2
using System.Collections;
3
using System.Collections.Concurrent;
4
using System.Collections.Generic;
1 5
using System.IO;
2 6
using System.Security.Cryptography;
3 7
using System.Text;
8
using System.Threading.Tasks;
9
using System.Linq;
10
using Pithos.Core;
4 11

  
5 12
public static class Signature
6 13
{
......
18 25
        }
19 26
        return hash;
20 27
    }
28

  
29
    /*public static FileHashMap CalculateHashMap(string path, int blockSize)
30
    {
31
        CalculateBlockHashes(path, blockSize)
32
            .ContinueWith(blockTask =>
33
                              {
34
                                  var hashes = blockTask.Result;
35
                                  var hashMapHash = CalculateHashmapHash(hashes);
36
                                  return new FileHashMap {Hash = hashMapHash, Hashes = hashes};
37
                              });
38
    }*/
39

  
40
    public static Task<IList<FileHash>> CalculateBlockHashesAsync(string path, int blockSize)
41
    {
42
        var hashMap = new ConcurrentQueue<FileHash>();
43
        var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 4096, true);
44
        
45
            return stream.ReadBuffersAsync(blockSize, (buffer, read) =>
46
            {
47
                using (var hasher = SHA256.Create())
48
                {
49
                    var hash = hasher.ComputeHash(buffer, 0, read);
50
                    hashMap.Enqueue(new FileHash{FilePath=path,Value=hash});
51
                }
52
            }).ContinueWith(t=>
53
                                {
54
                                    stream.Close();
55
                                    return (IList<FileHash>)hashMap.ToList();
56
                                });                
57
    }
58
    //I'd rather return an enumerable of hash calculation tasks, each of which can
59
    //be use to further store the hashes to storage without first creating the list of hashes
60

  
61
    /* //Or I could pass an action object, just like ReadBuffers does
62
     Task.Factory.Iterate(HashMapIterator(stream, blockSize,hashMap.Enqueue))
63
         .ContinueWith(t=>
64
                           {
65
                               SHA256.Create();
66
                           });*/
67
            
68

  
69

  
70
    public static byte[] CalculateHashmapHash(IList<FileHash> hashMap )
71
    {
72
        using (var stream = new MemoryStream())
73
        using(var hasher=SHA256.Create())
74
        {
75
            foreach (var hash in hashMap)
76
            {
77
                stream.Write(hash.Value, 0, hash.Value.Length);
78
            }
79
            return hasher.ComputeHash(stream);
80
        }
81
    }
82

  
83
    public static IEnumerable<byte[]> HashMapLinq(string path, int blockSize)
84
    {
85
        using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 4096, true))
86
        {
87

  
88
            var query = from block in stream.GetIterator(blockSize).AsParallel().AsOrdered()
89
                        select block;  
90
            
91
            return query;
92
        }
93
    }
94
    
95
    public class Block
96
    {
97
        public int Offset { get; set; }
98
        public byte[] Data { get; set; }
99
    }
100

  
101
    public static IEnumerable<byte[]> GetIterator(this Stream stream,int blockSize)
102
    {        
103
        var buffer = new byte[blockSize];
104
        while(true)
105
        {            
106
            stream.Read(buffer, 0, buffer.Length);            
107
            yield return buffer;
108
        }
109
    }
110

  
111

  
112

  
113
    private static IEnumerable<Task> HashMapIterator(Stream input, int bufferSize,Action<byte[]> hashAvailable )
114
    {
115
        // Create a buffer that will be used over and over
116
        var buffer = new byte[bufferSize];
117

  
118
        using (var hasher = SHA256.Create())
119
        {
120
            // Until there's no more data
121
            while (true)
122
            {
123
                // Asynchronously read a buffer and yield until the operation completes
124
                var readTask = input.ReadAsync(buffer, 0, buffer.Length);
125
                yield return readTask;
126

  
127
                // If there's no more data in the stream, we're done.
128
                if (readTask.Result <= 0) break;
129

  
130
                // Otherwise, hand the data off to the delegate
131
                var hashTask = Task.Factory.StartNew(() => hasher.ComputeHash(buffer, 0, readTask.Result));
132
                yield return hashTask;
133
                hashAvailable(hashTask.Result);
134
            }
135
        }
136
    }
137

  
21 138
}

Also available in: Unified diff