/// <summary> /// Loads previous versions stored from the specified file path. /// </summary> /// <param name="filePath">The file path.</param> /// <returns>FileVersionTracker.</returns> public static FileVersionTracker Load(string filePath) { // Try to compact it before using it FileVersionStorage.Compact(filePath); bool isFirstPass = true; while (true) { FileStream fileStream = null; // Try to open the file, if we get an exception, this might be due only because someone is locking the file to // save it while we are trying to open it const int RetryOpenFileStream = 20; var random = new Random(); for (int i = 0; i < RetryOpenFileStream; i++) { try { fileStream = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite); break; } catch (Exception) { if ((i + 1) == RetryOpenFileStream) { throw; } Thread.Sleep(50 + random.Next(100)); } } var tracker = new FileVersionTracker(fileStream); try { tracker.storage.LoadNewValues(); return(tracker); } catch (Exception) { // If an exception occurred, we are going to try to recover from it by reseting it. // reset file length to 0 fileStream.SetLength(0); tracker.Dispose(); if (!isFirstPass) { throw; } } isFirstPass = false; } }
/// <summary> /// Compacts the specified storage path. /// </summary> /// <param name="storagePath">The storage path.</param> /// <returns><c>true</c> if the storage path was successfully compacted, <c>false</c> otherwise.</returns> public static bool Compact(string storagePath) { FileStream fileStreamExclusive; try { fileStreamExclusive = new FileStream(storagePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None); } catch (Exception) { return(false); } try { using (var localTracker = new FileVersionStorage(fileStreamExclusive) { UseTransaction = true, AutoLoadNewValues = false }) { localTracker.LoadNewValues(); var latestVersion = new Dictionary <string, KeyValuePair <FileVersionKey, ObjectId> >(StringComparer.OrdinalIgnoreCase); foreach (var keyValue in localTracker.GetValues()) { var filePath = keyValue.Key.Path; KeyValuePair <FileVersionKey, ObjectId> previousKeyValue; if (!latestVersion.TryGetValue(filePath, out previousKeyValue) || keyValue.Key.LastModifiedDate > previousKeyValue.Key.LastModifiedDate) { latestVersion[filePath] = keyValue; } } localTracker.Reset(); localTracker.AddValues(latestVersion.Values); localTracker.Save(); } } catch (Exception) { return(false); } return(true); }
/// <summary> /// Initializes a new instance of the <see cref="FileVersionTracker"/> class. /// </summary> /// <param name="stream">The stream.</param> public FileVersionTracker(Stream stream) { storage = new FileVersionStorage(stream); locks = new Dictionary <FileVersionKey, object>(); }