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 | } |