From eeb94e1668433251fa6af2d47e2f14f2d076ec0f Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 25 Nov 2016 18:07:27 +0100 Subject: [PATCH 1/3] U4-9222 The in memory XML cache is cloned everytime there is a content save even if there is nothing published --- src/Umbraco.Web/umbraco.presentation/content.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/Umbraco.Web/umbraco.presentation/content.cs b/src/Umbraco.Web/umbraco.presentation/content.cs index 777fe80782..26076f8727 100644 --- a/src/Umbraco.Web/umbraco.presentation/content.cs +++ b/src/Umbraco.Web/umbraco.presentation/content.cs @@ -329,6 +329,17 @@ namespace umbraco if (c.Published) return; + //if it's a brand new entity, then this shouldn't affect the sort order of the document + if (c.IsNewEntity()) + return; + + //if the sort order didn't change and the published state didn't change then we don't need to continue + if (c.WasPropertyDirty("SortOrder") == false + && c.WasPropertyDirty("Published") == false) + { + return; + } + using (var safeXml = GetSafeXmlWriter(false)) { //TODO: This can be null: safeXml.Xml!!!! From 5b5e1847eba2dc4e1b5ad3257a54f29e0ecc4588 Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 25 Nov 2016 18:08:18 +0100 Subject: [PATCH 2/3] Updates legacy CMSNode and Document to use the PetaPoco Database intead of SqlHelper for the methods that the xml cache uses to update itself (so it's using one connection) --- src/umbraco.cms/businesslogic/CMSNode.cs | 30 +++++++++---------- src/umbraco.cms/businesslogic/web/Document.cs | 10 +++++-- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/umbraco.cms/businesslogic/CMSNode.cs b/src/umbraco.cms/businesslogic/CMSNode.cs index 632227a3c5..773c3da4c4 100644 --- a/src/umbraco.cms/businesslogic/CMSNode.cs +++ b/src/umbraco.cms/businesslogic/CMSNode.cs @@ -1103,23 +1103,24 @@ order by level,sortOrder"; protected virtual XmlNode GetPreviewXml(XmlDocument xd, Guid version) { + var xmlDoc = new XmlDocument(); - XmlDocument xmlDoc = new XmlDocument(); - using (XmlReader xmlRdr = SqlHelper.ExecuteXmlReader( - "select xml from cmsPreviewXml where nodeID = @nodeId and versionId = @versionId", - SqlHelper.CreateParameter("@nodeId", Id), - SqlHelper.CreateParameter("@versionId", version))) - { - xmlDoc.Load(xmlRdr); - } + var xmlStr = ApplicationContext.Current.DatabaseContext.Database.ExecuteScalar( + "select xml from cmsPreviewXml where nodeID = @nodeId and versionId = @versionId", + new { nodeId = Id, versionId = version }); + if (xmlStr.IsNullOrWhiteSpace()) return null; + + xmlDoc.LoadXml(xmlStr); + return xd.ImportNode(xmlDoc.FirstChild, true); } protected internal virtual bool PreviewExists(Guid versionId) { - return (SqlHelper.ExecuteScalar("SELECT COUNT(nodeId) FROM cmsPreviewXml WHERE nodeId=@nodeId and versionId = @versionId", - SqlHelper.CreateParameter("@nodeId", Id), SqlHelper.CreateParameter("@versionId", versionId)) != 0); + return ApplicationContext.Current.DatabaseContext.Database.ExecuteScalar( + "SELECT COUNT(nodeId) FROM cmsPreviewXml WHERE nodeId=@nodeId and versionId = @versionId", + new {nodeId = Id, versionId = versionId}) != 0; } @@ -1133,11 +1134,10 @@ order by level,sortOrder"; { string sql = PreviewExists(versionId) ? "UPDATE cmsPreviewXml SET xml = @xml, timestamp = @timestamp WHERE nodeId=@nodeId AND versionId = @versionId" : "INSERT INTO cmsPreviewXml(nodeId, versionId, timestamp, xml) VALUES (@nodeId, @versionId, @timestamp, @xml)"; - SqlHelper.ExecuteNonQuery(sql, - SqlHelper.CreateParameter("@nodeId", Id), - SqlHelper.CreateParameter("@versionId", versionId), - SqlHelper.CreateParameter("@timestamp", DateTime.Now), - SqlHelper.CreateParameter("@xml", x.OuterXml)); + + ApplicationContext.Current.DatabaseContext.Database.Execute( + sql, new {nodeId = Id, versionId = versionId, timestamp = DateTime.Now, xml = x.OuterXml}); + } protected void PopulateCMSNodeFromReader(IRecordsReader dr) diff --git a/src/umbraco.cms/businesslogic/web/Document.cs b/src/umbraco.cms/businesslogic/web/Document.cs index 43f375671e..7ae25c4731 100644 --- a/src/umbraco.cms/businesslogic/web/Document.cs +++ b/src/umbraco.cms/businesslogic/web/Document.cs @@ -1551,9 +1551,13 @@ namespace umbraco.cms.businesslogic.web private XmlNode importXml() { XmlDocument xmlDoc = new XmlDocument(); - XmlReader xmlRdr = SqlHelper.ExecuteXmlReader(string.Format( - "select xml from cmsContentXml where nodeID = {0}", Id)); - xmlDoc.Load(xmlRdr); + + var xmlStr = ApplicationContext.Current.DatabaseContext.Database.ExecuteScalar( + "select xml from cmsContentXml where nodeID = @nodeId", new {nodeId = Id}); + + if (xmlStr.IsNullOrWhiteSpace()) return null; + + xmlDoc.LoadXml(xmlStr); return xmlDoc.FirstChild; } From 3a216c055e4fa6dc6741bc30a4579aad6085450f Mon Sep 17 00:00:00 2001 From: Stephan Date: Mon, 28 Nov 2016 09:52:45 +0100 Subject: [PATCH 3/3] U4-9222 - use HasPublishedVersion test --- .../umbraco.presentation/content.cs | 53 +++++++++---------- 1 file changed, 24 insertions(+), 29 deletions(-) diff --git a/src/Umbraco.Web/umbraco.presentation/content.cs b/src/Umbraco.Web/umbraco.presentation/content.cs index 26076f8727..b232d434b1 100644 --- a/src/Umbraco.Web/umbraco.presentation/content.cs +++ b/src/Umbraco.Web/umbraco.presentation/content.cs @@ -50,7 +50,7 @@ namespace umbraco var profingLogger = new ProfilingLogger( logger, ProfilerResolver.HasCurrent ? ProfilerResolver.Current.Profiler : new LogProfiler(logger)); - + // prepare the persister task // there's always be one task keeping a ref to the runner // so it's safe to just create it as a local var here @@ -71,7 +71,7 @@ namespace umbraco // once released, the cache still works but does not write to file anymore, // which is OK with database server messenger but will cause data loss with // another messenger... - + runner.Shutdown(false, true); // wait until flushed _released = true; }); @@ -145,7 +145,7 @@ namespace umbraco } //NOTE: We CANNOT use this for a double check lock because it is a property, not a field and to do double - // check locking in c# you MUST have a volatile field. Even thoug this wraps a volatile field it will still + // check locking in c# you MUST have a volatile field. Even thoug this wraps a volatile field it will still // not work as expected for a double check lock because properties are treated differently in the clr. public virtual bool isInitializing { @@ -323,22 +323,17 @@ namespace umbraco // this updates the published cache to take care of the situation // without ContentService having to ... what exactly? - // no need to do it if the content is published without unpublished changes, - // though, because in that case the XML will get re-generated with the - // correct sort order. - if (c.Published) - return; - - //if it's a brand new entity, then this shouldn't affect the sort order of the document - if (c.IsNewEntity()) - return; - - //if the sort order didn't change and the published state didn't change then we don't need to continue - if (c.WasPropertyDirty("SortOrder") == false - && c.WasPropertyDirty("Published") == false) - { - return; - } + // no need to do it if + // - the content is published without unpublished changes (XML will be re-gen anyways) + // - the content has no published version (not in XML) + // - the sort order has not changed + // note that + // - if it is a new entity is has not published version + // - if Published is dirty and false it's getting unpublished and has no published version + // + if (c.Published) return; + if (c.HasPublishedVersion == false) return; + if (c.WasPropertyDirty("SortOrder") == false) return; using (var safeXml = GetSafeXmlWriter(false)) { @@ -426,7 +421,7 @@ namespace umbraco { XmlNode x; - // remove from xml db cache + // remove from xml db cache doc.XmlRemoveFromDB(); // clear xml cache @@ -442,7 +437,7 @@ namespace umbraco { var prov = (UmbracoSiteMapProvider)SiteMap.Provider; prov.RemoveNode(doc.Id); - } + } } } @@ -493,7 +488,7 @@ namespace umbraco if (UmbracoContext.Current != null && UmbracoContext.Current.HttpContext != null && UmbracoContext.Current.HttpContext.Items.Contains(XmlContextContentItemKey)) UmbracoContext.Current.HttpContext.Items.Remove(XmlContextContentItemKey); } - + /// /// Load content from database /// @@ -524,7 +519,7 @@ namespace umbraco public void PersistXmlToFile() { } - + internal DateTime GetCacheFileUpdateTime() { //TODO: Should there be a try/catch here in case the file is being written to while this is trying to be executed? @@ -573,7 +568,7 @@ namespace umbraco private static bool UseLegacySchema { get { return UmbracoConfig.For.UmbracoSettings().Content.UseLegacyXmlSchema; } - } + } #endregion @@ -777,9 +772,9 @@ namespace umbraco _releaser.Dispose(); _releaser = null; } - + } - + private static string ChildNodesXPath { get @@ -873,9 +868,9 @@ namespace umbraco // and in addition, writing async is never fully async because // althouth the writer is async, xml.WriteTo() will not async - // that one almost works but... "The elements are indented as long as the element + // that one almost works but... "The elements are indented as long as the element // does not contain mixed content. Once the WriteString or WriteWhitespace method - // is called to write out a mixed element content, the XmlWriter stops indenting. + // is called to write out a mixed element content, the XmlWriter stops indenting. // The indenting resumes once the mixed content element is closed." - says MSDN // about XmlWriterSettings.Indent @@ -1080,7 +1075,7 @@ namespace umbraco //TODO: This could be faster, might as well just iterate all children and filter // instead of selecting matching children (i.e. iterating all) and then iterating the // filtered items to remove, this also allocates more memory to store the list of children. - // Below we also then do another filtering of child nodes, if we just iterate all children we + // Below we also then do another filtering of child nodes, if we just iterate all children we // can perform both functions more efficiently var dataNodes = publishedNode.SelectNodes(DataNodesXPath); if (dataNodes == null) throw new Exception("oops");