public static BPlusTree <int, ContentNodeKit> GetTree(string filepath, bool exists, NuCacheSettings settings, ContentDataSerializer?contentDataSerializer = null) { var keySerializer = new PrimitiveSerializer(); var valueSerializer = new ContentNodeKitSerializer(contentDataSerializer); var options = new BPlusTree <int, ContentNodeKit> .OptionsV2(keySerializer, valueSerializer) { CreateFile = exists ? CreatePolicy.IfNeeded : CreatePolicy.Always, FileName = filepath, // read or write but do *not* keep in memory CachePolicy = CachePolicy.None, // default is 4096, min 2^9 = 512, max 2^16 = 64K FileBlockSize = GetBlockSize(settings), // HACK: Forces FileOptions to be WriteThrough here: https://github.com/mamift/CSharpTest.Net.Collections/blob/9f93733b3af7ee0e2de353e822ff54d908209b0b/src/CSharpTest.Net.Collections/IO/TransactedCompoundFile.cs#L316-L327, // as the reflection uses otherwise will failed in .NET Core as the "_handle" field in FileStream is renamed to "_fileHandle". StoragePerformance = StoragePerformance.CommitToDisk, // other options? }; var tree = new BPlusTree <int, ContentNodeKit>(options); // anything? // btree. return(tree); }
/// <summary> /// Construct a new <see cref="UmbracoXmlParser"/> instance by parsing the supplied /// umbraco.config XML cache file or NuCache database file. /// </summary> /// <param name="umbracoConfigOrNuCacheDb">Full path to umbraco.config XML cache file or NuCache database file.</param> /// <param name="options">Options to provide mappings for URL prefixes, doctypes (Umbraco 8 only) and users (Umbraco 8 only).</param> public UmbracoXmlParser(string umbracoConfigOrNuCacheDb, UmbracoParsingOptions options) { // Save options if (options != null) { Options = options; } // Remove any trailing slashes from URL prefixes as we don't want them if (Options.UrlPrefixMapping != null) { foreach (var key in Options.UrlPrefixMapping.Keys.ToList()) { if (Options.UrlPrefixMapping[key].EndsWith("/")) { Options.UrlPrefixMapping[key] = Options.UrlPrefixMapping[key].TrimEnd('/'); } } } // No file? if (string.IsNullOrEmpty(umbracoConfigOrNuCacheDb)) { throw new ArgumentException(umbracoConfigOrNuCacheDb); } // Check first few bytes. If it's XML it will start with '<' (potentially after a BOM) byte[] buffer = new byte[10]; using (var stream = new FileStream(umbracoConfigOrNuCacheDb, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { stream.Read(buffer, 0, 10); } // It's an umbraco 4 through 7 XML cache file if (buffer[0] == '<' || buffer[0] == 0xef && buffer[1] == 0xbb && buffer[2] == 0xbf && buffer[3] == '<') // UTF-8 BOM { try { // Load XML into an XDocument ParsedXml = XDocument.Load(umbracoConfigOrNuCacheDb); // Parse content into an in-memory dictionary of node ID and node information ParseXmlIntoUmbracoNodes(); // Destroy ParsedXml = null; return; } catch (UmbracoXmlParsingException ex) { ParsedXml = null; throw new UmbracoXmlParsingException($"Could not parse {umbracoConfigOrNuCacheDb} as XML - {ex.Message}"); } catch { ParsedXml = null; // Might be a NuCache file } } // Umbraco 8.0.1 or later NuCache db file try { var keySerializer = new PrimitiveSerializer(); var valueSerializer = new ContentNodeKitSerializer(); var bPlusTreeOptions = new BPlusTree <int, ContentNodeKit> .OptionsV2(keySerializer, valueSerializer) { CreateFile = CreatePolicy.Never, FileName = umbracoConfigOrNuCacheDb, ReadOnly = true }; // Read the file into a BPlusTreeObject ParsedTree = new BPlusTree <int, ContentNodeKit>(bPlusTreeOptions); } catch (Exception ex) { throw new UmbracoXmlParsingException($"Could not parse {umbracoConfigOrNuCacheDb} as a NuCache DB - {ex.Message}"); } // Parse content into an in-memory dictionary of node ID and node information ParseTreeIntoUmbracoNodes(); // Destroy ParsedTree.Dispose(); ParsedTree = null; }
public HttpResponseMessage GetNuCacheFile(string contentType) { var filePath = Path.Combine(globalSettings.LocalTempPath, "NuCache\\NuCache." + contentType + ".db"); var tempFileName = filePath.Replace(".db", ".Explorer.Temp.db"); try { //Check for valid filepath if (File.Exists(filePath) == false) { var message = $"No file exists on disk at {filePath}"; return(Request.CreateErrorResponse(HttpStatusCode.NotFound, message)); } //Check for file extension ends with .db //Don't want to attempt to any old file type if (Path.GetExtension(filePath) != ".db") { var message = $"The file {filePath} is not a .db file"; return(Request.CreateErrorResponse(HttpStatusCode.BadRequest, message)); } //We need to create a temp copy of the nucache DB - to avoid file locks if its in use whilst we try to read it //'NuCache.Content.db' will become 'NuCache.Content.Explorer.Temp.db' File.Copy(filePath, tempFileName, true); var keySerializer = new PrimitiveSerializer(); var valueSerializer = new ContentNodeKitSerializer(); var options = new BPlusTree <int, ContentNodeKit> .OptionsV2(keySerializer, valueSerializer) { CreateFile = CreatePolicy.Never, FileName = tempFileName, // default is 4096, min 2^9 = 512, max 2^16 = 64K FileBlockSize = GetBlockSize(), }; //Read the file into a BPlusTreeObject & select the kits var tree = new BPlusTree <int, ContentNodeKit>(options); var sw = Stopwatch.StartNew(); var kits = tree.Select(x => x.Value).ToArray(); sw.Stop(); tree.Dispose(); DeleteTempFile(tempFileName); //Add to our JSON object the stopwatch clock to read the DB/dictionary file var response = new ApiResponse { Items = kits, TotalItems = kits.Length, StopClock = new StopClock { Hours = sw.Elapsed.Hours, Minutes = sw.Elapsed.Minutes, Seconds = sw.Elapsed.Seconds, Milliseconds = sw.Elapsed.Milliseconds, Ticks = sw.Elapsed.Ticks } }; return(Request.CreateResponse(HttpStatusCode.OK, response)); } catch (Exception e) { DeleteTempFile(tempFileName); return(Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e.Message)); } }
public HttpResponseMessage GetNuCacheData(string filePath) { //Check for valid filepath if (File.Exists(filePath) == false) { var message = $"No file exists on disk at {filePath}"; return(Request.CreateErrorResponse(HttpStatusCode.NotFound, message)); } //Check for file extension ends with .db //Don't want to attempt to any old file type if (Path.GetExtension(filePath) != ".db") { var message = $"The file {filePath} is not a .db file"; return(Request.CreateErrorResponse(HttpStatusCode.BadRequest, message)); } //We need to create a temp copy of the nucache DB - to avoid file locks if its in use whilst we try to read it //'NuCache.Content.db' will become 'NuCache.Content.Explorer.Temp.db' var tempFileName = filePath.Replace(".db", ".Explorer.Temp.db"); File.Copy(filePath, tempFileName, true); var keySerializer = new PrimitiveSerializer(); var valueSerializer = new ContentNodeKitSerializer(); var options = new BPlusTree <int, ContentNodeKit> .OptionsV2(keySerializer, valueSerializer) { CreateFile = CreatePolicy.Never, FileName = tempFileName }; //Read the file into a BPlusTreeObject & select the kits var tree = new BPlusTree <int, ContentNodeKit>(options); var sw = Stopwatch.StartNew(); var kits = tree.Select(x => x.Value).ToArray(); sw.Stop(); tree.Dispose(); //Delete the file (seems like could be a lock, so we wait 100ms between each attempt upto 10 times) var ok = false; var attempts = 0; while (!ok) { System.Threading.Thread.Sleep(100); try { attempts++; File.Delete(tempFileName); ok = true; } catch { if (attempts == 10) { throw; } } } //Add to our JSON object the stopwatch clock to read the DB/dictionary file var response = new ApiResponse { Items = kits, TotalItems = kits.Length, StopClock = new StopClock { Hours = sw.Elapsed.Hours, Minutes = sw.Elapsed.Minutes, Seconds = sw.Elapsed.Seconds, Milliseconds = sw.Elapsed.Milliseconds, Ticks = sw.Elapsed.Ticks } }; return(Request.CreateResponse(HttpStatusCode.OK, response)); }