removes CompressedStorageAttribute, makes IPropertyCacheCompressionOptions which can be defined in DI to configure what properties can be compressed in memory and new IReadOnlyContentBase to provide some context to the IPropertyCacheCompressionOptions

This commit is contained in:
Shannon
2021-01-28 13:50:18 +11:00
parent 4bfba2eeba
commit 32f88dba95
25 changed files with 258 additions and 128 deletions

View File

@@ -1,12 +1,13 @@
using System;
using Umbraco.Core.Models;
namespace Umbraco.Web.PublishedCache.NuCache.DataSource
{
// read-only dto
internal class ContentSourceDto
internal class ContentSourceDto : IReadOnlyContentBase
{
public int Id { get; set; }
public Guid Uid { get; set; }
public Guid Key { get; set; }
public int ContentTypeId { get; set; }
public int Level { get; set; }
@@ -37,5 +38,10 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
public int PubTemplateId { get; set; }
public string PubData { get; set; }
public byte[] PubDataRaw { get; set; }
// Explicit implementation
DateTime IReadOnlyContentBase.UpdateDate => EditVersionDate;
string IReadOnlyContentBase.Name => EditName;
int IReadOnlyContentBase.WriterId => EditWriterId;
}
}

View File

@@ -383,7 +383,7 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
}
else
{
var deserializedContent = serializer.Deserialize(dto.ContentTypeId, dto.EditData, dto.EditDataRaw);
var deserializedContent = serializer.Deserialize(dto, dto.EditData, dto.EditDataRaw);
d = new ContentData
{
@@ -410,7 +410,7 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
}
else
{
var deserializedContent = serializer.Deserialize(dto.ContentTypeId, dto.PubData, dto.PubDataRaw);
var deserializedContent = serializer.Deserialize(dto, dto.PubData, dto.PubDataRaw);
p = new ContentData
{
@@ -427,7 +427,7 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
}
}
var n = new ContentNode(dto.Id, dto.Uid,
var n = new ContentNode(dto.Id, dto.Key,
dto.Level, dto.Path, dto.SortOrder, dto.ParentId, dto.CreateDate, dto.CreatorId);
var s = new ContentNodeKit
@@ -446,7 +446,7 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
if (dto.EditData == null && dto.EditDataRaw == null)
throw new InvalidOperationException("No data for media " + dto.Id);
var deserializedMedia = serializer.Deserialize(dto.ContentTypeId, dto.EditData, dto.EditDataRaw);
var deserializedMedia = serializer.Deserialize(dto, dto.EditData, dto.EditDataRaw);
var p = new ContentData
{
@@ -460,7 +460,7 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
CultureInfos = deserializedMedia.CultureData
};
var n = new ContentNode(dto.Id, dto.Uid,
var n = new ContentNode(dto.Id, dto.Key,
dto.Level, dto.Path, dto.SortOrder, dto.ParentId, dto.CreateDate, dto.CreatorId);
var s = new ContentNodeKit

View File

@@ -1,4 +1,4 @@
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Models;
namespace Umbraco.Web.PublishedCache.NuCache.DataSource
{
@@ -14,19 +14,12 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
/// <summary>
/// Deserialize the data into a <see cref="ContentCacheDataModel"/>
/// </summary>
/// <param name="contentTypeId"></param>
/// <param name="stringData"></param>
/// <param name="byteData"></param>
/// <returns></returns>
ContentCacheDataModel Deserialize(int contentTypeId, string stringData, byte[] byteData);
ContentCacheDataModel Deserialize(IReadOnlyContentBase content, string stringData, byte[] byteData);
/// <summary>
/// Serializes the <see cref="ContentCacheDataModel"/>
/// </summary>
/// <param name="contentTypeId"></param>
/// <param name="model"></param>
/// <returns></returns>
ContentCacheDataSerializationResult Serialize(int contentTypeId, ContentCacheDataModel model);
ContentCacheDataSerializationResult Serialize(IReadOnlyContentBase content, ContentCacheDataModel model);
}
}

View File

@@ -1,6 +1,7 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using Umbraco.Core.Models;
using Umbraco.Core.Serialization;
namespace Umbraco.Web.PublishedCache.NuCache.DataSource
@@ -21,7 +22,7 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
DateFormatString = "o"
};
public ContentCacheDataModel Deserialize(int contentTypeId, string stringData, byte[] byteData)
public ContentCacheDataModel Deserialize(IReadOnlyContentBase content, string stringData, byte[] byteData)
{
if (stringData == null && byteData != null)
throw new NotSupportedException($"{typeof(JsonContentNestedDataSerializer)} does not support byte[] serialization");
@@ -29,7 +30,7 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
return JsonConvert.DeserializeObject<ContentCacheDataModel>(stringData, _jsonSerializerSettings);
}
public ContentCacheDataSerializationResult Serialize(int contentTypeId, ContentCacheDataModel model)
public ContentCacheDataSerializationResult Serialize(IReadOnlyContentBase content, ContentCacheDataModel model)
{
// note that numeric values (which are Int32) are serialized without their
// type (eg "value":1234) and JsonConvert by default deserializes them as Int64

View File

@@ -4,6 +4,7 @@ using MessagePack.Resolvers;
using System;
using System.Linq;
using System.Text;
using Umbraco.Core.Models;
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Web.PublishedCache.NuCache.DataSource
@@ -15,9 +16,9 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
public class MsgPackContentNestedDataSerializer : IContentCacheDataSerializer
{
private readonly MessagePackSerializerOptions _options;
private readonly IPropertyCompressionOptions _propertyOptions;
private readonly IPropertyCacheCompression _propertyOptions;
public MsgPackContentNestedDataSerializer(IPropertyCompressionOptions propertyOptions)
public MsgPackContentNestedDataSerializer(IPropertyCacheCompression propertyOptions)
{
_propertyOptions = propertyOptions ?? throw new ArgumentNullException(nameof(propertyOptions));
@@ -46,21 +47,21 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
return json;
}
public ContentCacheDataModel Deserialize(int contentTypeId, string stringData, byte[] byteData)
public ContentCacheDataModel Deserialize(IReadOnlyContentBase content, string stringData, byte[] byteData)
{
if (byteData != null)
{
var content = MessagePackSerializer.Deserialize<ContentCacheDataModel>(byteData, _options);
Expand(contentTypeId, content);
return content;
var cacheModel = MessagePackSerializer.Deserialize<ContentCacheDataModel>(byteData, _options);
Expand(content, cacheModel);
return cacheModel;
}
else if (stringData != null)
{
// NOTE: We don't really support strings but it's possible if manually used (i.e. tests)
var bin = Convert.FromBase64String(stringData);
var content = MessagePackSerializer.Deserialize<ContentCacheDataModel>(bin, _options);
Expand(contentTypeId, content);
return content;
var cacheModel = MessagePackSerializer.Deserialize<ContentCacheDataModel>(bin, _options);
Expand(content, cacheModel);
return cacheModel;
}
else
{
@@ -68,9 +69,9 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
}
}
public ContentCacheDataSerializationResult Serialize(int contentTypeId, ContentCacheDataModel model)
public ContentCacheDataSerializationResult Serialize(IReadOnlyContentBase content, ContentCacheDataModel model)
{
Compress(contentTypeId, model);
Compress(content, model);
var bytes = MessagePackSerializer.Serialize(model, _options);
return new ContentCacheDataSerializationResult(null, bytes);
}
@@ -86,11 +87,11 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
/// read/decompressed as a string to be displayed on the front-end. This allows for potentially a significant
/// memory savings but could also affect performance of first rendering pages while decompression occurs.
/// </remarks>
private void Compress(int contentTypeId, ContentCacheDataModel model)
private void Compress(IReadOnlyContentBase content, ContentCacheDataModel model)
{
foreach(var propertyAliasToData in model.PropertyData)
{
if (_propertyOptions.IsCompressed(contentTypeId, propertyAliasToData.Key))
if (_propertyOptions.IsCompressed(content, propertyAliasToData.Key))
{
foreach(var property in propertyAliasToData.Value.Where(x => x.Value != null && x.Value is string))
{
@@ -104,11 +105,11 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
/// Used during deserialization to map the property data as lazy or expand the value
/// </summary>
/// <param name="nestedData"></param>
private void Expand(int contentTypeId, ContentCacheDataModel nestedData)
private void Expand(IReadOnlyContentBase content, ContentCacheDataModel nestedData)
{
foreach (var propertyAliasToData in nestedData.PropertyData)
{
if (_propertyOptions.IsCompressed(contentTypeId, propertyAliasToData.Key))
if (_propertyOptions.IsCompressed(content, propertyAliasToData.Key))
{
foreach (var property in propertyAliasToData.Value.Where(x => x.Value != null))
{

View File

@@ -12,14 +12,21 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
private readonly IMediaTypeService _mediaTypeService;
private readonly IMemberTypeService _memberTypeService;
private readonly PropertyEditorCollection _propertyEditors;
private readonly ConcurrentDictionary<(int, string), CompressedStorageAttribute> _compressedStoragePropertyEditorCache = new ConcurrentDictionary<(int, string), CompressedStorageAttribute>();
private readonly IPropertyCacheCompressionOptions _compressionOptions;
private readonly ConcurrentDictionary<(int, string), bool> _isCompressedCache = new ConcurrentDictionary<(int, string), bool>();
public MsgPackContentNestedDataSerializerFactory(IContentTypeService contentTypeService, IMediaTypeService mediaTypeService, IMemberTypeService memberTypeService, PropertyEditorCollection propertyEditors)
public MsgPackContentNestedDataSerializerFactory(
IContentTypeService contentTypeService,
IMediaTypeService mediaTypeService,
IMemberTypeService memberTypeService,
PropertyEditorCollection propertyEditors,
IPropertyCacheCompressionOptions compressionOptions)
{
_contentTypeService = contentTypeService;
_mediaTypeService = mediaTypeService;
_memberTypeService = memberTypeService;
_propertyEditors = propertyEditors;
_compressionOptions = compressionOptions;
}
public IContentCacheDataSerializer Create(ContentCacheDataSerializerEntityType types)
@@ -53,8 +60,8 @@ namespace Umbraco.Web.PublishedCache.NuCache.DataSource
}
}
var options = new CompressedStoragePropertyEditorCompressionOptions(contentTypes, _propertyEditors, _compressedStoragePropertyEditorCache);
var serializer = new MsgPackContentNestedDataSerializer(options);
var compression = new PropertyCacheCompression(_compressionOptions, contentTypes, _propertyEditors, _isCompressedCache);
var serializer = new MsgPackContentNestedDataSerializer(compression);
return serializer;
}

View File

@@ -20,9 +20,11 @@ namespace Umbraco.Web.PublishedCache.NuCache
}
else
{
composition.RegisterUnique<IContentCacheDataSerializerFactory, MsgPackContentNestedDataSerializerFactory>();
composition.RegisterUnique<IContentCacheDataSerializerFactory, MsgPackContentNestedDataSerializerFactory>();
}
composition.RegisterUnique<IPropertyCacheCompressionOptions, NoopPropertyCacheCompressionOptions>();
composition.RegisterUnique(factory => new ContentDataSerializer(new DictionaryOfPropertyDataSerializer()));
// register the NuCache database data source

View File

@@ -1456,7 +1456,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
UrlSegment = content.GetUrlSegment(_urlSegmentProviders)
};
var serialized = serializer.Serialize(content.ContentTypeId, contentCacheData);
var serialized = serializer.Serialize(ReadOnlyContentBaseAdapter.Create(content), contentCacheData);
var dto = new ContentNuDto
{