/// <summary>
        /// Start building state for a BatchRangeSet.
        /// call sequence should be:
        ///      StartBuildingBatchRangeSet( prevRs )
        ///      AddSyncId(Sid)
        ///      ...
        ///      AddSyncId(Sid)
        ///      StartNextTable( tname )
        ///      AddSyncId(Sid)
        ///      result = FinishBuildingBatchRangeSet()
        ///
        /// Note that this implicitly starts the range with the end of
        /// prevRS+1
        /// ***** We don't track the prevRS internally because we want to be able
        /// ***** to rebuild a rangeset from scratch if we for
        /// ***** instance change the batching limits
        /// </summary>
        /// <param name="prevRS">
        /// The prev rangeset that was built.
        /// </param>
        public void StartBuildingBatchRangeSet(BatchRangeSet prevRS)
        {
            Debug.Assert(_inProgressRS == null);

            BatchRange prevLast = prevRS.Last;

            _inProgressRS = new BatchRangeSet();

            // check that this rangeset was not built as the last
            // rangeset for a knowledge.
            Debug.Assert(prevLast.End != _tableRanges[prevLast.TableName].End);

            // was the end of the last range usable?
            if (!prevLast.RangeIsUsable)
            {
                Debug.Assert(prevLast.TableName != null);
                Debug.Assert(prevLast.Start != null);
                // if the prev range moved to the current table but did
                // not have any rows then we are starting the table again.
                // just take the unusable range as our own
                _inProgressRS.Add(new BatchRange(prevLast));
            }
            else
            {
                // We have a started the current table already
                // So continue from one greater than the last range
                BatchRange nextRange = new BatchRange();
                nextRange.TableName = prevLast.TableName;
                nextRange.Start     = IdPlusOne(_idFormat, prevLast.End);
                // leave End as null
                _inProgressRS.Add(nextRange);
            }
        }
        // adds range for given table to current range set
        private void AppendNewTableRange(string tableName)
        {
            // take the predetermined start range for the current
            // table and leave the current range in an unusable state
            // until the first row is added or this table ends
            BatchRange nextRange = new BatchRange();

            nextRange.TableName = tableName;
            nextRange.Start     = _tableRanges[tableName].Start;
            _inProgressRS.Add(nextRange);
        }
        /// <summary>
        /// Creates a Range set build and pre calculates the effective
        /// tables ranges for use later when building a BatchRangeSet.
        /// </summary>
        /// <param name="idFormat">
        /// The id format for the SyncIds
        /// </param>
        /// <param name="tableNames">
        /// All the table names in that will be in the sum of the
        /// batches. Order does not matter.
        /// </param>
        public BatchRangeSetBuilder(SyncIdFormat idFormat, List <string> tableNames)
        {
            _tableRanges = new Dictionary <string, BatchRange>(tableNames.Count);
            _idFormat    = idFormat;

            int numTables = tableNames.Count;
            SortedList <SyncId, string> tablesSortedBySyncId
                = new SortedList <SyncId, string>(numTables);

            List <object> emptyPkVals = new List <object>(0);

            foreach (string curTable in tableNames)
            {
                SyncId idBeforeTable = SyncUtil.InitRowId(curTable, emptyPkVals);
                tablesSortedBySyncId.Add(idBeforeTable, curTable);
            }

            // for each table we need to determine the:
            // - starting SyncId (zero or first id in table)
            // - ending SyncId (just before next table or infinity)
            BatchRange prevTableRange = null;

            foreach (KeyValuePair <SyncId, string> curElem in tablesSortedBySyncId)
            {
                BatchRange curTableRange = new BatchRange();
                curTableRange.TableName = curElem.Value;
                // assume this is the last table and then fix this if
                // there is another table
                curTableRange.End = _idFormat.Infinity;
                if (prevTableRange == null)
                {
                    // first table starts at zero
                    curTableRange.Start = _idFormat.Zero;
                }
                else
                {
                    // fix up prev end to be correct
                    // set it's end to be one before current tables
                    // starting SyncId
                    prevTableRange.End  = curElem.Key;
                    curTableRange.Start = IdPlusOne(_idFormat, curElem.Key);
                }
                prevTableRange = curTableRange;
                _tableRanges.Add(curTableRange.TableName, curTableRange);
            }
        }
 public BatchRange(BatchRange src)
 {
     TableName = src.TableName;
     Start     = src.Start;
     End       = src.End;
 }
 public void Add(BatchRange newRange)
 {
     Debug.Assert((Count == 0) || Last.RangeIsUsable);
     _ranges.Add(newRange);
 }
 public BatchRange( BatchRange src ) 
 {
     TableName = src.TableName;
     Start     = src.Start;
     End       = src.End;
 }
 // adds range for given table to current range set
 private void AppendNewTableRange( string tableName )
 {
     // take the predetermined start range for the current
     // table and leave the current range in an unusable state
     // until the first row is added or this table ends
     BatchRange nextRange = new BatchRange();
     nextRange.TableName = tableName;
     nextRange.Start = _tableRanges[tableName].Start;
     _inProgressRS.Add( nextRange );
 }
        /// <summary>
        /// Start building state for a BatchRangeSet.
        /// call sequence should be:
        ///      StartBuildingBatchRangeSet( prevRs )
        ///      AddSyncId(Sid)
        ///      ...
        ///      AddSyncId(Sid)
        ///      StartNextTable( tname ) 
        ///      AddSyncId(Sid)
        ///      result = FinishBuildingBatchRangeSet()
        ///
        /// Note that this implicitly starts the range with the end of
        /// prevRS+1
        /// ***** We don't track the prevRS internally because we want to be able
        /// ***** to rebuild a rangeset from scratch if we for
        /// ***** instance change the batching limits
        /// </summary>
        /// <param name="prevRS"> 
        /// The prev rangeset that was built.
        /// </param>
        public void StartBuildingBatchRangeSet( BatchRangeSet prevRS )
        {
            Debug.Assert( _inProgressRS == null );

            BatchRange prevLast = prevRS.Last;
            _inProgressRS = new BatchRangeSet();

            // check that this rangeset was not built as the last
            // rangeset for a knowledge. 
            Debug.Assert( prevLast.End != _tableRanges[prevLast.TableName].End );

            // was the end of the last range usable?
            if( !prevLast.RangeIsUsable ) 
            {
                Debug.Assert( prevLast.TableName != null );
                Debug.Assert( prevLast.Start != null );
                // if the prev range moved to the current table but did
                // not have any rows then we are starting the table again.
                // just take the unusable range as our own
                _inProgressRS.Add(new BatchRange(prevLast));
            }
            else 
            {
                // We have a started the current table already 
                // So continue from one greater than the last range
                BatchRange nextRange = new BatchRange();
                nextRange.TableName = prevLast.TableName;
                nextRange.Start = IdPlusOne( _idFormat, prevLast.End );
                // leave End as null
                _inProgressRS.Add( nextRange );
            }
        }
        /// <summary>
        /// Creates a Range set build and pre calculates the effective
        /// tables ranges for use later when building a BatchRangeSet.
        /// </summary>
        /// <param name="idFormat"> 
        /// The id format for the SyncIds
        /// </param>
        /// <param name="tableNames"> 
        /// All the table names in that will be in the sum of the
        /// batches. Order does not matter.
        /// </param>
        public BatchRangeSetBuilder( SyncIdFormat idFormat, List<string> tableNames )
        {
            _tableRanges = new Dictionary<string, BatchRange>( tableNames.Count );
            _idFormat = idFormat;

            int numTables = tableNames.Count;
            SortedList<SyncId,string> tablesSortedBySyncId 
                = new SortedList<SyncId,string>(numTables);

            List<object> emptyPkVals = new List<object>(0);

            foreach( string curTable in tableNames ) 
            {
                SyncId idBeforeTable = SyncUtil.InitRowId( curTable, emptyPkVals );
                tablesSortedBySyncId.Add( idBeforeTable, curTable );
            }

            // for each table we need to determine the:
            // - starting SyncId (zero or first id in table)
            // - ending SyncId (just before next table or infinity)
            BatchRange prevTableRange = null;
            
            foreach( KeyValuePair<SyncId,string> curElem in tablesSortedBySyncId ) 
            {
                BatchRange curTableRange = new BatchRange();
                curTableRange.TableName = curElem.Value;
                // assume this is the last table and then fix this if
                // there is another table
                curTableRange.End = _idFormat.Infinity;
                if( prevTableRange == null ) 
                {
                    // first table starts at zero
                    curTableRange.Start = _idFormat.Zero;
                } 
                else 
                {
                    // fix up prev end to be correct
                    // set it's end to be one before current tables
                    // starting SyncId
                    prevTableRange.End = curElem.Key;
                    curTableRange.Start = IdPlusOne( _idFormat, curElem.Key );
                }
                prevTableRange = curTableRange;
                _tableRanges.Add( curTableRange.TableName, curTableRange );
            }
        }
 public void Add( BatchRange newRange )
 {
     Debug.Assert( (Count == 0)||Last.RangeIsUsable );
     _ranges.Add( newRange );
 }