Пример #1
0
 /// <summary>
 /// Given a <paramref name="key"/> either adds a new <typeparamref name="TEntity"/> OR updates an existing one.
 /// </summary>
 /// <typeparam name="TKey">The type of the key.</typeparam>
 /// <typeparam name="TEntity">The type of the entity.</typeparam>
 /// <param name="self">The self.</param>
 /// <param name="key">The key.</param>
 /// <param name="newView">The new view that will be saved, if entity does not already exist</param>
 /// <param name="updateViewFactory">The update method (called to update an existing entity, if it exists).</param>
 /// <param name="hint">The hint.</param>
 /// <returns></returns>
 public static TEntity AddOrUpdate <TKey, TEntity>(this IDocumentWriter <TKey, TEntity> self, TKey key,
                                                   TEntity newView, Action <TEntity> updateViewFactory, AddOrUpdateHint hint = AddOrUpdateHint.ProbablyExists)
 {
     return(self.AddOrUpdate(key, () => newView, view =>
     {
         updateViewFactory(view);
         return view;
     }, hint));
 }
Пример #2
0
 public static TView UpdateEnforcingNew <TView>(this IDocumentWriter <unit, TView> self, Action <TView> update,
                                                AddOrUpdateHint hint = AddOrUpdateHint.ProbablyExists)
     where TView : new()
 {
     return(self.UpdateEnforcingNew(unit.it, update, hint));
 }
Пример #3
0
 /// <summary>
 /// Given a <paramref name="key"/> either adds a new <typeparamref name="TEntity"/> OR updates an existing one.
 /// </summary>
 /// <typeparam name="TKey">The type of the key.</typeparam>
 /// <typeparam name="TEntity">The type of the entity.</typeparam>
 /// <param name="self">The self.</param>
 /// <param name="key">The key.</param>
 /// <param name="addFactory">The add factory (used to create a new entity, if it is not found).</param>
 /// <param name="update">The update method (called to update an existing entity, if it exists).</param>
 /// <param name="hint">The hint.</param>
 /// <returns></returns>
 public static TEntity AddOrUpdate <TKey, TEntity>(this IDocumentWriter <TKey, TEntity> self, TKey key,
                                                   Func <TEntity> addFactory, Action <TEntity> update, AddOrUpdateHint hint = AddOrUpdateHint.ProbablyExists)
 {
     return(self.AddOrUpdate(key, addFactory, entity =>
     {
         update(entity);
         return entity;
     }, hint));
 }
Пример #4
0
        public TEntity AddOrUpdate(TKey key, Func <TEntity> addFactory, Func <TEntity, TEntity> update, AddOrUpdateHint hint)
        {
            var id     = _entityPrefix + _strategy.GetNameForEntity(typeof(TEntity), key);
            var result = default(TEntity);

            _store.AddOrUpdate(id, s =>
            {
                result = addFactory();
                using (var memory = new MemoryStream())
                {
                    _strategy.Serialize(result, memory);
                    return(memory.ToArray());
                }
            }, (s2, bytes) =>
            {
                TEntity entity;
                using (var memory = new MemoryStream(bytes))
                {
                    entity = _strategy.Deserialize <TEntity>(memory);
                }
                result = update(entity);
                using (var memory = new MemoryStream())
                {
                    _strategy.Serialize(result, memory);
                    return(memory.ToArray());
                }
            });
            return(result);
        }
 public TView AddOrUpdate(TKey key, Func <TView> addFactory, Func <TView, TView> update,
                          AddOrUpdateHint hint = AddOrUpdateHint.ProbablyExists)
 {
     return(_inner.AddOrUpdate(key, addFactory, update, hint));
 }
        public TEntity AddOrUpdate(TKey key, Func <TEntity> addFactory, Func <TEntity, TEntity> update, AddOrUpdateHint hint)
        {
            var result = default(TEntity);

            this._store.AddOrUpdate(this.GetName(key), s =>
            {
                result = addFactory();
                return(result);
            }, (s2, savedEntity) =>
            {
                var entity = ( TEntity )savedEntity;
                result     = update(entity);
                return(result);
            });
            return(result);
        }
        public Task <TEntity> AddOrUpdateAsync(TKey key, Func <TEntity> addFactory, Func <TEntity, TEntity> update, AddOrUpdateHint hint = AddOrUpdateHint.ProbablyExists)
        {
            var result = this.AddOrUpdate(key, addFactory, update, hint);

            return(Task.FromResult(result));
        }
Пример #8
0
        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);
            }
        }
Пример #9
0
        public TEntity AddOrUpdate(TKey key, Func <TEntity> addViewFactory, Func <TEntity, TEntity> updateViewFactory,
                                   AddOrUpdateHint hint)
        {
            string  etag = null;
            var     blob = GetBlobReference(key);
            TEntity view;

            byte[] bytes = new byte[0];
            try
            {
                // atomic entities should be small, so we can use the simple method
                bytes = blob.DownloadByteArray();
                using (var stream = new MemoryStream(bytes))
                {
                    view = _strategy.Deserialize <TEntity>(stream);
                }

                view = updateViewFactory(view);
                etag = blob.Attributes.Properties.ETag;
            }
            catch (StorageClientException ex)
            {
                switch (ex.ErrorCode)
                {
                case StorageErrorCode.ContainerNotFound:
                    var s = string.Format(
                        "Container '{0}' does not exist. You need to initialize this atomic storage and ensure that '{1}' is known to '{2}'.",
                        blob.Container.Name, typeof(TEntity).Name, _strategy.GetType().Name);
                    throw new InvalidOperationException(s, ex);

                case StorageErrorCode.BlobNotFound:
                case StorageErrorCode.ResourceNotFound:
                    view = addViewFactory();
                    break;

                default:
                    throw;
                }
            }
            // atomic entities should be small, so we can use the simple method
            // http://toolheaven.net/post/Azure-and-blob-write-performance.aspx
            using (var memory = new MemoryStream())
            {
                _strategy.Serialize(view, memory);
                // note that upload from stream does weird things
                var bro = etag != null
                    ? new BlobRequestOptions {
                    AccessCondition = AccessCondition.IfMatch(etag)
                }
                    : new BlobRequestOptions {
                    AccessCondition = AccessCondition.IfNoneMatch("*")
                };


                // make sure that upload is not rejected due to cashed content MD5
                // http://social.msdn.microsoft.com/Forums/hu-HU/windowsazuredata/thread/4764e38f-b200-4efe-ada2-7de442dc4452
                blob.Properties.ContentMD5 = null;
                var content = memory.ToArray();

                // upload only if content has changed
                if (!content.SequenceEqual(bytes))
                {
                    blob.UploadByteArray(content, bro);
                }
            }
            return(view);
        }
Пример #10
0
 public TEntity AddOrUpdate(TKey key, Func <TEntity> addFactory, Func <TEntity, TEntity> update, AddOrUpdateHint hint)
 {
     return(this.AddOrUpdateAsync(key, addFactory, update, hint).GetAwaiter().GetResult());
 }
        public TEntity AddOrUpdate(TKey key, Func <TEntity> addFactory, Func <TEntity, TEntity> update, AddOrUpdateHint hint)
        {
            var name = GetName(key);

            try
            {
                var subfolder = Path.GetDirectoryName(name);
                if (subfolder != null && !Directory.Exists(subfolder))
                {
                    Directory.CreateDirectory(subfolder);
                }

                // we are locking the file.
                using (var file = File.Open(name, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None))
                {
                    byte[]  initial = new byte[0];
                    TEntity result;
                    if (file.Length == 0)
                    {
                        result = addFactory();
                    }
                    else
                    {
                        using (var mem = new MemoryStream())
                        {
                            file.CopyTo(mem);
                            mem.Seek(0, SeekOrigin.Begin);
                            var entity = _strategy.Deserialize <TEntity>(mem);
                            initial = mem.ToArray();
                            result  = update(entity);
                        }
                    }


                    using (var mem = new MemoryStream())
                    {
                        _strategy.Serialize(result, mem);
                        var data = mem.ToArray();

                        if (!data.SequenceEqual(initial))
                        {
                            // upload only if we changed
                            file.Seek(0, SeekOrigin.Begin);
                            file.Write(data, 0, data.Length);
                            // truncate this file
                            file.SetLength(data.Length);
                        }
                    }

                    return(result);
                }
            }
            catch (FileNotFoundException)
            {
                var s = string.Format("File '{0}' does not exist.", name);
                throw new InvalidOperationException(s);
            }
            catch (DirectoryNotFoundException)
            {
                var s = string.Format("Container '{0}' does not exist.", _folder);
                throw new InvalidOperationException(s);
            }
            catch (IOException) // fix for fast read / slow write concurency
            {
                _log.WriteLine("File write failed for {0} - {1} with key {2}. Will retry.", _folder, name, key);
                Thread.Sleep(120);
                return(AddOrUpdate(key, addFactory, update, hint));
            }
        }
        public TEntity AddOrUpdate(TKey key, Func <TEntity> addViewFactory, Func <TEntity, TEntity> updateViewFactory, AddOrUpdateHint hint)
        {
            // TODO: implement proper locking and order
            var     blob = GetBlobReference(key);
            TEntity view;

            try
            {
                using (var stream = blob.OpenRead())
                {
                    view = _strategy.Deserialize <TEntity>(stream);
                }

                view = updateViewFactory(view);
            }
            catch (StorageClientException ex)
            {
                switch (ex.ErrorCode)
                {
                case StorageErrorCode.ContainerNotFound:
                    var s = string.Format(
                        "Container '{0}' does not exist. You need to initialize this atomic storage and ensure that '{1}' is known to '{2}'.",
                        blob.Container.Name, typeof(TEntity).Name, _strategy.GetType().Name);
                    throw new InvalidOperationException(s, ex);

                case StorageErrorCode.BlobNotFound:
                case StorageErrorCode.ResourceNotFound:
                    view = addViewFactory();
                    break;

                default:
                    throw;
                }
            }
            using (var mem = blob.OpenWrite())
            {
                _strategy.Serialize(view, mem);
            }
            return(view);
        }
Пример #13
0
        public async Task <TEntity> AddOrUpdateAsync(TKey key, Func <TEntity> addFactory, Func <TEntity, TEntity> update, AddOrUpdateHint hint = AddOrUpdateHint.ProbablyExists)
        {
            var keyString = this.GetKeyString(key);

            if (this._viewsCache.ContainsKey(keyString))
            {
                return(this._viewsCache.AddOrUpdate(keyString, k => addFactory(), (k, e) => update(e)));
            }

            var loadedEntity = await this._reader.GetAsync(key);

            loadedEntity.IfValue(e => this._viewsCache.TryAdd(keyString, e));
            this.RemoveFromDelete(keyString);
            return(this._viewsCache.AddOrUpdate(keyString, k => addFactory(), (k, e) => update(e)));
        }
Пример #14
0
 public TEntity AddOrUpdate(TKey key, Func <TEntity> addFactory, Func <TEntity, TEntity> update, AddOrUpdateHint hint = AddOrUpdateHint.ProbablyExists)
 {
     return(this.AddOrUpdateAsync(key, addFactory, update, hint).Result);
 }