public async Task <Maybe <TEntity> > GetAsync(TKey key) { try { var name = this.GetName(key); StorageProfiler.CountReadRequest(name); if (!File.Exists(name)) { return(Maybe <TEntity> .Empty); } using (var fs = new FileStream(name, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, FileOptions.Asynchronous)) { if (fs.Length == 0) { return(Maybe <TEntity> .Empty); } var bytes = new byte[fs.Length]; var readBytes = await fs.ReadAsync(bytes, 0, bytes.Length).ConfigureAwait(false); if (readBytes != bytes.Length) { throw new IOException("Not all bytes were read async. Need to implement better async reader."); } using (var ms = new MemoryStream(bytes)) return(this._strategy.Deserialize <TEntity>(ms)); } } catch (FileNotFoundException) { // if file happened to be deleted between the moment of check and actual read. return(Maybe <TEntity> .Empty); } catch (DirectoryNotFoundException) { return(Maybe <TEntity> .Empty); } }
public async Task SaveAsync(TKey key, TEntity entity) { var name = this.GetName(key); try { // This is fast and allows to have git-style subfolders in atomic strategy // to avoid NTFS performance degradation (when there are more than // 10000 files per folder). Kudos to Gabriel Schenker for pointing this out var subfolder = Path.GetDirectoryName(name); if (subfolder != null && !Directory.Exists(subfolder)) { Directory.CreateDirectory(subfolder); } // we are locking this file. using (var file = File.Open(name, FileMode.Create, FileAccess.ReadWrite, FileShare.None)) // some serializers have nasty habbit of closing the // underling stream using (var mem = new MemoryStream()) { this._strategy.Serialize(entity, mem); var data = mem.ToArray(); StorageProfiler.CountWriteRequest(name); // upload only if we changed await file.WriteAsync(data, 0, data.Length); // truncate this file file.SetLength(data.Length); } } catch (DirectoryNotFoundException) { var s = string.Format( "Container '{0}' does not exist.", this._folder); throw new InvalidOperationException(s); } }
public bool TryGet(TKey key, out TEntity view) { view = default(TEntity); try { var name = this.GetName(key); StorageProfiler.CountReadRequest(name); if (!File.Exists(name)) { return(false); } using (var stream = RetryPolicies.GetPolicy.Get(() => File.Open(name, FileMode.Open, FileAccess.Read, FileShare.Read))) { if (stream.Length == 0) { return(false); } view = this._strategy.Deserialize <TEntity>(stream); return(true); } } catch (FileNotFoundException) { // if file happened to be deleted between the moment of check and actual read. return(false); } catch (DirectoryNotFoundException) { return(false); } catch (IOException) { return(false); } }
public async Task <TEntity> AddOrUpdateAsync(TKey key, Func <TEntity> addFactory, Func <TEntity, TEntity> update, AddOrUpdateHint hint = AddOrUpdateHint.ProbablyExists) { var name = this.GetName(key); try { // This is fast and allows to have git-style subfolders in atomic strategy // to avoid NTFS performance degradation (when there are more than // 10000 files per folder). Kudos to Gabriel Schenker for pointing this out var subfolder = Path.GetDirectoryName(name); if (subfolder != null && !Directory.Exists(subfolder)) { Directory.CreateDirectory(subfolder); } // we are locking this file. using (var file = File.Open(name, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None)) { var initial = new byte[0]; TEntity result; if (file.Length == 0) { result = addFactory(); } else { using (var mem = new MemoryStream()) { StorageProfiler.CountReadRequest(name); await file.CopyToAsync(mem); mem.Seek(0, SeekOrigin.Begin); var entity = this._strategy.Deserialize <TEntity>(mem); initial = mem.ToArray(); result = update(entity); } } // some serializers have nasty habbit of closing the // underling stream using (var mem = new MemoryStream()) { this._strategy.Serialize(result, mem); var data = mem.ToArray(); if (!data.SequenceEqual(initial)) { StorageProfiler.CountWriteRequest(name); // upload only if we changed file.Seek(0, SeekOrigin.Begin); await file.WriteAsync(data, 0, data.Length); // truncate this file file.SetLength(data.Length); } } return(result); } } catch (DirectoryNotFoundException) { var s = string.Format( "Container '{0}' does not exist.", this._folder); throw new InvalidOperationException(s); } }