Пример #1
0
        /// <summary>
        /// Adds matching entities and removes removed entities from indexes
        /// </summary>
        private void UpdateIndexes(RedisTransactionWrapper transaction, string hashKeyValue, IDictionary <EntityKey, Document> addedEntities, IDictionary <EntityKey, Document> modifiedEntities, ICollection <EntityKey> removedEntities)
        {
            string indexListKey = this.GetIndexListKeyInCache(hashKeyValue);

            foreach (var indexEntry in this._redis.GetHashFieldsWithRetries(indexListKey))
            {
                string indexKey = indexEntry.Name;

                // The index itself might be dropped from cache already. We don't want the transaction to fail because of this
                if (!this._redis.HashFieldExistsWithRetries(indexKey, IndexVersionField.Name))
                {
                    this._redis.RemoveHashFieldsWithRetries(indexListKey, indexKey);
                    continue;
                }

                var filter = indexEntry.Value.ToObject <SearchConditions>();

                if (this.IsProjectionIndex(indexKey))
                {
                    this.UpdateProjectionIndex(transaction, hashKeyValue, indexKey, filter, addedEntities, modifiedEntities, removedEntities);
                }
                else
                {
                    this.UpdateIndex(transaction, indexKey, filter, addedEntities, modifiedEntities, removedEntities);
                }
            }
        }
Пример #2
0
            public RedisIndex(RedisTableCache parent, string indexKey, SearchConditions searchConditions)
            {
                this._parent           = parent;
                this.IndexKeyInCache   = indexKey;
                this._searchConditions = searchConditions;

                try
                {
                    // (re)registering it in the list of indexes (it should be visible for update operations)
                    this._parent._redis.SetHashWithRetries(this._parent.GetIndexListKeyInCache(), this.IndexKeyInCache, this._searchConditions.ToRedisValue());

                    // asynchronously checking the total number of indexes
                    Task.Run(() => this.TryKeepIndexListSlim(indexKey));

                    // creating an index and marking it as being rebuilt
                    this._parent._redis.CreateNewHashWithRetries(this.IndexKeyInCache, IndexVersionField.Name, IndexVersionField.IsBeingRebuiltValue);

                    this.RedisTransaction = this._parent._redis.BeginTransaction(IndexVersionField.IsBeingRebuiltCondition(this.IndexKeyInCache));
                    this._parent.Log("Index ({0}) was marked as being rebuilt", this._searchConditions.Key);
                }
                catch (Exception ex)
                {
                    this._parent.Log("Failed to start creating index: {0}", ex);

                    // if something goes wrong - dropping the index (but only from the list - we don't want to let parallel update transaction to fail)
                    this._parent._redis.RemoveHashFieldsWithRetries(this._parent.GetIndexListKeyInCache(), this.IndexKeyInCache);
                    throw;
                }
            }
Пример #3
0
        /// <summary>
        /// Adds matching entities and removes removed entities from index
        /// </summary>
        private void UpdateIndex(RedisTransactionWrapper transaction, string indexKey, SearchConditions filter, IDictionary <EntityKey, Document> addedEntities, IDictionary <EntityKey, Document> modifiedEntities, ICollection <EntityKey> removedEntities)
        {
            bool indexChanged = false;

            // adding added entities, if they match the index conditions
            foreach
            (
                var entityPair in addedEntities.Union(modifiedEntities).Where
                (
                    entityPair => filter.MatchesSearchConditions(entityPair.Value, this._tableEntityType)
                )
            )
            {
                transaction.HashSet(indexKey, entityPair.Key.ToRedisValue(), string.Empty);
                indexChanged = true;
            }

            // removing modified entities, if they do not match the index conditions any more
            foreach
            (
                var entityPair in modifiedEntities.Where
                (
                    entityPair => !filter.MatchesSearchConditions(entityPair.Value, this._tableEntityType)
                )
            )
            {
                transaction.HashRemove(indexKey, entityPair.Key.ToRedisValue());
                indexChanged = true;
            }

            // removing removed entities
            foreach (var entityKey in removedEntities)
            {
                transaction.HashRemove(indexKey, entityKey.ToRedisValue());
                indexChanged = true;
            }

            if (indexChanged)
            {
                // The index should exist in the cache at the moment transaction is being executed.
                // Otherwise this update operation will cause the index to occasionally "resurrect" after being expired.
                transaction.AddHashFieldExistsCondition(indexKey, IndexVersionField.Name);

                // also incrementing the version field
                transaction.HashIncrement(indexKey, IndexVersionField.Name);
            }
        }
Пример #4
0
 /// <summary>
 /// Checks if a projection index should be dropped because of some added/modified/removed entities
 /// </summary>
 private void UpdateProjectionIndex(RedisTransactionWrapper transaction, string hashKeyValue, string indexKey, SearchConditions filter, IDictionary <EntityKey, Document> addedEntities, IDictionary <EntityKey, Document> modifiedEntities, ICollection <EntityKey> removedEntities)
 {
     if
     (
         (modifiedEntities.Count > 0)
         ||
         (removedEntities.Count > 0)
         ||
         addedEntities.Values.Any // or some entities were added, that satisfy the index condition
         (
             en => filter.MatchesSearchConditions(en, this._tableEntityType)
         )
     )
     {
         // then the only option for us is to drop the index - as we don't know, if these entities conform to index's conditions or not
         this.Log("Projection index ({0}) removed because of some modified entities", indexKey);
         transaction.HashRemove(this.GetIndexListKeyInCache(hashKeyValue), indexKey);
         transaction.Remove(indexKey);
     }
 }