/// <summary>
        /// Sets the item counter.
        /// </summary>
        /// <param name="typeId">The type id.</param>
        /// <param name="outDeserializationContext">The OutDeserializationContext.</param>
        protected override void SetItemCounter(short typeId, OutDeserializationContext outDeserializationContext)
        {
            PerformanceCounters.Instance.SetCounterValue(PerformanceCounterEnum.NumOfItemsInIndexPerPagedIndexQuery,
                                                         typeId,
                                                         outDeserializationContext.TotalCount);

            PerformanceCounters.Instance.SetCounterValue(PerformanceCounterEnum.NumOfItemsReadPerPagedIndexQuery,
                                                         typeId,
                                                         outDeserializationContext.ReadItemCount);
        }
        /// <summary>
        /// Deserializes the internal item.
        /// </summary>
        /// <param name="internalItem">The internal item</param>
        /// <param name="inDeserializationContext">The in deserialization context.</param>
        /// <param name="outDeserializationContext">The out deserialization context.</param>
        /// <param name="reader">The reader.</param>
        private static void DeserializeTags(InternalItem internalItem,
                                            InDeserializationContext inDeserializationContext,
                                            OutDeserializationContext outDeserializationContext,
                                            IPrimitiveReader reader)
        {
            byte kvpListCount = reader.ReadByte();

            if (kvpListCount > 0)
            {
                internalItem.TagList = new List <KeyValuePair <int, byte[]> >(kvpListCount);
                for (byte j = 0; j < kvpListCount; j++)
                {
                    int    tagHashCode = reader.ReadInt32();
                    ushort tagValueLen = reader.ReadUInt16();
                    byte[] tagValue    = null;
                    if (tagValueLen > 0)
                    {
                        tagValue = reader.ReadBytes(tagValueLen);
                        if (inDeserializationContext.StringHashCodeDictionary != null &&
                            inDeserializationContext.StringHashCodeDictionary.Count > 0 &&
                            inDeserializationContext.StringHashCodeDictionary.ContainsKey(tagHashCode))
                        {
                            tagValue = inDeserializationContext.StringHashCollection.GetStringByteArray(inDeserializationContext.TypeId, tagValue);
                        }
                    }
                    internalItem.TagList.Add(new KeyValuePair <int, byte[]>(tagHashCode, tagValue));
                }
            }

            //Get Distinct Values
            if (!String.IsNullOrEmpty(inDeserializationContext.GetDistinctValuesFieldName))
            {
                byte[] distinctValue;
                if (String.Equals(inDeserializationContext.GetDistinctValuesFieldName, "ItemId", StringComparison.OrdinalIgnoreCase))
                {
                    distinctValue = internalItem.ItemId;
                }
                else
                {
                    internalItem.TryGetTagValue(inDeserializationContext.GetDistinctValuesFieldName, out distinctValue);
                }

                if (distinctValue != null)
                {
                    if (outDeserializationContext.DistinctValueCountMapping.ContainsKey(distinctValue))
                    {
                        outDeserializationContext.DistinctValueCountMapping[distinctValue] += 1;
                    }
                    else
                    {
                        outDeserializationContext.DistinctValueCountMapping.Add(distinctValue, 1);
                    }
                }
            }
        }
        /// <summary>
        /// Deserialize the class data from a stream.
        /// </summary>
        /// <param name="reader">The <see cref="IPrimitiveReader"/> that extracts used to extra data from a stream.</param>
        /// <param name="version">The value of <see cref="CurrentVersion"/> that was written to the stream when it was originally serialized to a stream;
        /// the version of the <paramref name="reader"/> data.</param>
        public void Deserialize(IPrimitiveReader reader, int version)
        {
            //Metadata
            ushort len = reader.ReadUInt16();

            if (len > 0)
            {
                Metadata = reader.ReadBytes(len);
            }

            //VirtualCount
            if (version >= 2)
            {
                virtualCount = reader.ReadInt32();
            }

            //Count
            outDeserializationContext = new OutDeserializationContext {
                TotalCount = reader.ReadInt32()
            };

            if (InDeserializationContext.DeserializeHeaderOnly)
            {
                //Note: If InDeserializationContext.DeserializeHeaderOnly property is set then InDeserializationContext.PartialByteArray shall hold all CacheIndexInternal
                //payload except metadata and header (just virtual count for now). This code path will only be used if just
                //header info like virtual count needs to be updated keeping rest of the index untouched.
                //InDeserializationContext.PartialByteArray shall be used in Serialize code
                outDeserializationContext.UnserializedCacheIndexInternal =
                    new byte[(int)reader.BaseStream.Length - (int)reader.BaseStream.Position + 1];
                reader.BaseStream.Read(outDeserializationContext.UnserializedCacheIndexInternal, 0, outDeserializationContext.UnserializedCacheIndexInternal.Length);
            }
            else
            {
                int actualItemCount = outDeserializationContext.TotalCount;

                //this.InDeserializationContext.MaxItemsPerIndex = 0 indicates need to extract all items
                //this.InDeserializationContext.MaxItemsPerIndex > 0 indicates need to extract only number of items indicated by InDeserializationContext.MaxItemsPerIndex
                if (InDeserializationContext.MaxItemsPerIndex > 0)
                {
                    if (InDeserializationContext.MaxItemsPerIndex < outDeserializationContext.TotalCount)
                    {
                        actualItemCount = InDeserializationContext.MaxItemsPerIndex;
                    }
                }

                #region Populate InternalItemList

                byte[]       itemId;
                InternalItem internalItem;
                bool         enterConditionPassed = false;

                InternalItemList = new InternalItemList();

                // Note: ---- Termination condition of the loop
                // For full index extraction loop shall terminate because of condition : internalItemList.Count < actualItemCount
                // For partial index extraction loop shall terminate because of following conditions
                //				a)  i < InDeserializationContext.TotalCount (when no sufficient items are found) OR
                //				b)  internalItemList.Count < actualItemCount (Item extraction cap is reached)
                int i = 0;
                while (InternalItemList.Count < actualItemCount && i < outDeserializationContext.TotalCount)
                {
                    i++;

                    #region Deserialize ItemId

                    len = reader.ReadUInt16();
                    if (len > 0)
                    {
                        itemId = reader.ReadBytes(len);
                    }
                    else
                    {
                        throw new Exception("Invalid ItemId - is null or length is zero for IndexId : " +
                                            IndexCacheUtils.GetReadableByteArray(InDeserializationContext.IndexId));
                    }

                    #endregion

                    #region Process IndexCondition

                    if (InDeserializationContext.EnterCondition != null || InDeserializationContext.ExitCondition != null)
                    {
                        #region Have Enter/Exit Condition

                        if (InDeserializationContext.PrimarySortInfo.IsTag == false)
                        {
                            #region Sort by ItemId

                            if (InDeserializationContext.EnterCondition != null && enterConditionPassed == false)
                            {
                                #region enter condition processing

                                if (InDeserializationContext.EnterCondition.Process(itemId))
                                {
                                    enterConditionPassed = true;
                                    internalItem         = DeserializeInternalItem(itemId, InDeserializationContext, reader);
                                    ApplyFilterAndAddItem(internalItem);
                                }
                                else
                                {
                                    SkipDeserializeInternalItem(reader);
                                    // no filter processing required
                                }

                                #endregion
                            }
                            else if (InDeserializationContext.ExitCondition != null)
                            {
                                #region exit condition processing

                                if (InDeserializationContext.ExitCondition.Process(itemId))
                                {
                                    // since item passed exit filter, we keep it.
                                    internalItem = DeserializeInternalItem(itemId, InDeserializationContext, reader);
                                    ApplyFilterAndAddItem(internalItem);
                                }
                                else
                                {
                                    // no need to search beyond this point
                                    break;
                                }

                                #endregion
                            }
                            else if (InDeserializationContext.EnterCondition != null && enterConditionPassed && InDeserializationContext.ExitCondition == null)
                            {
                                #region enter condition processing when no exit condition exists

                                internalItem = DeserializeInternalItem(itemId, InDeserializationContext, reader);
                                ApplyFilterAndAddItem(internalItem);

                                #endregion
                            }

                            #endregion
                        }
                        else
                        {
                            byte[] tagValue;

                            #region Deserialize InternalItem and fetch PrimarySortTag value

                            internalItem = DeserializeInternalItem(itemId, InDeserializationContext, reader);
                            if (!internalItem.TryGetTagValue(InDeserializationContext.PrimarySortInfo.FieldName, out tagValue))
                            {
                                throw new Exception("PrimarySortTag Not found:  " + InDeserializationContext.PrimarySortInfo.FieldName);
                            }

                            #endregion

                            #region Sort by Tag

                            if (InDeserializationContext.EnterCondition != null && enterConditionPassed == false)
                            {
                                #region enter condition processing

                                if (InDeserializationContext.EnterCondition.Process(tagValue))
                                {
                                    enterConditionPassed = true;
                                    ApplyFilterAndAddItem(internalItem);
                                }

                                #endregion
                            }
                            else if (InDeserializationContext.ExitCondition != null)
                            {
                                #region exit condition processing

                                if (InDeserializationContext.ExitCondition.Process(tagValue))
                                {
                                    // since item passed exit filter, we keep it.
                                    ApplyFilterAndAddItem(internalItem);
                                }
                                else
                                {
                                    // no need to search beyond this point
                                    break;
                                }

                                #endregion
                            }
                            else if (InDeserializationContext.EnterCondition != null && enterConditionPassed && InDeserializationContext.ExitCondition == null)
                            {
                                #region enter condition processing when no exit condition exists

                                ApplyFilterAndAddItem(internalItem);

                                #endregion
                            }

                            #endregion
                        }

                        #endregion
                    }
                    else
                    {
                        #region No Enter/Exit Condition

                        internalItem = DeserializeInternalItem(itemId, InDeserializationContext, reader);
                        ApplyFilterAndAddItem(internalItem);

                        #endregion
                    }

                    #endregion
                }

                //Set ReadItemCount on OutDeserializationContext
                outDeserializationContext.ReadItemCount = i;

                #endregion
            }
        }
 /// <summary>
 /// Sets the item counter.
 /// </summary>
 /// <param name="typeId">The type id.</param>
 /// <param name="outDeserializationContext">The OutDeserializationContext.</param>
 protected abstract void SetItemCounter(short typeId, OutDeserializationContext outDeserializationContext);