in src/Utilities/TrackedDependencies/FlatTrackingData.cs [400:554]
private void ConstructFileTable()
{
string tLogRootingMarker = null;
try
{
// construct a rooting marker from the tlog files
tLogRootingMarker = DependencyTableCache.FormatNormalizedTlogRootingMarker(_tlogFiles);
}
catch (ArgumentException e)
{
FileTracker.LogWarningWithCodeFromResources(_log, "Tracking_RebuildingDueToInvalidTLog", e.Message);
return;
}
if (!_tlogsAvailable)
{
lock (DependencyTableCache.DependencyTable)
{
// The tracking logs are not available, they may have been deleted at some point.
// Be safe and remove any references from the cache.
if (DependencyTableCache.DependencyTable.ContainsKey(tLogRootingMarker))
{
DependencyTableCache.DependencyTable.Remove(tLogRootingMarker);
}
}
return;
}
DependencyTableCacheEntry cachedEntry = null;
lock (DependencyTableCache.DependencyTable)
{
// Look in the dependency table cache to see if its available and up to date
cachedEntry = DependencyTableCache.GetCachedEntry(tLogRootingMarker);
}
// We have an up to date cached entry
if (cachedEntry != null)
{
_dependencyTable = (IDictionary<string, DateTime>)cachedEntry.DependencyTable;
// We may have stored the dependency table in the cache, but all the other information
// (newest file time, number of missing files, etc.) has been reset to default. Refresh
// the data.
this.UpdateFileEntryDetails();
// Log information about what we're using
FileTracker.LogMessageFromResources(_log, MessageImportance.Low, "Tracking_TrackingCached");
foreach (ITaskItem tlogItem in cachedEntry.TlogFiles)
{
FileTracker.LogMessage(_log, MessageImportance.Low, "\t{0}", tlogItem.ItemSpec);
}
return;
}
FileTracker.LogMessageFromResources(_log, MessageImportance.Low, "Tracking_TrackingLogs");
// Now we need to construct the rest of the table from the TLOG files
// If there are any errors in the tlogs, we want to warn, stop parsing tlogs, and empty
// out the dependency table, essentially forcing a rebuild.
bool encounteredInvalidTLogContents = false;
bool exceptionCaught = false;
string invalidTLogName = null;
foreach (ITaskItem tlogFileName in _tlogFiles)
{
try
{
FileTracker.LogMessage(_log, MessageImportance.Low, "\t{0}", tlogFileName.ItemSpec);
DateTime tlogLastWriteTimeUtc = NativeMethodsShared.GetLastWriteFileUtcTime(tlogFileName.ItemSpec);
if (tlogLastWriteTimeUtc > _newestTLogTimeUtc)
{
_newestTLogTimeUtc = tlogLastWriteTimeUtc;
_newestTLogFileName = tlogFileName.ItemSpec;
}
using (StreamReader tlog = File.OpenText(tlogFileName.ItemSpec))
{
string tlogEntry = tlog.ReadLine();
while (tlogEntry != null)
{
if (tlogEntry.Length == 0) // empty lines are a sign that something has gone wrong
{
encounteredInvalidTLogContents = true;
invalidTLogName = tlogFileName.ItemSpec;
break;
}
// Preprocessing for the line entry
else if (tlogEntry[0] == '#') // a comment marker should be skipped
{
tlogEntry = tlog.ReadLine();
continue;
}
else if (tlogEntry[0] == '^' && TreatRootMarkersAsEntries && tlogEntry.IndexOf('|') < 0) // This is a rooting non composite record, and we should keep it
{
tlogEntry = tlogEntry.Substring(1);
if (tlogEntry.Length == 0)
{
encounteredInvalidTLogContents = true;
invalidTLogName = tlogFileName.ItemSpec;
break;
}
}
else if (tlogEntry[0] == '^') // root marker is not being treated as an entry, skip it
{
tlogEntry = tlog.ReadLine();
continue;
}
// If we haven't seen this file before, then record it
if (!_dependencyTable.ContainsKey(tlogEntry))
{
// It may be that this is one of the locations that we should ignore
if (!FileTracker.FileIsExcludedFromDependencies(tlogEntry))
{
RecordEntryDetails(tlogEntry, true);
}
}
tlogEntry = tlog.ReadLine();
}
}
}
catch (Exception e) when (ExceptionHandling.IsIoRelatedException(e))
{
FileTracker.LogWarningWithCodeFromResources(_log, "Tracking_RebuildingDueToInvalidTLog", e.Message);
break;
}
if (encounteredInvalidTLogContents)
{
FileTracker.LogWarningWithCodeFromResources(_log, "Tracking_RebuildingDueToInvalidTLogContents", invalidTLogName);
break;
}
}
lock (DependencyTableCache.DependencyTable)
{
// There were problems with the tracking logs -- we've already warned or errored; now we want to make
// sure that we essentially force a rebuild of this particular root.
if (encounteredInvalidTLogContents || exceptionCaught)
{
if (DependencyTableCache.DependencyTable.ContainsKey(tLogRootingMarker))
{
DependencyTableCache.DependencyTable.Remove(tLogRootingMarker);
}
_dependencyTable = new Dictionary<string, DateTime>(StringComparer.OrdinalIgnoreCase);
}
else
{
// Record the newly built dependency table in the cache
DependencyTableCache.DependencyTable[tLogRootingMarker] = new DependencyTableCacheEntry(_tlogFiles, (IDictionary)_dependencyTable);
}
}
}