Exemple #1
0
        public void VerifyConsistency(VerificationLevel level, ExecutionDetails details)
        {
            if (details == null)
            {
                throw new ArgumentNullException("details");
            }

            // Verify there are enough index items
            if (_itemCount > _index.Length)
            {
                details.AddError(ExecutionDetails.ColumnDoesNotHaveEnoughValues, this.Name, _itemCount, _index.Length);
            }

            for (int i = 0; i < _itemCount; ++i)
            {
                BlockPosition p = _index[i];
                if (p.BatchIndex >= _batchCount)
                {
                    // Verify every index item points to a valid batch
                    details.AddError(ExecutionDetails.ByteBlockColumnBatchOutOfRange, this.Name, i, p.BatchIndex, _batchCount);
                }
                else
                {
                    // Verify every empty item is represented correctly and every non-oversize item points to a valid array range
                    BlockBatch batch = _batches[p.BatchIndex];
                    if (p.Length == 0)
                    {
                        if (p.Position != 0)
                        {
                            details.AddError(ExecutionDetails.ByteBlockEmptyValueMisrecorded, this.Name, i, p.Position);
                        }
                    }
                    else if (p.Length == ushort.MaxValue)
                    {
                        if (p.Position != 0)
                        {
                            details.AddError(ExecutionDetails.ByteBlockHugeValueMisrecorded, this.Name, i, p.Position);
                        }
                    }
                    else
                    {
                        if (p.Position >= batch.Array.Length || p.Position + p.Length > batch.Array.Length)
                        {
                            details.AddError(ExecutionDetails.ByteBlockColumnPositionOutOfRange, this.Name, i, p.Position, p.Length, batch.Array.Length);
                        }
                    }
                }
            }

            // Verify all out-of-range items are clear
            for (int i = _itemCount; i < _index.Length; ++i)
            {
                BlockPosition p = _index[i];
                if (p.BatchIndex != 0 || p.Position != 0 || p.Length != 0)
                {
                    details.AddError(ExecutionDetails.ByteBlockColumnUnclearedIndexEntry, this.Name, i, p);
                }
            }
        }
Exemple #2
0
        private bool CompactIfNeeded(int batchIndex, int additionalSizeNeeded)
        {
            BlockBatch batch = _batches[batchIndex];

            // If there's not enough waste, nothing to clean up
            double wastePercentage = ((double)batch.WasteSpace / batch.Array.Length);

            if (wastePercentage < CompactWasteThreshold)
            {
                return(false);
            }

            // Otherwise, create a new array
            int neededSize = batch.UsedSpace - batch.WasteSpace + additionalSizeNeeded;
            int newSize    = ArrayExtensions.RecommendedSize(batch.Array.Length, neededSize, ushort.MaxValue);

            byte[] oldArray = batch.Array;
            byte[] newArray = new byte[newSize];

            // Next, copy every non-empty item in this batch to the new array contiguously
            ushort nextWritePosition = 0;

            for (int i = 0; i < _itemCount; ++i)
            {
                BlockPosition p = _index[i];
                if (p.BatchIndex != batchIndex)
                {
                    continue;
                }
                if (p.Length == 0)
                {
                    continue;
                }

                Array.Copy(oldArray, p.Position, newArray, nextWritePosition, p.Length);
                p.Position = nextWritePosition;

                nextWritePosition += p.Length;
                _index[i]          = p;
            }

            // Update and rewrite the batch
            batch.Array          = newArray;
            batch.UsedSpace      = nextWritePosition;
            batch.WasteSpace     = 0;
            _batches[batchIndex] = batch;

            return(true);
        }
Exemple #3
0
        private bool TryWriteAppend(ref BlockPosition position, ByteBlock value)
        {
            BlockBatch appendBatch = _batches[_appendToBatchIndex];

            // If the new value is too big, can we expand?
            if (appendBatch.Array.Length - appendBatch.UsedSpace < value.Length)
            {
                // Compact, if reasonable, or expand if not
                if (CompactIfNeeded(_appendToBatchIndex, value.Length))
                {
                    appendBatch = _batches[_appendToBatchIndex];
                }
                else
                {
                    ArrayExtensions.Resize(ref appendBatch.Array, appendBatch.UsedSpace + value.Length, ushort.MaxValue);
                    _batches[_appendToBatchIndex] = appendBatch;
                }
            }

            // If the value is still too big, stop
            if (appendBatch.Array.Length - appendBatch.UsedSpace < value.Length)
            {
                return(false);
            }

            // Build the new position
            BlockPosition newPosition;

            newPosition.BatchIndex = _appendToBatchIndex;
            newPosition.Position   = (ushort)appendBatch.UsedSpace;
            newPosition.Length     = (ushort)value.Length;

            // Track the new used space
            appendBatch.UsedSpace        += (ushort)value.Length;
            _batches[_appendToBatchIndex] = appendBatch;

            // Write the value to the new position
            value.CopyTo(appendBatch.Array, newPosition.Position);

            // Update the position and return
            position = newPosition;
            return(true);
        }
Exemple #4
0
        private bool TryWriteInPlace(ref BlockPosition position, ByteBlock value)
        {
            BlockBatch containingBatch = _batches[position.BatchIndex];

            // If this item is new, there is no place to write it
            if (position.Length == 0)
            {
                return(false);
            }

            // If the old value was written alone, replace it with a new exact size array
            if (position.Length == ushort.MaxValue)
            {
                containingBatch.Array     = new byte[value.Length];
                containingBatch.UsedSpace = (ushort)value.Length;
                value.CopyTo(containingBatch.Array);
            }
            else
            {
                // If the new value is too big, we can't write it in place
                if (position.Length < value.Length)
                {
                    return(false);
                }

                // Reduce the waste for reusing the space (we added it all as waste before placement)
                containingBatch.WasteSpace -= (ushort)value.Length;

                // Write the array to the existing position and record the new length
                value.CopyTo(_batches[position.BatchIndex].Array, position.Position);
                position.Length = (ushort)value.Length;
            }

            // Update the batch
            _batches[position.BatchIndex] = containingBatch;

            return(true);
        }