/// <summary> /// Tries to set the AccessedUtc of the specified file to the current date (just in memory, not on the filesystem). /// </summary> /// <param name="relativePath"></param> /// <returns></returns> public bool bumpDateIfExists(string relativePath) { relativePath = checkRelativePath(relativePath); lock (_sync) { int slash = relativePath.IndexOf('/'); if (slash < 0) { //Update the accessed date. CachedFileInfo old; if (files.TryGetValue(relativePath, out old)) { files[relativePath] = new CachedFileInfo(old, DateTime.UtcNow); } return(true); //We updated it! } else { //Try to access subfolder string folder = relativePath.Substring(0, slash); CachedFolder f = null; if (!folders.TryGetValue(folder, out f)) { return(false); //If the folder doesn't exist, quit } if (f == null) { return(false); //If the folder is null, quit! } //Recurse if possible return(f.bumpDateIfExists(relativePath.Substring(slash + 1))); } } }
/// <summary> /// Uses old.AccessedUtc if it is newer than FileInfo.LastAccessTimeUtc /// </summary> /// <param name="f"></param> /// <param name="old"></param> public CachedFileInfo(FileInfo f, CachedFileInfo old) { modifiedUtc = f.LastWriteTimeUtc; accessedUtc = f.LastAccessTimeUtc; if (old != null && accessedUtc < old.accessedUtc) accessedUtc = old.accessedUtc; //Use the larger value updatedUtc = f.CreationTimeUtc; }
/// <summary> /// Verifies the file exists before returning the cached data. /// Discrepancies in file existence result in OnFileDisappeard being fired. /// </summary> /// <param name="relativePath"></param> /// <param name="physicalPath"></param> /// <returns></returns> public virtual CachedFileInfo getFileInfoCertainExists(string relativePath, string physicalPath) { relativePath = checkRelativePath(relativePath); bool fireEvent = false; CachedFileInfo f = null; lock (_sync) { bool exists = System.IO.File.Exists(physicalPath); f = getCachedFileInfo(relativePath); //cache miss if (f == null && exists) { //on cache miss f = new CachedFileInfo(new System.IO.FileInfo(physicalPath)); //Populate cache setCachedFileInfo(relativePath, f); } //cache wrong, discrepancy. File deleted by external actor if (f != null && !exists) { f = null; clear(); //Clear the cache completely. fireEvent = true; } } //Fire the event outside of the lock. if (fireEvent && FileDisappeared != null) { FileDisappeared(relativePath, physicalPath); } return(f);//Null only if the file doesn't exist. }
public bool MeetsOverMaxCriteria(CachedFileInfo i) { DateTime now = DateTime.UtcNow; //Only require the 'used' date to comply if it 1) doesn't match created date and 2) is above 0 return((now.Subtract(i.AccessedUtc) > ProhibitRemovalIfUsedWithin || ProhibitRemovalIfUsedWithin <= new TimeSpan(0) || i.AccessedUtc == i.UpdatedUtc) && (now.Subtract(i.UpdatedUtc) > ProhibitRemovalIfCreatedWithin || ProhibitRemovalIfCreatedWithin <= new TimeSpan(0))); }
/// <summary> /// Uses old.AccessedUtc if it is newer than FileInfo.LastAccessTimeUtc /// </summary> /// <param name="f"></param> /// <param name="old"></param> public CachedFileInfo(FileInfo f, CachedFileInfo old) { modifiedUtc = f.LastWriteTimeUtc; accessedUtc = f.LastAccessTimeUtc; if (old != null && accessedUtc < old.accessedUtc) { accessedUtc = old.accessedUtc; //Use the larger value } updatedUtc = f.CreationTimeUtc; }
public bool modifiedDateMatchesCertainExists(DateTime utc, string relativePath, string physicalPath) { CachedFileInfo f = getFileInfoCertainExists(relativePath, physicalPath); if (f == null) { return(false); } return(roughCompare(f.ModifiedUtc, utc)); }
public bool ShouldRemove(string relativePath, CachedFileInfo info, bool isOverMax) { if (isOverMax) { return(MeetsOverMaxCriteria(info)); } else { return(MeetsCleanupCriteria(info)); } }
public void FlushAccessedDate(CleanupWorkItem item) { CachedFileInfo c = cache.Index.getCachedFileInfo(item.RelativePath); if (c == null) { return; //File was already deleted, nothing to do. } try{ File.SetLastAccessTimeUtc(item.PhysicalPath, c.AccessedUtc); //In both of these exception cases, we don't care. }catch (FileNotFoundException) { }catch (UnauthorizedAccessException) { } }
/// <summary> /// Gets a CachedFileInfo object for the file even if it isn't in the cache (falls back to the filesystem) /// </summary> /// <param name="relativePath"></param> /// <param name="physicalPath"></param> /// <returns></returns> public virtual CachedFileInfo getFileInfo(string relativePath, string physicalPath) { relativePath = checkRelativePath(relativePath); lock (_sync) { CachedFileInfo f = getCachedFileInfo(relativePath); //On cache miss or no file if (f == null && System.IO.File.Exists(physicalPath)) { //on cache miss f = new CachedFileInfo(new System.IO.FileInfo(physicalPath)); //Populate cache setCachedFileInfo(relativePath, f); } return(f);//Null only if the file doesn't exist. } }
/// <summary> /// Sets the CachedFileInfo object for the specified path, creating any needed folders along the way. /// If 'null', the item will be removed, and no missing folder will be created. /// </summary> /// <param name="relativePath"></param> /// <param name="info"></param> public virtual void setCachedFileInfo(string relativePath, CachedFileInfo info) { relativePath = checkRelativePath(relativePath); lock (_sync) { int slash = relativePath.IndexOf('/'); if (slash < 0) { //Set or remove the file if (info == null) { files.Remove(relativePath); } else { files[relativePath] = info; } } else { //Try to access subfolder string folder = relativePath.Substring(0, slash); CachedFolder f; if (!folders.TryGetValue(folder, out f)) { f = null; } if (info == null && f == null) { return; //If the folder doesn't exist, the file definitely doesn't. Already accomplished. } //Create it if it doesn't exist if (f == null) { f = folders[folder] = new CachedFolder(); } //Recurse if possible f.setCachedFileInfo(relativePath.Substring(slash + 1), info); } } }
/// <summary> /// Updates the 'files' dictionary to match the files that exist on disk. Uses the accessedUtc values from the previous dictionary if they are newer. /// </summary> /// <param name="relativePath"></param> /// <param name="physicalPath"></param> protected void populateFiles(string relativePath, string physicalPath) { relativePath = checkRelativePath(relativePath); string[] physicalFiles = null; try { physicalFiles = System.IO.Directory.GetFiles(physicalPath); } catch (DirectoryNotFoundException) { physicalFiles = new string[] { }; //Pretend it's empty. We don't care, the next recursive will get rid of it. } Dictionary <string, CachedFileInfo> newFiles = new Dictionary <string, CachedFileInfo>(physicalFiles.Length, KeyComparer); CachedFolder f = getOrCreateFolder(relativePath, true); foreach (string s in physicalFiles) { string local = s.Substring(s.LastIndexOf(System.IO.Path.DirectorySeparatorChar) + 1); //Todo, add a callback that handles exclusion of files if (local.EndsWith(".config", StringComparison.OrdinalIgnoreCase)) { continue; } if (local.StartsWith(".")) { continue; //Skip files that start with a period } //What did we have on file? CachedFileInfo old = null; lock (_sync) { if (!f.files.TryGetValue(relativePath, out old)) { old = null; } } newFiles[local] = new CachedFileInfo(new FileInfo(s), old); } lock (_sync) { f.files = newFiles; } }
/// <summary> /// Sets the CachedFileInfo object for the specified path, creating any needed folders along the way. /// If 'null', the item will be removed, and no missing folder will be created. /// </summary> /// <param name="relativePath"></param> /// <param name="info"></param> public virtual void setCachedFileInfo(string relativePath, CachedFileInfo info) { relativePath = checkRelativePath(relativePath); lock (_sync) { int slash = relativePath.IndexOf('/'); if (slash < 0) { //Set or remove the file if (info == null) files.Remove(relativePath); else files[relativePath] = info; } else { //Try to access subfolder string folder = relativePath.Substring(0, slash); CachedFolder f; if (!folders.TryGetValue(folder, out f)) f = null; if (info == null && f == null) return; //If the folder doesn't exist, the file definitely doesn't. Already accomplished. //Create it if it doesn't exist if (f == null) f = folders[folder] = new CachedFolder(); //Recurse if possible f.setCachedFileInfo(relativePath.Substring(slash + 1), info); } } }
public CachedFileInfo(CachedFileInfo f, DateTime accessedDate) { this.modifiedUtc = f.modifiedUtc; this.updatedUtc = f.updatedUtc; this.accessedUtc = accessedDate; }
/// <summary> /// Tries to set the AccessedUtc of the specified file to the current date (just in memory, not on the filesystem). /// </summary> /// <param name="relativePath"></param> /// <returns></returns> public bool bumpDateIfExists(string relativePath) { relativePath = checkRelativePath(relativePath); lock (_sync) { int slash = relativePath.IndexOf('/'); if (slash < 0) { //Update the accessed date. CachedFileInfo old; if (files.TryGetValue(relativePath,out old)) files[relativePath] = new CachedFileInfo(old, DateTime.UtcNow); return true; //We updated it! } else { //Try to access subfolder string folder = relativePath.Substring(0, slash); CachedFolder f = null; if (!folders.TryGetValue(folder, out f)) return false;//If the folder doesn't exist, quit if (f == null) return false; //If the folder is null, quit! //Recurse if possible return f.bumpDateIfExists(relativePath.Substring(slash + 1)); } } }
public bool MeetsOverMaxCriteria(CachedFileInfo i) { DateTime now = DateTime.UtcNow; //Only require the 'used' date to comply if it 1) doesn't match created date and 2) is above 0 return ((now.Subtract(i.AccessedUtc) > ProhibitRemovalIfUsedWithin || ProhibitRemovalIfUsedWithin <= new TimeSpan(0) || i.AccessedUtc == i.UpdatedUtc) && (now.Subtract(i.UpdatedUtc) > ProhibitRemovalIfCreatedWithin || ProhibitRemovalIfCreatedWithin <= new TimeSpan(0))); }
/// <summary> /// Verifies the file exists before returning the cached data. /// Discrepancies in file existence result in OnFileDisappeard being fired. /// </summary> /// <param name="relativePath"></param> /// <param name="physicalPath"></param> /// <returns></returns> public virtual CachedFileInfo getFileInfoCertainExists(string relativePath, string physicalPath) { relativePath = checkRelativePath(relativePath); bool fireEvent = false; CachedFileInfo f = null; lock (_sync) { bool exists = System.IO.File.Exists(physicalPath); f = getCachedFileInfo(relativePath); //cache miss if (f == null && exists) { //on cache miss f = new CachedFileInfo(new System.IO.FileInfo(physicalPath)); //Populate cache setCachedFileInfo(relativePath, f); } //cache wrong, discrepancy. File deleted by external actor if (f != null && !exists) { f = null; clear(); //Clear the cache completely. fireEvent = true; } } //Fire the event outside of the lock. if (fireEvent && FileDisappeared != null) FileDisappeared(relativePath, physicalPath); return f;//Null only if the file doesn't exist. }
/// <summary> /// Gets a CachedFileInfo object for the file even if it isn't in the cache (falls back to the filesystem) /// </summary> /// <param name="relativePath"></param> /// <param name="physicalPath"></param> /// <returns></returns> public virtual CachedFileInfo getFileInfo(string relativePath, string physicalPath) { relativePath = checkRelativePath(relativePath); lock (_sync) { CachedFileInfo f = getCachedFileInfo(relativePath); //On cache miss or no file if (f == null && System.IO.File.Exists(physicalPath)) { //on cache miss f = new CachedFileInfo(new System.IO.FileInfo(physicalPath)); //Populate cache setCachedFileInfo(relativePath, f); } return f;//Null only if the file doesn't exist. } }
public bool ShouldRemove(string relativePath, CachedFileInfo info, bool isOverMax) { if (isOverMax) return MeetsOverMaxCriteria(info); else return MeetsCleanupCriteria(info); }
/// <summary> /// Updates the 'files' dictionary to match the files that exist on disk. Uses the accessedUtc values from the previous dictionary if they are newer. /// </summary> /// <param name="relativePath"></param> /// <param name="physicalPath"></param> protected void populateFiles(string relativePath, string physicalPath) { relativePath = checkRelativePath(relativePath); string[] physicalFiles = null; try { physicalFiles = System.IO.Directory.GetFiles(physicalPath); } catch (DirectoryNotFoundException) { physicalFiles = new string[] { }; //Pretend it's empty. We don't care, the next recursive will get rid of it. } Dictionary<string, CachedFileInfo> newFiles = new Dictionary<string, CachedFileInfo>(physicalFiles.Length, KeyComparer); CachedFolder f = getOrCreateFolder(relativePath, true); foreach (string s in physicalFiles) { string local = s.Substring(s.LastIndexOf(System.IO.Path.DirectorySeparatorChar) + 1); //Todo, add a callback that handles exclusion of files if (local.EndsWith(".config", StringComparison.OrdinalIgnoreCase)) continue; if (local.StartsWith(".")) continue; //Skip files that start with a period //What did we have on file? CachedFileInfo old = null; lock (_sync) { if (!f.files.TryGetValue(relativePath, out old)) old = null; } newFiles[local] = new CachedFileInfo(new FileInfo(s), old); } lock (_sync) { f.files = newFiles; } }