Пример #1
0
        /// <summary>
        /// Write a group of Blocks into Disk. NOTE: it will be more optimal if Blocks
        /// are sorted by its Data Address so this function can write contiguous blocks
        /// in one async write.
        /// </summary>
        public int WriteBlocksToDisk(Algorithm.Collection.ICollectionOnDisk parent,
                                     IDictionary <long, Sop.DataBlock> blocks, bool clear)
        {
            if (!parent.IsOpen)
            {
                return(0);
            }

            var blockSize = (int)parent.DataBlockSize;
            int r         = blocks.Count;

            if (BinaryWriter == null)
            {
                if (BufferStream == null)
                {
                    BufferStream = new MemoryStream();
                }
                BinaryWriter = new BinaryWriter(BufferStream, parent.File.Server.Encoding);
            }
            else
            {
                BinaryWriter.Seek(0, SeekOrigin.Begin);
            }

            const int sizeOfNumerics = Sop.DataBlock.OverheadSize;
            int       chunkSize      = (int)DataBlockSize.FiveTwentyFourTwoEightyEight * 4;

            if (chunkSize > blocks.Count * blockSize)
            {
                chunkSize = blocks.Count * blockSize;
            }

            if (_writeBuffer == null || _writeBuffer.Length < chunkSize)
            {
                _writeBuffer = new byte[chunkSize];
            }
            int  bufferIndex = 0, startIndex = 0, currentTargetBufferIndex = 0;
            long runningAddress = -1, startBlockAddress = -1;
            var  bulkWriter = new BulkWriter();
            var  dataChunks = new List <BulkWriter.DataChunk>(4);

            foreach (Sop.DataBlock block in blocks.Values)
            {
                SetIsDirty(block, false);
                if (block.DataAddress >= 0)
                {
                    #region Process special states, e.g. - buffer is full
                    if (startBlockAddress == -1)
                    {
                        startBlockAddress = runningAddress = block.DataAddress;
                    }
                    else
                    {
                        bool bufferIsFull = (bufferIndex - startIndex) + sizeOfNumerics + block.Data.Length +
                                            currentTargetBufferIndex > _writeBuffer.Length - block.Length;
                        if (block.DataAddress != runningAddress || bufferIsFull)
                        {
                            dataChunks.Add(new BulkWriter.DataChunk
                            {
                                TargetDataAddress =
                                    startBlockAddress == -1
                                                           ? block.DataAddress
                                                           : startBlockAddress,
                                Index = currentTargetBufferIndex + startIndex,
                                Size  = bufferIndex - startIndex
                            });
                            if (bufferIsFull)
                            {
                                //** write to disk
                                bulkWriter.Write(parent, _writeBuffer, dataChunks);
                                //** reset buffer
                                dataChunks.Clear();
                                currentTargetBufferIndex = 0;
                            }
                            else
                            {
                                currentTargetBufferIndex += (bufferIndex - startIndex);
                            }
                            startIndex     = bufferIndex = 0;
                            runningAddress = startBlockAddress = block.DataAddress;
                        }
                    }
                    #endregion
                }
                else
                {
                    throw new InvalidOperationException("Invalid (-) Block.DataAddress detected.");
                }

                //**** write Block Header and Data to disk
                BinaryWriter.Seek(0, SeekOrigin.Begin);
                // Byte 0 to 7: Next Item Address (64 bit long int) = 0 (no next item)
                BinaryWriter.Write(block.NextItemAddress);
                // Byte 8 to 11: Size Occupied
                BinaryWriter.Write(block.SizeOccupied);
                // Byte 12 to 19: Low-level next datablock address
                BinaryWriter.Write(block.InternalNextBlockAddress);
                // Byte 20: count of member blocks, max is 255.
                byte memberCount = 0;
                if (block.IsHead)
                {
                    int cm = block.CountMembers(true);
                    memberCount = cm > byte.MaxValue ? byte.MaxValue : (byte)cm;
                }
                BinaryWriter.Write(memberCount);

                byte[] b2 = BufferStream.GetBuffer();
                Array.Copy(b2, 0, _writeBuffer, currentTargetBufferIndex + bufferIndex, sizeOfNumerics);
                bufferIndex += sizeOfNumerics;

                //** Byte 20 to 20 + Data Length: USER DATA
                int cs = block.Data.Length;
                if (currentTargetBufferIndex + cs + bufferIndex > _writeBuffer.Length - block.Length)
                {
                    cs = _writeBuffer.Length - (currentTargetBufferIndex + bufferIndex);
                }
                Array.Copy(block.Data, 0, _writeBuffer, currentTargetBufferIndex + bufferIndex, cs);

                bufferIndex    += block.Data.Length;
                runningAddress += block.Length;
            }
            if (startBlockAddress != -1)
            {
                //** write to disk
                dataChunks.Add(new BulkWriter.DataChunk
                {
                    TargetDataAddress = startBlockAddress,
                    Index             = currentTargetBufferIndex + startIndex,
                    Size = bufferIndex - startIndex
                });
            }
            if (dataChunks.Count > 0)
            {
                bulkWriter.Write(parent, _writeBuffer, dataChunks);
            }

            return(r);
        }
Пример #2
0
        private void WriteBlocksToDisk(ConcurrentIOPoolManager readPool, ConcurrentIOPoolManager writePool,
                                       Algorithm.Collection.ICollectionOnDisk parent, IDictionary <long, Sop.DataBlock> blocks)
        {
            // todo: do this Async way, when time permits. :)

            if (BinaryWriter == null)
            {
                if (BufferStream == null)
                {
                    BufferStream = new MemoryStream();
                }
                BinaryWriter = new BinaryWriter(BufferStream, parent.File.Server.Encoding);
            }
            else
            {
                BinaryWriter.Seek(0, SeekOrigin.Begin);
            }

            const int sizeOfNumerics = Sop.DataBlock.OverheadSize;
            var       writeBuffer    = _writeBuffer;

            int  bufferIndex = 0, currentTargetBufferIndex = 0;
            long runningAddress = -1, startBlockAddress = -1;
            var  bulkWriter = new BulkWriter();
            var  dataChunks = new List <BulkWriter.DataChunk>(4);

            #region resize data file before appending to it...
            if (readPool == null || writePool == null)
            {
                long currentAddress = -1;
                if (((Collections.Generic.ISortedDictionary <long, Sop.DataBlock>)blocks).MoveLast())
                {
                    currentAddress = ((Collections.Generic.ISortedDictionary <long, Sop.DataBlock>)blocks).CurrentKey;
                }
                if (currentAddress > -1)
                {
                    // thread safe increase File Size to accomodate data to be appended...
                    var FileSize = currentAddress + (int)parent.DataBlockSize;
                    if (parent.FileStream.Length < FileSize)
                    {
                        if (parent.Transaction != null)
                        {
                            lock (parent.Transaction)
                            {
                                if (parent.FileStream.Length < FileSize)
                                {
                                    parent.FileStream.SetLength(FileSize);
                                }
                            }
                        }
                        else
                        {
                            parent.FileStream.SetLength(FileSize);
                        }
                    }
                }
            }
            #endregion
            Sop.DataBlock[] blocksCopy = new Sop.DataBlock[blocks.Count];
            blocks.Values.CopyTo(blocksCopy, 0);
            foreach (Sop.DataBlock block in blocksCopy)
            {
                SetIsDirty(block, false);
                if (block.DataAddress >= 0)
                {
                    #region Process special states, e.g. - buffer is full, current block Address is fragmented from previous block's
                    if (startBlockAddress == -1)
                    {
                        startBlockAddress = runningAddress = block.DataAddress;
                    }
                    else
                    {
                        bool bufferIsFull = bufferIndex + sizeOfNumerics + block.Data.Length +
                                            currentTargetBufferIndex > writeBuffer.Length - block.Length;
                        if (block.DataAddress != runningAddress || bufferIsFull)
                        {
                            dataChunks.Add(new BulkWriter.DataChunk
                            {
                                TargetDataAddress = startBlockAddress,
                                Index             = currentTargetBufferIndex, // Index in the buffer of 1st byte of this segment
                                Size = bufferIndex                            // size of the segment
                            });
                            if (bufferIsFull)
                            {
                                //** write to disk
                                if (readPool != null && writePool != null)
                                {
                                    bulkWriter.Backup(readPool, writePool, parent, writeBuffer, dataChunks);
                                    if (writePool.AsyncThreadException != null)
                                    {
                                        throw writePool.AsyncThreadException;
                                    }
                                    else if (readPool.AsyncThreadException != null)
                                    {
                                        throw readPool.AsyncThreadException;
                                    }
                                }
                                else if (writePool != null)
                                {
                                    bulkWriter.Write(writePool, parent, writeBuffer, dataChunks);
                                    if (writePool.AsyncThreadException != null)
                                    {
                                        throw writePool.AsyncThreadException;
                                    }
                                }
                                else
                                {
                                    throw new SopException("WriteBlocksToDisk has a bug!");
                                }

                                // create new buffer for succeeding chunks...
                                dataChunks  = new List <BulkWriter.DataChunk>(4);
                                writeBuffer = new byte[writeBuffer.Length];
                                currentTargetBufferIndex = 0;
                            }
                            else
                            {
                                currentTargetBufferIndex += bufferIndex;
                            }
                            bufferIndex    = 0;
                            runningAddress = startBlockAddress = block.DataAddress;
                        }
                    }
                    #endregion
                }
                else
                {
                    throw new InvalidOperationException("Invalid (-) Block.DataAddress detected.");
                }

                //**** write Block Header and Data to disk
                BinaryWriter.Seek(0, SeekOrigin.Begin);
                // Byte 0 to 7: Next Item Address (64 bit long int) = 0 (no next item)
                BinaryWriter.Write(block.NextItemAddress);
                // Byte 8 to 11: Size Occupied
                BinaryWriter.Write(block.SizeOccupied);
                // Byte 12 to 19: Low-level next datablock address
                BinaryWriter.Write(block.InternalNextBlockAddress);
                // Byte 20: count of member blocks, max is 65535.
                ushort memberCount = 0;
                if (block.IsHead)
                {
                    int cm = block.CountMembers(true);
                    memberCount = cm > Sop.DataBlock.MaxChainMemberCount ? Sop.DataBlock.MaxChainMemberCount : (ushort)cm;
                }
                BinaryWriter.Write(memberCount);

                byte[] b2 = BufferStream.GetBuffer();
                Array.Copy(b2, 0, writeBuffer, currentTargetBufferIndex + bufferIndex, sizeOfNumerics);
                bufferIndex += sizeOfNumerics;

                //** Byte 20 to 20 + Data Length: USER DATA
                int cs = block.Data.Length;
                //if (currentTargetBufferIndex + cs + bufferIndex > writeBuffer.Length - block.Length)
                //    cs = writeBuffer.Length - (currentTargetBufferIndex + bufferIndex);
                Array.Copy(block.Data, 0, writeBuffer, currentTargetBufferIndex + bufferIndex, cs);

                bufferIndex    += block.Data.Length;
                runningAddress += block.Length;
            }

            // write the last chunk set to disk...
            if (startBlockAddress != -1)
            {
                //** write to disk
                dataChunks.Add(new BulkWriter.DataChunk
                {
                    TargetDataAddress = startBlockAddress,
                    Index             = currentTargetBufferIndex,
                    Size = bufferIndex
                });
            }
            if (dataChunks.Count > 0)
            {
                if (readPool != null && writePool != null)
                {
                    bulkWriter.Backup(readPool, writePool, parent, writeBuffer, dataChunks);
                }
                else if (writePool != null)
                {
                    bulkWriter.Write(writePool, parent, writeBuffer, dataChunks);
                }
                else
                {
                    throw new SopException("WriteBlocksToDisk has a bug!");
                }
            }
        }