Statistics
| Branch: | Revision:

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

History | View | Annotate | Download (50 kB)

1 c561991c pkanavos
#region
2 c561991c pkanavos
/* -----------------------------------------------------------------------
3 c561991c pkanavos
 * <copyright file="StatusAgent.cs" company="GRNet">
4 c561991c pkanavos
 * 
5 c561991c pkanavos
 * Copyright 2011-2012 GRNET S.A. All rights reserved.
6 c561991c pkanavos
 *
7 c561991c pkanavos
 * Redistribution and use in source and binary forms, with or
8 c561991c pkanavos
 * without modification, are permitted provided that the following
9 c561991c pkanavos
 * conditions are met:
10 c561991c pkanavos
 *
11 c561991c pkanavos
 *   1. Redistributions of source code must retain the above
12 c561991c pkanavos
 *      copyright notice, this list of conditions and the following
13 c561991c pkanavos
 *      disclaimer.
14 c561991c pkanavos
 *
15 c561991c pkanavos
 *   2. Redistributions in binary form must reproduce the above
16 c561991c pkanavos
 *      copyright notice, this list of conditions and the following
17 c561991c pkanavos
 *      disclaimer in the documentation and/or other materials
18 c561991c pkanavos
 *      provided with the distribution.
19 c561991c pkanavos
 *
20 c561991c pkanavos
 *
21 c561991c pkanavos
 * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
22 c561991c pkanavos
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 c561991c pkanavos
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 c561991c pkanavos
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
25 c561991c pkanavos
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 c561991c pkanavos
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 c561991c pkanavos
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
28 c561991c pkanavos
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 c561991c pkanavos
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 c561991c pkanavos
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 c561991c pkanavos
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 c561991c pkanavos
 * POSSIBILITY OF SUCH DAMAGE.
33 c561991c pkanavos
 *
34 c561991c pkanavos
 * The views and conclusions contained in the software and
35 c561991c pkanavos
 * documentation are those of the authors and should not be
36 c561991c pkanavos
 * interpreted as representing official policies, either expressed
37 c561991c pkanavos
 * or implied, of GRNET S.A.
38 c561991c pkanavos
 * </copyright>
39 c561991c pkanavos
 * -----------------------------------------------------------------------
40 c561991c pkanavos
 */
41 c561991c pkanavos
#endregion
42 c561991c pkanavos
using System;
43 c561991c pkanavos
using System.Collections.Generic;
44 c561991c pkanavos
using System.ComponentModel.Composition;
45 c561991c pkanavos
using System.Data;
46 562c42a7 pkanavos
using System.Data.SqlServerCe;
47 c561991c pkanavos
using System.Diagnostics;
48 c561991c pkanavos
using System.Diagnostics.Contracts;
49 c561991c pkanavos
using System.IO;
50 c561991c pkanavos
using System.Linq;
51 c561991c pkanavos
using System.Reflection;
52 c561991c pkanavos
using System.Threading;
53 8d38a269 pkanavos
using System.Threading.Tasks;
54 c561991c pkanavos
using NHibernate;
55 c561991c pkanavos
using NHibernate.Cfg;
56 7e39367d pkanavos
using NHibernate.Cfg.MappingSchema;
57 7e39367d pkanavos
using NHibernate.Criterion;
58 c561991c pkanavos
using NHibernate.Dialect;
59 7e39367d pkanavos
using NHibernate.Linq;
60 7e39367d pkanavos
using NHibernate.Mapping.ByCode;
61 7e39367d pkanavos
using NHibernate.Tool.hbm2ddl;
62 c561991c pkanavos
using Pithos.Interfaces;
63 c561991c pkanavos
using Pithos.Network;
64 c561991c pkanavos
using log4net;
65 c561991c pkanavos
using Environment = System.Environment;
66 c561991c pkanavos
67 c561991c pkanavos
namespace Pithos.Core.Agents
68 c561991c pkanavos
{
69 c561991c pkanavos
    [Export(typeof(IStatusChecker)),Export(typeof(IStatusKeeper))]
70 c561991c pkanavos
    public class StatusAgent:IStatusChecker,IStatusKeeper
71 c561991c pkanavos
    {
72 c561991c pkanavos
        private static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
73 c561991c pkanavos
74 c561991c pkanavos
        [System.ComponentModel.Composition.Import]
75 c561991c pkanavos
        public IPithosSettings Settings { get; set; }
76 c561991c pkanavos
77 c561991c pkanavos
        [System.ComponentModel.Composition.Import]
78 c561991c pkanavos
        public IStatusNotification StatusNotification { get; set; }
79 c561991c pkanavos
80 7e39367d pkanavos
        //private Agent<Action> _persistenceAgent;
81 c561991c pkanavos
82 c561991c pkanavos
83 c561991c pkanavos
84 c561991c pkanavos
        public StatusAgent()
85 7e39367d pkanavos
        {
86 c561991c pkanavos
            var appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
87 c561991c pkanavos
88 7e39367d pkanavos
            _pithosDataPath = Path.Combine(appDataPath, "GRNET\\PITHOS");
89 c561991c pkanavos
            if (!Directory.Exists(_pithosDataPath))
90 c561991c pkanavos
                Directory.CreateDirectory(_pithosDataPath);
91 c561991c pkanavos
92 562c42a7 pkanavos
            var dbPath = Path.Combine(_pithosDataPath, "pithos.sdf");
93 562c42a7 pkanavos
94 7e39367d pkanavos
            //MigrateOldDb(dbPath, appDataPath);
95 c561991c pkanavos
96 c561991c pkanavos
97 7e39367d pkanavos
            var cfg = Configure(dbPath);
98 c561991c pkanavos
99 7e39367d pkanavos
            var connectionString = "Data Source=" + dbPath;
100 7e39367d pkanavos
            using (var sqlCeEngine = new SqlCeEngine(connectionString))
101 c561991c pkanavos
            {
102 7e39367d pkanavos
                if (!File.Exists(dbPath))
103 c561991c pkanavos
                {
104 7e39367d pkanavos
                    sqlCeEngine.CreateDatabase();
105 7e39367d pkanavos
                    new SchemaExport(cfg).Execute(true, true, false);
106 7e39367d pkanavos
                    _factory = cfg.BuildSessionFactory();
107 7e39367d pkanavos
                    using (var session = _factory.OpenStatelessSession())
108 7e39367d pkanavos
                    {
109 7e39367d pkanavos
                        session.Insert(new PithosVersion {Id = 1, Version = "0.0.0.0"});
110 7e39367d pkanavos
                    }
111 c561991c pkanavos
                }
112 c561991c pkanavos
                else
113 d56d7903 pkanavos
                {
114 d56d7903 pkanavos
                    try
115 d56d7903 pkanavos
                    {
116 d56d7903 pkanavos
                        if (!sqlCeEngine.Verify(VerifyOption.Enhanced))
117 d56d7903 pkanavos
                            sqlCeEngine.Repair(connectionString, RepairOption.RecoverAllOrFail);
118 d56d7903 pkanavos
                    }
119 d56d7903 pkanavos
                    catch(SqlCeException ex)
120 d56d7903 pkanavos
                    {
121 d56d7903 pkanavos
                        //Rethrow except for sharing errors while repairing
122 d56d7903 pkanavos
                        if (ex.NativeError != 25035)
123 d56d7903 pkanavos
                            throw;
124 d56d7903 pkanavos
                    }
125 9315efdf pkanavos
126 9315efdf pkanavos
                    
127 7f67c2aa pkanavos
                    var update = new SchemaUpdate(cfg);
128 7f67c2aa pkanavos
                    update.Execute(script=>Log.WarnFormat("[DBUPDATE] : {0}",script),true);
129 7e39367d pkanavos
                    _factory = cfg.BuildSessionFactory();                    
130 c561991c pkanavos
                }
131 7e39367d pkanavos
                UpgradeDatabase();
132 c561991c pkanavos
            }
133 c561991c pkanavos
        }
134 c561991c pkanavos
135 7e39367d pkanavos
        private void UpgradeDatabase()
136 c561991c pkanavos
        {
137 7e39367d pkanavos
            using (var session = _factory.OpenSession())
138 c561991c pkanavos
            {
139 7e39367d pkanavos
140 7e39367d pkanavos
                var storedVersion = session.Get<PithosVersion>(1);
141 7e39367d pkanavos
                var actualVersion = Assembly.GetEntryAssembly().GetName().Version;
142 7e39367d pkanavos
143 7e39367d pkanavos
                if (actualVersion == new Version(storedVersion.Version)) 
144 7e39367d pkanavos
                    return;
145 7e39367d pkanavos
                
146 7e39367d pkanavos
                storedVersion.Version = actualVersion.ToString();
147 7e39367d pkanavos
                session.Update(storedVersion);
148 7e39367d pkanavos
                session.Flush();
149 c561991c pkanavos
            }
150 c561991c pkanavos
        }
151 c561991c pkanavos
152 c561991c pkanavos
153 7e39367d pkanavos
        private static Configuration Configure(string pithosDbPath)
154 c561991c pkanavos
        {
155 c561991c pkanavos
            if (String.IsNullOrWhiteSpace(pithosDbPath))
156 c561991c pkanavos
                throw new ArgumentNullException("pithosDbPath");
157 c561991c pkanavos
            if (!Path.IsPathRooted(pithosDbPath))
158 c561991c pkanavos
                throw new ArgumentException("path must be a rooted path", "pithosDbPath");
159 c561991c pkanavos
            Contract.EndContractBlock();
160 c561991c pkanavos
161 7e39367d pkanavos
162 7e39367d pkanavos
            var cfg = new Configuration();                
163 7e39367d pkanavos
                cfg.DataBaseIntegration(db=>
164 7e39367d pkanavos
                                         {
165 7e39367d pkanavos
                                             db.Dialect<MsSqlCe40Dialect>();
166 7e39367d pkanavos
                                             db.ConnectionString = "Data Source=" + pithosDbPath;
167 7e39367d pkanavos
                                             db.AutoCommentSql = true;
168 7e39367d pkanavos
                                             db.KeywordsAutoImport = Hbm2DDLKeyWords.AutoQuote;
169 7e39367d pkanavos
                                             db.SchemaAction = SchemaAutoAction.Update;
170 9315efdf pkanavos
                                             db.LogSqlInConsole = false;                                             
171 7e39367d pkanavos
                                         })                                                     
172 7e39367d pkanavos
                .SessionFactory()                      
173 7e39367d pkanavos
                    .GenerateStatistics()                    
174 7e39367d pkanavos
                    .Integrate.Schema
175 7e39367d pkanavos
                        .Updating();            
176 7e39367d pkanavos
            var mapping = GetMapping();            
177 7e39367d pkanavos
            cfg.AddMapping(mapping);
178 7e39367d pkanavos
179 7e39367d pkanavos
            return cfg;
180 7e39367d pkanavos
        }
181 7e39367d pkanavos
182 7e39367d pkanavos
        private static HbmMapping GetMapping()
183 7e39367d pkanavos
        {
184 7e39367d pkanavos
            var mapper = new ModelMapper();
185 7e39367d pkanavos
            mapper.Class<FileState>(fm =>
186 7e39367d pkanavos
                                        {
187 7e39367d pkanavos
                                            fm.Id(x => x.Id, m => m.Generator(Generators.GuidComb));
188 7e39367d pkanavos
                                            fm.Property(x => x.ObjectID, m =>
189 7e39367d pkanavos
                                            {
190 7e39367d pkanavos
                                                m.Index("IX_FileState_ObjectID");
191 7e39367d pkanavos
                                            });
192 7e39367d pkanavos
                                            fm.Property(x => x.FilePath, m =>
193 7e39367d pkanavos
                                            {
194 7e39367d pkanavos
                                                m.Unique(true);
195 7e39367d pkanavos
                                                m.UniqueKey("U_FileState_FilePath");
196 7e39367d pkanavos
                                                m.Index("IX_FileState_FilePath");                                                
197 1ba5e72f pkanavos
                                                m.Length(1024);
198 7e39367d pkanavos
                                            });
199 7e39367d pkanavos
                                            fm.Property(x => x.OverlayStatus);
200 7e39367d pkanavos
                                            fm.Property(x => x.FileStatus);
201 7e39367d pkanavos
                                            fm.Property(x => x.ConflictReason);
202 7e39367d pkanavos
                                            fm.Property(x => x.Checksum, m => m.Length(64));
203 7e39367d pkanavos
                                            fm.Property(x => x.ETag, m => m.Length(64));
204 dc18b138 pkanavos
                                            fm.Property(x => x.Hashes, m => m.Type(NHibernateUtil.StringClob));
205 7e39367d pkanavos
                                            fm.Property(x => x.LastWriteDate);
206 7e39367d pkanavos
                                            fm.Property(x => x.LastLength);
207 7e39367d pkanavos
                                            fm.Property(x => x.Version);
208 7e39367d pkanavos
                                            fm.Property(x => x.VersionTimeStamp);
209 7e39367d pkanavos
                                            fm.Property(x => x.IsShared);
210 7e39367d pkanavos
                                            fm.Property(x => x.SharedBy);
211 7e39367d pkanavos
                                            fm.Property(x => x.ShareWrite);
212 7e39367d pkanavos
                                            fm.Property(x => x.IsFolder);
213 7f67c2aa pkanavos
                                            fm.Property(x => x.Modified);                                            
214 7e39367d pkanavos
                                        });
215 7e39367d pkanavos
            mapper.Class<PithosVersion>(fm =>
216 7e39367d pkanavos
                                        {
217 7e39367d pkanavos
                                            fm.Id(x => x.Id, m => m.Generator(Generators.Assigned));
218 7e39367d pkanavos
                                            fm.Property(x => x.Version, m => m.Length(20));
219 7e39367d pkanavos
                                        });
220 7e39367d pkanavos
221 7e39367d pkanavos
222 7e39367d pkanavos
            var mapping = mapper.CompileMappingFor(new[] {typeof (FileState),typeof(PithosVersion)});
223 7e39367d pkanavos
            return mapping;
224 c561991c pkanavos
        }
225 c561991c pkanavos
226 c561991c pkanavos
        public void StartProcessing(CancellationToken token)
227 c561991c pkanavos
        {
228 7e39367d pkanavos
           
229 c561991c pkanavos
            
230 c561991c pkanavos
        }
231 c561991c pkanavos
232 c561991c pkanavos
       
233 c561991c pkanavos
234 c561991c pkanavos
        public void Stop()
235 c561991c pkanavos
        {
236 7e39367d pkanavos
          
237 c561991c pkanavos
        }
238 c561991c pkanavos
239 c561991c pkanavos
240 c561991c pkanavos
        public void ProcessExistingFiles(IEnumerable<FileInfo> existingFiles)
241 c561991c pkanavos
        {
242 c561991c pkanavos
            if (existingFiles == null)
243 c561991c pkanavos
                throw new ArgumentNullException("existingFiles");
244 c561991c pkanavos
            Contract.EndContractBlock();
245 c561991c pkanavos
246 c561991c pkanavos
            //Find new or matching files with a left join to the stored states
247 7e39367d pkanavos
            using (var session = _factory.OpenSession())
248 c561991c pkanavos
            {
249 7e39367d pkanavos
250 7e39367d pkanavos
                var fileStates = session.Query<FileState>().ToList();
251 7e39367d pkanavos
                var currentFiles = from file in existingFiles
252 7e39367d pkanavos
                                   join state in fileStates on file.FullName.ToLower() equals state.FilePath.ToLower()
253 7e39367d pkanavos
                                       into
254 7e39367d pkanavos
                                       gs
255 7e39367d pkanavos
                                   from substate in gs.DefaultIfEmpty()
256 7e39367d pkanavos
                                   select Tuple.Create(file, substate);
257 7e39367d pkanavos
258 7e39367d pkanavos
                //To get the deleted files we must get the states that have no corresponding
259 7e39367d pkanavos
                //files. 
260 7e39367d pkanavos
                //We can't use the File.Exists method inside a query, so we get all file paths from the states
261 7e39367d pkanavos
                var statePaths = (from state in fileStates
262 7e39367d pkanavos
                                  select new {state.Id, state.FilePath}).ToList();
263 7e39367d pkanavos
                //and check each one
264 7e39367d pkanavos
                var missingStates = (from path in statePaths
265 7e39367d pkanavos
                                     where !File.Exists(path.FilePath) && !Directory.Exists(path.FilePath)
266 7e39367d pkanavos
                                     select path.Id).ToList();
267 7e39367d pkanavos
                //Finally, retrieve the states that correspond to the deleted files            
268 7e39367d pkanavos
                var deletedFiles = from state in fileStates
269 7e39367d pkanavos
                                   where missingStates.Contains(state.Id)
270 7e39367d pkanavos
                                   select Tuple.Create(default(FileInfo), state);
271 7e39367d pkanavos
272 7e39367d pkanavos
                var pairs = currentFiles.Union(deletedFiles).ToList();
273 7e39367d pkanavos
274 7e39367d pkanavos
                i = 1;
275 7e39367d pkanavos
                var total = pairs.Count;
276 7e39367d pkanavos
                foreach (var pair in pairs)
277 7e39367d pkanavos
                {
278 7e39367d pkanavos
                    ProcessFile(session,total, pair);
279 7e39367d pkanavos
                }
280 7e39367d pkanavos
                session.Flush();
281 c561991c pkanavos
            }
282 c561991c pkanavos
        }
283 c561991c pkanavos
284 c561991c pkanavos
        int i = 1;
285 c561991c pkanavos
286 7e39367d pkanavos
        private void ProcessFile(ISession session,int total, System.Tuple<FileInfo, FileState> pair)
287 c561991c pkanavos
        {
288 c561991c pkanavos
            var idx = Interlocked.Increment(ref i);
289 cfb09103 pkanavos
            using (StatusNotification.GetNotifier("Indexing file {0} of {1}", "Indexed file {0} of {1} ", true,idx, total))
290 c561991c pkanavos
            {
291 c561991c pkanavos
                var fileState = pair.Item2;
292 c561991c pkanavos
                var file = pair.Item1;
293 c561991c pkanavos
                if (fileState == null)
294 c561991c pkanavos
                {
295 c561991c pkanavos
                    //This is a new file                        
296 7e39367d pkanavos
                    var createState = FileState.CreateFor(file,StatusNotification);                    
297 7e39367d pkanavos
                    session.Save(createState);
298 7e39367d pkanavos
                    //_persistenceAgent.Post(createState.Create);
299 c561991c pkanavos
                }
300 c561991c pkanavos
                else if (file == null)
301 c561991c pkanavos
                {
302 c561991c pkanavos
                    //This file was deleted while we were down. We should mark it as deleted
303 c561991c pkanavos
                    //We have to go through UpdateStatus here because the state object we are using
304 c561991c pkanavos
                    //was created by a different ORM session.
305 7e39367d pkanavos
                    UpdateStatusDirect(session,fileState.Id, FileStatus.Deleted);
306 7e39367d pkanavos
                    //_persistenceAgent.Post(() => UpdateStatusDirect((Guid) fileState.Id, FileStatus.Deleted));
307 c561991c pkanavos
                }
308 3906933e George Pantazis
                //else
309 3906933e George Pantazis
                //{
310 3906933e George Pantazis
                //    //This file has a matching state. Need to check for possible changes
311 3906933e George Pantazis
                //    //To check for changes, we use the cheap (in CPU terms) MD5 algorithm
312 3906933e George Pantazis
                //    //on the entire file.
313 3906933e George Pantazis
314 3906933e George Pantazis
                //    var hashString = file.ComputeShortHash(StatusNotification);
315 3906933e George Pantazis
                //    Debug.Assert(hashString.Length==32);
316 3906933e George Pantazis
317 3906933e George Pantazis
318 3906933e George Pantazis
                //    //TODO: Need a way to attach the hashes to the filestate so we don't
319 3906933e George Pantazis
                //    //recalculate them each time a call to calculate has is made
320 3906933e George Pantazis
                //    //We can either store them to the filestate or add them to a 
321 3906933e George Pantazis
                //    //dictionary
322 3906933e George Pantazis
323 3906933e George Pantazis
                //    //If the hashes don't match the file was changed
324 3906933e George Pantazis
                //    if (fileState.ETag != hashString)
325 3906933e George Pantazis
                //    {
326 3906933e George Pantazis
                //        _persistenceAgent.Post(() => UpdateStatusDirect((Guid) fileState.Id, FileStatus.Modified));
327 3906933e George Pantazis
                //    }
328 3906933e George Pantazis
                //}
329 c561991c pkanavos
            }
330 c561991c pkanavos
        }
331 c561991c pkanavos
332 c561991c pkanavos
333 7e39367d pkanavos
        private int UpdateStatusDirect(ISession session,Guid id, FileStatus status)
334 c561991c pkanavos
        {
335 b1303755 pkanavos
            using (ThreadContext.Stacks["StatusAgent"].Push("UpdateStatusDirect"))
336 c561991c pkanavos
            {
337 c561991c pkanavos
338 c561991c pkanavos
                try
339 c561991c pkanavos
                {
340 c561991c pkanavos
                        //var updatecmd = session.CreateSQLQuery(
341 7e39367d pkanavos
                    var updatecmd = session.CreateQuery(
342 397b9100 pkanavos
                        "update FileState set FileStatus= :fileStatus, Modified=:modified where Id = :id  ")
343 7e39367d pkanavos
                        .SetGuid("id", id)
344 397b9100 pkanavos
                        .SetEnum("fileStatus", status)
345 397b9100 pkanavos
                        .SetDateTime("modified",DateTime.Now);
346 7e39367d pkanavos
                    var affected = updatecmd.ExecuteUpdate();
347 7e39367d pkanavos
                        session.Flush();
348 7e39367d pkanavos
                    return affected;
349 c561991c pkanavos
                }
350 c561991c pkanavos
                catch (Exception exc)
351 c561991c pkanavos
                {
352 c561991c pkanavos
                    Log.Error(exc.ToString());
353 c561991c pkanavos
                    throw;
354 c561991c pkanavos
                }
355 c561991c pkanavos
            }
356 c561991c pkanavos
        }
357 c561991c pkanavos
358 c561991c pkanavos
359 c561991c pkanavos
        public string BlockHash { get; set; }
360 c561991c pkanavos
361 c561991c pkanavos
        public int BlockSize { get; set; }
362 7e39367d pkanavos
363 c561991c pkanavos
        public void ChangeRoots(string oldPath, string newPath)
364 c561991c pkanavos
        {
365 c561991c pkanavos
            if (String.IsNullOrWhiteSpace(oldPath))
366 c561991c pkanavos
                throw new ArgumentNullException("oldPath");
367 c561991c pkanavos
            if (!Path.IsPathRooted(oldPath))
368 c561991c pkanavos
                throw new ArgumentException("oldPath must be an absolute path", "oldPath");
369 b1303755 pkanavos
            if (String.IsNullOrWhiteSpace(newPath))
370 c561991c pkanavos
                throw new ArgumentNullException("newPath");
371 c561991c pkanavos
            if (!Path.IsPathRooted(newPath))
372 c561991c pkanavos
                throw new ArgumentException("newPath must be an absolute path", "newPath");
373 c561991c pkanavos
            Contract.EndContractBlock();
374 c561991c pkanavos
375 7e39367d pkanavos
            ChangeRootPath(oldPath,newPath);
376 c561991c pkanavos
377 c561991c pkanavos
        }
378 c561991c pkanavos
379 c561991c pkanavos
380 c561991c pkanavos
381 c561991c pkanavos
        private readonly string _pithosDataPath;
382 7e39367d pkanavos
        private readonly ISessionFactory _factory;
383 c561991c pkanavos
384 c561991c pkanavos
        public FileState GetStateByFilePath(string path)
385 c561991c pkanavos
        {
386 c561991c pkanavos
            if (String.IsNullOrWhiteSpace(path))
387 c561991c pkanavos
                throw new ArgumentNullException("path");
388 c561991c pkanavos
            if (!Path.IsPathRooted(path))
389 c561991c pkanavos
                throw new ArgumentException("The path must be rooted", "path");
390 c561991c pkanavos
            Contract.EndContractBlock();
391 c561991c pkanavos
392 c561991c pkanavos
            try
393 c561991c pkanavos
            {
394 c561991c pkanavos
                
395 7e39367d pkanavos
                using(var session=_factory.OpenStatelessSession())
396 c561991c pkanavos
                {
397 7e39367d pkanavos
                    var state=session.Query<FileState>().SingleOrDefault(s => s.FilePath == path);
398 7e39367d pkanavos
                    if (state==null)
399 7e39367d pkanavos
                        return null;
400 7e39367d pkanavos
                    state.FilePath=state.FilePath??String.Empty;
401 7e39367d pkanavos
                    state.OverlayStatus = state.OverlayStatus ??FileOverlayStatus.Unversioned;
402 7e39367d pkanavos
                    state.FileStatus = state.FileStatus ?? FileStatus.Missing;
403 7e39367d pkanavos
                    state.Checksum = state.Checksum ?? String.Empty;
404 7e39367d pkanavos
                    state.ETag = state.ETag ?? String.Empty;
405 7e39367d pkanavos
                    state.SharedBy = state.SharedBy ?? String.Empty;
406 7e39367d pkanavos
                    return state;
407 c561991c pkanavos
                }
408 7e39367d pkanavos
409 c561991c pkanavos
            }
410 c561991c pkanavos
            catch (Exception exc)
411 c561991c pkanavos
            {
412 c561991c pkanavos
                Log.ErrorFormat(exc.ToString());
413 c561991c pkanavos
                throw;
414 c561991c pkanavos
            }            
415 c561991c pkanavos
        }
416 c561991c pkanavos
417 c561991c pkanavos
        public FileOverlayStatus GetFileOverlayStatus(string path)
418 c561991c pkanavos
        {
419 c561991c pkanavos
            if (String.IsNullOrWhiteSpace(path))
420 c561991c pkanavos
                throw new ArgumentNullException("path");
421 c561991c pkanavos
            if (!Path.IsPathRooted(path))
422 c561991c pkanavos
                throw new ArgumentException("The path must be rooted", "path");
423 c561991c pkanavos
            Contract.EndContractBlock();
424 c561991c pkanavos
425 c561991c pkanavos
            try
426 c561991c pkanavos
            {
427 c561991c pkanavos
                
428 7e39367d pkanavos
                using(var session=_factory.OpenStatelessSession())
429 c561991c pkanavos
                {
430 7e39367d pkanavos
                    return (from state in session.Query<FileState>()
431 7e39367d pkanavos
                            where state.FilePath == path
432 7e39367d pkanavos
                            select state.OverlayStatus)
433 7e39367d pkanavos
                            .Single()
434 7e39367d pkanavos
                            .GetValueOrDefault(FileOverlayStatus.Unversioned);
435 c561991c pkanavos
                }
436 c561991c pkanavos
            }
437 c561991c pkanavos
            catch (Exception exc)
438 c561991c pkanavos
            {
439 c561991c pkanavos
                Log.ErrorFormat(exc.ToString());
440 c561991c pkanavos
                return FileOverlayStatus.Unversioned;
441 c561991c pkanavos
            }
442 c561991c pkanavos
        }
443 c561991c pkanavos
444 7e39367d pkanavos
        public void SetFileOverlayStatus(string path, FileOverlayStatus overlayStatus)
445 c561991c pkanavos
        {
446 c561991c pkanavos
            if (String.IsNullOrWhiteSpace(path))
447 c561991c pkanavos
                throw new ArgumentNullException("path");
448 c561991c pkanavos
            if (!Path.IsPathRooted(path))
449 c561991c pkanavos
                throw new ArgumentException("The path must be rooted","path");
450 c561991c pkanavos
            Contract.EndContractBlock();
451 c561991c pkanavos
452 7e39367d pkanavos
            StoreOverlayStatus(path,overlayStatus);
453 c561991c pkanavos
        }
454 c561991c pkanavos
455 c561991c pkanavos
        public void SetFileState(string path, FileStatus fileStatus, FileOverlayStatus overlayStatus, string conflictReason)
456 c561991c pkanavos
        {
457 c561991c pkanavos
            if (String.IsNullOrWhiteSpace(path))
458 c561991c pkanavos
                throw new ArgumentNullException("path");
459 c561991c pkanavos
            if (!Path.IsPathRooted(path))
460 c561991c pkanavos
                throw new ArgumentException("The path must be rooted", "path");
461 c561991c pkanavos
            Contract.EndContractBlock();
462 c561991c pkanavos
463 c561991c pkanavos
            Debug.Assert(!path.Contains(FolderConstants.CacheFolder));
464 3b4a5c4e pkanavos
            Debug.Assert(!path.EndsWith(".ignore"));
465 3b4a5c4e pkanavos
            using (ThreadContext.Stacks["StatusAgent"].Push("SetFileState"))
466 7e39367d pkanavos
            {
467 c561991c pkanavos
468 7e39367d pkanavos
                try
469 7e39367d pkanavos
                {
470 7e39367d pkanavos
471 7e39367d pkanavos
                    using (var session = _factory.OpenSession())
472 7e39367d pkanavos
                    using (var tx=session.BeginTransaction(IsolationLevel.ReadCommitted))
473 7e39367d pkanavos
                    {
474 8d38a269 pkanavos
                        var state = session.Query<FileState>().FirstOrDefault(s => s.FilePath == path)
475 1ba5e72f pkanavos
                                          ?? 
476 1ba5e72f pkanavos
                                          ((path.Length<=260) 
477 1ba5e72f pkanavos
                                               ?FileState.CreateFor(FileInfoExtensions.FromPath(path), StatusNotification)
478 1ba5e72f pkanavos
                                               :new FileState{
479 1ba5e72f pkanavos
                                                   FilePath = path,
480 1ba5e72f pkanavos
                                                   OverlayStatus = FileOverlayStatus.Conflict,
481 1ba5e72f pkanavos
                                                   FileStatus = Pithos.Core.FileStatus.Conflict,               
482 1ba5e72f pkanavos
                                                   ETag=String.Empty,
483 1ba5e72f pkanavos
                                                   //LastMD5=md5,
484 1ba5e72f pkanavos
                                                   LastWriteDate = DateTime.Today,
485 1ba5e72f pkanavos
                                                   LastLength = 0,
486 1ba5e72f pkanavos
                                                   IsFolder=Directory.Exists(path),
487 1ba5e72f pkanavos
                                                   Modified=DateTime.Now
488 1ba5e72f pkanavos
                                               });
489 8d38a269 pkanavos
                        state.FileStatus = fileStatus;
490 8d38a269 pkanavos
                        state.OverlayStatus = overlayStatus;
491 8d38a269 pkanavos
                        state.ConflictReason = conflictReason;
492 8d38a269 pkanavos
                        state.Modified = DateTime.Now;
493 8d38a269 pkanavos
                        session.SaveOrUpdate(state);
494 8d38a269 pkanavos
/*
495 7e39367d pkanavos
                        //var updatecmd = session.CreateSQLQuery("update FileState set OverlayStatus= :overlayStatus, FileStatus= :fileStatus,ConflictReason= :conflictReason where FilePath = :path ")
496 397b9100 pkanavos
                        var updatecmd = session.CreateQuery("update FileState set OverlayStatus= :overlayStatus, FileStatus= :fileStatus,ConflictReason= :conflictReason, Modified=:modified where FilePath = :path")
497 7e39367d pkanavos
                            .SetString("path", path)
498 7e39367d pkanavos
                            .SetEnum("fileStatus", fileStatus)
499 7e39367d pkanavos
                            .SetEnum("overlayStatus", overlayStatus)
500 397b9100 pkanavos
                            .SetString("conflictReason", conflictReason)
501 397b9100 pkanavos
                            .SetDateTime("modified",DateTime.Now);
502 7e39367d pkanavos
                        var affected = updatecmd.ExecuteUpdate();
503 7e39367d pkanavos
504 7e39367d pkanavos
                        if (affected == 0)
505 7e39367d pkanavos
                        {
506 7e39367d pkanavos
                            //Can happen when downloading a new file
507 7e39367d pkanavos
                            var createdState = FileState.CreateFor(FileInfoExtensions.FromPath(path), StatusNotification);
508 7e39367d pkanavos
                            createdState.FileStatus = fileStatus;
509 7e39367d pkanavos
                            createdState.OverlayStatus = overlayStatus;                            
510 7e39367d pkanavos
                            createdState.ConflictReason = conflictReason;
511 7e39367d pkanavos
                            session.Save(createdState);
512 7e39367d pkanavos
                            //createdState.Create();
513 8d38a269 pkanavos
                        }*/
514 7e39367d pkanavos
                        session.Flush();
515 7e39367d pkanavos
                        tx.Commit();                        
516 7e39367d pkanavos
                    }
517 7e39367d pkanavos
                }
518 7e39367d pkanavos
                catch (Exception exc)
519 7e39367d pkanavos
                {
520 7e39367d pkanavos
                    Log.Error(exc.ToString());
521 7e39367d pkanavos
                    throw;
522 7e39367d pkanavos
                }
523 7e39367d pkanavos
            }            
524 c561991c pkanavos
        }
525 c561991c pkanavos
526 b1303755 pkanavos
527 b1303755 pkanavos
        public void StoreInfo(string path, ObjectInfo objectInfo, TreeHash treeHash)
528 b1303755 pkanavos
        {
529 b1303755 pkanavos
            if (String.IsNullOrWhiteSpace(path))
530 b1303755 pkanavos
                throw new ArgumentNullException("path");
531 b1303755 pkanavos
            if (treeHash==null)
532 b1303755 pkanavos
                throw new ArgumentNullException("treeHash");
533 b1303755 pkanavos
            if (!Path.IsPathRooted(path))
534 b1303755 pkanavos
                throw new ArgumentException("The path must be rooted", "path");
535 b1303755 pkanavos
            if (objectInfo == null)
536 b1303755 pkanavos
                throw new ArgumentNullException("objectInfo", "objectInfo can't be empty");
537 b1303755 pkanavos
            Contract.EndContractBlock();
538 b1303755 pkanavos
539 7e39367d pkanavos
            StoreInfoDirect(path, objectInfo, treeHash);
540 b1303755 pkanavos
541 b1303755 pkanavos
        }
542 b1303755 pkanavos
543 c561991c pkanavos
        public void StoreInfo(string path, ObjectInfo objectInfo)
544 c561991c pkanavos
        {
545 c561991c pkanavos
            if (String.IsNullOrWhiteSpace(path))
546 c561991c pkanavos
                throw new ArgumentNullException("path");
547 c561991c pkanavos
            if (!Path.IsPathRooted(path))
548 c561991c pkanavos
                throw new ArgumentException("The path must be rooted", "path");
549 c561991c pkanavos
            if (objectInfo == null)
550 c561991c pkanavos
                throw new ArgumentNullException("objectInfo", "objectInfo can't be empty");
551 c561991c pkanavos
            Contract.EndContractBlock();
552 c561991c pkanavos
553 7e39367d pkanavos
            StoreInfoDirect(path, objectInfo, null);
554 c561991c pkanavos
555 c561991c pkanavos
        }
556 c561991c pkanavos
557 b1303755 pkanavos
        private void StoreInfoDirect(string path, ObjectInfo objectInfo,TreeHash treeHash)
558 c561991c pkanavos
        {
559 c561991c pkanavos
            try
560 c561991c pkanavos
            {
561 7e39367d pkanavos
                    using (var session = _factory.OpenSession())
562 c561991c pkanavos
                    using (var tx=session.BeginTransaction(IsolationLevel.ReadCommitted))
563 8d38a269 pkanavos
                    {                        
564 c561991c pkanavos
                        //An entry for the new path may exist, 
565 c561991c pkanavos
                        IQuery deletecmd = session.CreateQuery(
566 dc18b138 pkanavos
                            "delete from FileState where FilePath=:path and ObjectID is null")
567 dc18b138 pkanavos
                            .SetString("path", path);
568 c561991c pkanavos
                        deletecmd.ExecuteUpdate();
569 c561991c pkanavos
570 3906933e George Pantazis
                        //string md5=treeHash.NullSafe(t=>t.MD5);                        
571 dc18b138 pkanavos
                        string hashes = treeHash.NullSafe(t => t.ToJson());
572 b1303755 pkanavos
573 b1303755 pkanavos
                        var info = FileInfoExtensions.FromPath(path);
574 b1303755 pkanavos
                        var lastWriteTime = info.LastWriteTime;
575 b1303755 pkanavos
                        var isFolder = (info is DirectoryInfo);
576 dc18b138 pkanavos
                        var lastLength = isFolder ? 0 : ((FileInfo) info).Length;
577 dc18b138 pkanavos
578 dc18b138 pkanavos
                        var state = session.Query<FileState>().SingleOrDefault(s => s.ObjectID == (objectInfo.UUID??"?"))   //Handle null UUIDs
579 dc18b138 pkanavos
                                     ?? session.Query<FileState>().SingleOrDefault(s => s.FilePath == path)
580 dc18b138 pkanavos
                                     ?? new FileState();
581 dc18b138 pkanavos
                        state.FilePath = path;
582 dc18b138 pkanavos
                        state.IsFolder = isFolder;
583 dc18b138 pkanavos
                        state.LastWriteDate = lastWriteTime;
584 dc18b138 pkanavos
                        state.LastLength = lastLength;
585 dc18b138 pkanavos
                        state.Checksum = objectInfo.X_Object_Hash;
586 dc18b138 pkanavos
                        state.Hashes = hashes;
587 dc18b138 pkanavos
                        state.Version = objectInfo.Version.GetValueOrDefault();
588 dc18b138 pkanavos
                        state.VersionTimeStamp = objectInfo.VersionTimestamp;
589 dc18b138 pkanavos
                        state.ETag = objectInfo.ETag;
590 dc18b138 pkanavos
                        state.FileStatus = FileStatus.Unchanged;
591 dc18b138 pkanavos
                        state.OverlayStatus = FileOverlayStatus.Normal;
592 dc18b138 pkanavos
                        state.ObjectID = objectInfo.UUID;
593 dc18b138 pkanavos
                        state.Modified = DateTime.Now;
594 dc18b138 pkanavos
                        session.SaveOrUpdate(state);
595 b1303755 pkanavos
596 b1303755 pkanavos
597 b1303755 pkanavos
598 dc18b138 pkanavos
                        session.Flush();
599 dc18b138 pkanavos
                        tx.Commit();
600 2f1909cd pkanavos
                        if (Log.IsDebugEnabled)
601 2f1909cd pkanavos
                            Log.DebugFormat("DebugDB [{0}]:[{1}]\r\n{2}", path, objectInfo.UUID, objectInfo.X_Object_Hash);
602 c561991c pkanavos
                    }
603 c561991c pkanavos
            }
604 c561991c pkanavos
            catch (Exception exc)
605 c561991c pkanavos
            {
606 c561991c pkanavos
                Log.ErrorFormat("Failed to update [{0}]:[{1}]\r\n{2}",path,objectInfo.UUID, exc);
607 c561991c pkanavos
                throw;
608 c561991c pkanavos
            }
609 c561991c pkanavos
        }
610 c561991c pkanavos
611 c561991c pkanavos
612 c561991c pkanavos
613 c561991c pkanavos
        public void SetFileStatus(string path, FileStatus status)
614 c561991c pkanavos
        {
615 c561991c pkanavos
            if (String.IsNullOrWhiteSpace(path))
616 c561991c pkanavos
                throw new ArgumentNullException("path");
617 c561991c pkanavos
            if (!Path.IsPathRooted(path))
618 c561991c pkanavos
                throw new ArgumentException("The path must be rooted", "path");
619 c561991c pkanavos
            Contract.EndContractBlock();
620 7e39367d pkanavos
621 3b4a5c4e pkanavos
            using (ThreadContext.Stacks["StatusAgent"].Push("SetFileStatus"))
622 7e39367d pkanavos
            {
623 7e39367d pkanavos
624 7e39367d pkanavos
                try
625 7e39367d pkanavos
                {                    
626 7e39367d pkanavos
                    using (var session = _factory.OpenSession())
627 7e39367d pkanavos
                    using (var tx=session.BeginTransaction(IsolationLevel.ReadCommitted))
628 7e39367d pkanavos
                    {
629 7e39367d pkanavos
630 7e39367d pkanavos
                        //var updatecmd = session.CreateSQLQuery(
631 7e39367d pkanavos
                        var updatecmd = session.CreateQuery(
632 397b9100 pkanavos
                            "update FileState set FileStatus= :fileStatus, Modified=:modified where FilePath = :path ")
633 7e39367d pkanavos
                            .SetString("path", path)
634 397b9100 pkanavos
                            .SetEnum("fileStatus", status)
635 397b9100 pkanavos
                            .SetDateTime("modified",DateTime.Now);
636 7e39367d pkanavos
                        var affected = updatecmd.ExecuteUpdate();
637 7e39367d pkanavos
638 7e39367d pkanavos
                        if (affected == 0)
639 7e39367d pkanavos
                        {                            
640 7e39367d pkanavos
                            var createdState = FileState.CreateFor(FileInfoExtensions.FromPath(path), StatusNotification);
641 7e39367d pkanavos
                            createdState.FileStatus = status;
642 7e39367d pkanavos
                            session.Save(createdState);
643 7e39367d pkanavos
                        }
644 7e39367d pkanavos
                        session.Flush();
645 7e39367d pkanavos
                        tx.Commit();
646 7e39367d pkanavos
                    }
647 7e39367d pkanavos
                }
648 7e39367d pkanavos
                catch (Exception exc)
649 7e39367d pkanavos
                {
650 7e39367d pkanavos
                    Log.Error(exc.ToString());
651 7e39367d pkanavos
                    throw;
652 7e39367d pkanavos
                }
653 7e39367d pkanavos
            }            
654 c561991c pkanavos
        }
655 c561991c pkanavos
656 c561991c pkanavos
        public FileStatus GetFileStatus(string path)
657 c561991c pkanavos
        {
658 c561991c pkanavos
            if (String.IsNullOrWhiteSpace(path))
659 c561991c pkanavos
                throw new ArgumentNullException("path");
660 c561991c pkanavos
            if (!Path.IsPathRooted(path))
661 c561991c pkanavos
                throw new ArgumentException("The path must be rooted", "path");
662 c561991c pkanavos
            Contract.EndContractBlock();
663 c561991c pkanavos
664 c561991c pkanavos
            
665 7e39367d pkanavos
            using(var session=_factory.OpenStatelessSession())
666 7e39367d pkanavos
                return (from state in session.Query<FileState>()
667 7e39367d pkanavos
                        select state.FileStatus).SingleOrDefault()??FileStatus.Missing;
668 c561991c pkanavos
        }
669 c561991c pkanavos
670 c561991c pkanavos
        /// <summary>
671 c561991c pkanavos
        /// Deletes the status of the specified file
672 c561991c pkanavos
        /// </summary>
673 c561991c pkanavos
        /// <param name="path"></param>
674 c561991c pkanavos
        public void ClearFileStatus(string path)
675 c561991c pkanavos
        {
676 c561991c pkanavos
            if (String.IsNullOrWhiteSpace(path))
677 c561991c pkanavos
                throw new ArgumentNullException("path");
678 c561991c pkanavos
            if (!Path.IsPathRooted(path))
679 c561991c pkanavos
                throw new ArgumentException("The path must be rooted", "path");
680 c561991c pkanavos
            Contract.EndContractBlock();
681 7e39367d pkanavos
            using(var session=_factory.OpenSession())
682 7e39367d pkanavos
            {
683 7e39367d pkanavos
                DeleteDirect(session,path);
684 7e39367d pkanavos
                session.Flush();                
685 7e39367d pkanavos
            }
686 c561991c pkanavos
        }
687 c561991c pkanavos
688 c561991c pkanavos
        /// <summary>
689 c561991c pkanavos
        /// Deletes the status of the specified folder and all its contents
690 c561991c pkanavos
        /// </summary>
691 c561991c pkanavos
        /// <param name="path"></param>
692 c561991c pkanavos
        public void ClearFolderStatus(string path)
693 c561991c pkanavos
        {
694 c561991c pkanavos
            if (String.IsNullOrWhiteSpace(path))
695 c561991c pkanavos
                throw new ArgumentNullException("path");
696 c561991c pkanavos
            if (!Path.IsPathRooted(path))
697 c561991c pkanavos
                throw new ArgumentException("The path must be rooted", "path");
698 c561991c pkanavos
            Contract.EndContractBlock();
699 7e39367d pkanavos
            using (ThreadContext.Stacks["StatusAgent"].Push("DeleteDirect"))
700 7e39367d pkanavos
            {
701 7e39367d pkanavos
702 7e39367d pkanavos
                try
703 7e39367d pkanavos
                {
704 7e39367d pkanavos
                    using (var session = _factory.OpenSession())
705 7e39367d pkanavos
                    {
706 7e39367d pkanavos
                        DeleteDirect(session,path);
707 7e39367d pkanavos
                        session.Flush();
708 7e39367d pkanavos
                    }
709 7e39367d pkanavos
                }
710 7e39367d pkanavos
                catch (Exception exc)
711 7e39367d pkanavos
                {
712 7e39367d pkanavos
                    Log.Error(exc.ToString());
713 7e39367d pkanavos
                    throw;
714 7e39367d pkanavos
                }
715 7e39367d pkanavos
            }            
716 c561991c pkanavos
        }
717 c561991c pkanavos
718 c561991c pkanavos
        public IEnumerable<FileState> GetChildren(FileState fileState)
719 c561991c pkanavos
        {
720 c561991c pkanavos
            if (fileState == null)
721 c561991c pkanavos
                throw new ArgumentNullException("fileState");
722 c561991c pkanavos
            Contract.EndContractBlock();
723 c561991c pkanavos
724 7e39367d pkanavos
            var session = _factory.GetCurrentSession();
725 7e39367d pkanavos
            var children = from state in session.Query<FileState>()
726 c561991c pkanavos
                           where state.FilePath.StartsWith(fileState.FilePath + "\\")
727 c561991c pkanavos
                           select state;
728 c561991c pkanavos
            return children;
729 c561991c pkanavos
        }
730 c561991c pkanavos
731 c561991c pkanavos
        public void EnsureFileState(string path)
732 c561991c pkanavos
        {
733 c561991c pkanavos
            var existingState = GetStateByFilePath(path);
734 c561991c pkanavos
            if (existingState != null)
735 c561991c pkanavos
                return;
736 c561991c pkanavos
            var fileInfo = FileInfoExtensions.FromPath(path);
737 7e39367d pkanavos
            
738 7e39367d pkanavos
            using (var session=_factory.OpenSession())
739 c561991c pkanavos
            {
740 c561991c pkanavos
                var newState = FileState.CreateFor(fileInfo,StatusNotification);
741 c561991c pkanavos
                newState.FileStatus=FileStatus.Missing;
742 7e39367d pkanavos
                session.SaveOrUpdate(newState);
743 7e39367d pkanavos
                session.Flush();
744 7e39367d pkanavos
                //_persistenceAgent.PostAndAwait(newState.CreateAndFlush).Wait();
745 c561991c pkanavos
            }
746 c561991c pkanavos
747 c561991c pkanavos
        }
748 c561991c pkanavos
749 7e39367d pkanavos
        private void DeleteDirect(ISession session,string filePath)
750 c561991c pkanavos
        {
751 b1303755 pkanavos
            using (ThreadContext.Stacks["StatusAgent"].Push("DeleteDirect"))
752 c561991c pkanavos
            {
753 c561991c pkanavos
754 c561991c pkanavos
                try
755 c561991c pkanavos
                {
756 7e39367d pkanavos
                    var deletes= session.CreateQuery("delete from FileState where FilePath = :path")
757 7e39367d pkanavos
                        .SetParameter("path", filePath)
758 7e39367d pkanavos
                        .ExecuteUpdate();                    
759 c561991c pkanavos
                }
760 c561991c pkanavos
                catch (Exception exc)
761 c561991c pkanavos
                {
762 c561991c pkanavos
                    Log.Error(exc.ToString());
763 c561991c pkanavos
                    throw;
764 c561991c pkanavos
                }
765 c561991c pkanavos
            }
766 c561991c pkanavos
        }
767 c561991c pkanavos
768 12c87c0e pkanavos
769 c561991c pkanavos
770 c561991c pkanavos
771 c561991c pkanavos
        public void CleanupOrphanStates()
772 c561991c pkanavos
        {
773 c561991c pkanavos
            //Orphan states are those that do not correspond to an account, ie. their paths
774 c561991c pkanavos
            //do not start with the root path of any registered account
775 c561991c pkanavos
776 c561991c pkanavos
            var roots=(from account in Settings.Accounts
777 c561991c pkanavos
                      select account.RootPath).ToList();
778 c561991c pkanavos
779 7e39367d pkanavos
            using (var session = _factory.OpenSession())
780 c561991c pkanavos
            {
781 7e39367d pkanavos
                var allStates = from state in session.Query<FileState>()
782 7e39367d pkanavos
                                select state.FilePath;
783 7e39367d pkanavos
784 7e39367d pkanavos
                foreach (var statePath in allStates)
785 7e39367d pkanavos
                {
786 7e39367d pkanavos
                    if (!roots.Any(root => statePath.StartsWith(root, StringComparison.InvariantCultureIgnoreCase)))
787 7e39367d pkanavos
                        this.DeleteDirect(session,statePath);
788 7e39367d pkanavos
                }
789 7e39367d pkanavos
                session.Flush();
790 7e39367d pkanavos
            }
791 7e39367d pkanavos
        }
792 7e39367d pkanavos
793 7e39367d pkanavos
        public void SaveCopy<T>(T state) where T:class
794 7e39367d pkanavos
        {
795 7e39367d pkanavos
            using (var session = _factory.OpenSession())
796 c561991c pkanavos
            {
797 7e39367d pkanavos
                session.Merge(state);
798 7e39367d pkanavos
                session.Flush();
799 c561991c pkanavos
            }
800 c561991c pkanavos
        }
801 c561991c pkanavos
802 c561991c pkanavos
        public void CleanupStaleStates(AccountInfo accountInfo, List<ObjectInfo> objectInfos)
803 c561991c pkanavos
        {
804 c561991c pkanavos
            if (accountInfo == null)
805 c561991c pkanavos
                throw new ArgumentNullException("accountInfo");
806 c561991c pkanavos
            if (objectInfos == null)
807 c561991c pkanavos
                throw new ArgumentNullException("objectInfos");
808 c561991c pkanavos
            Contract.EndContractBlock();
809 c561991c pkanavos
            
810 c561991c pkanavos
811 c561991c pkanavos
812 c561991c pkanavos
            //Stale states are those that have no corresponding local or server file
813 c561991c pkanavos
            
814 c561991c pkanavos
815 c561991c pkanavos
            var agent=FileAgent.GetFileAgent(accountInfo);
816 c561991c pkanavos
817 c561991c pkanavos
            var localFiles=agent.EnumerateFiles();
818 c561991c pkanavos
            var localSet = new HashSet<string>(localFiles);
819 c561991c pkanavos
820 c561991c pkanavos
            //RelativeUrlToFilePath will fail for
821 c561991c pkanavos
            //infos of accounts, containers which have no Name
822 c561991c pkanavos
823 c561991c pkanavos
            var serverFiles = from info in objectInfos
824 c561991c pkanavos
                              where info.Name != null
825 c561991c pkanavos
                              select Path.Combine(accountInfo.AccountPath,info.RelativeUrlToFilePath(accountInfo.UserName));
826 c561991c pkanavos
            var serverSet = new HashSet<string>(serverFiles);
827 c561991c pkanavos
828 7e39367d pkanavos
            using (var session = _factory.OpenSession())
829 c561991c pkanavos
            {
830 c561991c pkanavos
831 7e39367d pkanavos
                var allStates = from state in session.Query<FileState>()
832 7e39367d pkanavos
                                where state.FilePath.StartsWith(agent.RootPath)
833 7e39367d pkanavos
                                select state.FilePath;
834 7e39367d pkanavos
                var stateSet = new HashSet<string>(allStates);
835 7e39367d pkanavos
                stateSet.ExceptWith(serverSet);
836 7e39367d pkanavos
                stateSet.ExceptWith(localSet);
837 7e39367d pkanavos
838 7e39367d pkanavos
                foreach (var remainder in stateSet)
839 7e39367d pkanavos
                {
840 7e39367d pkanavos
                    DeleteDirect(session,remainder);
841 7e39367d pkanavos
                }
842 7e39367d pkanavos
                session.Flush();
843 7e39367d pkanavos
            }
844 c561991c pkanavos
        }
845 b1303755 pkanavos
846 dc18b138 pkanavos
        public static TreeHash CalculateTreeHash(FileSystemInfo fileInfo, AccountInfo accountInfo, FileState fileState, byte hashingParallelism, CancellationToken cancellationToken, IProgress<HashProgress> progress)
847 b1303755 pkanavos
        {
848 d7288179 pkanavos
            fileInfo.Refresh();
849 d7288179 pkanavos
            //If the file doesn't exist, return the empty treehash
850 d7288179 pkanavos
            if (!fileInfo.Exists)
851 d7288179 pkanavos
                return TreeHash.Empty;
852 d7288179 pkanavos
853 b1303755 pkanavos
            //FileState may be null if there is no stored state for this file
854 3906933e George Pantazis
            //if (fileState==null)
855 8d38a269 pkanavos
                return TaskEx.Run(async () =>await Signature.CalculateTreeHashAsync(fileInfo,
856 b1303755 pkanavos
                                                 accountInfo.BlockSize,
857 b1303755 pkanavos
                                                 accountInfo.BlockHash,
858 b1303755 pkanavos
                                                 hashingParallelism,
859 8d38a269 pkanavos
                                                 cancellationToken, progress).ConfigureAwait(false)).Result;
860 b1303755 pkanavos
            //Can we use the stored hashes?
861 3906933e George Pantazis
            //var localTreeHash = fileState.LastMD5 == Signature.CalculateMD5(fileInfo)
862 3906933e George Pantazis
            //                        ? TreeHash.Parse(fileState.Hashes)
863 3906933e George Pantazis
            //                        : Signature.CalculateTreeHashAsync(fileInfo,
864 3906933e George Pantazis
            //                                                           accountInfo.BlockSize,
865 3906933e George Pantazis
            //                                                           accountInfo.BlockHash,
866 3906933e George Pantazis
            //                                                           hashingParallelism,
867 3906933e George Pantazis
            //                                                           cancellationToken, progress);
868 3906933e George Pantazis
            //return localTreeHash;
869 b1303755 pkanavos
        }
870 7e39367d pkanavos
871 7e39367d pkanavos
872 7e39367d pkanavos
873 7e39367d pkanavos
        private object ExecuteWithRetry(Func<ISession, object, object> call, object state)
874 7e39367d pkanavos
        {
875 7e39367d pkanavos
            int retries = 3;
876 7e39367d pkanavos
            while (retries > 0)
877 7e39367d pkanavos
                try
878 7e39367d pkanavos
                {
879 7e39367d pkanavos
                    using (var session=_factory.OpenSession())
880 7e39367d pkanavos
                    {
881 7e39367d pkanavos
                        var result=call(session, state);
882 7e39367d pkanavos
                        session.Flush();
883 7e39367d pkanavos
                        return result;
884 7e39367d pkanavos
                    }
885 7e39367d pkanavos
                }
886 7e39367d pkanavos
                catch (Exception/* ActiveRecordException */)
887 7e39367d pkanavos
                {
888 7e39367d pkanavos
                    retries--;
889 7e39367d pkanavos
                    if (retries <= 0)
890 7e39367d pkanavos
                        throw;
891 7e39367d pkanavos
                }
892 7e39367d pkanavos
            return null;
893 7e39367d pkanavos
        }
894 7e39367d pkanavos
895 b069042e pkanavos
        //TODO: Must separate between UpdateChecksum and UpdateFileHashes
896 7e39367d pkanavos
897 7e39367d pkanavos
        public  void ChangeRootPath(string oldPath, string newPath)
898 7e39367d pkanavos
        {
899 7e39367d pkanavos
            if (String.IsNullOrWhiteSpace(oldPath))
900 7e39367d pkanavos
                throw new ArgumentNullException("oldPath");
901 7e39367d pkanavos
            if (!Path.IsPathRooted(oldPath))
902 7e39367d pkanavos
                throw new ArgumentException("oldPath must be an absolute path", "oldPath");
903 7e39367d pkanavos
            if (string.IsNullOrWhiteSpace(newPath))
904 7e39367d pkanavos
                throw new ArgumentNullException("newPath");
905 7e39367d pkanavos
            if (!Path.IsPathRooted(newPath))
906 7e39367d pkanavos
                throw new ArgumentException("newPath must be an absolute path", "newPath");
907 7e39367d pkanavos
            Contract.EndContractBlock();
908 7e39367d pkanavos
909 7e39367d pkanavos
            //Ensure the paths end with the same character
910 7e39367d pkanavos
            if (!oldPath.EndsWith("\\"))
911 7e39367d pkanavos
                oldPath = oldPath + "\\";
912 7e39367d pkanavos
            if (!newPath.EndsWith("\\"))
913 7e39367d pkanavos
                newPath = newPath + "\\";
914 7e39367d pkanavos
915 7e39367d pkanavos
            ExecuteWithRetry((session, instance) =>
916 7e39367d pkanavos
            {
917 7e39367d pkanavos
                const string hqlUpdate =
918 397b9100 pkanavos
                    "update FileState set FilePath = replace(FilePath,:oldPath,:newPath), Modified=:modified where FilePath like :oldPath || '%' ";
919 7e39367d pkanavos
                var renames = session.CreateQuery(hqlUpdate)
920 7e39367d pkanavos
                    .SetString("oldPath", oldPath)
921 7e39367d pkanavos
                    .SetString("newPath", newPath)
922 397b9100 pkanavos
                    .SetDateTime("modified",DateTime.Now)
923 7e39367d pkanavos
                    .ExecuteUpdate();
924 7e39367d pkanavos
                return renames;
925 7e39367d pkanavos
            }, null);
926 7e39367d pkanavos
        }
927 7e39367d pkanavos
928 7e39367d pkanavos
929 7e39367d pkanavos
        /// <summary>
930 7e39367d pkanavos
        /// Mark Unversioned all FileState rows from the database whose path
931 7e39367d pkanavos
        /// starts with one of the removed paths
932 7e39367d pkanavos
        /// </summary>
933 7e39367d pkanavos
        /// <param name="removed"></param>
934 7e39367d pkanavos
        public void UnversionPaths(List<string> removed)
935 7e39367d pkanavos
        {
936 7e39367d pkanavos
            if (removed == null)
937 7e39367d pkanavos
                return;
938 7e39367d pkanavos
            if (removed.Count == 0)
939 7e39367d pkanavos
                return;
940 7e39367d pkanavos
941 7e39367d pkanavos
            //Create a disjunction (list of OR statements
942 7e39367d pkanavos
            var disjunction = new Disjunction();
943 7e39367d pkanavos
            foreach (var path in removed)
944 7e39367d pkanavos
            {
945 7e39367d pkanavos
                //with the restriction FileState.FilePath like '@path%'
946 7e39367d pkanavos
                disjunction.Add(Restrictions.On<FileState>(s => s.FilePath)
947 bf6dc483 pkanavos
                                    .IsLike(path, MatchMode.Start));
948 7e39367d pkanavos
            }
949 7e39367d pkanavos
950 7e39367d pkanavos
            //Generate a query from the disjunction
951 7e39367d pkanavos
            var query = QueryOver.Of<FileState>().Where(disjunction);
952 7e39367d pkanavos
953 bf6dc483 pkanavos
            using (var session = _factory.OpenSession())
954 bf6dc483 pkanavos
            using (var tx = session.BeginTransaction())
955 7e39367d pkanavos
            {
956 bf6dc483 pkanavos
                
957 bf6dc483 pkanavos
                var states = query.GetExecutableQueryOver(session).List();
958 bf6dc483 pkanavos
                foreach (var state in states)
959 7e39367d pkanavos
                {
960 bf6dc483 pkanavos
                    state.FileStatus = FileStatus.Unversioned;
961 bf6dc483 pkanavos
                    state.OverlayStatus = FileOverlayStatus.Unversioned;
962 bf6dc483 pkanavos
                    session.Update(state);
963 7e39367d pkanavos
                }
964 bf6dc483 pkanavos
                tx.Commit();
965 bf6dc483 pkanavos
                session.Flush();
966 bf6dc483 pkanavos
            }
967 bf6dc483 pkanavos
968 bf6dc483 pkanavos
969 7e39367d pkanavos
        }
970 7e39367d pkanavos
971 7e39367d pkanavos
        public List<FileState> GetAllStates()
972 7e39367d pkanavos
        {
973 7e39367d pkanavos
            using(var session=_factory.OpenSession())
974 7e39367d pkanavos
            {
975 7e39367d pkanavos
                return session.Query<FileState>().ToList();
976 7e39367d pkanavos
            }
977 7e39367d pkanavos
        }
978 7e39367d pkanavos
979 7e39367d pkanavos
        public List<string> GetAllStatePaths()
980 7e39367d pkanavos
        {
981 7e39367d pkanavos
            using (var session = _factory.OpenSession())
982 7e39367d pkanavos
            {
983 7e39367d pkanavos
                return session.Query<FileState>().Select(state => state.FilePath).ToList();
984 7e39367d pkanavos
            }
985 7e39367d pkanavos
        }
986 7e39367d pkanavos
987 7e39367d pkanavos
        public List<FileState> GetConflictStates()
988 7e39367d pkanavos
        {
989 7e39367d pkanavos
            using (var session = _factory.OpenSession())
990 7e39367d pkanavos
            {
991 7e39367d pkanavos
                var fileStates = from state in session.Query<FileState>()
992 7e39367d pkanavos
                                 where state.FileStatus == FileStatus.Conflict ||
993 7e39367d pkanavos
                                       state.OverlayStatus == FileOverlayStatus.Conflict
994 7e39367d pkanavos
                                 select state;
995 7e39367d pkanavos
                return fileStates.ToList();
996 7e39367d pkanavos
            }
997 b1303755 pkanavos
        }
998 7e39367d pkanavos
999 1f3d113a pkanavos
        public void MoveFileState(string oldFullPath, string newFullPath, ObjectInfo objectInfo, TreeHash treeHash)
1000 1f3d113a pkanavos
        {
1001 1f3d113a pkanavos
            if (String.IsNullOrWhiteSpace(oldFullPath))
1002 1f3d113a pkanavos
                throw new ArgumentNullException("oldFullPath");
1003 1f3d113a pkanavos
            if (!Path.IsPathRooted(oldFullPath))
1004 1f3d113a pkanavos
                throw new ArgumentException("The path must be rooted", "oldFullPath");
1005 1f3d113a pkanavos
            if (String.IsNullOrWhiteSpace(newFullPath))
1006 1f3d113a pkanavos
                throw new ArgumentNullException("newFullPath");
1007 1f3d113a pkanavos
            if (!Path.IsPathRooted(newFullPath))
1008 1f3d113a pkanavos
                throw new ArgumentException("The path must be rooted", "newFullPath");
1009 1f3d113a pkanavos
            if (treeHash == null)
1010 1f3d113a pkanavos
                throw new ArgumentNullException("treeHash");
1011 1f3d113a pkanavos
            if (objectInfo == null)
1012 1f3d113a pkanavos
                throw new ArgumentNullException("objectInfo", "objectInfo can't be empty");
1013 1f3d113a pkanavos
            Contract.EndContractBlock();
1014 1f3d113a pkanavos
1015 1f3d113a pkanavos
1016 1f3d113a pkanavos
            try
1017 1f3d113a pkanavos
            {
1018 1f3d113a pkanavos
                using (var session = _factory.OpenSession())
1019 1f3d113a pkanavos
                using (var tx=session.BeginTransaction(IsolationLevel.ReadCommitted))
1020 1f3d113a pkanavos
                {
1021 1f3d113a pkanavos
                    //An entry for the new path may exist, 
1022 1f3d113a pkanavos
                    IQuery deletecmd = session.CreateQuery(
1023 1f3d113a pkanavos
                        "delete from FileState where FilePath=:path and ObjectID is null")
1024 1f3d113a pkanavos
                        .SetString("path", newFullPath);
1025 1f3d113a pkanavos
                    deletecmd.ExecuteUpdate();
1026 1f3d113a pkanavos
1027 1f3d113a pkanavos
                    //string md5=treeHash.NullSafe(t=>t.MD5);                        
1028 1f3d113a pkanavos
                    string hashes = treeHash.NullSafe(t => t.ToJson());
1029 1f3d113a pkanavos
1030 1f3d113a pkanavos
                    var info = FileInfoExtensions.FromPath(newFullPath);
1031 1f3d113a pkanavos
                    var lastWriteTime = info.LastWriteTime;
1032 1f3d113a pkanavos
                    var isFolder = (info is DirectoryInfo);
1033 1f3d113a pkanavos
                    var lastLength = isFolder ? 0 : ((FileInfo) info).Length;
1034 1f3d113a pkanavos
1035 1f3d113a pkanavos
                    var state = session.Query<FileState>().SingleOrDefault(s => s.ObjectID == (objectInfo.UUID??"?"))   //Handle null UUIDs
1036 1f3d113a pkanavos
                                ?? session.Query<FileState>().SingleOrDefault(s => s.FilePath == newFullPath)
1037 1f3d113a pkanavos
                                ?? new FileState();
1038 1f3d113a pkanavos
                    state.FilePath = newFullPath;
1039 1f3d113a pkanavos
                    state.IsFolder = isFolder;
1040 1f3d113a pkanavos
                    state.LastWriteDate = lastWriteTime;
1041 1f3d113a pkanavos
                    state.LastLength = lastLength;
1042 1f3d113a pkanavos
                    state.Checksum = objectInfo.X_Object_Hash;
1043 1f3d113a pkanavos
                    state.Hashes = hashes;
1044 1f3d113a pkanavos
                    state.Version = objectInfo.Version.GetValueOrDefault();
1045 1f3d113a pkanavos
                    state.VersionTimeStamp = objectInfo.VersionTimestamp;
1046 1f3d113a pkanavos
                    state.ETag = objectInfo.ETag;
1047 1f3d113a pkanavos
                    state.FileStatus = FileStatus.Unchanged;
1048 1f3d113a pkanavos
                    state.OverlayStatus = FileOverlayStatus.Normal;
1049 1f3d113a pkanavos
                    state.ObjectID = objectInfo.UUID;
1050 1f3d113a pkanavos
                    state.Modified = DateTime.Now;
1051 1f3d113a pkanavos
                    session.SaveOrUpdate(state);
1052 1f3d113a pkanavos
1053 1f3d113a pkanavos
1054 1f3d113a pkanavos
                    //Delete the old path entry if it still exists (eg. for folders)
1055 1f3d113a pkanavos
                    session.CreateQuery("delete from FileState where FilePath = :path")
1056 1f3d113a pkanavos
                        .SetParameter("path", oldFullPath)
1057 1f3d113a pkanavos
                        .ExecuteUpdate();
1058 1f3d113a pkanavos
                    
1059 1f3d113a pkanavos
1060 1f3d113a pkanavos
                    session.Flush();
1061 1f3d113a pkanavos
                    tx.Commit();
1062 1f3d113a pkanavos
                    if (Log.IsDebugEnabled)
1063 1f3d113a pkanavos
                        Log.DebugFormat("DebugDB [{0}]:[{1}]\r\n{2}", newFullPath, objectInfo.UUID, objectInfo.X_Object_Hash);
1064 1f3d113a pkanavos
                }
1065 1f3d113a pkanavos
            }
1066 1f3d113a pkanavos
            catch (Exception exc)
1067 1f3d113a pkanavos
            {
1068 1f3d113a pkanavos
                Log.ErrorFormat("Failed to update [{0}]:[{1}]\r\n{2}",newFullPath,objectInfo.UUID, exc);
1069 1f3d113a pkanavos
                throw;
1070 1f3d113a pkanavos
            }
1071 1f3d113a pkanavos
        }
1072 1f3d113a pkanavos
1073 b069042e pkanavos
        public void UpdateFileChecksum(string path, string etag, TreeHash treeHash)
1074 b069042e pkanavos
        {
1075 b069042e pkanavos
            if (String.IsNullOrWhiteSpace(path))
1076 b069042e pkanavos
                throw new ArgumentNullException("path");
1077 b069042e pkanavos
            if (!Path.IsPathRooted(path))
1078 b069042e pkanavos
                throw new ArgumentException("The path must be rooted", "path");
1079 c010b69c pkanavos
            
1080 b069042e pkanavos
1081 b069042e pkanavos
            var hashes = treeHash.ToJson();
1082 b069042e pkanavos
            var topHash = treeHash.TopHash.ToHashString();
1083 7e39367d pkanavos
1084 b069042e pkanavos
            ExecuteWithRetry((session, instance) =>
1085 b069042e pkanavos
            {
1086 397b9100 pkanavos
                const string hqlUpdate = "update FileState set Checksum= :checksum,Hashes=:hashes,ETag=:etag, Modified=:modified where FilePath = :path ";
1087 b069042e pkanavos
                var updatedEntities = session.CreateQuery(hqlUpdate)
1088 b069042e pkanavos
                    .SetString("path", path)
1089 b069042e pkanavos
                    .SetString("checksum", topHash)
1090 b069042e pkanavos
                    .SetString("hashes", hashes)
1091 b069042e pkanavos
                    .SetString("etag", etag)
1092 397b9100 pkanavos
                    .SetDateTime("modified", DateTime.Now)
1093 b069042e pkanavos
                    .ExecuteUpdate();
1094 b069042e pkanavos
                return updatedEntities;
1095 b069042e pkanavos
            }, null);
1096 b069042e pkanavos
        }
1097 b069042e pkanavos
1098 b069042e pkanavos
        //Store only the hashes
1099 33a3ca72 pkanavos
        public  void UpdateFileHashes(FileInfo file, TreeHash treeHash)
1100 7e39367d pkanavos
        {
1101 33a3ca72 pkanavos
            if (file==null)
1102 33a3ca72 pkanavos
                throw new ArgumentNullException("file");
1103 7e39367d pkanavos
            Contract.EndContractBlock();
1104 7e39367d pkanavos
1105 7e39367d pkanavos
            var hashes = treeHash.ToJson();
1106 7e39367d pkanavos
            var topHash = treeHash.TopHash.ToHashString();
1107 7e39367d pkanavos
1108 7e39367d pkanavos
            ExecuteWithRetry((session, instance) =>
1109 7e39367d pkanavos
            {
1110 7e39367d pkanavos
1111 670f03d3 pkanavos
                const string hqlUpdate = "update FileState set Hashes=:hashes,Modified=:modified,LastWriteDate=:date, LastLength=:length where FilePath = :path ";
1112 b069042e pkanavos
/*
1113 7e39367d pkanavos
                const string hqlUpdate = "update FileState set Checksum= :checksum,Hashes=:hashes where FilePath = :path ";
1114 b069042e pkanavos
*/
1115 7e39367d pkanavos
                var updatedEntities = session.CreateQuery(hqlUpdate)
1116 33a3ca72 pkanavos
                    .SetString("path", file.FullName)
1117 33a3ca72 pkanavos
                    .SetDateTime("date",file.LastWriteTime)
1118 33a3ca72 pkanavos
                    .SetInt64("length",file.Length)
1119 b069042e pkanavos
                    //.SetString("checksum", topHash)
1120 7e39367d pkanavos
                    //                    .SetString("md5",treeHash.MD5)
1121 7e39367d pkanavos
                    .SetString("hashes", hashes)
1122 397b9100 pkanavos
                    .SetDateTime("modified", DateTime.Now)
1123 7e39367d pkanavos
                    .ExecuteUpdate();
1124 7e39367d pkanavos
                return updatedEntities;
1125 7e39367d pkanavos
            }, null);
1126 7e39367d pkanavos
        }
1127 7e39367d pkanavos
1128 7e39367d pkanavos
1129 7e39367d pkanavos
        public void RenameState(string oldPath, string newPath)
1130 7e39367d pkanavos
        {
1131 7e39367d pkanavos
            if (string.IsNullOrWhiteSpace(oldPath))
1132 7e39367d pkanavos
                throw new ArgumentNullException("oldPath");
1133 7e39367d pkanavos
            Contract.EndContractBlock();
1134 7e39367d pkanavos
1135 7e39367d pkanavos
            ExecuteWithRetry((session, instance) =>
1136 7e39367d pkanavos
            {
1137 7e39367d pkanavos
                const string hqlUpdate =
1138 397b9100 pkanavos
                    "update FileState set FilePath= :newPath, Modified=:modified where FilePath = :oldPath ";
1139 7e39367d pkanavos
                var updatedEntities = session.CreateQuery(hqlUpdate)
1140 7e39367d pkanavos
                    .SetString("oldPath", oldPath)
1141 7e39367d pkanavos
                    .SetString("newPath", newPath)
1142 397b9100 pkanavos
                    .SetDateTime("modified", DateTime.Now)
1143 7e39367d pkanavos
                    .ExecuteUpdate();
1144 7e39367d pkanavos
                return updatedEntities;
1145 7e39367d pkanavos
            }, null);
1146 7e39367d pkanavos
1147 7e39367d pkanavos
        }
1148 7e39367d pkanavos
1149 7e39367d pkanavos
        public void StoreOverlayStatus(string absolutePath, FileOverlayStatus newStatus)
1150 7e39367d pkanavos
        {
1151 7e39367d pkanavos
            if (string.IsNullOrWhiteSpace(absolutePath))
1152 7e39367d pkanavos
                throw new ArgumentNullException("absolutePath");
1153 7e39367d pkanavos
            Contract.EndContractBlock();
1154 7e39367d pkanavos
1155 dc18b138 pkanavos
            using(var session=_factory.OpenSession())
1156 7e39367d pkanavos
            {
1157 7e39367d pkanavos
                using (var tx = session.BeginTransaction())
1158 7e39367d pkanavos
                {
1159 dc18b138 pkanavos
                    var state = session.Query<FileState>().SingleOrDefault(s => s.FilePath == absolutePath) 
1160 dc18b138 pkanavos
                        ?? new FileState{
1161 7e39367d pkanavos
                            FilePath = absolutePath,                            
1162 7e39367d pkanavos
                            OverlayStatus = newStatus,
1163 7e39367d pkanavos
                            ETag = Signature.MERKLE_EMPTY,
1164 7e39367d pkanavos
                            //LastMD5=String.Empty,
1165 397b9100 pkanavos
                            IsFolder = Directory.Exists(absolutePath),
1166 397b9100 pkanavos
                            Modified=DateTime.Now
1167 7e39367d pkanavos
                        };
1168 dc18b138 pkanavos
                    state.OverlayStatus = newStatus;
1169 dc18b138 pkanavos
                    session.SaveOrUpdate(state);
1170 dc18b138 pkanavos
                    session.Flush();
1171 dc18b138 pkanavos
                    tx.Commit();                    
1172 7e39367d pkanavos
                }
1173 dc18b138 pkanavos
            };
1174 7e39367d pkanavos
        }
1175 7e39367d pkanavos
1176 c561991c pkanavos
    }
1177 c561991c pkanavos
1178 c561991c pkanavos
   
1179 c561991c pkanavos
}