mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2026-02-09 09:16:41 +08:00
Compressing output cache content in Redis
This commit is contained in:
@@ -3,6 +3,9 @@
|
||||
namespace Orchard.OutputCache.Models {
|
||||
[Serializable]
|
||||
public class CacheItem {
|
||||
// used for serialization compatibility
|
||||
public static readonly string Version = "1";
|
||||
|
||||
public DateTime CachedOnUtc { get; set; }
|
||||
public int Duration { get; set; }
|
||||
public int GraceTime { get; set; }
|
||||
|
||||
+66
-7
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using Orchard.Environment.Configuration;
|
||||
using Orchard.Environment.Extensions;
|
||||
using Orchard.Logging;
|
||||
@@ -10,11 +9,23 @@ using Orchard.OutputCache.Models;
|
||||
using Orchard.OutputCache.Services;
|
||||
using Orchard.Redis.Extensions;
|
||||
using StackExchange.Redis;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
|
||||
namespace Orchard.Redis.OutputCache {
|
||||
|
||||
[OrchardFeature("Orchard.Redis.OutputCache")]
|
||||
[OrchardSuppressDependency("Orchard.OutputCache.Services.DefaultCacheStorageProvider")]
|
||||
/// <summary>
|
||||
/// This implementation stores a <see cref="CacheItem"/> instance to a Redis server.
|
||||
/// The item is serialized using a <see cref="BinaryFormatter"/> and GZipped. We rely
|
||||
/// on compression at this level of the implementation as other output cache providers
|
||||
/// might not want to rely on it, or transform the data to binary. The content is compressed
|
||||
/// as HTML pages can be consequent, like several hundreds of KB, and the network be clogged.
|
||||
/// To prevent versioning issues with serialized data, the Redis keys contain the
|
||||
/// <see cref="CacheItem.Version"/> property.
|
||||
/// </summary>
|
||||
public class RedisOutputCacheStorageProvider : IOutputCacheStorageProvider {
|
||||
|
||||
private readonly ShellSettings _shellSettings;
|
||||
@@ -43,12 +54,19 @@ namespace Orchard.Redis.OutputCache {
|
||||
}
|
||||
|
||||
public void Set(string key, CacheItem cacheItem) {
|
||||
if(cacheItem == null) {
|
||||
throw new ArgumentNullException("cacheItem");
|
||||
}
|
||||
|
||||
if (cacheItem.ValidFor <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var value = JsonConvert.SerializeObject(cacheItem);
|
||||
Database.StringSet(GetLocalizedKey(key), value, TimeSpan.FromSeconds(cacheItem.ValidFor));
|
||||
using (var decompressedStream = Serialize(cacheItem)) {
|
||||
using (var compressedStream = Compress(decompressedStream)) {
|
||||
Database.StringSet(GetLocalizedKey(key), compressedStream.ToArray(), TimeSpan.FromSeconds(cacheItem.ValidFor));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Remove(string key) {
|
||||
@@ -60,12 +78,21 @@ namespace Orchard.Redis.OutputCache {
|
||||
}
|
||||
|
||||
public CacheItem GetCacheItem(string key) {
|
||||
string value = Database.StringGet(GetLocalizedKey(key));
|
||||
if (String.IsNullOrEmpty(value)) {
|
||||
var value = Database.StringGet(GetLocalizedKey(key));
|
||||
|
||||
if (value.IsNullOrEmpty) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return JsonConvert.DeserializeObject<CacheItem>(value);
|
||||
using (var compressedStream = new MemoryStream(value)) {
|
||||
if(compressedStream.Length == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
using(var decompressedStream = Decompress(compressedStream)) {
|
||||
return Deserialize(decompressedStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<CacheItem> GetCacheItems(int skip, int count) {
|
||||
@@ -88,7 +115,7 @@ namespace Orchard.Redis.OutputCache {
|
||||
/// <param name="key">The key to localized.</param>
|
||||
/// <returns>A localized key based on the tenant name.</returns>
|
||||
private string GetLocalizedKey(string key) {
|
||||
return _shellSettings.Name + ":OutputCache:" + key;
|
||||
return _shellSettings.Name + ":OC:" + CacheItem.Version + ":" + key;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -111,5 +138,37 @@ namespace Orchard.Redis.OutputCache {
|
||||
|
||||
return _keysCache;
|
||||
}
|
||||
|
||||
private static MemoryStream Serialize(CacheItem item) {
|
||||
BinaryFormatter binaryFormatter = new BinaryFormatter();
|
||||
var memoryStream = new MemoryStream();
|
||||
binaryFormatter.Serialize(memoryStream, item);
|
||||
memoryStream.Seek(0, SeekOrigin.Begin);
|
||||
return memoryStream;
|
||||
}
|
||||
|
||||
private static CacheItem Deserialize(Stream stream) {
|
||||
BinaryFormatter binaryFormatter = new BinaryFormatter();
|
||||
var result = (CacheItem)binaryFormatter.Deserialize(stream);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static MemoryStream Compress(Stream stream) {
|
||||
var compressedStream = new MemoryStream();
|
||||
using (var compressionStream = new GZipStream(compressedStream, CompressionMode.Compress)) {
|
||||
stream.CopyTo(compressionStream);
|
||||
return compressedStream;
|
||||
}
|
||||
}
|
||||
|
||||
private static Stream Decompress(Stream stream) {
|
||||
var decompressedStream = new MemoryStream();
|
||||
using (GZipStream decompressionStream = new GZipStream(stream, CompressionMode.Decompress)) {
|
||||
decompressionStream.CopyTo(decompressedStream);
|
||||
decompressedStream.Seek(0, SeekOrigin.Begin);
|
||||
return decompressedStream;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user