Ensure U4-8720 is properly merged into v8

This commit is contained in:
Stephan
2016-11-05 12:22:57 +01:00
parent 467ed87c3b
commit 8aa730d986
10 changed files with 179 additions and 34 deletions

View File

@@ -1,4 +1,5 @@
using System;
using System.Linq;
using NUnit.Framework;
using Umbraco.Web.PublishedCache.NuCache;
@@ -448,7 +449,7 @@ namespace Umbraco.Tests.Cache
Assert.AreEqual(3, d.Test.LiveGen);
Assert.IsFalse(d.Test.NextGen);
Assert.AreEqual(3, d.SnapCount);
s1.Dispose();
@@ -706,5 +707,38 @@ namespace Umbraco.Tests.Cache
Assert.IsFalse(d.Test.NextGen);
Assert.AreEqual("ein", s4.Get(1));
}
[Test]
public void GetAll()
{
var d = new SnapDictionary<int, string>();
d.Test.CollectAuto = false;
Assert.AreEqual(0, d.Test.GetValues(1).Length);
d.Set(1, "one");
d.Set(2, "two");
d.Set(3, "three");
d.Set(4, "four");
var s1 = d.CreateSnapshot();
var all = s1.GetAll().ToArray();
Assert.AreEqual(4, all.Length);
Assert.AreEqual("one", all[0]);
Assert.AreEqual("four", all[3]);
d.Set(1, "uno");
var s2 = d.CreateSnapshot();
all = s1.GetAll().ToArray();
Assert.AreEqual(4, all.Length);
Assert.AreEqual("one", all[0]);
Assert.AreEqual("four", all[3]);
all = s2.GetAll().ToArray();
Assert.AreEqual(4, all.Length);
Assert.AreEqual("uno", all[0]);
Assert.AreEqual("four", all[3]);
}
}
}

View File

@@ -72,6 +72,8 @@ namespace Umbraco.Tests.PublishedContent
base.MoreSetUp();
}
private readonly Guid _node1173Guid = Guid.NewGuid();
protected override string GetXmlContent(int templateId)
{
return @"<?xml version=""1.0"" encoding=""utf-8""?>
@@ -87,7 +89,7 @@ namespace Umbraco.Tests.PublishedContent
<umbracoUrlAlias><![CDATA[this/is/my/alias, anotheralias]]></umbracoUrlAlias>
<umbracoNaviHide>1</umbracoNaviHide>
<testRecursive><![CDATA[This is the recursive val]]></testRecursive>
<Home id=""1173"" parentID=""1046"" level=""2"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" sortOrder=""1"" createDate=""2012-07-20T18:06:45"" updateDate=""2012-07-20T19:07:31"" nodeName=""Sub1"" urlName=""sub1"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173"" isDoc="""">
<Home id=""1173"" parentID=""1046"" level=""2"" writerID=""0"" creatorID=""0"" nodeType=""1044"" template=""" + templateId + @""" sortOrder=""1"" createDate=""2012-07-20T18:06:45"" updateDate=""2012-07-20T19:07:31"" nodeName=""Sub1"" urlName=""sub1"" writerName=""admin"" creatorName=""admin"" path=""-1,1046,1173"" isDoc="""" key=""" + _node1173Guid + @""">
<content><![CDATA[<div>This is some content</div>]]></content>
<umbracoUrlAlias><![CDATA[page2/alias, 2ndpagealias]]></umbracoUrlAlias>
<testRecursive><![CDATA[]]></testRecursive>
@@ -122,6 +124,23 @@ namespace Umbraco.Tests.PublishedContent
return doc;
}
[Test]
public void GetNodeByIds()
{
var ctx = GetUmbracoContext("/test");
var contentById = ctx.ContentCache.GetById(1173);
Assert.IsNotNull(contentById);
var contentByGuid = ctx.ContentCache.GetById(_node1173Guid);
Assert.IsNotNull(contentByGuid);
Assert.AreEqual(contentById.Id, contentByGuid.Id);
Assert.AreEqual(contentById.Key, contentByGuid.Key);
contentById = ctx.ContentCache.GetById(666);
Assert.IsNull(contentById);
contentByGuid = ctx.ContentCache.GetById(Guid.NewGuid());
Assert.IsNull(contentByGuid);
}
[Test]
public void Is_Last_From_Where_Filter_Dynamic_Linq()
{

View File

@@ -21,9 +21,9 @@ namespace Umbraco.Web
IEnumerable<IPublishedContent> ContentAtRoot();
IPublishedContent Media(int id);
//IPublishedContent Media(Guid id);
IPublishedContent Media(Guid id);
IEnumerable<IPublishedContent> Media(IEnumerable<int> ids);
//IEnumerable<IPublishedContent> Media(IEnumerable<Guid> ids);
IEnumerable<IPublishedContent> Media(IEnumerable<Guid> ids);
IEnumerable<IPublishedContent> MediaAtRoot();
/// <summary>

View File

@@ -15,7 +15,7 @@ using Umbraco.Web.Routing;
namespace Umbraco.Web.PublishedCache.NuCache
{
class ContentCache : PublishedCacheBase, IPublishedContentCache, INavigableData, IDisposable
internal class ContentCache : PublishedCacheBase, IPublishedContentCache, INavigableData, IDisposable
{
private readonly ContentStore2.Snapshot _snapshot;
private readonly ICacheProvider _facadeCache;
@@ -209,11 +209,15 @@ namespace Umbraco.Web.PublishedCache.NuCache
: n.Published;
}
public override IPublishedContent GetById(bool preview, Guid nodeId)
public override IPublishedContent GetById(bool preview, Guid contentId)
{
// fixme - implement in a more efficient way
const string xpath = "//* [@isDoc and @key=$guid]";
return GetSingleByXPath(preview, xpath, new[] { new XPathVariable("guid", nodeId.ToString()) });
var n = _snapshot.Get(contentId);
if (n == null) return null;
// both .Draft and .Published cannot be null at the same time
return preview
? n.Draft ?? GetPublishedContentAsPreviewing(n.Published)
: n.Published;
}
public override bool HasById(bool preview, int contentId)

View File

@@ -180,7 +180,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
_localDb = null;
});
}
#endregion
#region Content types
@@ -295,7 +295,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
// unknown = bad
if (_contentTypesById.TryGetValue(kit.ContentTypeId, out link) == false || link.Value == null)
return false;
// not checking ByAlias, assuming we don't have internal errors
// register
@@ -560,7 +560,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
// already in the dict
if (link.Gen != _liveGen)
{
// for an older gen - if value is different then insert a new
// for an older gen - if value is different then insert a new
// link for the new gen, with the new value
if (link.Value != value)
dict.TryUpdate(key, new LinkedNode<TValue>(value, _liveGen, link), link);
@@ -619,7 +619,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
break;
link = link.Next;
}
if (link != null && link.Value != null)
if (link?.Value != null)
yield return Get(kvp.Key, gen);
}
}
@@ -638,6 +638,27 @@ namespace Umbraco.Web.PublishedCache.NuCache
return null;
}
public IEnumerable<ContentNode> GetAll(long gen)
{
// enumerating on .Values locks the concurrent dictionary,
// so better get a shallow clone in an array and release
var links = _contentNodes.Values.ToArray();
foreach (var l in links)
{
var link = l;
while (link != null)
{
if (link.Gen <= gen)
{
if (link.Value != null)
yield return link.Value;
break;
}
link = link.Next;
}
}
}
public bool IsEmpty(long gen)
{
var has = _contentNodes.Any(x =>
@@ -737,7 +758,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
{
if (_collectTask != null)
return _collectTask;
// ReSharper disable InconsistentlySynchronizedField
var task = _collectTask = Task.Run(() => Collect());
_collectTask.ContinueWith(_ =>
@@ -795,7 +816,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
#if DEBUG
//_logger.Debug<ContentStore2>("Collect id:" + kvp.Key + ", gen:" + link.Gen +
// ", nxt:" + (link.Next == null ? "null" : "link") +
// ", nxt:" + (link.Next == null ? "null" : "link") +
// ", val:" + (link.Value == null ? "null" : "value"));
#endif
@@ -807,7 +828,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
if (link.Gen < liveGen && link.Value == null
&& (link.Next == null || link.Gen <= _floorGen))
{
// not live, null value, no next link = remove that one -- but only if
// not live, null value, no next link = remove that one -- but only if
// the dict has not been updated, have to do it via ICollection<> (thanks
// Mr Toub) -- and if the dict has been updated there is nothing to collect
var idict = dict as ICollection<KeyValuePair<TKey, LinkedNode<TValue>>>;
@@ -891,7 +912,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
}
internal TestHelper Test { get { return _unitTesting ?? (_unitTesting = new TestHelper(this)); } }
#endregion
#region Classes
@@ -951,6 +972,14 @@ namespace Umbraco.Web.PublishedCache.NuCache
return _store.Get(id, _gen);
}
public ContentNode Get(Guid id)
{
if (_gen < 0)
throw new ObjectDisposedException("snapshot" /*+ " (" + _thisCount + ")"*/);
// fixme - optimize with an index - getAll/iterating is expensive
return _store.GetAll(_gen).FirstOrDefault(x => x.Uid == id);
}
public IEnumerable<ContentNode> GetAtRoot()
{
if (_gen < 0)
@@ -972,6 +1001,17 @@ namespace Umbraco.Web.PublishedCache.NuCache
return _store.GetContentType(alias, _gen);
}
// this code is here just so you don't try to implement it
// the only way we can iterate over "all" without locking the entire cache forever
// is by shallow cloning the cache, which is quite expensive, so we should probably not do it,
// and implement cache-level indexes
//public IEnumerable<ContentNode> GetAll()
//{
// if (_gen < 0)
// throw new ObjectDisposedException("snapshot" /*+ " (" + _thisCount + ")"*/);
// return _store.GetAll(_gen);
//}
public bool IsEmpty
{
get

View File

@@ -2,9 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Xml.XPath;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Xml;
using Umbraco.Core.Xml.XPath;
@@ -12,7 +10,7 @@ using Umbraco.Web.PublishedCache.NuCache.Navigable;
namespace Umbraco.Web.PublishedCache.NuCache
{
class MediaCache : PublishedCacheBase, IPublishedMediaCache, INavigableData, IDisposable
internal class MediaCache : PublishedCacheBase, IPublishedMediaCache, INavigableData, IDisposable
{
private readonly ContentStore2.Snapshot _snapshot;
private readonly ICacheProvider _facadeCache;
@@ -40,9 +38,8 @@ namespace Umbraco.Web.PublishedCache.NuCache
public override IPublishedContent GetById(bool preview, Guid contentId)
{
// fixme - test + implement in a more efficient way
const string xpath = "//* [@isDoc and @key=$guid]";
return GetSingleByXPath(preview, xpath, new[] { new XPathVariable("guid", contentId.ToString()) });
var n = _snapshot.Get(contentId);
return n?.Published;
}
public override bool HasById(bool preview, int contentId)

View File

@@ -252,16 +252,20 @@ namespace Umbraco.Web.PublishedCache.NuCache
// enumerating on .Values locks the concurrent dictionary,
// so better get a shallow clone in an array and release
var links = _items.Values.ToArray();
return links.Select(link =>
foreach (var l in links)
{
var link = l;
while (link != null)
{
if (link.Gen <= gen)
return link.Value; // may be null
{
if (link.Value != null)
yield return link.Value;
break;
}
link = link.Next;
}
return null;
}).Where(x => x != null);
}
}
public bool IsEmpty(long gen)

View File

@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Xml;
using System.Xml.XPath;
using Umbraco.Core.Configuration;
@@ -11,8 +10,6 @@ using Umbraco.Core.Xml;
using Umbraco.Web.Routing;
using System.Linq;
using Umbraco.Core.Cache;
using Umbraco.Core.Services;
using Task = System.Threading.Tasks.Task;
namespace Umbraco.Web.PublishedCache.XmlPublishedCache
{
@@ -358,9 +355,45 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
public override IPublishedContent GetById(bool preview, Guid nodeId)
{
// todo - implement in a more efficient way
const string xpath = "//* [@isDoc and @key=$guid]";
return GetSingleByXPath(preview, xpath, new [] { new XPathVariable("guid", nodeId.ToString()) });
// implement this, but in a more efficient way
//const string xpath = "//* [@isDoc and @key=$guid]";
//return GetSingleByXPath(preview, xpath, new[] { new XPathVariable("guid", nodeId.ToString()) });
var keyMatch = nodeId.ToString();
var nav = GetXml(preview).CreateNavigator();
if (nav.MoveToFirstChild() == false) return null; // from / to /root
if (nav.MoveToFirstChild() == false) return null; // from /root to /root/*
while (true)
{
var isDoc = false;
string key = null;
if (nav.HasAttributes)
{
nav.MoveToFirstAttribute();
do
{
if (nav.Name == "isDoc") isDoc = true;
if (nav.Name == "key") key = nav.Value;
if (isDoc && key != null) break;
} while (nav.MoveToNextAttribute());
nav.MoveToParent();
}
if (isDoc == false || key != keyMatch)
{
if (isDoc && nav.MoveToFirstChild())
continue;
while (nav.MoveToNext(XPathNodeType.Element) == false)
if (nav.MoveToParent() == false || nav.NodeType == XPathNodeType.Root) return null;
continue;
}
var elt = nav.UnderlyingObject as XmlNode;
return ConvertToDocument(elt, preview);
}
}
public override bool HasById(bool preview, int contentId)

View File

@@ -110,6 +110,13 @@ namespace Umbraco.Web
: _query.Media(id);
}
public IPublishedContent Media(Guid id)
{
return _query == null
? ItemById(id, _mediaCache)
: _query.Media(id);
}
public IEnumerable<IPublishedContent> Media(IEnumerable<int> ids)
{
return _query == null
@@ -117,6 +124,13 @@ namespace Umbraco.Web
: _query.Media(ids);
}
public IEnumerable<IPublishedContent> Media(IEnumerable<Guid> ids)
{
return _query == null
? ItemsByIds(_mediaCache, ids)
: _query.Media(ids);
}
public IEnumerable<IPublishedContent> MediaAtRoot()
{
return _query == null

View File

@@ -670,7 +670,7 @@ namespace Umbraco.Web
int intId;
if (ConvertIdObjectToInt(id, out intId))
return ContentQuery.Media(intId);
Guid guidId;
//Guid guidId;
//if (ConvertIdObjectToGuid(id, out guidId))
// return ContentQuery.Media(guidId);
return null;