Esempio n. 1
0
        /// <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);
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Returns the range set that we are using and resets the in
        /// progress state.
        /// </summary>
        public BatchRangeSet FinishBuildingBatchRangeSet()
        {
            Debug.Assert(_inProgressRS != null);
            // check if the in progress range set is valid
            if (_inProgressRS.Count == 1 && !_inProgressRS.Last.RangeIsUsable)
            {
                // there where no tables finished or SyncIds added to
                // this range set!

                throw new DbSyncException("InteralBatchRangeSetError");
            }
            BatchRangeSet retSet = _inProgressRS;

            _inProgressRS = null;
            return(retSet);
        }
Esempio n. 3
0
        //
        // **** Methods for pulling sorted data
        //
        public IEnumerable <SortedBatch> PullSortedBatches()
        {
            // start the first batch and range
            SortedBatch pendingBatch = new SortedBatch();
            long        sizeOfBatch  = 0;

            // intialize the range set build because we will be pullig
            // rows now and need to calculate the correct range sets
            BatchRangeSetBuilder rangeSetBuilder = new BatchRangeSetBuilder(_srcKnowledge.GetSyncIdFormatGroup().ItemIdFormat, _tablesInApplyOrder);

            rangeSetBuilder.StartBuildingFirstBatchRangeSet();

            // for each table in apply order
            foreach (string tableName in _tablesInApplyOrder)
            {
                // start the next table range
                rangeSetBuilder.StartNextTable(tableName);

                // if we have a datatable for this name
                SortedTable curTable;
                if (_sortedTables.TryGetValue(tableName, out curTable) &&
                    curTable._schema != null)
                {
                    // add the current table to the batch we are working
                    // on
                    DataTable curDataTable = curTable._schema.Clone();
                    pendingBatch.sortedDataSet.Tables.Add(curDataTable);
                    curDataTable.BeginLoadData();

                    // if there are no rows in the table just add it to
                    // the current dataset and move on
                    SyncId maxIdInCurrentTable = null;
                    // pull the rows in SyncId order
                    foreach (KeyValuePair <SyncId, SortedRow> kvp in curTable._rows)
                    {
                        long curRowSize = SyncUtil.GetRowSizeForObjectArray(kvp.Value._rowValues);
                        if (curRowSize > (_maxSortedBatchSizeInKB * 1024))
                        {
                            // Note: This code is modified to throw a more specific exception.
                            // If we end up merging this code with the provider, then the caller has to be tested to
                            // make sure it works with the logic in the provider codebase.
                            throw SyncServiceException.CreateInternalServerError(
                                      String.Format(Strings.RowExceedsConfiguredBatchSize, _maxSortedBatchSizeInKB, tableName, curRowSize));
                        }
                        // fixme: if this row won't fit then return
                        // the current batch
                        if ((sizeOfBatch + curRowSize) > (_maxSortedBatchSizeInKB * 1024))
                        {
                            // * done loading data
                            curDataTable.EndLoadData();
                            // * add last sync id in batch
                            if (maxIdInCurrentTable == null)
                            {
                                // we have not added any rows to the
                                // current table so we should create a
                                // dummy id in the current table for
                                // the range
                                maxIdInCurrentTable = rangeSetBuilder.MakeDummyFirstRowID(tableName);
                            }

                            rangeSetBuilder.AddSyncId(tableName, maxIdInCurrentTable);
                            // start a new batch
                            BatchRangeSet curRS = rangeSetBuilder.FinishBuildingBatchRangeSet();
                            pendingBatch.sortedDataSetKnowledge = curRS.ProjectOnKnowledge(_srcKnowledge);

                            yield return(pendingBatch);

                            // *** tricky
                            // after yielding the current batch we
                            // need to start a new one for the rest of
                            // the rows in this table.
                            // we must reset all the neede state and
                            // this is tricky
                            maxIdInCurrentTable = null;
                            // start a new batch
                            pendingBatch = new SortedBatch();
                            sizeOfBatch  = 0;
                            // start a new range after the current one
                            rangeSetBuilder.StartBuildingBatchRangeSet(curRS);
                            // add the current table to the batch we are working
                            // on
                            curDataTable = curTable._schema.Clone();
                            pendingBatch.sortedDataSet.Tables.Add(curDataTable);
                            curDataTable.BeginLoadData();
                        }
                        AddSortedRowToDataTable(curDataTable, kvp.Value);
                        sizeOfBatch        += curRowSize;
                        maxIdInCurrentTable = kvp.Key;
                    }
                    curDataTable.EndLoadData();
                }
            }
            // we should always be working on a batch
            {
                Debug.Assert(pendingBatch != null);
                BatchRangeSet curRS = rangeSetBuilder.FinishLastBatchRangeSet();
                pendingBatch.sortedDataSetKnowledge = curRS.ProjectOnKnowledge(_srcKnowledge);
            }
            yield return(pendingBatch);
        }
Esempio n. 4
0
 /// <summary>
 /// Aborts the partially build range set if it exists.
 /// </summary>
 public void AbortRangeSet()
 {
     _inProgressRS = null;
 }
Esempio n. 5
0
 /// <summary>
 /// Start building state for a BatchRangeSet.
 /// call sequence should be:
 ///      StartBuildingFirstBatchRangeSet( )
 ///      AddSyncId(Sid)
 ///      ...
 ///      AddSyncId(Sid)
 ///      StartNextTable( tname )
 ///      AddSyncId(Sid)
 ///      result = FinishBuildingBatchRangeSet()
 /// Note that this implicetly starts the range with
 /// </summary>
 public void StartBuildingFirstBatchRangeSet()
 {
     // not valid to start a new range set while one is in progress
     Debug.Assert(_inProgressRS == null);
     _inProgressRS = new BatchRangeSet();
 }
Esempio n. 6
0
 /// <summary>
 /// Aborts the partially build range set if it exists.
 /// </summary>
 public void AbortRangeSet()
 {
     _inProgressRS = null;
 }
Esempio n. 7
0
        /// <summary>
        /// Returns the range set that we are using and resets the in
        /// progress state.
        /// </summary>
        public BatchRangeSet FinishBuildingBatchRangeSet()
        {
            Debug.Assert( _inProgressRS != null );
            // check if the in progress range set is valid
            if( _inProgressRS.Count == 1 && !_inProgressRS.Last.RangeIsUsable ) {
                // there where no tables finished or SyncIds added to
                // this range set!

                throw new DbSyncException("InteralBatchRangeSetError");
            }
            BatchRangeSet retSet = _inProgressRS;
            _inProgressRS = null;
            return retSet;
        }
Esempio n. 8
0
 /// <summary>
 /// Start building state for a BatchRangeSet.
 /// call sequence should be:
 ///      StartBuildingFirstBatchRangeSet( )
 ///      AddSyncId(Sid)
 ///      ...
 ///      AddSyncId(Sid)
 ///      StartNextTable( tname ) 
 ///      AddSyncId(Sid)
 ///      result = FinishBuildingBatchRangeSet()
 /// Note that this implicetly starts the range with 
 /// </summary>
 public void StartBuildingFirstBatchRangeSet()
 {
     // not valid to start a new range set while one is in progress
     Debug.Assert( _inProgressRS == null );
     _inProgressRS = new BatchRangeSet();
 }
Esempio n. 9
0
        /// <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 );
            }
        }