Revision 174bbb6e trunk/Pithos.Core/Agents/StatusAgent.cs
b/trunk/Pithos.Core/Agents/StatusAgent.cs | ||
---|---|---|
48 | 48 |
using System.IO; |
49 | 49 |
using System.Linq; |
50 | 50 |
using System.Reflection; |
51 |
using System.Security.Cryptography; |
|
51 | 52 |
using System.Text; |
52 | 53 |
using System.Threading; |
53 | 54 |
using System.Threading.Tasks; |
54 | 55 |
using Castle.ActiveRecord; |
56 |
using Castle.ActiveRecord.Framework; |
|
55 | 57 |
using Castle.ActiveRecord.Framework.Config; |
56 | 58 |
using Pithos.Interfaces; |
57 | 59 |
using Pithos.Network; |
... | ... | |
185 | 187 |
{ |
186 | 188 |
Log.ErrorFormat("[ERROR] STATE \n{0}", ex); |
187 | 189 |
} |
190 |
queue.NotifyComplete(action); |
|
188 | 191 |
// ReSharper disable AccessToModifiedClosure |
189 | 192 |
queue.DoAsync(loop); |
190 | 193 |
// ReSharper restore AccessToModifiedClosure |
... | ... | |
201 | 204 |
{ |
202 | 205 |
_persistenceAgent.Stop(); |
203 | 206 |
} |
204 |
|
|
207 |
|
|
205 | 208 |
|
206 | 209 |
public void ProcessExistingFiles(IEnumerable<FileInfo> existingFiles) |
207 | 210 |
{ |
... | ... | |
230 | 233 |
where missingStates.Contains(state.Id) |
231 | 234 |
select new { File = default(FileInfo), State = state }; |
232 | 235 |
|
233 |
var pairs = currentFiles.Union(deletedFiles); |
|
236 |
var pairs = currentFiles.Union(deletedFiles).ToList();
|
|
234 | 237 |
|
235 |
foreach(var pair in pairs)
|
|
238 |
using (var shortHasher = HashAlgorithm.Create("sha1"))
|
|
236 | 239 |
{ |
237 |
var fileState = pair.State; |
|
238 |
var file = pair.File; |
|
239 |
if (fileState == null) |
|
240 |
{ |
|
241 |
//This is a new file |
|
242 |
var fullPath = pair.File.FullName; |
|
243 |
var createState = FileState.CreateForAsync(fullPath, BlockSize, BlockHash); |
|
244 |
createState.ContinueWith(state => _persistenceAgent.Post(state.Result.Create)); |
|
245 |
} |
|
246 |
else if (file == null) |
|
240 |
foreach (var pair in pairs) |
|
247 | 241 |
{ |
248 |
//This file was deleted while we were down. We should mark it as deleted |
|
249 |
//We have to go through UpdateStatus here because the state object we are using |
|
250 |
//was created by a different ORM session. |
|
251 |
_persistenceAgent.Post(()=> UpdateStatusDirect(fileState.Id, FileStatus.Deleted)); |
|
252 |
} |
|
253 |
else |
|
254 |
{ |
|
255 |
//This file has a matching state. Need to check for possible changes |
|
256 |
var hashString = file.CalculateHash(BlockSize,BlockHash); |
|
257 |
//TODO: Need a way to attach the hashes to the filestate so we don't |
|
258 |
//recalculate them each time a call to calculate has is made |
|
259 |
//We can either store them to the filestate or add them to a |
|
260 |
//dictionary |
|
261 |
|
|
262 |
//If the hashes don't match the file was changed |
|
263 |
if (fileState.Checksum != hashString) |
|
242 |
var fileState = pair.State; |
|
243 |
var file = pair.File; |
|
244 |
if (fileState == null) |
|
264 | 245 |
{ |
265 |
_persistenceAgent.Post(() => UpdateStatusDirect(fileState.Id, FileStatus.Modified)); |
|
266 |
} |
|
246 |
//This is a new file |
|
247 |
var createState = FileState.CreateFor(file); |
|
248 |
_persistenceAgent.Post(createState.Create); |
|
249 |
} |
|
250 |
else if (file == null) |
|
251 |
{ |
|
252 |
//This file was deleted while we were down. We should mark it as deleted |
|
253 |
//We have to go through UpdateStatus here because the state object we are using |
|
254 |
//was created by a different ORM session. |
|
255 |
_persistenceAgent.Post(() => UpdateStatusDirect(fileState.Id, FileStatus.Deleted)); |
|
256 |
} |
|
257 |
else |
|
258 |
{ |
|
259 |
//This file has a matching state. Need to check for possible changes |
|
260 |
//To check for changes, we use the cheap (in CPU terms) SHA1 algorithm |
|
261 |
//on the entire file. |
|
262 |
|
|
263 |
var hashString = file.ComputeShortHash(shortHasher); |
|
264 |
//TODO: Need a way to attach the hashes to the filestate so we don't |
|
265 |
//recalculate them each time a call to calculate has is made |
|
266 |
//We can either store them to the filestate or add them to a |
|
267 |
//dictionary |
|
268 |
|
|
269 |
//If the hashes don't match the file was changed |
|
270 |
if (fileState.ShortHash != hashString) |
|
271 |
{ |
|
272 |
_persistenceAgent.Post(() => UpdateStatusDirect(fileState.Id, FileStatus.Modified)); |
|
273 |
} |
|
274 |
} |
|
267 | 275 |
} |
268 |
}; |
|
276 |
} |
|
277 |
|
|
269 | 278 |
|
270 | 279 |
} |
280 |
|
|
281 |
|
|
271 | 282 |
|
272 | 283 |
private int UpdateStatusDirect(Guid id, FileStatus status) |
273 | 284 |
{ |
... | ... | |
387 | 398 |
|
388 | 399 |
} |
389 | 400 |
|
390 |
private PithosStatus _pithosStatus=PithosStatus.InSynch; |
|
391 |
|
|
392 |
public void SetPithosStatus(PithosStatus status) |
|
393 |
{ |
|
394 |
_pithosStatus = status; |
|
395 |
} |
|
396 |
|
|
397 |
public PithosStatus GetPithosStatus() |
|
398 |
{ |
|
399 |
return _pithosStatus; |
|
400 |
} |
|
401 | 401 |
|
402 | 402 |
|
403 | 403 |
private readonly string _pithosDataPath; |
... | ... | |
415 | 415 |
{ |
416 | 416 |
|
417 | 417 |
using (var connection = GetConnection()) |
418 |
using (var command = new SQLiteCommand("select Id, FilePath, OverlayStatus,FileStatus ,Checksum ,Version ,VersionTimeStamp,IsShared ,SharedBy ,ShareWrite from FileState where FilePath=:path COLLATE NOCASE", connection))
|
|
418 |
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))
|
|
419 | 419 |
{ |
420 | 420 |
|
421 | 421 |
command.Parameters.AddWithValue("path", path); |
... | ... | |
433 | 433 |
OverlayStatus =reader.IsDBNull(2)?FileOverlayStatus.Unversioned: (FileOverlayStatus) reader.GetInt64(2), |
434 | 434 |
FileStatus = reader.IsDBNull(3)?FileStatus.Missing:(FileStatus) reader.GetInt64(3), |
435 | 435 |
Checksum = reader.IsDBNull(4)?"":reader.GetString(4), |
436 |
Version = reader.IsDBNull(5)?default(long):reader.GetInt64(5), |
|
437 |
VersionTimeStamp = reader.IsDBNull(6)?default(DateTime):reader.GetDateTime(6), |
|
438 |
IsShared = !reader.IsDBNull(7) && reader.GetBoolean(7), |
|
439 |
SharedBy = reader.IsDBNull(8)?"":reader.GetString(8), |
|
440 |
ShareWrite = !reader.IsDBNull(9) && reader.GetBoolean(9) |
|
436 |
ShortHash= reader.IsDBNull(5)?"":reader.GetString(5), |
|
437 |
Version = reader.IsDBNull(6)?default(long):reader.GetInt64(6), |
|
438 |
VersionTimeStamp = reader.IsDBNull(7)?default(DateTime):reader.GetDateTime(7), |
|
439 |
IsShared = !reader.IsDBNull(8) && reader.GetBoolean(8), |
|
440 |
SharedBy = reader.IsDBNull(9)?"":reader.GetString(9), |
|
441 |
ShareWrite = !reader.IsDBNull(10) && reader.GetBoolean(10) |
|
441 | 442 |
}; |
442 | 443 |
/* |
443 | 444 |
var state = new FileState |
... | ... | |
518 | 519 |
return connection; |
519 | 520 |
} |
520 | 521 |
|
521 |
public void SetFileOverlayStatus(string path, FileOverlayStatus overlayStatus) |
|
522 |
/* public void SetFileOverlayStatus(string path, FileOverlayStatus overlayStatus)
|
|
522 | 523 |
{ |
523 | 524 |
if (String.IsNullOrWhiteSpace(path)) |
524 | 525 |
throw new ArgumentNullException("path"); |
... | ... | |
527 | 528 |
Contract.EndContractBlock(); |
528 | 529 |
|
529 | 530 |
_persistenceAgent.Post(() => FileState.StoreOverlayStatus(path,overlayStatus)); |
531 |
}*/ |
|
532 |
|
|
533 |
public Task SetFileOverlayStatus(string path, FileOverlayStatus overlayStatus, string shortHash = null) |
|
534 |
{ |
|
535 |
if (String.IsNullOrWhiteSpace(path)) |
|
536 |
throw new ArgumentNullException("path"); |
|
537 |
if (!Path.IsPathRooted(path)) |
|
538 |
throw new ArgumentException("The path must be rooted","path"); |
|
539 |
Contract.EndContractBlock(); |
|
540 |
|
|
541 |
return _persistenceAgent.PostAndAwait(() => FileState.StoreOverlayStatus(path,overlayStatus,shortHash)); |
|
530 | 542 |
} |
531 | 543 |
|
532 | 544 |
/* public void RenameFileOverlayStatus(string oldPath, string newPath) |
... | ... | |
627 | 639 |
else |
628 | 640 |
{ |
629 | 641 |
command.CommandText = |
630 |
"INSERT INTO FileState (Id,FilePath,Checksum,Version,VersionTimeStamp,FileStatus,OverlayStatus) VALUES (:id,:path,:checksum,:version,:versionTimeStamp,:fileStatus,:overlayStatus)";
|
|
642 |
"INSERT INTO FileState (Id,FilePath,Checksum,Version,VersionTimeStamp,ShortHash,FileStatus,OverlayStatus) VALUES (:id,:path,:checksum,:version,:versionTimeStamp,:shortHash,:fileStatus,:overlayStatus)";
|
|
631 | 643 |
command.Parameters.AddWithValue("id", Guid.NewGuid()); |
632 | 644 |
} |
633 | 645 |
|
634 | 646 |
command.Parameters.AddWithValue("path", path); |
635 | 647 |
command.Parameters.AddWithValue("checksum", objectInfo.Hash); |
648 |
command.Parameters.AddWithValue("shortHash", ""); |
|
636 | 649 |
command.Parameters.AddWithValue("version", objectInfo.Version); |
637 | 650 |
command.Parameters.AddWithValue("versionTimeStamp", |
638 | 651 |
objectInfo.VersionTimestamp); |
... | ... | |
736 | 749 |
return children; |
737 | 750 |
} |
738 | 751 |
|
752 |
public void EnsureFileState(string path) |
|
753 |
{ |
|
754 |
var existingState = GetStateByFilePath(path); |
|
755 |
if (existingState != null) |
|
756 |
return; |
|
757 |
var fileInfo = FileInfoExtensions.FromPath(path); |
|
758 |
using (new SessionScope()) |
|
759 |
{ |
|
760 |
var newState = FileState.CreateFor(fileInfo); |
|
761 |
newState.FileStatus=FileStatus.Missing; |
|
762 |
_persistenceAgent.PostAndAwait(newState.CreateAndFlush).Wait(); |
|
763 |
} |
|
764 |
|
|
765 |
} |
|
766 |
|
|
739 | 767 |
private int DeleteDirect(string filePath) |
740 | 768 |
{ |
741 | 769 |
using (log4net.ThreadContext.Stacks["StatusAgent"].Push("DeleteDirect")) |
... | ... | |
792 | 820 |
} |
793 | 821 |
} |
794 | 822 |
|
795 |
public void UpdateFileChecksum(string path, string checksum) |
|
823 |
public void UpdateFileChecksum(string path, string shortHash, string checksum)
|
|
796 | 824 |
{ |
797 | 825 |
if (String.IsNullOrWhiteSpace(path)) |
798 | 826 |
throw new ArgumentNullException("path"); |
... | ... | |
800 | 828 |
throw new ArgumentException("The path must be rooted", "path"); |
801 | 829 |
Contract.EndContractBlock(); |
802 | 830 |
|
803 |
_persistenceAgent.Post(() => FileState.UpdateChecksum(path, checksum)); |
|
831 |
_persistenceAgent.Post(() => FileState.UpdateChecksum(path, shortHash,checksum));
|
|
804 | 832 |
} |
805 | 833 |
|
806 | 834 |
} |
Also available in: Unified diff