Created
October 5, 2011 15:01
-
-
Save jakejscott/1264646 to your computer and use it in GitHub Desktop.
Lightspeed ORM second level cache using MongoDB (Doesn't support expirying items yet..todo)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.IO; | |
using System.Runtime.Serialization.Formatters.Binary; | |
using Loot.Logging; | |
using Mindscape.LightSpeed.Caching; | |
using MongoDB.Driver; | |
using MongoDB.Driver.Builders; | |
namespace Loot | |
{ | |
public class MongoCache : ICache, IDisposable | |
{ | |
/// <summary> | |
/// Assumes that MongoDB and Lightspeed are both setup to use Local Time and not Utc Time! | |
/// </summary> | |
public MongoCache(MongoDatabase database) | |
{ | |
this.database = database; | |
cache = this.database.GetCollection<MongoCacheItem>("Cache"); | |
cache.RemoveAll(SafeMode.True); | |
} | |
public object GetItem(string key) | |
{ | |
var cacheItem = cache.FindOneById(key); | |
if (cacheItem == null) | |
return null; | |
if (DateTime.Now > cacheItem.ExpireAt) | |
{ | |
log.Info(string.Format("Found an item that has expired at {0}. The time now is {1}.", cacheItem.ExpireAt, DateTime.Now)); | |
return null; | |
} | |
using (var stream = new MemoryStream(cacheItem.Value)) | |
{ | |
var formatter = new BinaryFormatter(); | |
return formatter.Deserialize(stream); | |
} | |
} | |
public void AddItem(string key, object item, TimeSpan expiry) | |
{ | |
using (var stream = new MemoryStream()) | |
{ | |
var formatter = new BinaryFormatter(); | |
formatter.Serialize(stream, item); | |
var bytes = StreamHelper.ReadToEnd(stream); | |
var cacheItem = new MongoCacheItem | |
{ | |
Id = key, | |
Value = bytes, | |
ExpireAt = DateTime.Now + expiry | |
}; | |
log.Info(string.Format("Adding item to expire at {0}. The time now is {1}.", cacheItem.ExpireAt, DateTime.Now)); | |
cache.Insert(cacheItem, SafeMode.True); | |
} | |
} | |
public void SetItem(string key, object item, TimeSpan expiry) | |
{ | |
using (var stream = new MemoryStream()) | |
{ | |
var formatter = new BinaryFormatter(); | |
formatter.Serialize(stream, item); | |
var bytes = StreamHelper.ReadToEnd(stream); | |
var expiresAt = DateTime.Now + expiry; | |
log.Info(string.Format("Setting item to expire at {0}. The time now is {1}.", expiresAt, DateTime.Now)); | |
cache.Update(Query.EQ("_id", key), Update.Set("Value", bytes).Set("ExpireAt", expiresAt), SafeMode.True); | |
} | |
} | |
public void RemoveItem(string key) | |
{ | |
log.Info("Removing item. The time now is " + DateTime.Now); | |
cache.Remove(Query.EQ("_id", key), SafeMode.True); | |
} | |
~MongoCache() | |
{ | |
Cleanup(); | |
} | |
public void Dispose() | |
{ | |
Cleanup(); | |
GC.SuppressFinalize(this); | |
} | |
private void Cleanup() | |
{ | |
if (disposed) | |
return; | |
disposed = true; | |
cache.RemoveAll(SafeMode.True); | |
} | |
private readonly ILog log = LogManager.GetLogger(typeof(MongoCache)); | |
private bool disposed = false; | |
private readonly MongoDatabase database; | |
private readonly MongoCollection<MongoCacheItem> cache; | |
} | |
public class MongoCacheItem | |
{ | |
public string Id { get; set; } | |
public byte[] Value { get; set; } | |
public DateTime ExpireAt { get; set; } | |
} | |
public class StreamHelper | |
{ | |
public static byte[] ReadToEnd(Stream stream) | |
{ | |
long originalPosition = stream.Position; | |
stream.Position = 0; | |
try | |
{ | |
byte[] readBuffer = new byte[4096]; | |
int totalBytesRead = 0; | |
int bytesRead; | |
while ((bytesRead = stream.Read(readBuffer, totalBytesRead, readBuffer.Length - totalBytesRead)) > 0) | |
{ | |
totalBytesRead += bytesRead; | |
if (totalBytesRead == readBuffer.Length) | |
{ | |
int nextByte = stream.ReadByte(); | |
if (nextByte != -1) | |
{ | |
byte[] temp = new byte[readBuffer.Length * 2]; | |
Buffer.BlockCopy(readBuffer, 0, temp, 0, readBuffer.Length); | |
Buffer.SetByte(temp, totalBytesRead, (byte)nextByte); | |
readBuffer = temp; | |
totalBytesRead++; | |
} | |
} | |
} | |
byte[] buffer = readBuffer; | |
if (readBuffer.Length != totalBytesRead) | |
{ | |
buffer = new byte[totalBytesRead]; | |
Buffer.BlockCopy(readBuffer, 0, buffer, 0, totalBytesRead); | |
} | |
return buffer; | |
} | |
finally | |
{ | |
stream.Position = originalPosition; | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment