/// <summary> /// Return the key object /// </summary> /// <param name="rootfiles"></param> /// <param name="treename"></param> /// <param name="inputObjects"></param> /// <param name="query"></param> /// <returns></returns> public IQueryResultCacheKey GetKey(Uri[] unsortedRootfiles, string treename, object[] inputObjects, string[] unsortedCrumbs, QueryModel query, bool recheckDates = false, Func <Uri, DateTime> dateChecker = null) { /// /// Quick check to make sure everything is good /// TraceHelpers.TraceInfo(23, "GetKey: Initial query calculation"); if (unsortedRootfiles.Any(f => f == null)) { throw new ArgumentException("one of the root files is null"); } if (string.IsNullOrWhiteSpace(treename)) { throw new ArgumentException("tree name must be valid"); } if (inputObjects != null && inputObjects.Any(o => o == null)) { throw new ArgumentException("one of the input objects is null - not allowed"); } /// /// Build the hash, which is a bit of a pain in the butt. /// For the root files we don't care about the order given to us in or the order they /// are processed in. What we care about is what is there! /// var rootfiles = (from r in unsortedRootfiles orderby r.OriginalString ascending select r).ToArray(); TraceHelpers.TraceInfo(24, "GetKey: Creating big string file name and calculating hash"); int fnameLength = rootfiles.Select(f => f.OriginalString).Sum(w => w.Length) + 100; StringBuilder fullSourceName = new StringBuilder(fnameLength); foreach (var f in rootfiles) { fullSourceName.Append(f.OriginalString); } var fileHash = fullSourceName.ToString().GetHashCode(); // // Next, the crumbs. They should also be sorted in order, and we will need // a hash code for them too. // string[] crumbs = null; int crumbHash = 0; if (unsortedCrumbs == null) { crumbs = new string[0]; } else { crumbs = (from c in unsortedCrumbs orderby c select c).Distinct().ToArray(); StringBuilder crumbString = new StringBuilder(); foreach (var c in crumbs) { crumbString.Append(c); } crumbHash = crumbString.ToString().GetHashCode(); } /// /// Save the names of the files for a descriptor we will write out. /// KeyInfo result = new KeyInfo(); TraceHelpers.TraceInfo(25, "GetKey: Saving description lines"); result.DescriptionLines = (from f in rootfiles select f.OriginalString).ToArray(); result.ExtraQueryInfoLines = crumbs; /// /// Text for the query. There are strings like "generated_x" where x is a number. These get incremented each time they are used, /// so to protect the caching we need to swap those out with a dummy. /// TraceHelpers.TraceInfo(26, "GetKey: Pretty printing the query"); result.QueryText = FormattingQueryVisitor.Format(query); result.QueryText = result.QueryText.SwapOutWithUninqueString("\\<generated\\>_[0-9]+"); /// /// And the directory name - we use the first name of the file. /// TraceHelpers.TraceInfo(27, "GetKey: Getting the cache directory"); var fpathName = Path.GetFileNameWithoutExtension(rootfiles[0].PathAndQuery.SanitizedPathName(100)); result.CacheDirectory = new DirectoryInfo(CacheDirectory.FullName + "\\" + fileHash + " - " + treename + "-" + fpathName); /// /// Scan the files that we are input and find the oldest one there /// TraceHelpers.TraceInfo(28, "GetKey: calculating the most recent file dates"); result.OldestSourceFileDate = GetRecentFileDates(rootfiles, recheckDates, dateChecker).Max(); /// /// And now the file that the query should be cached in /// TraceHelpers.TraceInfo(29, "GetKey: Calculating query hash"); var queryHash = result.QueryText.GetHashCode(); TraceHelpers.TraceInfo(30, "GetKey: Calculating the input object hash"); var inputObjectHash = CalcObjectHash(inputObjects); string queryNameBase = string.Format(@"\\query {0}-inp{1}-crm{2}", queryHash.ToString(), inputObjectHash, crumbHash); result.RootFile = new FileInfo(result.CacheDirectory.FullName + queryNameBase + "_%%CYCLE%%.root"); // And a complete unique hash string. result.UniqueHashString = $"files{fileHash.ToString()}-query{queryHash.ToString()}-objs{inputObjectHash}-crm{crumbHash}"; TraceHelpers.TraceInfo(31, "GetKey: Done"); return(result); }
/// <summary> /// Create a new LINQ Querable object that will go after a TTree. The ntuple type must have been /// generated with the proper meta data so things like the scanner source file can be found! /// Runs on data in a multiple source files. /// </summary> /// <param name="rootFiles">A complete and existing file list that we should run over</param> /// <param name="treeName">Name of the tree in the list of files we are to process</param> public QueriableTTree(FileInfo[] rootFiles, string treeName) : base(CreateLINQToTTreeParser(), new TTreeQueryExecutor(rootFiles.Select(u => new Uri("file://" + u.FullName)).ToArray(), treeName, typeof(T))) { TraceHelpers.TraceInfo(1, string.Format("Creating new Queriable ttree with {1} file for tree '{0}'", treeName, rootFiles.Length)); }
/// <summary> /// Create a new LINQ Querable object that will go after a TTree. The ntuple type must have been /// generated with the proper meta data so things like the scanner source file can be found! /// Runs on data in a multiple source files. /// </summary> /// <param name="rootFiles">The uri of a root file. Should use one of the support schemes (see docs)</param> /// <param name="treeName">Name of the tree in the list of files we are to process</param> public QueriableTTree(Uri[] rootFiles, string treeName) : base(CreateLINQToTTreeParser(), new TTreeQueryExecutor(rootFiles, treeName, typeof(T))) { TraceHelpers.TraceInfo(1, string.Format("Creating new Queriable ttree with {1} file for tree '{0}'", treeName, rootFiles.Length)); }
/// <summary> /// Create a new LINQ Querable object that will go after a TTree. The ntuple type must have been /// generated with the proper meta data so things like the scanner source file can be found! /// Runs on data in a multiple source files. /// </summary> /// <param name="rootFile">A complete and existing file that we should run over</param> /// <param name="treeName">Name of the tree in the list of files we are to process</param> public QueriableTTree(FileInfo rootFile, string treeName) : base(CreateLINQToTTreeParser(), new TTreeQueryExecutor(new Uri[] { new Uri("file://" + rootFile.FullName) }, treeName, typeof(T))) { TraceHelpers.TraceInfo(1, string.Format("Creating new Queriable ttree with 1 file for tree '{0}'", treeName)); }
/// <summary> /// Create a new LINQ Querable object that will go after a TTree. The ntuple type must have been /// generated with the proper meta data so things like the scanner source file can be found! /// Runs on data in a single source file. /// </summary> /// <param name="rootFile">The uri of a root file. Should use one of the support schemes (see docs)</param> /// <param name="treeName">Name of the tree in the list of files we are to process</param> public QueriableTTree(Uri rootFile, string treeName) : base(CreateLINQToTTreeParser(), new TTreeQueryExecutor(new Uri[] { rootFile }, treeName, typeof(T))) { TraceHelpers.TraceInfo(1, $"Creating new Queriable ttree with 1 Uri for tree '{treeName}'"); }