Added hammock project to debug streaming issues
[pithos-ms-client] / trunk / Pithos.Core / StatusKeeper.cs
1 using System;
2 using System.Collections.Concurrent;
3 using System.Collections.Generic;
4 using System.ComponentModel.Composition;
5 using System.Diagnostics;
6 using System.Diagnostics.Contracts;
7 using System.IO;
8 using System.Linq;
9 using System.Security.Cryptography;
10 using System.Text;
11 using System.Threading;
12 using System.Threading.Tasks;
13 using Castle.ActiveRecord;
14 using Castle.ActiveRecord.Framework;
15 using Castle.ActiveRecord.Framework.Config;
16 using Pithos.Interfaces;
17
18 namespace Pithos.Core
19 {
20     [Export(typeof(IStatusChecker)),Export(typeof(IStatusKeeper))]
21     public class StatusKeeper:IStatusChecker,IStatusKeeper
22     {
23         [System.ComponentModel.Composition.Import]
24         public IPithosSettings Settings { get; set; }
25
26         private BlockingCollection<Action> _statusUpdateQueue = new BlockingCollection<Action>();
27         //private readonly CancellationToken _cancel=new CancellationToken();
28
29         public StatusKeeper()
30         {
31             var source = new XmlConfigurationSource("DbConfig.xml");
32             ActiveRecordStarter.Initialize(source,typeof(FileState));            
33             
34             if (!File.Exists("pithos.db"))
35                 ActiveRecordStarter.CreateSchema();
36
37             Task.Factory.StartNew(ProcessUpdates);
38         }
39
40         public void ProcessUpdates()
41         {            
42             foreach (var action in _statusUpdateQueue.GetConsumingEnumerable())
43             {
44                 action();
45             }
46         }
47
48         public void Stop()
49         {
50             _statusUpdateQueue.CompleteAdding();
51         }
52
53         public FileOverlayStatus GetFileOverlayStatus(string path)
54         {
55             try
56             {
57                 var state = FileState.TryFind(path.ToLower());
58                 return state == null ? FileOverlayStatus.Unversioned : state.OverlayStatus;
59             }
60             catch (Exception exc)
61             {
62                 Trace.TraceError(exc.ToString());
63                 return FileOverlayStatus.Unversioned;
64             }
65         }
66
67         public IEnumerable<string> StoreUnversionedFiles(ParallelQuery<string> paths)
68         {            
69             var existingFiles = from state in  FileState.Queryable
70                                     select state.FilePath;
71
72             var newFiles = (from file in paths.Except(existingFiles.AsParallel())
73                             select new FileState
74                                        {
75                                            FilePath = file,
76                                            OverlayStatus = FileOverlayStatus.Unversioned,
77                                            FileStatus=FileStatus.Created,     
78                                            Checksum=Signature.CalculateHash(file)
79                                        }
80                            );
81             
82             //var files=new ConcurrentBag<string>();
83             newFiles.ForAll(state=> _statusUpdateQueue.Add(state.Save));
84
85             return newFiles.Select(state => state.FilePath);// files.GetConsumingEnumerable();
86
87         }
88
89 /*
90         private static Task<string> CalculateHashAsync(string path)
91         {
92
93             string hash;
94             using (var hasher = MD5.Create())
95             {
96                 return FileAsync.ReadAllBytes(path)
97                     .ContinueWith(t => hasher.ComputeHash(t.Result))
98                     .ContinueWith(t =>
99                                       {
100                                           //var hashBuilder = new StringBuilder();
101                                           return (from byte b in t.Result.AsParallel()
102                                                   select b.ToString("x2").ToLower()).Aggregate((s1, s2) => s1 + s2);                                         
103                                       });
104             }
105             /*using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 4096, true))
106             {
107                 
108                 stream.ReadAllBytes()
109                     .ContinueWith(result => hasher.ComputeHash(result.Result))
110                     .;
111                 var hashBytes = hasher.ComputeHash(stream);
112                 var hashBuilder = new StringBuilder();
113                 foreach (byte b in hasher.ComputeHash(stream))
114                     hashBuilder.Append(b.ToString("x2").ToLower());
115                 hash = hashBuilder.ToString();
116
117             }
118             return hash;#1#
119         }
120 */
121
122
123         private PithosStatus _pithosStatus=PithosStatus.InSynch;       
124
125         public void SetPithosStatus(PithosStatus status)
126         {
127             _pithosStatus = status;
128         }
129
130         public PithosStatus GetPithosStatus()
131         {
132             return _pithosStatus;
133         }
134
135         public void SetFileOverlayStatus(string path, FileOverlayStatus overlayStatus)
136         {
137             _statusUpdateQueue.Add(() => 
138                 InnerSetOverlayStatus(path, overlayStatus));
139         }
140
141         private static void InnerSetOverlayStatus(string path, FileOverlayStatus overlayStatus)
142         {
143             var state = FileState.TryFind(path.ToLower());
144             if (state != null)
145             {
146                 state.OverlayStatus = overlayStatus;
147                 state.Update();
148             }
149             else
150             {
151                 state = new FileState
152                             {FilePath = path, OverlayStatus = overlayStatus};
153                 state.Save();
154             }
155         }
156
157         public void RemoveFileOverlayStatus(string path)
158         {
159             _statusUpdateQueue.Add(() =>
160                 InnerRemoveFileOverlayStatus(path));
161         }
162
163         private static void InnerRemoveFileOverlayStatus(string path)
164         {
165             FileState.DeleteAll(new[] {path});
166         }
167
168         public void RenameFileOverlayStatus(string oldPath, string newPath)
169         {
170             _statusUpdateQueue.Add(() =>
171                 InnerRenameFileOverlayStatus(oldPath, newPath));
172         }
173
174         private static void InnerRenameFileOverlayStatus(string oldPath, string newPath)
175         {
176             var state = FileState.Find(oldPath);
177             //NOTE: This will cause problems if path is used as a key in relationships
178             state.FilePath = newPath;
179             state.Update();
180         }
181
182         public void SetFileStatus(string path, FileStatus status)
183         {
184             _statusUpdateQueue.Add(() =>
185                 InnerSetFileStatus(path, status));
186         }
187
188         private static void InnerSetFileStatus(string path, FileStatus status)
189         {
190             var state = FileState.Find(path);
191             state.FileStatus = status;
192         }
193
194         public FileStatus GetFileStatus(string path)
195         {
196             var state = FileState.TryFind(path.ToLower());
197             return (state==null)?FileStatus.Missing:state.FileStatus ;
198         }
199
200         public void ClearFileStatus(string path)
201         {
202             //TODO:SHOULDN'T need both clear file status and remove overlay status
203             FileState.DeleteAll(new[] { path });   
204         }
205
206         public void UpdateFileChecksum(string path, string checksum)
207         {
208             var state = FileState.Find(path);
209             state.Checksum = checksum;
210             state.Update();
211         }
212     }
213 }