Skip to content
This repository has been archived by the owner on Nov 6, 2018. It is now read-only.

Commit

Permalink
Modify PollingWildCardChangeToken to include the timestamp of the files
Browse files Browse the repository at this point in the history
Fixes #238
  • Loading branch information
pranavkm committed Sep 30, 2016
1 parent 204821f commit 9d60f64
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@ public class PollingWildCardChangeToken : IChangeToken
{
// Internal for unit testing.
internal static readonly TimeSpan DefaultPollingInterval = TimeSpan.FromSeconds(4);
private static readonly byte[] Separator = Encoding.Unicode.GetBytes("|");
private readonly object _enumerationLock = new object();
private readonly DirectoryInfoBase _directoryInfo;
private readonly Matcher _matcher;
private bool _changed;
private DateTime? _lastScanTimeUtc;
private byte[] _fileNameBuffer;
private byte[] _byteBuffer;
private byte[] _previousHash;

/// <summary>
Expand Down Expand Up @@ -100,14 +101,15 @@ private bool CalculateChanges()
{
foreach (var file in files)
{
if (_lastScanTimeUtc != null && _lastScanTimeUtc < GetLastWriteUtc(file.Path))
var lastWriteTimeUtc = GetLastWriteUtc(file.Path);
if (_lastScanTimeUtc != null && _lastScanTimeUtc < lastWriteTimeUtc)
{
// _lastScanTimeUtc is the greatest timestamp that any last writes could have been.
// If a file has a newer timestamp than this value, it must've changed.
return true;
}

ComputeHash(sha256, file.Path);
ComputeHash(sha256, file.Path, lastWriteTimeUtc);
}

var currentHash = sha256.GetHashAndReset();
Expand Down Expand Up @@ -153,16 +155,28 @@ private static bool ArrayEquals(byte[] previousHash, byte[] currentHash)
return true;
}

private void ComputeHash(IncrementalHash sha256, string path)
private void ComputeHash(IncrementalHash sha256, string path, DateTime lastChangedUtc)
{
var byteCount = Encoding.Unicode.GetByteCount(path);
if (_fileNameBuffer == null || byteCount > _fileNameBuffer.Length)
if (_byteBuffer == null || byteCount > _byteBuffer.Length)
{
_fileNameBuffer = new byte[Math.Max(byteCount, 256)];
_byteBuffer = new byte[Math.Max(byteCount, 256)];
}

var length = Encoding.Unicode.GetBytes(path, 0, path.Length, _fileNameBuffer, 0);
sha256.AppendData(_fileNameBuffer, 0, length);
var length = Encoding.Unicode.GetBytes(path, 0, path.Length, _byteBuffer, 0);
sha256.AppendData(_byteBuffer, 0, length);
sha256.AppendData(Separator, 0, Separator.Length);

Debug.Assert(_byteBuffer.Length > sizeof(long));
unsafe
{
fixed (byte* b = _byteBuffer)
{
*((long*)b) = lastChangedUtc.Ticks;
}
}
sha256.AppendData(_byteBuffer, 0, sizeof(long));
sha256.AppendData(Separator, 0, Separator.Length);
}

IDisposable IChangeToken.RegisterChangeCallback(Action<object> callback, object state) =>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"version": "1.1.0-*",
"buildOptions": {
"allowUnsafe": true,
"warningsAsErrors": true,
"keyFile": "../../tools/Key.snk",
"xmlDoc": true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,34 @@ public void HasChanged_ReturnsTrueIfFilesWereModified()
Assert.True(result2);
}

[Fact]
public void HasChanged_ReturnsTrueIfFileWasModifiedButRetainedAnOlderTimestamp()
{
// Arrange
var filePath1 = "1.txt";
var filePath2 = "2.txt";
var directoryInfo = new Mock<DirectoryInfoBase>();
directoryInfo.Setup(d => d.EnumerateFileSystemInfos())
.Returns(new[] { CreateFile(filePath1), CreateFile(filePath2) });
var clock = new TestClock();
var token = new TestablePollingWildCardChangeToken(directoryInfo.Object, "**/*.txt", clock);

// Act - 1
clock.Increment();
var result1 = token.HasChanged;

// Assert - 1
Assert.False(result1);

// Act - 2
token.FileTimestampLookup[filePath2] = clock.UtcNow.AddMilliseconds(-100);
clock.Increment();
var result2 = token.HasChanged;

// Assert - 2
Assert.True(result2);
}

private static FileInfoBase CreateFile(string filePath)
{
var fileInfo = new Mock<FileInfoBase>();
Expand Down

0 comments on commit 9d60f64

Please sign in to comment.