Esempio n. 1
0
        /// <summary>
        ///  Add or Update the given items with the given values. The specific values added are represented in the linked list
        ///  starting at partitionChains[chainHead]
        /// </summary>
        /// <param name="values">Set of Columns and values to add or update</param>
        /// <param name="partitionChains">storage for the set of linked lists indicating which values are in each partition.  The index is the row number in values
        /// of the corresponding item.  The value is the next item in the chain with -1 indicating the end.</param>
        /// <param name="chainHead">starting index for the list of items that this partition should add</param>
        public void AddOrUpdate(DataBlock.ReadOnlyDataBlock values, AddOrUpdateOptions options)
        {
            int columnCount   = values.ColumnCount;
            int idColumnIndex = values.IndexOfColumn(this.IDColumn.Name);

            // Look up the LID for each item or add it
            ushort[] itemLIDs = FindOrAssignLIDs(values, idColumnIndex, options.Mode);

            // If there are new items, resize every column for them
            ushort newCount = (ushort)(_itemCount);

            foreach (IColumn <object> column in this.Columns.Values)
            {
                if (column.Count != newCount)
                {
                    column.SetSize(newCount);
                }
            }

            // Set values for each other provided column
            for (int columnIndex = 0; columnIndex < columnCount; ++columnIndex)
            {
                FillPartitionColumn(values, columnIndex, itemLIDs);
            }

            // Commit every column [ones with new values and ones resized with defaults]
            foreach (IColumn <object> column in this.Columns.Values)
            {
                if (column is ICommittable)
                {
                    (column as ICommittable).Commit();
                }
            }
        }
Esempio n. 2
0
        /// <summary>
        ///  Add or Update the given items with the given values. The ID column must be passed
        ///  and must be the first column. If an ID is not known, the item will be added.
        ///  For each item, the value for each column is set to the provided values.
        /// </summary>
        /// <param name="values">Set of Columns and values to add or update</param>
        /// <param name="options">Options to adjust behavior of AddOrUpdate</param>
        public void AddOrUpdate(DataBlock.ReadOnlyDataBlock values, AddOrUpdateOptions options)
        {
            _locker.EnterWriteLock();
            try
            {
                // Add columns from data, if this is the first data and columns weren't predefined
                if (options.AddMissingColumns)
                {
                    AddColumnsFromBlock(values);
                }

                ColumnDetails idColumn = _partitions[0].IDColumn;
                if (idColumn == null)
                {
                    throw new ArribaException("Items cannot be added to this Table because it does not yet have an ID column defined. Call AddColumn with exactly one column with 'IsPrimaryKey' true and then items may be added.");
                }
                int idColumnIndex = values.IndexOfColumn(idColumn.Name);
                if (idColumnIndex == -1)
                {
                    throw new ArribaException(StringExtensions.Format("AddOrUpdates must be passed the ID column, '{0}', in order to tell which items to update.", idColumn.Name));
                }

                // Verify all passed columns exist
                foreach (ColumnDetails column in values.Columns)
                {
                    ColumnDetails foundColumn;
                    if (!_partitions[0].DetailsByColumn.TryGetValue(column.Name, out foundColumn))
                    {
                        throw new ArribaException(StringExtensions.Format("AddOrUpdate failed because values were passed for column '{0}', which is not in the table. Use AddColumn to add all columns first or ensure the first block added to the Table has all desired columns.", column.Name));
                    }
                }

                // Non-Parallel Implementation
                if (_partitions.Count == 1)
                {
                    _partitions[0].AddOrUpdate(values, options);
                    return;
                }

                // Determine the partition each item should go to
                int[] partitionIds;
                TargetPartitionInfo[] partitionInfo;
                Type idColumnArrayType = values.GetTypeForColumn(idColumnIndex);
                if (_splitter == null || _splitter.Item2 == null || _splitter.Item1 != idColumnArrayType)
                {
                    IComputePartition splitter = NativeContainer.CreateTypedInstance <IComputePartition>(typeof(ComputePartitionHelper <>), idColumnArrayType);
                    _splitter = Tuple.Create(idColumnArrayType, splitter);
                }
                _splitter.Item2.ComputePartition(this, values, idColumnIndex, out partitionIds, out partitionInfo);

                // Sort/group the incoming items by paritition and then by index to ensure they
                // are processed in the order they were presented in the input ReadOnlyDataBlock
                int[] sortOrder = new int[values.RowCount];
                for (int i = 0; i < values.RowCount; ++i)
                {
                    int p          = partitionIds[i];
                    int startIndex = partitionInfo[p].StartIndex + partitionInfo[p].Count;
                    sortOrder[startIndex] = i;
                    partitionInfo[p].Count++;
                }

                Action <Tuple <int, int>, ParallelLoopState> forBody =
                    delegate(Tuple <int, int> range, ParallelLoopState unused)
                {
                    for (int p = range.Item1; p < range.Item2; ++p)
                    {
                        int startIndex = partitionInfo[p].StartIndex;
                        int length     = partitionInfo[p].Count;
                        DataBlock.ReadOnlyDataBlock partitionValues = values.ProjectChain(sortOrder, startIndex, length);
                        _partitions[p].AddOrUpdate(partitionValues, options);
                    }
                };

                // In parallel, each partition will add items which belong to it
                if (this.RunParallel)
                {
                    var rangePartitioner = Partitioner.Create(0, _partitions.Count);
                    Parallel.ForEach(rangePartitioner, this.ParallelOptions, forBody);
                }
                else
                {
                    var range = Tuple.Create(0, _partitions.Count);
                    forBody(range, null);
                }
            }
            finally
            {
                _locker.ExitWriteLock();
            }
        }