/// <summary> /// Adds the file to cache and file saving queue if it does not exists. /// </summary> /// <param name="key">Key to store/retrieve the file.</param> /// <param name="bytes">File data in bytes.</param> /// <param name="duration">Specifies how long an item should remain in the cache.</param> public virtual async Task AddToSavingQueueIfNotExistsAsync(string key, byte[] bytes, TimeSpan duration) { var sanitizedKey = key.ToSanitizedKey(); if (!_fileWritePendingTasks.TryAdd(sanitizedKey, 1)) return; await _currentWriteLock.WaitAsync().ConfigureAwait(false); // Make sure we don't add multiple continuations to the same task try { _currentWrite = _currentWrite.ContinueWith(async t => { await Task.Yield(); // forces it to be scheduled for later try { CacheEntry oldEntry; if (_entries.TryGetValue(sanitizedKey, out oldEntry)) { string oldFilepath = Path.Combine(_cachePath, oldEntry.FileName); if (File.Exists(oldFilepath)) File.Delete(oldFilepath); } string filename = sanitizedKey + "." + (long)duration.TotalSeconds; string filepath = Path.Combine(_cachePath, filename); await FileStore.WriteBytesAsync(filepath, bytes, CancellationToken.None).ConfigureAwait(false); _entries[sanitizedKey] = new CacheEntry(DateTime.UtcNow, duration, filename); } catch (Exception ex) // Since we don't observe the task (it's not awaited, we should catch all exceptions) { Logger.Error(string.Format("An error occured while caching to disk image '{0}'.", key), ex); } finally { byte finishedTask; _fileWritePendingTasks.TryRemove(sanitizedKey, out finishedTask); } }); } finally { _currentWriteLock.Release(); } }
/// <summary> /// Adds the file to cache and file saving queue if not exists. /// </summary> /// <param name="key">Key.</param> /// <param name="bytes">Bytes.</param> /// <param name="duration">Duration.</param> public void AddToSavingQueueIfNotExists(string key, byte[] bytes, TimeSpan duration) { var sanitizedKey = SanitizeKey(key); if (fileWritePendingTasks.TryAdd(sanitizedKey, 1)) { #pragma warning disable 4014 Task.Run(async () => { try { await fileWriteLock.WaitAsync().ConfigureAwait(false); bool existed = entries.ContainsKey(sanitizedKey); string filepath = Path.Combine(basePath, sanitizedKey); if (!existed) { using (var fs = FileStore.GetOutputStream(filepath)) { await fs.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false); } } AppendToJournal(existed ? JournalOp.Modified : JournalOp.Created, sanitizedKey, DateTime.UtcNow, duration); entries[sanitizedKey] = new CacheEntry(DateTime.UtcNow, duration); } catch (Exception ex) // Since we don't observe the task (it's not awaited, we should catch all exceptions) { Console.WriteLine(string.Format("An error occured while caching to disk image '{0}'.", key)); Console.WriteLine(ex.ToString()); } finally { byte finishedTask; fileWritePendingTasks.TryRemove(sanitizedKey, out finishedTask); fileWriteLock.Release(); } }); #pragma warning restore 4014 } }
void InitializeWithJournal() { lock (lockJournal) { if(!File.Exists(journalPath)) { using(var writer = new StreamWriter(journalPath, false, encoding)) { writer.WriteLine(Magic); writer.WriteLine(version); } return; } string line = null; using(var reader = new StreamReader(journalPath, encoding)) { if (!EnsureHeader(reader)) throw new InvalidOperationException("Invalid header"); while((line = reader.ReadLine()) != null) { try { var op = ParseOp(line); string key; DateTime origin; TimeSpan duration; switch (op) { case JournalOp.Created: ParseEntry(line, out key, out origin, out duration); entries.TryAdd(key, new CacheEntry(origin, duration)); break; case JournalOp.Modified: ParseEntry(line, out key, out origin, out duration); entries[key] = new CacheEntry(origin, duration); break; case JournalOp.Deleted: ParseEntry(line, out key); CacheEntry oldEntry; entries.TryRemove(key, out oldEntry); break; } } catch { } } } } }
public async Task AddOrUpdateAsync(string key, Stream stream, CancellationToken token, TimeSpan duration) { await isInitialized; key = SanitizeKey(key); bool existed = entries.ContainsKey(key); try { await fileWriteLock.WaitAsync(); var file = await cacheFolder.CreateFileAsync(key, CreationCollisionOption.ReplaceExisting); using (var fs = await file.OpenStreamForWriteAsync()) { await stream.CopyToAsync(fs, BufferSize, token).ConfigureAwait(false); } } finally { fileWriteLock.Release(); } await AppendToJournal(existed ? JournalOp.Modified : JournalOp.Created, key, DateTime.UtcNow, duration); entries[key] = new CacheEntry(DateTime.UtcNow, duration); }
/// <summary> /// Adds the file to cache and file saving queue if not exists. /// </summary> /// <param name="key">Key.</param> /// <param name="bytes">Bytes.</param> /// <param name="duration">Duration.</param> public async Task AddToSavingQueueIfNotExistsAsync(string key, byte[] bytes, TimeSpan duration) { await initTask.ConfigureAwait(false); var sanitizedKey = SanitizeKey(key); if (!fileWritePendingTasks.TryAdd(sanitizedKey, 1)) return; await _currentWriteLock.WaitAsync().ConfigureAwait(false); // Make sure we don't add multiple continuations to the same task try { _currentWrite = _currentWrite.ContinueWith(async t => { await Task.Yield(); // forces it to be scheduled for later await initTask.ConfigureAwait(false); try { await fileWriteLock.WaitAsync().ConfigureAwait(false); string filename = sanitizedKey + "." + duration.TotalSeconds; var file = await cacheFolder.CreateFileAsync(filename, CreationCollisionOption.ReplaceExisting); using (var fs = await file.OpenStreamForWriteAsync().ConfigureAwait(false)) { await fs.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false); } entries[sanitizedKey] = new CacheEntry(DateTime.UtcNow, duration, filename); } catch (Exception ex) // Since we don't observe the task (it's not awaited, we should catch all exceptions) { //TODO WinRT doesn't have Console System.Diagnostics.Debug.WriteLine(string.Format("An error occured while caching to disk image '{0}'.", key)); System.Diagnostics.Debug.WriteLine(ex.ToString()); } finally { byte finishedTask; fileWritePendingTasks.TryRemove(sanitizedKey, out finishedTask); fileWriteLock.Release(); } }); } finally { _currentWriteLock.Release(); } }
/// <summary> /// Adds the file to cache and file saving queue if not exists. /// </summary> /// <param name="key">Key.</param> /// <param name="bytes">Bytes.</param> /// <param name="duration">Duration.</param> public async void AddToSavingQueueIfNotExists(string key, byte[] bytes, TimeSpan duration) { await initTask.ConfigureAwait(false); var sanitizedKey = SanitizeKey(key); if (fileWritePendingTasks.TryAdd(sanitizedKey, 1)) { #pragma warning disable 4014 Task.Run(async () => { await initTask.ConfigureAwait(false); try { await fileWriteLock.WaitAsync().ConfigureAwait(false); bool existed = entries.ContainsKey(sanitizedKey); if (!existed) { var file = await cacheFolder.CreateFileAsync(key, CreationCollisionOption.ReplaceExisting); using (var fs = await file.OpenStreamForWriteAsync().ConfigureAwait(false)) { await fs.WriteAsync(bytes, 0, bytes.Length).ConfigureAwait(false); } } await AppendToJournalAsync(existed ? JournalOp.Modified : JournalOp.Created, sanitizedKey, DateTime.UtcNow, duration).ConfigureAwait(false); entries[sanitizedKey] = new CacheEntry(DateTime.UtcNow, duration); } catch (Exception ex) // Since we don't observe the task (it's not awaited, we should catch all exceptions) { //TODO WinRT doesn't have Console System.Diagnostics.Debug.WriteLine(string.Format("An error occured while caching to disk image '{0}'.", key)); System.Diagnostics.Debug.WriteLine(ex.ToString()); } finally { byte finishedTask; fileWritePendingTasks.TryRemove(sanitizedKey, out finishedTask); fileWriteLock.Release(); } }); #pragma warning restore 4014 } }
async Task InitializeWithJournal() { await semaphoreSlim.WaitAsync(); try { try { journalFile = await cacheFolder.GetFileAsync(JournalFileName); } catch (Exception) { journalFile = null; } if (journalFile == null) { journalFile = await cacheFolder.CreateFileAsync(JournalFileName, CreationCollisionOption.ReplaceExisting); //using (var stream = await journalFile.OpenStreamForWriteAsync()) //using (var writer = new StreamWriter(stream, encoding)) //{ // await writer.WriteLineAsync(Magic); // await writer.WriteLineAsync(version); // await writer.FlushAsync(); //} return; } else { string line = null; using (var stream = await journalFile.OpenStreamForReadAsync()) using (var reader = new StreamReader(stream, encoding)) { /* if (!EnsureHeader(reader)) { throw new InvalidOperationException("Invalid header"); } */ while ((line = await reader.ReadLineAsync()) != null) { try { var op = ParseOp(line); string key; DateTime origin; TimeSpan duration; switch (op) { case JournalOp.Created: ParseEntry(line, out key, out origin, out duration); entries.TryAdd(key, new CacheEntry(origin, duration)); break; case JournalOp.Modified: ParseEntry(line, out key, out origin, out duration); entries[key] = new CacheEntry(origin, duration); break; case JournalOp.Deleted: ParseEntry(line, out key); CacheEntry oldEntry; entries.TryRemove(key, out oldEntry); break; } } catch { break; } } } } } finally { semaphoreSlim.Release(); } }
async Task InitializeWithJournal() { await journalLock.WaitAsync().ConfigureAwait(false); try { try { journalFile = await cacheFolder.GetFileAsync(JournalFileName); } catch (Exception) { journalFile = null; } if (journalFile == null) { journalFile = await cacheFolder.CreateFileAsync(JournalFileName, CreationCollisionOption.ReplaceExisting); return; } else { string line = null; using (var stream = await journalFile.OpenStreamForReadAsync().ConfigureAwait(false)) using (var reader = new StreamReader(stream, encoding)) { while ((line = await reader.ReadLineAsync().ConfigureAwait(false)) != null) { try { var op = ParseOp(line); string key; DateTime origin; TimeSpan duration; switch (op) { case JournalOp.Created: ParseEntry(line, out key, out origin, out duration); entries.TryAdd(key, new CacheEntry(origin, duration)); break; case JournalOp.Modified: ParseEntry(line, out key, out origin, out duration); entries[key] = new CacheEntry(origin, duration); break; case JournalOp.Deleted: ParseEntry(line, out key); CacheEntry oldEntry; entries.TryRemove(key, out oldEntry); break; } } catch { break; } } } } } finally { journalLock.Release(); } }
/// <summary> /// Adds the file to cache and file saving queue if it does not exists. /// </summary> /// <param name="key">Key to store/retrieve the file.</param> /// <param name="bytes">File data in bytes.</param> /// <param name="duration">Specifies how long an item should remain in the cache.</param> /// <param name="writeFinished">Write finished.</param> public virtual async Task AddToSavingQueueIfNotExistsAsync(string key, byte[] bytes, TimeSpan duration, Action writeFinished = null) { if (!_fileWritePendingTasks.TryAdd(key, 1)) { Logger?.Error("Can't save to disk as another write with the same key is pending: " + key); return; } await _currentWriteLock.WaitAsync().ConfigureAwait(false); // Make sure we don't add multiple continuations to the same task try { _currentWrite = _currentWrite.ContinueWith(async t => { await Task.Yield(); // forces it to be scheduled for later try { if (!Directory.Exists(_cachePath)) { Directory.CreateDirectory(_cachePath); } CacheEntry oldEntry; if (_entries.TryGetValue(key, out oldEntry)) { string oldFilepath = Path.Combine(_cachePath, oldEntry.FileName); if (File.Exists(oldFilepath)) { File.Delete(oldFilepath); } } string filename = key + "." + (long)duration.TotalSeconds; string filepath = Path.Combine(_cachePath, filename); await FileStore.WriteBytesAsync(filepath, bytes, CancellationToken.None).ConfigureAwait(false); _entries[key] = new CacheEntry(DateTime.UtcNow, duration, filename); writeFinished?.Invoke(); if (Configuration.VerboseLogging) { Logger?.Debug(string.Format("File {0} saved to disk cache for key {1}", filepath, key)); } } catch (Exception ex) // Since we don't observe the task (it's not awaited, we should catch all exceptions) { Logger?.Error(string.Format("An error occured while writing to disk cache for {0}", key), ex); } finally { byte finishedTask; _fileWritePendingTasks.TryRemove(key, out finishedTask); } }); } finally { _currentWriteLock.Release(); } }
public async Task AddOrUpdateAsync (string key, Stream stream, CancellationToken token, TimeSpan duration) { key = SanitizeKey (key); bool existed = entries.ContainsKey (key); string filepath = Path.Combine(basePath, key); try { await fileWriteLock.WaitAsync(); using (var fs = FileStore.GetOutputStream(filepath)) { await stream.CopyToAsync(fs, BufferSize, token).ConfigureAwait(false); } } finally { fileWriteLock.Release(); } AppendToJournal (existed ? JournalOp.Modified : JournalOp.Created, key, DateTime.UtcNow, duration); entries[key] = new CacheEntry (DateTime.UtcNow, duration); }
public async Task AddOrUpdateAsync (string key, byte[] data, TimeSpan duration) { key = SanitizeKey (key); bool existed = entries.ContainsKey (key); string filepath = Path.Combine(basePath, key); await FileStore.WriteBytesAsync(filepath, data).ConfigureAwait(false); AppendToJournal (existed ? JournalOp.Modified : JournalOp.Created, key, DateTime.UtcNow, duration); entries[key] = new CacheEntry (DateTime.UtcNow, duration); }