Statistics
| Branch: | Revision:

root / trunk / Pithos.Core / Agents / StatusAgent.cs @ 8f44fd3a

History | View | Annotate | Download (36.9 kB)

1 255f5f86 Panagiotis Kanavos
#region
2 255f5f86 Panagiotis Kanavos
/* -----------------------------------------------------------------------
3 255f5f86 Panagiotis Kanavos
 * <copyright file="StatusAgent.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 0eea575a Panagiotis Kanavos
using System;
43 0eea575a Panagiotis Kanavos
using System.Collections.Generic;
44 0eea575a Panagiotis Kanavos
using System.ComponentModel.Composition;
45 a0dcfcc9 Panagiotis Kanavos
using System.Data.SQLite;
46 0eea575a Panagiotis Kanavos
using System.Diagnostics;
47 0eea575a Panagiotis Kanavos
using System.Diagnostics.Contracts;
48 0eea575a Panagiotis Kanavos
using System.IO;
49 0eea575a Panagiotis Kanavos
using System.Linq;
50 db8a9589 Panagiotis Kanavos
using System.Reflection;
51 174bbb6e Panagiotis Kanavos
using System.Security.Cryptography;
52 540b8cf8 Panagiotis Kanavos
using System.Text;
53 0eea575a Panagiotis Kanavos
using System.Threading;
54 0eea575a Panagiotis Kanavos
using System.Threading.Tasks;
55 0eea575a Panagiotis Kanavos
using Castle.ActiveRecord;
56 174bbb6e Panagiotis Kanavos
using Castle.ActiveRecord.Framework;
57 0eea575a Panagiotis Kanavos
using Castle.ActiveRecord.Framework.Config;
58 6f03d6e1 Panagiotis Kanavos
using NHibernate.ByteCode.Castle;
59 6f03d6e1 Panagiotis Kanavos
using NHibernate.Cfg;
60 6f03d6e1 Panagiotis Kanavos
using NHibernate.Cfg.Loquacious;
61 6f03d6e1 Panagiotis Kanavos
using NHibernate.Dialect;
62 0eea575a Panagiotis Kanavos
using Pithos.Interfaces;
63 77e10b4f Panagiotis Kanavos
using Pithos.Network;
64 cfed7823 Panagiotis Kanavos
using log4net;
65 6f03d6e1 Panagiotis Kanavos
using Environment = System.Environment;
66 0eea575a Panagiotis Kanavos
67 cfed7823 Panagiotis Kanavos
namespace Pithos.Core.Agents
68 0eea575a Panagiotis Kanavos
{
69 0eea575a Panagiotis Kanavos
    [Export(typeof(IStatusChecker)),Export(typeof(IStatusKeeper))]
70 cfed7823 Panagiotis Kanavos
    public class StatusAgent:IStatusChecker,IStatusKeeper
71 0eea575a Panagiotis Kanavos
    {
72 db8a9589 Panagiotis Kanavos
        private static readonly ILog Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
73 db8a9589 Panagiotis Kanavos
74 0eea575a Panagiotis Kanavos
        [System.ComponentModel.Composition.Import]
75 0eea575a Panagiotis Kanavos
        public IPithosSettings Settings { get; set; }
76 0eea575a Panagiotis Kanavos
77 4ec636f6 Panagiotis Kanavos
        private Agent<Action> _persistenceAgent;
78 0eea575a Panagiotis Kanavos
79 cfed7823 Panagiotis Kanavos
80 cfed7823 Panagiotis Kanavos
81 cfed7823 Panagiotis Kanavos
        public StatusAgent()
82 3c43ec9b Panagiotis Kanavos
        {            
83 3c43ec9b Panagiotis Kanavos
            var appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
84 3c43ec9b Panagiotis Kanavos
85 adfa4645 Panagiotis Kanavos
            _pithosDataPath = Path.Combine(appDataPath , "GRNET\\PITHOS");
86 9c4346c9 Panagiotis Kanavos
            if (!Directory.Exists(_pithosDataPath))
87 9c4346c9 Panagiotis Kanavos
                Directory.CreateDirectory(_pithosDataPath);
88 618015f4 Panagiotis Kanavos
89 618015f4 Panagiotis Kanavos
            var dbPath = Path.Combine(_pithosDataPath, "pithos.db");
90 618015f4 Panagiotis Kanavos
91 618015f4 Panagiotis Kanavos
            MigrateOldDb(dbPath, appDataPath);
92 618015f4 Panagiotis Kanavos
93 6f03d6e1 Panagiotis Kanavos
94 9c4346c9 Panagiotis Kanavos
            var source = GetConfiguration(_pithosDataPath);
95 9c4346c9 Panagiotis Kanavos
            ActiveRecordStarter.Initialize(source,typeof(FileState),typeof(FileTag));
96 6f03d6e1 Panagiotis Kanavos
            
97 cfed7823 Panagiotis Kanavos
            ActiveRecordStarter.UpdateSchema();
98 9c4346c9 Panagiotis Kanavos
99 618015f4 Panagiotis Kanavos
100 618015f4 Panagiotis Kanavos
            if (!File.Exists(dbPath))
101 0eea575a Panagiotis Kanavos
                ActiveRecordStarter.CreateSchema();
102 9c4346c9 Panagiotis Kanavos
103 540b8cf8 Panagiotis Kanavos
            CreateTrigger();
104 025046f1 Panagiotis Kanavos
            
105 540b8cf8 Panagiotis Kanavos
        }
106 540b8cf8 Panagiotis Kanavos
107 618015f4 Panagiotis Kanavos
108 618015f4 Panagiotis Kanavos
        private static void MigrateOldDb(string dbPath, string appDataPath)
109 618015f4 Panagiotis Kanavos
        {
110 d78d765c pkanavos
            if(String.IsNullOrWhiteSpace(dbPath))
111 d78d765c pkanavos
                throw new ArgumentNullException("dbPath");
112 d78d765c pkanavos
            if(String.IsNullOrWhiteSpace(appDataPath))
113 d78d765c pkanavos
                throw new ArgumentNullException("appDataPath");
114 d78d765c pkanavos
            Contract.EndContractBlock();
115 81c5c310 pkanavos
116 618015f4 Panagiotis Kanavos
            var oldDbPath = Path.Combine(appDataPath, "Pithos", "pithos.db");
117 618015f4 Panagiotis Kanavos
            var oldDbInfo = new FileInfo(oldDbPath);
118 618015f4 Panagiotis Kanavos
            if (oldDbInfo.Exists && !File.Exists(dbPath))
119 618015f4 Panagiotis Kanavos
            {
120 81c5c310 pkanavos
                Log.InfoFormat("Moving database from {0} to {1}",oldDbInfo.FullName,dbPath);
121 618015f4 Panagiotis Kanavos
                var oldDirectory = oldDbInfo.Directory;
122 81c5c310 pkanavos
                oldDbInfo.MoveTo(dbPath);
123 81c5c310 pkanavos
                
124 81c5c310 pkanavos
                if (Log.IsDebugEnabled)
125 81c5c310 pkanavos
                    Log.DebugFormat("Deleting {0}",oldDirectory.FullName);
126 81c5c310 pkanavos
                
127 618015f4 Panagiotis Kanavos
                oldDirectory.Delete(true);
128 618015f4 Panagiotis Kanavos
            }
129 618015f4 Panagiotis Kanavos
        }
130 618015f4 Panagiotis Kanavos
131 540b8cf8 Panagiotis Kanavos
        private void CreateTrigger()
132 540b8cf8 Panagiotis Kanavos
        {
133 540b8cf8 Panagiotis Kanavos
            using (var connection = GetConnection())
134 540b8cf8 Panagiotis Kanavos
            using (var triggerCommand = connection.CreateCommand())
135 540b8cf8 Panagiotis Kanavos
            {
136 540b8cf8 Panagiotis Kanavos
                var cmdText = new StringBuilder()
137 540b8cf8 Panagiotis Kanavos
                    .AppendLine("CREATE TRIGGER IF NOT EXISTS update_last_modified UPDATE ON FileState FOR EACH ROW")
138 540b8cf8 Panagiotis Kanavos
                    .AppendLine("BEGIN")
139 540b8cf8 Panagiotis Kanavos
                    .AppendLine("UPDATE FileState SET Modified=datetime('now')  WHERE Id=old.Id;")
140 540b8cf8 Panagiotis Kanavos
                    .AppendLine("END;")
141 540b8cf8 Panagiotis Kanavos
                    .AppendLine("CREATE TRIGGER IF NOT EXISTS insert_last_modified INSERT ON FileState FOR EACH ROW")
142 540b8cf8 Panagiotis Kanavos
                    .AppendLine("BEGIN")
143 540b8cf8 Panagiotis Kanavos
                    .AppendLine("UPDATE FileState SET Modified=datetime('now')  WHERE Id=new.Id;")
144 540b8cf8 Panagiotis Kanavos
                    .AppendLine("END;")
145 540b8cf8 Panagiotis Kanavos
                    .ToString();
146 540b8cf8 Panagiotis Kanavos
                triggerCommand.CommandText = cmdText;                
147 540b8cf8 Panagiotis Kanavos
                triggerCommand.ExecuteNonQuery();
148 540b8cf8 Panagiotis Kanavos
            }
149 540b8cf8 Panagiotis Kanavos
        }
150 039a89e5 Panagiotis Kanavos
151 039a89e5 Panagiotis Kanavos
152 3c43ec9b Panagiotis Kanavos
        private static InPlaceConfigurationSource GetConfiguration(string pithosDbPath)
153 3c43ec9b Panagiotis Kanavos
        {
154 9c4346c9 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(pithosDbPath))
155 9c4346c9 Panagiotis Kanavos
                throw new ArgumentNullException("pithosDbPath");
156 9c4346c9 Panagiotis Kanavos
            if (!Path.IsPathRooted(pithosDbPath))
157 9c4346c9 Panagiotis Kanavos
                throw new ArgumentException("path must be a rooted path", "pithosDbPath");
158 9c4346c9 Panagiotis Kanavos
            Contract.EndContractBlock();
159 9c4346c9 Panagiotis Kanavos
160 3c43ec9b Panagiotis Kanavos
            var properties = new Dictionary<string, string>
161 3c43ec9b Panagiotis Kanavos
                                 {
162 3c43ec9b Panagiotis Kanavos
                                     {"connection.driver_class", "NHibernate.Driver.SQLite20Driver"},
163 3c43ec9b Panagiotis Kanavos
                                     {"dialect", "NHibernate.Dialect.SQLiteDialect"},
164 3c43ec9b Panagiotis Kanavos
                                     {"connection.provider", "NHibernate.Connection.DriverConnectionProvider"},
165 3c43ec9b Panagiotis Kanavos
                                     {
166 3c43ec9b Panagiotis Kanavos
                                         "proxyfactory.factory_class",
167 3c43ec9b Panagiotis Kanavos
                                         "NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle"
168 3c43ec9b Panagiotis Kanavos
                                         },
169 3c43ec9b Panagiotis Kanavos
                                 };
170 3c43ec9b Panagiotis Kanavos
171 e81dd1f6 Panagiotis Kanavos
            var connectionString = String.Format(@"Data Source={0}\pithos.db;Version=3;Enlist=N", pithosDbPath);
172 3c43ec9b Panagiotis Kanavos
            properties.Add("connection.connection_string", connectionString);
173 3c43ec9b Panagiotis Kanavos
174 5120f3cb Panagiotis Kanavos
            var source = new InPlaceConfigurationSource();                        
175 3c43ec9b Panagiotis Kanavos
            source.Add(typeof (ActiveRecordBase), properties);
176 5120f3cb Panagiotis Kanavos
            source.SetDebugFlag(false);            
177 3c43ec9b Panagiotis Kanavos
            return source;
178 3c43ec9b Panagiotis Kanavos
        }
179 3c43ec9b Panagiotis Kanavos
180 3c43ec9b Panagiotis Kanavos
        public void StartProcessing(CancellationToken token)
181 3c43ec9b Panagiotis Kanavos
        {
182 4ec636f6 Panagiotis Kanavos
            _persistenceAgent = Agent<Action>.Start(queue =>
183 9c4346c9 Panagiotis Kanavos
            {
184 4ec636f6 Panagiotis Kanavos
                Action loop = null;
185 4ec636f6 Panagiotis Kanavos
                loop = () =>
186 4ec636f6 Panagiotis Kanavos
                {
187 4ec636f6 Panagiotis Kanavos
                    var job = queue.Receive();
188 4ec636f6 Panagiotis Kanavos
                    job.ContinueWith(t =>
189 5e31048f Panagiotis Kanavos
                    {
190 4ec636f6 Panagiotis Kanavos
                        var action = job.Result;
191 4ec636f6 Panagiotis Kanavos
                        try
192 4ec636f6 Panagiotis Kanavos
                        {
193 4ec636f6 Panagiotis Kanavos
                            action();
194 4ec636f6 Panagiotis Kanavos
                        }
195 a0dcfcc9 Panagiotis Kanavos
                        catch (SQLiteException ex)
196 a0dcfcc9 Panagiotis Kanavos
                        {
197 a0dcfcc9 Panagiotis Kanavos
                            Log.ErrorFormat("[ERROR] SQL \n{0}", ex);
198 a0dcfcc9 Panagiotis Kanavos
                        }
199 4ec636f6 Panagiotis Kanavos
                        catch (Exception ex)
200 4ec636f6 Panagiotis Kanavos
                        {
201 a0dcfcc9 Panagiotis Kanavos
                            Log.ErrorFormat("[ERROR] STATE \n{0}", ex);
202 4ec636f6 Panagiotis Kanavos
                        }
203 174bbb6e Panagiotis Kanavos
                        queue.NotifyComplete(action);
204 a0dcfcc9 Panagiotis Kanavos
// ReSharper disable AccessToModifiedClosure
205 4ec636f6 Panagiotis Kanavos
                        queue.DoAsync(loop);
206 a0dcfcc9 Panagiotis Kanavos
// ReSharper restore AccessToModifiedClosure
207 4ec636f6 Panagiotis Kanavos
                    });
208 4ec636f6 Panagiotis Kanavos
                };
209 4ec636f6 Panagiotis Kanavos
                loop();
210 9c4346c9 Panagiotis Kanavos
            });
211 d15e99b4 Panagiotis Kanavos
            
212 0eea575a Panagiotis Kanavos
        }
213 0eea575a Panagiotis Kanavos
214 d15e99b4 Panagiotis Kanavos
       
215 0eea575a Panagiotis Kanavos
216 0eea575a Panagiotis Kanavos
        public void Stop()
217 0eea575a Panagiotis Kanavos
        {
218 4ec636f6 Panagiotis Kanavos
            _persistenceAgent.Stop();            
219 0eea575a Panagiotis Kanavos
        }
220 174bbb6e Panagiotis Kanavos
               
221 0eea575a Panagiotis Kanavos
222 0af3141d Panagiotis Kanavos
        public void ProcessExistingFiles(IEnumerable<FileInfo> existingFiles)
223 9c4346c9 Panagiotis Kanavos
        {
224 0af3141d Panagiotis Kanavos
            if(existingFiles  ==null)
225 0af3141d Panagiotis Kanavos
                throw new ArgumentNullException("existingFiles");
226 0af3141d Panagiotis Kanavos
            Contract.EndContractBlock();
227 9c4346c9 Panagiotis Kanavos
            
228 0af3141d Panagiotis Kanavos
            //Find new or matching files with a left join to the stored states
229 0af3141d Panagiotis Kanavos
            var fileStates = FileState.Queryable;
230 0af3141d Panagiotis Kanavos
            var currentFiles=from file in existingFiles
231 0af3141d Panagiotis Kanavos
                      join state in fileStates on file.FullName.ToLower() equals state.FilePath.ToLower() into gs
232 0af3141d Panagiotis Kanavos
                      from substate in gs.DefaultIfEmpty()
233 0af3141d Panagiotis Kanavos
                               select new {File = file, State = substate};
234 0af3141d Panagiotis Kanavos
235 0af3141d Panagiotis Kanavos
            //To get the deleted files we must get the states that have no corresponding
236 0af3141d Panagiotis Kanavos
            //files. 
237 0af3141d Panagiotis Kanavos
            //We can't use the File.Exists method inside a query, so we get all file paths from the states
238 0af3141d Panagiotis Kanavos
            var statePaths = (from state in fileStates
239 0af3141d Panagiotis Kanavos
                             select new {state.Id, state.FilePath}).ToList();
240 0af3141d Panagiotis Kanavos
            //and check each one
241 0af3141d Panagiotis Kanavos
            var missingStates= (from path in statePaths
242 4ec636f6 Panagiotis Kanavos
                                where !File.Exists(path.FilePath) && !Directory.Exists(path.FilePath)
243 0af3141d Panagiotis Kanavos
                               select path.Id).ToList();
244 0af3141d Panagiotis Kanavos
            //Finally, retrieve the states that correspond to the deleted files            
245 0af3141d Panagiotis Kanavos
            var deletedFiles = from state in fileStates 
246 0af3141d Panagiotis Kanavos
                        where missingStates.Contains(state.Id)
247 0af3141d Panagiotis Kanavos
                        select new { File = default(FileInfo), State = state };
248 0af3141d Panagiotis Kanavos
249 174bbb6e Panagiotis Kanavos
            var pairs = currentFiles.Union(deletedFiles).ToList();
250 0af3141d Panagiotis Kanavos
251 174bbb6e Panagiotis Kanavos
            using (var shortHasher = HashAlgorithm.Create("sha1"))
252 0eea575a Panagiotis Kanavos
            {
253 174bbb6e Panagiotis Kanavos
                foreach (var pair in pairs)
254 0af3141d Panagiotis Kanavos
                {
255 174bbb6e Panagiotis Kanavos
                    var fileState = pair.State;
256 174bbb6e Panagiotis Kanavos
                    var file = pair.File;
257 174bbb6e Panagiotis Kanavos
                    if (fileState == null)
258 9c4346c9 Panagiotis Kanavos
                    {
259 174bbb6e Panagiotis Kanavos
                        //This is a new file                        
260 174bbb6e Panagiotis Kanavos
                        var createState = FileState.CreateFor(file);
261 174bbb6e Panagiotis Kanavos
                        _persistenceAgent.Post(createState.Create);                        
262 174bbb6e Panagiotis Kanavos
                    }
263 174bbb6e Panagiotis Kanavos
                    else if (file == null)
264 174bbb6e Panagiotis Kanavos
                    {
265 174bbb6e Panagiotis Kanavos
                        //This file was deleted while we were down. We should mark it as deleted
266 174bbb6e Panagiotis Kanavos
                        //We have to go through UpdateStatus here because the state object we are using
267 174bbb6e Panagiotis Kanavos
                        //was created by a different ORM session.
268 174bbb6e Panagiotis Kanavos
                        _persistenceAgent.Post(() => UpdateStatusDirect(fileState.Id, FileStatus.Deleted));
269 174bbb6e Panagiotis Kanavos
                    }
270 174bbb6e Panagiotis Kanavos
                    else
271 174bbb6e Panagiotis Kanavos
                    {
272 174bbb6e Panagiotis Kanavos
                        //This file has a matching state. Need to check for possible changes
273 174bbb6e Panagiotis Kanavos
                        //To check for changes, we use the cheap (in CPU terms) SHA1 algorithm
274 174bbb6e Panagiotis Kanavos
                        //on the entire file.
275 174bbb6e Panagiotis Kanavos
                        
276 174bbb6e Panagiotis Kanavos
                        var hashString = file.ComputeShortHash(shortHasher);                        
277 174bbb6e Panagiotis Kanavos
                        //TODO: Need a way to attach the hashes to the filestate so we don't
278 174bbb6e Panagiotis Kanavos
                        //recalculate them each time a call to calculate has is made
279 174bbb6e Panagiotis Kanavos
                        //We can either store them to the filestate or add them to a 
280 174bbb6e Panagiotis Kanavos
                        //dictionary
281 174bbb6e Panagiotis Kanavos
282 174bbb6e Panagiotis Kanavos
                        //If the hashes don't match the file was changed
283 174bbb6e Panagiotis Kanavos
                        if (fileState.ShortHash != hashString)
284 174bbb6e Panagiotis Kanavos
                        {
285 174bbb6e Panagiotis Kanavos
                            _persistenceAgent.Post(() => UpdateStatusDirect(fileState.Id, FileStatus.Modified));
286 174bbb6e Panagiotis Kanavos
                        }
287 174bbb6e Panagiotis Kanavos
                    }
288 0af3141d Panagiotis Kanavos
                }
289 174bbb6e Panagiotis Kanavos
            }
290 174bbb6e Panagiotis Kanavos
                        
291 0af3141d Panagiotis Kanavos
         
292 0eea575a Panagiotis Kanavos
        }
293 174bbb6e Panagiotis Kanavos
        
294 174bbb6e Panagiotis Kanavos
295 0eea575a Panagiotis Kanavos
296 e81dd1f6 Panagiotis Kanavos
        private int UpdateStatusDirect(Guid id, FileStatus status)
297 e81dd1f6 Panagiotis Kanavos
        {
298 039a89e5 Panagiotis Kanavos
            using (log4net.ThreadContext.Stacks["StatusAgent"].Push("UpdateStatusDirect"))
299 e81dd1f6 Panagiotis Kanavos
            {
300 e81dd1f6 Panagiotis Kanavos
301 039a89e5 Panagiotis Kanavos
                try
302 e81dd1f6 Panagiotis Kanavos
                {
303 1b4a7550 Panagiotis Kanavos
                    
304 039a89e5 Panagiotis Kanavos
                    using (var connection = GetConnection())
305 039a89e5 Panagiotis Kanavos
                    using (
306 039a89e5 Panagiotis Kanavos
                        var command = new SQLiteCommand("update FileState set FileStatus= :fileStatus where Id = :id  ",
307 039a89e5 Panagiotis Kanavos
                                                        connection))
308 039a89e5 Panagiotis Kanavos
                    {                                                
309 039a89e5 Panagiotis Kanavos
                        command.Parameters.AddWithValue("fileStatus", status);
310 039a89e5 Panagiotis Kanavos
311 039a89e5 Panagiotis Kanavos
                        command.Parameters.AddWithValue("id", id);
312 039a89e5 Panagiotis Kanavos
                        
313 039a89e5 Panagiotis Kanavos
                        var affected = command.ExecuteNonQuery();
314 039a89e5 Panagiotis Kanavos
                        
315 039a89e5 Panagiotis Kanavos
                        return affected;
316 039a89e5 Panagiotis Kanavos
                    }
317 e81dd1f6 Panagiotis Kanavos
318 039a89e5 Panagiotis Kanavos
                }
319 039a89e5 Panagiotis Kanavos
                catch (Exception exc)
320 039a89e5 Panagiotis Kanavos
                {
321 039a89e5 Panagiotis Kanavos
                    Log.Error(exc.ToString());
322 039a89e5 Panagiotis Kanavos
                    throw;
323 e81dd1f6 Panagiotis Kanavos
                }
324 e81dd1f6 Panagiotis Kanavos
            }
325 e81dd1f6 Panagiotis Kanavos
        }
326 e81dd1f6 Panagiotis Kanavos
        
327 e81dd1f6 Panagiotis Kanavos
        private int UpdateStatusDirect(string path, FileStatus status)
328 e81dd1f6 Panagiotis Kanavos
        {
329 039a89e5 Panagiotis Kanavos
            using (log4net.ThreadContext.Stacks["StatusAgent"].Push("UpdateStatusDirect"))
330 e81dd1f6 Panagiotis Kanavos
            {
331 e81dd1f6 Panagiotis Kanavos
332 039a89e5 Panagiotis Kanavos
                try
333 e81dd1f6 Panagiotis Kanavos
                {
334 039a89e5 Panagiotis Kanavos
335 1b4a7550 Panagiotis Kanavos
                    
336 039a89e5 Panagiotis Kanavos
                    using (var connection = GetConnection())
337 039a89e5 Panagiotis Kanavos
                    using (
338 039a89e5 Panagiotis Kanavos
                        var command =
339 3c76f045 Panagiotis Kanavos
                            new SQLiteCommand("update FileState set FileStatus= :fileStatus where FilePath = :path COLLATE NOCASE",
340 039a89e5 Panagiotis Kanavos
                                              connection))
341 039a89e5 Panagiotis Kanavos
                    {
342 e81dd1f6 Panagiotis Kanavos
343 e81dd1f6 Panagiotis Kanavos
344 039a89e5 Panagiotis Kanavos
                        command.Parameters.AddWithValue("fileStatus", status);
345 039a89e5 Panagiotis Kanavos
346 3c76f045 Panagiotis Kanavos
                        command.Parameters.AddWithValue("path", path);
347 039a89e5 Panagiotis Kanavos
                        
348 039a89e5 Panagiotis Kanavos
                        var affected = command.ExecuteNonQuery();
349 8f44fd3a pkanavos
                        if (affected == 0)
350 8f44fd3a pkanavos
                        {
351 8f44fd3a pkanavos
                            var createdState = FileState.CreateFor(FileInfoExtensions.FromPath(path));
352 8f44fd3a pkanavos
                            createdState.FileStatus = status;
353 8f44fd3a pkanavos
                            _persistenceAgent.Post(createdState.Create);
354 8f44fd3a pkanavos
                        }
355 039a89e5 Panagiotis Kanavos
                        return affected;
356 039a89e5 Panagiotis Kanavos
                    }
357 039a89e5 Panagiotis Kanavos
                }
358 039a89e5 Panagiotis Kanavos
                catch (Exception exc)
359 039a89e5 Panagiotis Kanavos
                {
360 039a89e5 Panagiotis Kanavos
                    Log.Error(exc.ToString());
361 039a89e5 Panagiotis Kanavos
                    throw;
362 e81dd1f6 Panagiotis Kanavos
                }
363 e81dd1f6 Panagiotis Kanavos
            }
364 e81dd1f6 Panagiotis Kanavos
        }
365 e81dd1f6 Panagiotis Kanavos
366 e81dd1f6 Panagiotis Kanavos
        private int UpdateStatusDirect(string absolutePath, FileStatus fileStatus, FileOverlayStatus overlayStatus)
367 e81dd1f6 Panagiotis Kanavos
        {
368 039a89e5 Panagiotis Kanavos
            using (log4net.ThreadContext.Stacks["StatusAgent"].Push("UpdateStatusDirect"))
369 e81dd1f6 Panagiotis Kanavos
            {
370 e81dd1f6 Panagiotis Kanavos
371 039a89e5 Panagiotis Kanavos
                try
372 e81dd1f6 Panagiotis Kanavos
                {
373 039a89e5 Panagiotis Kanavos
374 1b4a7550 Panagiotis Kanavos
                    
375 039a89e5 Panagiotis Kanavos
                    using (var connection = GetConnection())
376 039a89e5 Panagiotis Kanavos
                    using (
377 039a89e5 Panagiotis Kanavos
                        var command =
378 039a89e5 Panagiotis Kanavos
                            new SQLiteCommand(
379 3c76f045 Panagiotis Kanavos
                                "update FileState set OverlayStatus= :overlayStatus, FileStatus= :fileStatus where FilePath = :path COLLATE NOCASE ",
380 039a89e5 Panagiotis Kanavos
                                connection))
381 039a89e5 Panagiotis Kanavos
                    {
382 039a89e5 Panagiotis Kanavos
383 3c76f045 Panagiotis Kanavos
                        command.Parameters.AddWithValue("path", absolutePath);
384 039a89e5 Panagiotis Kanavos
                        command.Parameters.AddWithValue("fileStatus", fileStatus);
385 039a89e5 Panagiotis Kanavos
                        command.Parameters.AddWithValue("overlayStatus", overlayStatus);
386 039a89e5 Panagiotis Kanavos
                        
387 039a89e5 Panagiotis Kanavos
                        var affected = command.ExecuteNonQuery();
388 8f44fd3a pkanavos
                        if (affected == 0)
389 8f44fd3a pkanavos
                        {
390 8f44fd3a pkanavos
                            var createdState=FileState.CreateFor(FileInfoExtensions.FromPath(absolutePath));
391 8f44fd3a pkanavos
                            createdState.FileStatus = fileStatus;
392 8f44fd3a pkanavos
                            createdState.OverlayStatus = overlayStatus;
393 8f44fd3a pkanavos
                            _persistenceAgent.Post(createdState.Create);  
394 8f44fd3a pkanavos
                        }
395 039a89e5 Panagiotis Kanavos
                        return affected;
396 039a89e5 Panagiotis Kanavos
                    }
397 039a89e5 Panagiotis Kanavos
                }
398 039a89e5 Panagiotis Kanavos
                catch (Exception exc)
399 039a89e5 Panagiotis Kanavos
                {
400 039a89e5 Panagiotis Kanavos
                    Log.Error(exc.ToString());
401 039a89e5 Panagiotis Kanavos
                    throw;
402 e81dd1f6 Panagiotis Kanavos
                }
403 e81dd1f6 Panagiotis Kanavos
            }
404 e81dd1f6 Panagiotis Kanavos
        }
405 e81dd1f6 Panagiotis Kanavos
        
406 0af3141d Panagiotis Kanavos
407 0eea575a Panagiotis Kanavos
408 9c4346c9 Panagiotis Kanavos
        public string BlockHash { get; set; }
409 9c4346c9 Panagiotis Kanavos
410 9c4346c9 Panagiotis Kanavos
        public int BlockSize { get; set; }
411 5120f3cb Panagiotis Kanavos
        public void ChangeRoots(string oldPath, string newPath)
412 5120f3cb Panagiotis Kanavos
        {
413 5120f3cb Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(oldPath))
414 5120f3cb Panagiotis Kanavos
                throw new ArgumentNullException("oldPath");
415 5120f3cb Panagiotis Kanavos
            if (!Path.IsPathRooted(oldPath))
416 5120f3cb Panagiotis Kanavos
                throw new ArgumentException("oldPath must be an absolute path", "oldPath");
417 5120f3cb Panagiotis Kanavos
            if (string.IsNullOrWhiteSpace(newPath))
418 5120f3cb Panagiotis Kanavos
                throw new ArgumentNullException("newPath");
419 5120f3cb Panagiotis Kanavos
            if (!Path.IsPathRooted(newPath))
420 5120f3cb Panagiotis Kanavos
                throw new ArgumentException("newPath must be an absolute path", "newPath");
421 5120f3cb Panagiotis Kanavos
            Contract.EndContractBlock();
422 5120f3cb Panagiotis Kanavos
423 5120f3cb Panagiotis Kanavos
            FileState.ChangeRootPath(oldPath,newPath);
424 5120f3cb Panagiotis Kanavos
425 5120f3cb Panagiotis Kanavos
        }
426 9c4346c9 Panagiotis Kanavos
427 0eea575a Panagiotis Kanavos
428 283809f3 Panagiotis Kanavos
429 a0dcfcc9 Panagiotis Kanavos
        private readonly string _pithosDataPath;
430 283809f3 Panagiotis Kanavos
431 283809f3 Panagiotis Kanavos
432 039a89e5 Panagiotis Kanavos
        public FileState GetStateByFilePath(string path)
433 039a89e5 Panagiotis Kanavos
        {
434 039a89e5 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(path))
435 039a89e5 Panagiotis Kanavos
                throw new ArgumentNullException("path");
436 039a89e5 Panagiotis Kanavos
            if (!Path.IsPathRooted(path))
437 039a89e5 Panagiotis Kanavos
                throw new ArgumentException("The path must be rooted", "path");
438 039a89e5 Panagiotis Kanavos
            Contract.EndContractBlock();
439 039a89e5 Panagiotis Kanavos
440 039a89e5 Panagiotis Kanavos
            try
441 039a89e5 Panagiotis Kanavos
            {
442 039a89e5 Panagiotis Kanavos
                
443 039a89e5 Panagiotis Kanavos
                using (var connection = GetConnection())
444 174bbb6e Panagiotis Kanavos
                using (var command = new SQLiteCommand("select Id, FilePath, OverlayStatus,FileStatus ,Checksum ,ShortHash,Version    ,VersionTimeStamp,IsShared   ,SharedBy   ,ShareWrite  from FileState where FilePath=:path COLLATE NOCASE", connection))
445 039a89e5 Panagiotis Kanavos
                {
446 039a89e5 Panagiotis Kanavos
                    
447 3c76f045 Panagiotis Kanavos
                    command.Parameters.AddWithValue("path", path);
448 039a89e5 Panagiotis Kanavos
                    
449 039a89e5 Panagiotis Kanavos
                    using (var reader = command.ExecuteReader())
450 039a89e5 Panagiotis Kanavos
                    {
451 039a89e5 Panagiotis Kanavos
                        if (reader.Read())
452 039a89e5 Panagiotis Kanavos
                        {
453 039a89e5 Panagiotis Kanavos
                            //var values = new object[reader.FieldCount];
454 039a89e5 Panagiotis Kanavos
                            //reader.GetValues(values);
455 039a89e5 Panagiotis Kanavos
                            var state = new FileState
456 039a89e5 Panagiotis Kanavos
                                            {
457 039a89e5 Panagiotis Kanavos
                                                Id = reader.GetGuid(0),
458 039a89e5 Panagiotis Kanavos
                                                FilePath = reader.IsDBNull(1)?"":reader.GetString(1),
459 039a89e5 Panagiotis Kanavos
                                                OverlayStatus =reader.IsDBNull(2)?FileOverlayStatus.Unversioned: (FileOverlayStatus) reader.GetInt64(2),
460 039a89e5 Panagiotis Kanavos
                                                FileStatus = reader.IsDBNull(3)?FileStatus.Missing:(FileStatus) reader.GetInt64(3),
461 039a89e5 Panagiotis Kanavos
                                                Checksum = reader.IsDBNull(4)?"":reader.GetString(4),
462 174bbb6e Panagiotis Kanavos
                                                ShortHash= reader.IsDBNull(5)?"":reader.GetString(5),
463 174bbb6e Panagiotis Kanavos
                                                Version = reader.IsDBNull(6)?default(long):reader.GetInt64(6),
464 174bbb6e Panagiotis Kanavos
                                                VersionTimeStamp = reader.IsDBNull(7)?default(DateTime):reader.GetDateTime(7),
465 174bbb6e Panagiotis Kanavos
                                                IsShared = !reader.IsDBNull(8) && reader.GetBoolean(8),
466 174bbb6e Panagiotis Kanavos
                                                SharedBy = reader.IsDBNull(9)?"":reader.GetString(9),
467 174bbb6e Panagiotis Kanavos
                                                ShareWrite = !reader.IsDBNull(10) && reader.GetBoolean(10)
468 039a89e5 Panagiotis Kanavos
                                            };
469 039a89e5 Panagiotis Kanavos
/*
470 039a89e5 Panagiotis Kanavos
                            var state = new FileState
471 039a89e5 Panagiotis Kanavos
                                            {
472 039a89e5 Panagiotis Kanavos
                                                Id = (Guid) values[0],
473 039a89e5 Panagiotis Kanavos
                                                FilePath = (string) values[1],
474 039a89e5 Panagiotis Kanavos
                                                OverlayStatus = (FileOverlayStatus) (long)values[2],
475 039a89e5 Panagiotis Kanavos
                                                FileStatus = (FileStatus) (long)values[3],
476 039a89e5 Panagiotis Kanavos
                                                Checksum = (string) values[4],
477 039a89e5 Panagiotis Kanavos
                                                Version = (long?) values[5],
478 039a89e5 Panagiotis Kanavos
                                                VersionTimeStamp = (DateTime?) values[6],
479 039a89e5 Panagiotis Kanavos
                                                IsShared = (long)values[7] == 1,
480 039a89e5 Panagiotis Kanavos
                                                SharedBy = (string) values[8],
481 039a89e5 Panagiotis Kanavos
                                                ShareWrite = (long)values[9] == 1
482 039a89e5 Panagiotis Kanavos
                                            };
483 039a89e5 Panagiotis Kanavos
*/
484 039a89e5 Panagiotis Kanavos
                            return state;
485 039a89e5 Panagiotis Kanavos
                        }
486 039a89e5 Panagiotis Kanavos
                        else
487 039a89e5 Panagiotis Kanavos
                        {
488 039a89e5 Panagiotis Kanavos
                            return null;
489 039a89e5 Panagiotis Kanavos
                        }
490 039a89e5 Panagiotis Kanavos
491 039a89e5 Panagiotis Kanavos
                    }                    
492 039a89e5 Panagiotis Kanavos
                }
493 039a89e5 Panagiotis Kanavos
            }
494 039a89e5 Panagiotis Kanavos
            catch (Exception exc)
495 039a89e5 Panagiotis Kanavos
            {
496 039a89e5 Panagiotis Kanavos
                Log.ErrorFormat(exc.ToString());
497 039a89e5 Panagiotis Kanavos
                throw;
498 039a89e5 Panagiotis Kanavos
            }            
499 039a89e5 Panagiotis Kanavos
        }
500 039a89e5 Panagiotis Kanavos
501 283809f3 Panagiotis Kanavos
        public FileOverlayStatus GetFileOverlayStatus(string path)
502 283809f3 Panagiotis Kanavos
        {
503 cfed7823 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(path))
504 cfed7823 Panagiotis Kanavos
                throw new ArgumentNullException("path");
505 cfed7823 Panagiotis Kanavos
            if (!Path.IsPathRooted(path))
506 cfed7823 Panagiotis Kanavos
                throw new ArgumentException("The path must be rooted", "path");
507 cfed7823 Panagiotis Kanavos
            Contract.EndContractBlock();
508 cfed7823 Panagiotis Kanavos
509 283809f3 Panagiotis Kanavos
            try
510 283809f3 Panagiotis Kanavos
            {
511 039a89e5 Panagiotis Kanavos
                
512 039a89e5 Panagiotis Kanavos
                using (var connection = GetConnection())
513 3c76f045 Panagiotis Kanavos
                using (var command = new SQLiteCommand("select OverlayStatus from FileState where FilePath=:path  COLLATE NOCASE", connection))
514 e81dd1f6 Panagiotis Kanavos
                {
515 1b4a7550 Panagiotis Kanavos
                    
516 3c76f045 Panagiotis Kanavos
                    command.Parameters.AddWithValue("path", path);
517 039a89e5 Panagiotis Kanavos
                    
518 e81dd1f6 Panagiotis Kanavos
                    var s = command.ExecuteScalar();
519 e81dd1f6 Panagiotis Kanavos
                    return (FileOverlayStatus) Convert.ToInt32(s);
520 e81dd1f6 Panagiotis Kanavos
                }
521 283809f3 Panagiotis Kanavos
            }
522 283809f3 Panagiotis Kanavos
            catch (Exception exc)
523 283809f3 Panagiotis Kanavos
            {
524 5120f3cb Panagiotis Kanavos
                Log.ErrorFormat(exc.ToString());
525 283809f3 Panagiotis Kanavos
                return FileOverlayStatus.Unversioned;
526 283809f3 Panagiotis Kanavos
            }
527 283809f3 Panagiotis Kanavos
        }
528 283809f3 Panagiotis Kanavos
529 e81dd1f6 Panagiotis Kanavos
        private string GetConnectionString()
530 e81dd1f6 Panagiotis Kanavos
        {
531 14ecd267 Panagiotis Kanavos
            var connectionString = String.Format(@"Data Source={0}\pithos.db;Version=3;Enlist=N;Pooling=True", _pithosDataPath);
532 e81dd1f6 Panagiotis Kanavos
            return connectionString;
533 e81dd1f6 Panagiotis Kanavos
        }
534 e81dd1f6 Panagiotis Kanavos
535 039a89e5 Panagiotis Kanavos
        private SQLiteConnection GetConnection()
536 039a89e5 Panagiotis Kanavos
        {
537 039a89e5 Panagiotis Kanavos
            var connectionString = GetConnectionString();
538 039a89e5 Panagiotis Kanavos
            var connection = new SQLiteConnection(connectionString);
539 039a89e5 Panagiotis Kanavos
            connection.Open();
540 039a89e5 Panagiotis Kanavos
            using(var cmd =connection.CreateCommand())
541 039a89e5 Panagiotis Kanavos
            {
542 039a89e5 Panagiotis Kanavos
                cmd.CommandText = "PRAGMA journal_mode=WAL";
543 039a89e5 Panagiotis Kanavos
                cmd.ExecuteNonQuery();
544 039a89e5 Panagiotis Kanavos
            }
545 039a89e5 Panagiotis Kanavos
            return connection;
546 039a89e5 Panagiotis Kanavos
        }
547 039a89e5 Panagiotis Kanavos
548 174bbb6e Panagiotis Kanavos
       /* public void SetFileOverlayStatus(string path, FileOverlayStatus overlayStatus)
549 0eea575a Panagiotis Kanavos
        {
550 cfed7823 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(path))
551 cfed7823 Panagiotis Kanavos
                throw new ArgumentNullException("path");
552 cfed7823 Panagiotis Kanavos
            if (!Path.IsPathRooted(path))
553 cfed7823 Panagiotis Kanavos
                throw new ArgumentException("The path must be rooted","path");
554 cfed7823 Panagiotis Kanavos
            Contract.EndContractBlock();
555 cfed7823 Panagiotis Kanavos
556 3c76f045 Panagiotis Kanavos
            _persistenceAgent.Post(() => FileState.StoreOverlayStatus(path,overlayStatus));
557 174bbb6e Panagiotis Kanavos
        }*/
558 174bbb6e Panagiotis Kanavos
559 174bbb6e Panagiotis Kanavos
        public Task SetFileOverlayStatus(string path, FileOverlayStatus overlayStatus, string shortHash = null)
560 174bbb6e Panagiotis Kanavos
        {
561 174bbb6e Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(path))
562 174bbb6e Panagiotis Kanavos
                throw new ArgumentNullException("path");
563 174bbb6e Panagiotis Kanavos
            if (!Path.IsPathRooted(path))
564 174bbb6e Panagiotis Kanavos
                throw new ArgumentException("The path must be rooted","path");
565 174bbb6e Panagiotis Kanavos
            Contract.EndContractBlock();
566 174bbb6e Panagiotis Kanavos
567 174bbb6e Panagiotis Kanavos
            return _persistenceAgent.PostAndAwait(() => FileState.StoreOverlayStatus(path,overlayStatus,shortHash));
568 0eea575a Panagiotis Kanavos
        }
569 0eea575a Panagiotis Kanavos
570 a0dcfcc9 Panagiotis Kanavos
       /* public void RenameFileOverlayStatus(string oldPath, string newPath)
571 bfc13ed8 Panagiotis Kanavos
        {
572 cfed7823 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(oldPath))
573 cfed7823 Panagiotis Kanavos
                throw new ArgumentNullException("oldPath");
574 cfed7823 Panagiotis Kanavos
            if (!Path.IsPathRooted(oldPath))
575 cfed7823 Panagiotis Kanavos
                throw new ArgumentException("The oldPath must be rooted", "oldPath");
576 cfed7823 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(newPath))
577 cfed7823 Panagiotis Kanavos
                throw new ArgumentNullException("newPath");
578 cfed7823 Panagiotis Kanavos
            if (!Path.IsPathRooted(newPath))
579 cfed7823 Panagiotis Kanavos
                throw new ArgumentException("The newPath must be rooted", "newPath");
580 cfed7823 Panagiotis Kanavos
            Contract.EndContractBlock();
581 cfed7823 Panagiotis Kanavos
582 ab2f6f79 Panagiotis Kanavos
            _persistenceAgent.Post(() =>FileState.RenameState(oldPath, newPath));
583 a0dcfcc9 Panagiotis Kanavos
        }*/
584 0eea575a Panagiotis Kanavos
585 0a9d4d18 pkanavos
        public void SetFileState(string path, FileStatus fileStatus, FileOverlayStatus overlayStatus, string localFileMissingFromServer)
586 0eea575a Panagiotis Kanavos
        {
587 283809f3 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(path))
588 cfed7823 Panagiotis Kanavos
                throw new ArgumentNullException("path");
589 cfed7823 Panagiotis Kanavos
            if (!Path.IsPathRooted(path))
590 cfed7823 Panagiotis Kanavos
                throw new ArgumentException("The path must be rooted", "path");
591 bfc13ed8 Panagiotis Kanavos
            Contract.EndContractBlock();
592 bfc13ed8 Panagiotis Kanavos
593 ab2f6f79 Panagiotis Kanavos
            Debug.Assert(!path.Contains(FolderConstants.CacheFolder));
594 ab2f6f79 Panagiotis Kanavos
            Debug.Assert(!path.EndsWith(".ignore"));
595 4ec636f6 Panagiotis Kanavos
596 3c76f045 Panagiotis Kanavos
            _persistenceAgent.Post(() => UpdateStatusDirect(path, fileStatus, overlayStatus));
597 0eea575a Panagiotis Kanavos
        }
598 0eea575a Panagiotis Kanavos
599 039a89e5 Panagiotis Kanavos
/*
600 283809f3 Panagiotis Kanavos
        public void StoreInfo(string path,ObjectInfo objectInfo)
601 0eea575a Panagiotis Kanavos
        {
602 283809f3 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(path))
603 cfed7823 Panagiotis Kanavos
                throw new ArgumentNullException("path");
604 cfed7823 Panagiotis Kanavos
            if (!Path.IsPathRooted(path))
605 cfed7823 Panagiotis Kanavos
                throw new ArgumentException("The path must be rooted", "path");            
606 cfed7823 Panagiotis Kanavos
            if (objectInfo == null)
607 283809f3 Panagiotis Kanavos
                throw new ArgumentNullException("objectInfo", "objectInfo can't be empty");
608 bfc13ed8 Panagiotis Kanavos
            Contract.EndContractBlock();
609 5ce54458 Panagiotis Kanavos
610 5ce54458 Panagiotis Kanavos
            _persistenceAgent.Post(() =>
611 3c43ec9b Panagiotis Kanavos
            {
612 5ce54458 Panagiotis Kanavos
                var filePath = path.ToLower();
613 5ce54458 Panagiotis Kanavos
                //Load the existing files state and set its properties in one session            
614 5ce54458 Panagiotis Kanavos
                using (new SessionScope())
615 5ce54458 Panagiotis Kanavos
                {
616 5ce54458 Panagiotis Kanavos
                    //Forgetting to use a sessionscope results in two sessions being created, one by 
617 5ce54458 Panagiotis Kanavos
                    //FirstOrDefault and one by Save()
618 bfc13ed8 Panagiotis Kanavos
                    var state =FileState.FindByFilePath(filePath);
619 ab2f6f79 Panagiotis Kanavos
                    
620 5ce54458 Panagiotis Kanavos
                    //Create a new empty state object if this is a new file
621 5ce54458 Panagiotis Kanavos
                    state = state ?? new FileState();
622 5ce54458 Panagiotis Kanavos
623 5ce54458 Panagiotis Kanavos
                    state.FilePath = filePath;
624 5ce54458 Panagiotis Kanavos
                    state.Checksum = objectInfo.Hash;
625 bfc13ed8 Panagiotis Kanavos
                    state.Version = objectInfo.Version;
626 bfc13ed8 Panagiotis Kanavos
                    state.VersionTimeStamp = objectInfo.VersionTimestamp;
627 bfc13ed8 Panagiotis Kanavos
628 5ce54458 Panagiotis Kanavos
                    state.FileStatus = FileStatus.Unchanged;
629 5ce54458 Panagiotis Kanavos
                    state.OverlayStatus = FileOverlayStatus.Normal;
630 bfc13ed8 Panagiotis Kanavos
                    
631 a0dcfcc9 Panagiotis Kanavos
                  
632 5ce54458 Panagiotis Kanavos
                    //Do the save
633 5ce54458 Panagiotis Kanavos
                    state.Save();
634 5ce54458 Panagiotis Kanavos
                }
635 5ce54458 Panagiotis Kanavos
            });
636 5ce54458 Panagiotis Kanavos
637 283809f3 Panagiotis Kanavos
        }
638 039a89e5 Panagiotis Kanavos
*/
639 039a89e5 Panagiotis Kanavos
        
640 039a89e5 Panagiotis Kanavos
        public void StoreInfo(string path, ObjectInfo objectInfo)
641 1b4a7550 Panagiotis Kanavos
        {
642 1b4a7550 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(path))
643 1b4a7550 Panagiotis Kanavos
                throw new ArgumentNullException("path");
644 1b4a7550 Panagiotis Kanavos
            if (!Path.IsPathRooted(path))
645 1b4a7550 Panagiotis Kanavos
                throw new ArgumentException("The path must be rooted", "path");
646 1b4a7550 Panagiotis Kanavos
            if (objectInfo == null)
647 1b4a7550 Panagiotis Kanavos
                throw new ArgumentNullException("objectInfo", "objectInfo can't be empty");
648 1b4a7550 Panagiotis Kanavos
            Contract.EndContractBlock();
649 1b4a7550 Panagiotis Kanavos
650 039a89e5 Panagiotis Kanavos
            _persistenceAgent.Post(() => StoreInfoDirect(path, objectInfo));
651 1b4a7550 Panagiotis Kanavos
652 1b4a7550 Panagiotis Kanavos
        }
653 1b4a7550 Panagiotis Kanavos
654 039a89e5 Panagiotis Kanavos
        private void StoreInfoDirect(string path, ObjectInfo objectInfo)
655 039a89e5 Panagiotis Kanavos
        {
656 039a89e5 Panagiotis Kanavos
            try
657 039a89e5 Panagiotis Kanavos
            {
658 039a89e5 Panagiotis Kanavos
                
659 039a89e5 Panagiotis Kanavos
                using (var connection = GetConnection())
660 039a89e5 Panagiotis Kanavos
                using (var command = new SQLiteCommand(connection))
661 039a89e5 Panagiotis Kanavos
                {
662 039a89e5 Panagiotis Kanavos
                    if (StateExists(path, connection))
663 039a89e5 Panagiotis Kanavos
                        command.CommandText =
664 3c76f045 Panagiotis Kanavos
                            "update FileState set FileStatus= :fileStatus where FilePath = :path  COLLATE NOCASE ";
665 039a89e5 Panagiotis Kanavos
                    else
666 039a89e5 Panagiotis Kanavos
                    {
667 039a89e5 Panagiotis Kanavos
                        command.CommandText =
668 174bbb6e Panagiotis Kanavos
                            "INSERT INTO FileState (Id,FilePath,Checksum,Version,VersionTimeStamp,ShortHash,FileStatus,OverlayStatus) VALUES (:id,:path,:checksum,:version,:versionTimeStamp,:shortHash,:fileStatus,:overlayStatus)";
669 039a89e5 Panagiotis Kanavos
                        command.Parameters.AddWithValue("id", Guid.NewGuid());
670 039a89e5 Panagiotis Kanavos
                    }
671 039a89e5 Panagiotis Kanavos
672 3c76f045 Panagiotis Kanavos
                    command.Parameters.AddWithValue("path", path);
673 039a89e5 Panagiotis Kanavos
                    command.Parameters.AddWithValue("checksum", objectInfo.Hash);
674 174bbb6e Panagiotis Kanavos
                    command.Parameters.AddWithValue("shortHash", "");
675 039a89e5 Panagiotis Kanavos
                    command.Parameters.AddWithValue("version", objectInfo.Version);
676 039a89e5 Panagiotis Kanavos
                    command.Parameters.AddWithValue("versionTimeStamp",
677 039a89e5 Panagiotis Kanavos
                                                    objectInfo.VersionTimestamp);
678 039a89e5 Panagiotis Kanavos
                    command.Parameters.AddWithValue("fileStatus", FileStatus.Unchanged);
679 039a89e5 Panagiotis Kanavos
                    command.Parameters.AddWithValue("overlayStatus",
680 039a89e5 Panagiotis Kanavos
                                                    FileOverlayStatus.Normal);
681 039a89e5 Panagiotis Kanavos
682 039a89e5 Panagiotis Kanavos
                    var affected = command.ExecuteNonQuery();
683 039a89e5 Panagiotis Kanavos
                    return;
684 039a89e5 Panagiotis Kanavos
                }
685 039a89e5 Panagiotis Kanavos
            }
686 039a89e5 Panagiotis Kanavos
            catch (Exception exc)
687 039a89e5 Panagiotis Kanavos
            {
688 039a89e5 Panagiotis Kanavos
                Log.Error(exc.ToString());
689 039a89e5 Panagiotis Kanavos
                throw;
690 039a89e5 Panagiotis Kanavos
            }
691 039a89e5 Panagiotis Kanavos
        }
692 039a89e5 Panagiotis Kanavos
693 1b4a7550 Panagiotis Kanavos
        private bool StateExists(string filePath,SQLiteConnection connection)
694 1b4a7550 Panagiotis Kanavos
        {
695 3c76f045 Panagiotis Kanavos
            using (var command = new SQLiteCommand("Select count(*) from FileState where FilePath=:path  COLLATE NOCASE", connection))
696 1b4a7550 Panagiotis Kanavos
            {
697 3c76f045 Panagiotis Kanavos
                command.Parameters.AddWithValue("path", filePath);
698 039a89e5 Panagiotis Kanavos
                var result = command.ExecuteScalar();
699 039a89e5 Panagiotis Kanavos
                return ((long)result >= 1);
700 039a89e5 Panagiotis Kanavos
            }
701 1b4a7550 Panagiotis Kanavos
702 1b4a7550 Panagiotis Kanavos
        }
703 283809f3 Panagiotis Kanavos
704 283809f3 Panagiotis Kanavos
        public void SetFileStatus(string path, FileStatus status)
705 ab2f6f79 Panagiotis Kanavos
        {
706 ab2f6f79 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(path))
707 ab2f6f79 Panagiotis Kanavos
                throw new ArgumentNullException("path");
708 ab2f6f79 Panagiotis Kanavos
            if (!Path.IsPathRooted(path))
709 ab2f6f79 Panagiotis Kanavos
                throw new ArgumentException("The path must be rooted", "path");
710 ab2f6f79 Panagiotis Kanavos
            Contract.EndContractBlock();
711 e81dd1f6 Panagiotis Kanavos
            
712 3c76f045 Panagiotis Kanavos
            _persistenceAgent.Post(() => UpdateStatusDirect(path, status));
713 283809f3 Panagiotis Kanavos
        }
714 283809f3 Panagiotis Kanavos
715 0eea575a Panagiotis Kanavos
        public FileStatus GetFileStatus(string path)
716 bfc13ed8 Panagiotis Kanavos
        {
717 cfed7823 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(path))
718 cfed7823 Panagiotis Kanavos
                throw new ArgumentNullException("path");
719 cfed7823 Panagiotis Kanavos
            if (!Path.IsPathRooted(path))
720 cfed7823 Panagiotis Kanavos
                throw new ArgumentException("The path must be rooted", "path");
721 cfed7823 Panagiotis Kanavos
            Contract.EndContractBlock();
722 cfed7823 Panagiotis Kanavos
723 039a89e5 Panagiotis Kanavos
            
724 039a89e5 Panagiotis Kanavos
            using (var connection = GetConnection())
725 e81dd1f6 Panagiotis Kanavos
            {
726 3c76f045 Panagiotis Kanavos
                var command = new SQLiteCommand("select FileStatus from FileState where FilePath=:path  COLLATE NOCASE", connection);
727 3c76f045 Panagiotis Kanavos
                command.Parameters.AddWithValue("path", path);
728 039a89e5 Panagiotis Kanavos
                
729 025046f1 Panagiotis Kanavos
                var statusValue = command.ExecuteScalar();
730 025046f1 Panagiotis Kanavos
                if (statusValue==null)
731 025046f1 Panagiotis Kanavos
                    return FileStatus.Missing;
732 025046f1 Panagiotis Kanavos
                return (FileStatus)Convert.ToInt32(statusValue);
733 e81dd1f6 Panagiotis Kanavos
            }
734 0eea575a Panagiotis Kanavos
        }
735 0eea575a Panagiotis Kanavos
736 3c76f045 Panagiotis Kanavos
        /// <summary>
737 3c76f045 Panagiotis Kanavos
        /// Deletes the status of the specified file
738 3c76f045 Panagiotis Kanavos
        /// </summary>
739 3c76f045 Panagiotis Kanavos
        /// <param name="path"></param>
740 0eea575a Panagiotis Kanavos
        public void ClearFileStatus(string path)
741 0eea575a Panagiotis Kanavos
        {
742 cfed7823 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(path))
743 cfed7823 Panagiotis Kanavos
                throw new ArgumentNullException("path");
744 cfed7823 Panagiotis Kanavos
            if (!Path.IsPathRooted(path))
745 cfed7823 Panagiotis Kanavos
                throw new ArgumentException("The path must be rooted", "path");
746 cfed7823 Panagiotis Kanavos
            Contract.EndContractBlock();
747 e81dd1f6 Panagiotis Kanavos
748 e81dd1f6 Panagiotis Kanavos
            _persistenceAgent.Post(() => DeleteDirect(path));   
749 e81dd1f6 Panagiotis Kanavos
        }
750 e81dd1f6 Panagiotis Kanavos
751 3c76f045 Panagiotis Kanavos
        /// <summary>
752 3c76f045 Panagiotis Kanavos
        /// Deletes the status of the specified folder and all its contents
753 3c76f045 Panagiotis Kanavos
        /// </summary>
754 3c76f045 Panagiotis Kanavos
        /// <param name="path"></param>
755 3c76f045 Panagiotis Kanavos
        public void ClearFolderStatus(string path)
756 3c76f045 Panagiotis Kanavos
        {
757 3c76f045 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(path))
758 3c76f045 Panagiotis Kanavos
                throw new ArgumentNullException("path");
759 3c76f045 Panagiotis Kanavos
            if (!Path.IsPathRooted(path))
760 3c76f045 Panagiotis Kanavos
                throw new ArgumentException("The path must be rooted", "path");
761 3c76f045 Panagiotis Kanavos
            Contract.EndContractBlock();
762 3c76f045 Panagiotis Kanavos
763 3c76f045 Panagiotis Kanavos
            _persistenceAgent.Post(() => DeleteFolderDirect(path));   
764 3c76f045 Panagiotis Kanavos
        }
765 3c76f045 Panagiotis Kanavos
766 3c76f045 Panagiotis Kanavos
        public IEnumerable<FileState> GetChildren(FileState fileState)
767 3c76f045 Panagiotis Kanavos
        {
768 3c76f045 Panagiotis Kanavos
            if (fileState == null)
769 3c76f045 Panagiotis Kanavos
                throw new ArgumentNullException("fileState");
770 3c76f045 Panagiotis Kanavos
            Contract.EndContractBlock();
771 3c76f045 Panagiotis Kanavos
772 3c76f045 Panagiotis Kanavos
            var children = from state in FileState.Queryable
773 3c76f045 Panagiotis Kanavos
                           where state.FilePath.StartsWith(fileState.FilePath + "\\")
774 3c76f045 Panagiotis Kanavos
                           select state;
775 3c76f045 Panagiotis Kanavos
            return children;
776 3c76f045 Panagiotis Kanavos
        }
777 3c76f045 Panagiotis Kanavos
778 174bbb6e Panagiotis Kanavos
        public void EnsureFileState(string path)
779 174bbb6e Panagiotis Kanavos
        {
780 174bbb6e Panagiotis Kanavos
            var existingState = GetStateByFilePath(path);
781 174bbb6e Panagiotis Kanavos
            if (existingState != null)
782 174bbb6e Panagiotis Kanavos
                return;
783 174bbb6e Panagiotis Kanavos
            var fileInfo = FileInfoExtensions.FromPath(path);
784 174bbb6e Panagiotis Kanavos
            using (new SessionScope())
785 174bbb6e Panagiotis Kanavos
            {
786 174bbb6e Panagiotis Kanavos
                var newState = FileState.CreateFor(fileInfo);
787 174bbb6e Panagiotis Kanavos
                newState.FileStatus=FileStatus.Missing;
788 174bbb6e Panagiotis Kanavos
                _persistenceAgent.PostAndAwait(newState.CreateAndFlush).Wait();
789 174bbb6e Panagiotis Kanavos
            }
790 174bbb6e Panagiotis Kanavos
791 174bbb6e Panagiotis Kanavos
        }
792 174bbb6e Panagiotis Kanavos
793 e81dd1f6 Panagiotis Kanavos
        private int DeleteDirect(string filePath)
794 e81dd1f6 Panagiotis Kanavos
        {
795 039a89e5 Panagiotis Kanavos
            using (log4net.ThreadContext.Stacks["StatusAgent"].Push("DeleteDirect"))
796 e81dd1f6 Panagiotis Kanavos
            {
797 e81dd1f6 Panagiotis Kanavos
798 039a89e5 Panagiotis Kanavos
                try
799 e81dd1f6 Panagiotis Kanavos
                {
800 e81dd1f6 Panagiotis Kanavos
801 039a89e5 Panagiotis Kanavos
                    
802 039a89e5 Panagiotis Kanavos
                    using (var connection = GetConnection())
803 039a89e5 Panagiotis Kanavos
                    {
804 3c76f045 Panagiotis Kanavos
                        var command = new SQLiteCommand("delete from FileState where FilePath = :path  COLLATE NOCASE",
805 3c76f045 Panagiotis Kanavos
                                                        connection);
806 3c76f045 Panagiotis Kanavos
807 3c76f045 Panagiotis Kanavos
                        command.Parameters.AddWithValue("path", filePath);
808 3c76f045 Panagiotis Kanavos
                        
809 3c76f045 Panagiotis Kanavos
                        var affected = command.ExecuteNonQuery();
810 3c76f045 Panagiotis Kanavos
                        return affected;
811 3c76f045 Panagiotis Kanavos
                    }
812 3c76f045 Panagiotis Kanavos
                }
813 3c76f045 Panagiotis Kanavos
                catch (Exception exc)
814 3c76f045 Panagiotis Kanavos
                {
815 3c76f045 Panagiotis Kanavos
                    Log.Error(exc.ToString());
816 3c76f045 Panagiotis Kanavos
                    throw;
817 3c76f045 Panagiotis Kanavos
                }
818 3c76f045 Panagiotis Kanavos
            }
819 3c76f045 Panagiotis Kanavos
        }
820 3c76f045 Panagiotis Kanavos
821 3c76f045 Panagiotis Kanavos
        private int DeleteFolderDirect(string filePath)
822 3c76f045 Panagiotis Kanavos
        {
823 3c76f045 Panagiotis Kanavos
            using (log4net.ThreadContext.Stacks["StatusAgent"].Push("DeleteDirect"))
824 3c76f045 Panagiotis Kanavos
            {
825 3c76f045 Panagiotis Kanavos
826 3c76f045 Panagiotis Kanavos
                try
827 3c76f045 Panagiotis Kanavos
                {
828 3c76f045 Panagiotis Kanavos
829 3c76f045 Panagiotis Kanavos
                    
830 3c76f045 Panagiotis Kanavos
                    using (var connection = GetConnection())
831 3c76f045 Panagiotis Kanavos
                    {
832 fe62b7f4 Panagiotis Kanavos
                        var command = new SQLiteCommand(@"delete from FileState where FilePath = :path or FilePath like :path || '\%'  COLLATE NOCASE",
833 039a89e5 Panagiotis Kanavos
                                                        connection);
834 039a89e5 Panagiotis Kanavos
835 3c76f045 Panagiotis Kanavos
                        command.Parameters.AddWithValue("path", filePath);
836 039a89e5 Panagiotis Kanavos
                        
837 039a89e5 Panagiotis Kanavos
                        var affected = command.ExecuteNonQuery();
838 039a89e5 Panagiotis Kanavos
                        return affected;
839 039a89e5 Panagiotis Kanavos
                    }
840 039a89e5 Panagiotis Kanavos
                }
841 039a89e5 Panagiotis Kanavos
                catch (Exception exc)
842 039a89e5 Panagiotis Kanavos
                {
843 039a89e5 Panagiotis Kanavos
                    Log.Error(exc.ToString());
844 039a89e5 Panagiotis Kanavos
                    throw;
845 e81dd1f6 Panagiotis Kanavos
                }
846 e81dd1f6 Panagiotis Kanavos
            }
847 0eea575a Panagiotis Kanavos
        }
848 0eea575a Panagiotis Kanavos
849 174bbb6e Panagiotis Kanavos
        public void UpdateFileChecksum(string path, string shortHash, string checksum)
850 cfed7823 Panagiotis Kanavos
        {
851 cfed7823 Panagiotis Kanavos
            if (String.IsNullOrWhiteSpace(path))
852 cfed7823 Panagiotis Kanavos
                throw new ArgumentNullException("path");
853 cfed7823 Panagiotis Kanavos
            if (!Path.IsPathRooted(path))
854 cfed7823 Panagiotis Kanavos
                throw new ArgumentException("The path must be rooted", "path");            
855 cfed7823 Panagiotis Kanavos
            Contract.EndContractBlock();
856 cfed7823 Panagiotis Kanavos
857 174bbb6e Panagiotis Kanavos
            _persistenceAgent.Post(() => FileState.UpdateChecksum(path, shortHash,checksum));
858 0eea575a Panagiotis Kanavos
        }
859 283809f3 Panagiotis Kanavos
860 bc27bb7e Panagiotis Kanavos
861 bc27bb7e Panagiotis Kanavos
        public void CleanupOrphanStates()
862 bc27bb7e Panagiotis Kanavos
        {
863 bc27bb7e Panagiotis Kanavos
            //Orphan states are those that do not correspond to an account, ie. their paths
864 bc27bb7e Panagiotis Kanavos
            //do not start with the root path of any registered account
865 bc27bb7e Panagiotis Kanavos
866 bc27bb7e Panagiotis Kanavos
            var roots=(from account in Settings.Accounts
867 bc27bb7e Panagiotis Kanavos
                      select account.RootPath).ToList();
868 bc27bb7e Panagiotis Kanavos
            
869 bc27bb7e Panagiotis Kanavos
            var allStates = from state in FileState.Queryable
870 bc27bb7e Panagiotis Kanavos
                select state.FilePath;
871 bc27bb7e Panagiotis Kanavos
872 bc27bb7e Panagiotis Kanavos
            foreach (var statePath in allStates)
873 bc27bb7e Panagiotis Kanavos
            {
874 bc27bb7e Panagiotis Kanavos
                if (!roots.Any(root=>statePath.StartsWith(root,StringComparison.InvariantCultureIgnoreCase)))
875 bc27bb7e Panagiotis Kanavos
                    this.DeleteDirect(statePath);
876 bc27bb7e Panagiotis Kanavos
            }
877 bc27bb7e Panagiotis Kanavos
        }
878 bc27bb7e Panagiotis Kanavos
879 bc27bb7e Panagiotis Kanavos
        public void CleanupStaleStates(AccountInfo accountInfo, List<ObjectInfo> objectInfos)
880 bc27bb7e Panagiotis Kanavos
        {
881 bc27bb7e Panagiotis Kanavos
            if (accountInfo == null)
882 bc27bb7e Panagiotis Kanavos
                throw new ArgumentNullException("accountInfo");
883 bc27bb7e Panagiotis Kanavos
            if (objectInfos == null)
884 bc27bb7e Panagiotis Kanavos
                throw new ArgumentNullException("objectInfos");
885 bc27bb7e Panagiotis Kanavos
            Contract.EndContractBlock();
886 bc27bb7e Panagiotis Kanavos
            
887 bc27bb7e Panagiotis Kanavos
888 bc27bb7e Panagiotis Kanavos
889 bc27bb7e Panagiotis Kanavos
            //Stale states are those that have no corresponding local or server file
890 97d149c1 pkanavos
            
891 bc27bb7e Panagiotis Kanavos
892 bc27bb7e Panagiotis Kanavos
            var agent=FileAgent.GetFileAgent(accountInfo);
893 bc27bb7e Panagiotis Kanavos
894 bc27bb7e Panagiotis Kanavos
            var localFiles=agent.EnumerateFiles();
895 bc27bb7e Panagiotis Kanavos
            var localSet = new HashSet<string>(localFiles);
896 bc27bb7e Panagiotis Kanavos
897 026a6c5a Panagiotis Kanavos
            //RelativeUrlToFilePath will fail for
898 026a6c5a Panagiotis Kanavos
            //infos of accounts, containers which have no Name
899 026a6c5a Panagiotis Kanavos
900 bc27bb7e Panagiotis Kanavos
            var serverFiles = from info in objectInfos
901 97d149c1 pkanavos
                              where info.Name != null
902 bc27bb7e Panagiotis Kanavos
                              select Path.Combine(accountInfo.AccountPath,info.RelativeUrlToFilePath(accountInfo.UserName));
903 bc27bb7e Panagiotis Kanavos
            var serverSet = new HashSet<string>(serverFiles);
904 bc27bb7e Panagiotis Kanavos
905 bc27bb7e Panagiotis Kanavos
            var allStates = from state in FileState.Queryable
906 bc27bb7e Panagiotis Kanavos
                            where state.FilePath.StartsWith(agent.RootPath)
907 bc27bb7e Panagiotis Kanavos
                            select state.FilePath;
908 bc27bb7e Panagiotis Kanavos
            var stateSet = new HashSet<string>(allStates);
909 bc27bb7e Panagiotis Kanavos
            stateSet.ExceptWith(serverSet);
910 bc27bb7e Panagiotis Kanavos
            stateSet.ExceptWith(localSet);
911 bc27bb7e Panagiotis Kanavos
912 bc27bb7e Panagiotis Kanavos
            foreach (var remainder in stateSet)
913 bc27bb7e Panagiotis Kanavos
            {
914 bc27bb7e Panagiotis Kanavos
                DeleteDirect(remainder);
915 bc27bb7e Panagiotis Kanavos
            }
916 bc27bb7e Panagiotis Kanavos
917 bc27bb7e Panagiotis Kanavos
            
918 bc27bb7e Panagiotis Kanavos
        }
919 283809f3 Panagiotis Kanavos
    }
920 5ce54458 Panagiotis Kanavos
921 5ce54458 Panagiotis Kanavos
   
922 0eea575a Panagiotis Kanavos
}