Esempio n. 1
0
            public ushort[] FindOrAssignLIDs(Partition p, DataBlock.ReadOnlyDataBlock values, int idColumnIndex, AddOrUpdateMode mode)
            {
                // TODO: consider keeping one instance of the worker long term? if so, this becomes a private class field
                ValueTypeReference <T> vtr = new ValueTypeReference <T>();
                Value v = Value.Create(null);

                ushort[] itemLIDs = new ushort[values.RowCount];
                int      addCount = 0;

                IUntypedColumn idColumn      = p.Columns[p.IDColumn.Name];
                IColumn <T>    typedIdColumn = null;

                if (typeof(T) == idColumn.ColumnType)
                {
                    typedIdColumn = (IColumn <T>)idColumn.InnerColumn;
                }

                for (int index = 0; index < values.RowCount; ++index)
                {
                    // Look for the LIDs a
                    T externalID = values.GetValueT <T>(index, idColumnIndex);
                    if (typedIdColumn != null)
                    {
                        typedIdColumn.TryGetIndexOf(externalID, out itemLIDs[index]);
                    }
                    else
                    {
                        idColumn.TryGetIndexOf(externalID, out itemLIDs[index]);
                    }

                    if (itemLIDs[index] == ushort.MaxValue)
                    {
                        addCount++;
                    }

                    // Verify this item was routed to the right partition
                    vtr.Value = externalID;
                    v.Assign(vtr);
                    int idHash = v.GetHashCode();
                    if (!p.Mask.Matches(idHash))
                    {
                        throw new ArribaException(StringExtensions.Format("Item with ID '{0}', hash '{1:x}' incorrectly routed to Partition {2}.", externalID, idHash, p.Mask));
                    }
                }

                // Go back and add the items which need to be added in a batch
                if (mode != AddOrUpdateMode.UpdateAndIgnoreAdds)
                {
                    Dictionary <T, ushort> newlyAssignedLIDs = null;

                    for (int index = 0; index < values.RowCount; ++index)
                    {
                        T      idValue = values.GetValueT <T>(index, idColumnIndex);
                        ushort lid     = itemLIDs[index];

                        // If this is an add...
                        if (lid == ushort.MaxValue)
                        {
                            // If we have adds, we'll need to track new IDs
                            if (newlyAssignedLIDs == null)
                            {
                                newlyAssignedLIDs = new Dictionary <T, ushort>(addCount);
                            }

                            T externalID = idValue;

                            // If this ID was already added in this batch, this time it's an update
                            if (newlyAssignedLIDs.TryGetValue(externalID, out lid) == false)
                            {
                                // If in "UpdateOnly" mode, throw
                                if (mode == AddOrUpdateMode.UpdateOnly)
                                {
                                    throw new ArribaWriteException(externalID, p.IDColumn.Name, externalID,
                                                                   new ArribaException("AddOrUpdate was in UpdateOnly mode but contained a new ID, which is an error."));
                                }

                                // If this was a new item and not added in this batch, assign it a LID
                                lid = p._itemCount;

                                if (lid == ushort.MaxValue)
                                {
                                    throw new ArribaWriteException(externalID, p.IDColumn.Name, externalID,
                                                                   new ArribaException("Column full in Partition. Unable to add items."));
                                }

                                p._itemCount++;
                                idColumn.SetSize((ushort)(p._itemCount));

                                if (typedIdColumn != null)
                                {
                                    typedIdColumn[lid] = externalID;
                                }
                                else
                                {
                                    idColumn[lid] = externalID;
                                }

                                newlyAssignedLIDs[externalID] = lid;
                            }
                        }

                        itemLIDs[index] = lid;
                    }

                    // Commit the updates to the values column if the column requires it (FastAddSortedColumn does)
                    if (idColumn is ICommittable)
                    {
                        (idColumn as ICommittable).Commit();
                    }
                }

                return(itemLIDs);
            }
Esempio n. 2
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));
        }