private List <LogInfo> LoadLinks(BackgroundWorker worker) { List <LogInfo> logs = new List <LogInfo>(32); List <int> removeIdxs = new List <int>(); // Doing this will consume memory, but also greatly increase performance. DB_ScriptCache[] cacheDB = null; if (scriptCache != null) { cacheDB = scriptCache.Table <DB_ScriptCache>().Where(x => true).ToArray(); } var links = allProjectScripts.Where(x => x.Type == ScriptType.Link); Debug.Assert(links.Count(x => x.IsDirLink) == 0); Task[] tasks = links.Select(p => { return(Task.Run(() => { Script link = null; bool valid = false; int cached = 2; try { do { string linkPath = p.Sections["Main"].IniDict["Link"]; string linkFullPath = Path.Combine(baseDir, linkPath); if (File.Exists(linkFullPath) == false) // Invalid link { break; } // Load .link's linked scripts with cache if (scriptCache != null) { // Case of ScriptCache enabled FileInfo f = new FileInfo(linkFullPath); DB_ScriptCache pCache = cacheDB.FirstOrDefault(x => x.Hash == linkPath.GetHashCode()); if (pCache != null && pCache.Path.Equals(linkPath, StringComparison.Ordinal) && DateTime.Equals(pCache.LastWriteTimeUtc, f.LastWriteTimeUtc) && pCache.FileSize == f.Length) { try { using (MemoryStream memStream = new MemoryStream(pCache.Serialized)) { BinaryFormatter formatter = new BinaryFormatter(); link = (Script)formatter.Deserialize(memStream); } link.Project = p.Project; link.IsDirLink = false; cached = 3; } catch { } } } if (link == null) { // TODO : Lazy loading of link, takes too much time at start string ext = Path.GetExtension(linkFullPath); ScriptType type = ScriptType.Script; if (ext.Equals(".link", StringComparison.OrdinalIgnoreCase)) { type = ScriptType.Link; } link = new Script(type, Path.Combine(baseDir, linkFullPath), p.Project, projectRoot, null, false, false, false); Debug.Assert(p != null); } // Check Script Link's validity // Also, convert nested link to one-depth link if (link == null) { break; } if (link.Type == ScriptType.Script) { valid = true; break; } link = link.Link; }while (link.Type != ScriptType.Script); } catch (Exception e) { // Parser Error logs.Add(new LogInfo(LogState.Error, Logger.LogExceptionMessage(e))); } if (valid) { p.LinkLoaded = true; p.Link = link; if (worker != null) { worker.ReportProgress(cached, Path.GetDirectoryName(p.ShortPath)); } } else // Error { int idx = allProjectScripts.IndexOf(p); removeIdxs.Add(idx); if (worker != null) { worker.ReportProgress(cached); } } })); }).ToArray(); Task.WaitAll(tasks); // Remove malformed link var idxs = removeIdxs.OrderByDescending(x => x); foreach (int idx in idxs) { allProjectScripts.RemoveAt(idx); } return(logs); }
/// <returns>Return true if cache is updated</returns> private bool CacheScript(Script p, DB_ScriptCache[] memDB, List <DB_ScriptCache> updateDB) { if (memDB == null) { throw new ArgumentNullException("memDB"); } // Does cache exist? FileInfo f = new FileInfo(p.DirectFullPath); string sPath = p.DirectFullPath.Remove(0, p.Project.BaseDir.Length + 1); bool updated = false; // int memIdx = 0; DB_ScriptCache pCache = null; // Retrieve Cache pCache = memDB.FirstOrDefault(x => x.Hash == sPath.GetHashCode()); // Update Cache into updateDB if (pCache == null) { // Cache not exists pCache = new DB_ScriptCache() { Hash = sPath.GetHashCode(), Path = sPath, LastWriteTimeUtc = f.LastWriteTimeUtc, FileSize = f.Length, }; BinaryFormatter formatter = new BinaryFormatter(); using (MemoryStream ms = new MemoryStream()) { formatter.Serialize(ms, p); pCache.Serialized = ms.ToArray(); } listLock.EnterWriteLock(); try { updateDB.Add(pCache); updated = true; } finally { listLock.ExitWriteLock(); } } else if (pCache.Path.Equals(sPath, StringComparison.Ordinal) && (DateTime.Equals(pCache.LastWriteTimeUtc, f.LastWriteTime) == false || pCache.FileSize != f.Length)) { // Cache is outdated BinaryFormatter formatter = new BinaryFormatter(); using (MemoryStream ms = new MemoryStream()) { formatter.Serialize(ms, p); pCache.Serialized = ms.ToArray(); pCache.LastWriteTimeUtc = f.LastWriteTimeUtc; pCache.FileSize = f.Length; } listLock.EnterWriteLock(); try { updateDB.Add(pCache); updated = true; } finally { listLock.ExitWriteLock(); } } if (p.Type == ScriptType.Link && p.LinkLoaded) { bool linkUpdated = CacheScript(p.Link, memDB, updateDB); updated = updated || linkUpdated; } return(updated); }