Exemplo n.º 1
0
        private ushort[] FindOrAssignLIDs(DataBlock.ReadOnlyDataBlock values, int idColumnIndex, AddOrUpdateMode mode)
        {
            Type idColumnDataType = values.GetTypeForColumn(idColumnIndex);

            // If the insert array matches types with the column then we can use the native type to do a direct assignment from the input array
            // to the column array.  If the types do not match, we need to fallback to object to allow the Value class to handle the type conversion
            ITypedAddOrUpdateWorker worker = NativeContainer.CreateTypedInstance <ITypedAddOrUpdateWorker>(typeof(AddOrUpdateWorker <>), idColumnDataType);

            return(worker.FindOrAssignLIDs(this, values, idColumnIndex, mode));
        }
Exemplo n.º 2
0
        private void FillPartitionColumn(DataBlock.ReadOnlyDataBlock values, int columnIndex, ushort[] itemLIDs)
        {
            string columnName = values.Columns[columnIndex].Name;

            if (columnName.Equals(this.IDColumn.Name, StringComparison.OrdinalIgnoreCase))
            {
                return;
            }

            Type dataBlockColumnDataType = values.GetTypeForColumn(columnIndex);

            // If the insert array matches types with the column then we can use the native type to do a direct assignment from the input array
            // to the column array.  If the types do not match, we need to fallback to object to allow the Value class to handle the type conversion
            ITypedAddOrUpdateWorker worker = NativeContainer.CreateTypedInstance <ITypedAddOrUpdateWorker>(typeof(AddOrUpdateWorker <>), dataBlockColumnDataType);

            worker.FillPartitionColumn(this, values, columnIndex, itemLIDs);
        }
Exemplo n.º 3
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();
            }
        }
Exemplo n.º 4
0
        public void AddColumnsFromBlock(DataBlock.ReadOnlyDataBlock values)
        {
            List <ColumnDetails> columnsToAdd = new List <ColumnDetails>();

            // Find the ID column
            //  [The existing one, or one marked as primary key on the block, or one ending with 'ID', or the first column]
            ColumnDetails idColumn = _partitions[0].IDColumn
                                     ?? values.Columns.FirstOrDefault((cd) => cd.IsPrimaryKey)
                                     ?? values.Columns.FirstOrDefault((cd) => cd.Name.EndsWith("ID"))
                                     ?? values.Columns.FirstOrDefault();

            // Mark the ID column
            idColumn.IsPrimaryKey = true;

            for (int columnIndex = 0; columnIndex < values.ColumnCount; ++columnIndex)
            {
                ColumnDetails details             = values.Columns[columnIndex];
                bool          hasNonDefaultValues = false;

                // If this column was already added, no need to scan these values
                if (_partitions[0].ContainsColumn(details.Name))
                {
                    continue;
                }

                // Figure out the column type. Did the DataBlock provide one?
                Type determinedType = ColumnFactory.GetTypeFromTypeString(details.Type);

                // If not, is the DataBlock column array typed?
                determinedType = determinedType ?? values.GetTypeForColumn(columnIndex);
                if (determinedType == typeof(object) || determinedType == typeof(Value))
                {
                    determinedType = null;
                }

                // Get the column default, if provided, or the default for the type, if provided
                object columnDefault = details.Default;
                if (columnDefault == null && determinedType != null)
                {
                    columnDefault = ColumnFactory.GetDefaultValueFromTypeString(determinedType.Name);
                }

                Type     inferredType = null;
                Value    v            = Value.Create(null);
                DateTime defaultUtc   = default(DateTime).ToUniversalTime();

                for (int rowIndex = 0; rowIndex < values.RowCount; ++rowIndex)
                {
                    object value = values[rowIndex, columnIndex];

                    // Identify the best type for all block values, if no type was already determined
                    if (determinedType == null)
                    {
                        v.Assign(value);
                        Type newBestType = v.BestType(inferredType);

                        // If the type has changed, get an updated default value
                        if (newBestType != determinedType)
                        {
                            columnDefault = ColumnFactory.GetDefaultValueFromTypeString(newBestType.Name);
                            inferredType  = newBestType;
                        }
                    }

                    // Track whether any non-default values were seen [could be raw types or Value wrapper]
                    if (hasNonDefaultValues == false && value != null && !value.Equals("") && !value.Equals(defaultUtc))
                    {
                        if (columnDefault == null || value.Equals(columnDefault) == false)
                        {
                            hasNonDefaultValues = true;
                        }
                    }
                }

                // Set the column type
                if (String.IsNullOrEmpty(details.Type) || details.Type.Equals(Arriba.Model.Column.ColumnDetails.UnknownType))
                {
                    details.Type = ColumnFactory.GetCanonicalTypeName(determinedType ?? inferredType ?? typeof(string));
                }

                // Add the column if it had any non-default values (and didn't already exist)
                if (hasNonDefaultValues || details.IsPrimaryKey)
                {
                    columnsToAdd.Add(details);
                }
            }

            // Add the discovered columns. If any names match existing columns they'll be merged properly in Partition.AddColumn.
            AddColumns(columnsToAdd);
        }