Created
June 24, 2011 09:24
-
-
Save aidanmorgan/1044490 to your computer and use it in GitHub Desktop.
This file contains 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
/// <summary> | |
/// This writer thread attempts to serialize all writes to the MongoDB database in a background thread. | |
/// </summary> | |
public class MongoDbLoggerWriteThread | |
{ | |
/// <summary> | |
/// The lock object guarding access to the <see cref="_entries"/> and <see cref="_keyedEntries"/> lists. | |
/// </summary> | |
private static readonly object LOCK_OBJECT = new object(); | |
/// <summary> | |
/// The <see cref="ILogRepository"/> that this writer will use to perform the actual writes. | |
/// </summary> | |
private readonly ILogRepository _repositoryImpl; | |
/// <summary> | |
/// A <see cref="IList"/> of <see cref="LogEntry"/> that are waiting to be picked up by the background thread. | |
/// This list will be automatically cleared by the background thread when it clones the lists for processing. | |
/// </summary> | |
private readonly IList<LogEntry> _entries; | |
/// <summary> | |
/// A <see cref="IList"/> of <see cref="KeyedLogEntry"/> that are waiting to be picked up by the background thread. | |
/// This list will be automatically cleared by the background thread when it clones the lists for processing. | |
/// </summary> | |
private readonly IList<KeyedLogEntry> _keyedEntries; | |
/// <summary> | |
/// Constructor | |
/// </summary> | |
public MongoDbLoggerWriteThread(ILogRepository repo) | |
{ | |
_repositoryImpl = repo; | |
_entries = new List<LogEntry>(); | |
_keyedEntries = new List<KeyedLogEntry>(); | |
} | |
/// <summary> | |
/// Adds the provided <see cref="LogEntry"/> to the internal queue, waiting to be processed by the background thread. | |
/// </summary> | |
public void AddLogEntry(LogEntry entry) | |
{ | |
// lock on the LOCK_OBJECT to ensure we won't attempt to append to the queue if the background thread is currently pulling | |
// values from the queue | |
lock (LOCK_OBJECT) | |
{ | |
_entries.Add(entry); | |
Monitor.PulseAll(LOCK_OBJECT); | |
} | |
} | |
/// <summary> | |
/// Adds the provided <see cref="KeyedLogEntry"/> to the internal queue, waiting to be processed by the background thread. | |
/// </summary> | |
public void AddLogEntry(KeyedLogEntry entry) | |
{ | |
// lock on the LOCK_OBJECT to ensure we won't attempt to append to the queue if the background thread is currently pulling | |
// values from the queue | |
lock (LOCK_OBJECT) | |
{ | |
_keyedEntries.Add(entry); | |
Monitor.PulseAll(LOCK_OBJECT); | |
} | |
} | |
public void Run() | |
{ | |
while (true) | |
{ | |
List<LogEntry> entries; | |
List<KeyedLogEntry> keyedEntries; | |
// Lock on the LOCK_OBJECT to gain exclusive access to the queues, ensures that no other threads are enqueueing items | |
// whilst we are taking them off. | |
lock(LOCK_OBJECT) | |
{ | |
// clone the queues to prevent data race conditions. | |
entries = new List<LogEntry>(_entries); | |
keyedEntries = new List<KeyedLogEntry>(_keyedEntries); | |
_entries.Clear(); | |
_keyedEntries.Clear(); | |
} | |
// if there is nothing to process, just wait on the wait condition. | |
if(entries.Count == 0 && keyedEntries.Count == 0) | |
{ | |
lock (LOCK_OBJECT) | |
{ | |
Monitor.Wait(LOCK_OBJECT); | |
} | |
} | |
else | |
{ | |
// we have been pulsed, and there are entries to be processed! | |
foreach (LogEntry le in entries) | |
{ | |
try | |
{ | |
_repositoryImpl.AddLog(le.Logger, le); | |
} | |
catch(SocketException) {} | |
} | |
foreach (KeyedLogEntry kle in keyedEntries) | |
{ | |
try | |
{ | |
_repositoryImpl.AddLog(kle.Logger, kle); | |
}catch(SocketException) {} | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment