Beispiel #1
0
 /// <summary>
 /// Backup Data of a certain disk region onto the transaction log file
 /// </summary>
 internal void BackupData(List <KeyValuePair <RecordKey, Region> > dataRegions)
 {
     using (var writePool = new ConcurrentIOPoolManager())
     {
         using (var readPool = new ConcurrentIOPoolManager())
         {
             BackupData(dataRegions, readPool, writePool);
         }
     }
 }
Beispiel #2
0
        /// <summary>
        /// Backup Data of a certain disk region onto the transaction log file
        /// </summary>
        internal void BackupData(List <KeyValuePair <RecordKey, Region> > dataRegions,
                                 ConcurrentIOPoolManager readPool, ConcurrentIOPoolManager writePool)
        {
            LogTracer.Verbose("BackupData: Start for Thread {0}.", Thread.CurrentThread.ManagedThreadId);
            foreach (KeyValuePair <RecordKey, Region> dataRegion in dataRegions)
            {
                RecordKey key    = dataRegion.Key;
                Region    region = dataRegion.Value;

                var    f         = (OnDisk.File.IFile)Server.GetFile(key.Filename);
                string fFilename = key.Filename;

                //** foreach disk area in region, copy it to transaction file
                foreach (KeyValuePair <long, int> area in region)
                {
                    // short circuit if IO exception was detected.
                    if (readPool.AsyncThreadException != null)
                    {
                        throw readPool.AsyncThreadException;
                    }
                    if (writePool.AsyncThreadException != null)
                    {
                        throw writePool.AsyncThreadException;
                    }

                    var logKey = new BackupDataLogKey();
                    logKey.SourceFilename    = f == null ? fFilename : f.Filename;
                    logKey.SourceDataAddress = area.Key;

                    IEnumerable <KeyValuePair <BackupDataLogKey, BackupDataLogValue> > intersectingLogs;
                    long mergedBlockStartAddress, mergedBlockSize;

                    // todo: optimize LogCollection locking!

                    //LogCollection.Locker.Lock();
                    LogTracer.Verbose("Transactin.BackupData: Thread {0}, Locking LogCollection, count {1}.", Thread.CurrentThread.ManagedThreadId, LogCollection.Count);

                    bool isIntersectingLogs = GetIntersectingLogs(logKey, area.Value, out intersectingLogs, out mergedBlockStartAddress,
                                                                  out mergedBlockSize);
                    if (isIntersectingLogs)
                    {
                        BackupDataWithIntersection(intersectingLogs, logKey, area, f, fFilename, readPool, writePool,
                                                   key);
                    }
                    else
                    {
                        BackupDataWithNoIntersection(intersectingLogs, logKey, area, f, fFilename, readPool, writePool,
                                                     key);
                    }

                    LogTracer.Verbose("Transactin.BackupData: Thread {0}, Unlocking LogCollection, count {1}.", Thread.CurrentThread.ManagedThreadId, LogCollection.Count);
                    //LogCollection.Locker.Unlock();
                }
            }
        }
Beispiel #3
0
        private static void CopyData(string serverRootPath, List <CopyParams> copyBlocks)
        {
            if (copyBlocks == null)
            {
                throw new ArgumentNullException("copyBlocks");
            }
            using (var writePool = new ConcurrentIOPoolManager())
            {
                using (var readPool = new ConcurrentIOPoolManager())
                {
                    string targetFile     = null;
                    long   readerFileSize = 0;
                    for (int i = 0; i < copyBlocks.Count; i++)
                    {
                        var rb   = copyBlocks[i];
                        int size = rb.DataSize;
                        if (targetFile == null || targetFile != rb.TargetFilename)
                        {
                            targetFile = rb.TargetFilename;
                        }

                        string systemBackupFilename = string.Format("{0}\\{1}", serverRootPath, rb.SourceFilename);

                        // copy backed up data onto the DB
                        var reader = readPool.GetInstance(systemBackupFilename, null, size);
                        var writer = writePool.GetInstance(targetFile, null, size);
                        if (reader == null || writer == null)
                        {
                            continue;
                        }

                        if (readerFileSize == 0)
                        {
                            readerFileSize = reader.FileStream.Length;
                        }
                        if (rb.SourceAddress + rb.DataSize <= readerFileSize)
                        {
                            reader.FileStream.Seek(rb.SourceAddress, SeekOrigin.Begin);
                            writer.FileStream.Seek(rb.TargetAddress, SeekOrigin.Begin);
                            reader.FileStream.BeginRead(reader.Buffer, 0, size,
                                                        ReadCallback,
                                                        new object[] { new[] { reader, writer }, false }
                                                        );
                        }
                        else
                        {
                            reader.Event.Set();
                            writer.Event.Set();
                        }
                        // end
                    }
                }
            }
        }
Beispiel #4
0
        private void BackupDataWithNoIntersection(
            IEnumerable <KeyValuePair <BackupDataLogKey, BackupDataLogValue> > intersectingLogs,
            BackupDataLogKey logKey, KeyValuePair <long, int> area, OnDisk.File.IFile f, string fFilename,
            ConcurrentIOPoolManager readPool, ConcurrentIOPoolManager writePool,
            RecordKey key)
        {
            string systemBackupFilename = Server.Path + DataBackupFilename;
            int    size = area.Value;

            key.Address = area.Key;

            // no intersection nor mergeable logs, add new log! backup and log the data area
            ConcurrentIOData reader = f != null
                                          ? readPool.GetInstance(f, size)
                                          : readPool.GetInstance(fFilename, null, size);

            ConcurrentIOData writer = writePool.GetInstance(systemBackupFilename, (TransactionRoot)Root);

            if (reader == null || writer == null)
            {
                throw new SopException("This program has a bug! 'didn't get reader or writer from Async IO Pool.");
            }

            LogTracer.Verbose("BackupDataWithNoIntersection: Start for Thread {0}.", Thread.CurrentThread.ManagedThreadId);


            var logValue = new BackupDataLogValue();

            logValue.DataSize      = size;
            logValue.TransactionId = Id;

            logValue.BackupFileHandle = GetLogBackupFileHandle(DataBackupFilename);

            // return the current backup file size and grow it to make room for data to be backed up...
            logValue.BackupDataAddress = GrowBackupFile(size, writer.FileStream);

            // save a record of the backed up data..
            LogCollection.Add(logKey, logValue);

            // log after data was backed up!!
            Sop.VoidFunc logBackedupData = () =>
            {
                UpdateLogger.LogLine("{0}{1}:{2} to {3}:{4} Size={5}",
                                     BackupFromToken, f != null ? f.Filename : fFilename, area.Key,
                                     DataBackupFilename, logValue.BackupDataAddress, size);
            };

            writer.FileStream.Seek(logValue.BackupDataAddress, SeekOrigin.Begin, true);
            reader.FileStream.Seek(area.Key, SeekOrigin.Begin, true);
            reader.FileStream.BeginRead(
                reader.Buffer, 0, size, ReadCallback,
                new object[] { new[] { reader, writer }, true, logKey, logBackedupData });
        }
Beispiel #5
0
 protected internal override bool RegisterRecycle(CollectionOnDisk collection, long blockAddress,
                                                  int blockSize)
 {
     if (!Transaction.RegisterRecycle(_addBlocksStore, _recycledBlocksStore, collection, blockAddress, blockSize))
     {
         using (var writePool = new ConcurrentIOPoolManager())
         {
             using (var readPool = new ConcurrentIOPoolManager())
             {
                 RegisterSave(collection, blockAddress, blockSize, readPool, writePool);
             }
         }
     }
     return(true);
 }
Beispiel #6
0
        private void RestoreData()
        {
            if (LogCollection == null)
            {
                return;
            }
            var lc = LogCollection;

            using (var writePool = new ConcurrentIOPoolManager())
            {
                using (var readPool = new ConcurrentIOPoolManager())
                {
                    OnDisk.File.IFile targetFile = null;
                    foreach (var de in lc)
                    {
                        var    key   = de.Key;
                        var    value = de.Value;
                        string systemBackupFilename = Server.Path + GetLogBackupFilename(value.BackupFileHandle);

                        int size = value.DataSize;
                        if (targetFile == null || targetFile.Filename != key.SourceFilename)
                        {
                            targetFile = (OnDisk.File.IFile)Server.GetFile(key.SourceFilename);
                        }

                        if (targetFile == null)
                        {
                            continue;
                        }

                        ConcurrentIOData reader = readPool.GetInstance(systemBackupFilename, (TransactionRoot)Root,
                                                                       size);
                        ConcurrentIOData writer = writePool.GetInstance(targetFile, size);
                        reader.FileStream.Seek(value.BackupDataAddress, SeekOrigin.Begin);
                        writer.FileStream.Seek(key.SourceDataAddress, SeekOrigin.Begin);
                        reader.FileStream.BeginRead(reader.Buffer, 0, size, ReadCallback,
                                                    new object[] { new[] { reader, writer }, false });
                    }
                }
            }
            ClearLogs();
        }
Beispiel #7
0
        /// <summary>
        /// Write a group of Blocks onto 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 chunkSize = MaxSegmentSize / 2;

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

            if (_writeBuffer == null || _writeBuffer.Length < chunkSize)
            {
                _writeBuffer = new byte[chunkSize];
            }

            Sop.Transaction.Transaction.LogTracer.Verbose("WriteBlocksToDisk: Start for Thread {0}.", Thread.CurrentThread.ManagedThreadId);

            using (var backupWritePool = new ConcurrentIOPoolManager())
            {
                // Backup the target blocks on disk
                using (var backupReadPool = new ConcurrentIOPoolManager())
                {
                    WriteBlocksToDisk(backupReadPool, backupWritePool, parent, blocks);
                }
            }
            // overwrite the target blocks on disk with source blocks.
            using (var writePool = new ConcurrentIOPoolManager())
            {
                WriteBlocksToDisk(null, writePool, parent, blocks);
            }

            Sop.Transaction.Transaction.LogTracer.Verbose("WriteBlocksToDisk: End for Thread {0}.", Thread.CurrentThread.ManagedThreadId);

            return(blocks.Count);
        }
Beispiel #8
0
        /// <summary>
        /// Backup Data of a certain disk region onto the transaction log file
        /// </summary>
        internal void BackupData(List <KeyValuePair <RecordKey, Region> > dataRegions,
                                 ConcurrentIOPoolManager readPool, ConcurrentIOPoolManager writePool)
        {
            foreach (KeyValuePair <RecordKey, Region> dataRegion in dataRegions)
            {
                RecordKey key    = dataRegion.Key;
                Region    region = dataRegion.Value;

                var    f         = (OnDisk.File.IFile)Server.GetFile(key.Filename);
                string fFilename = key.Filename;

                //** foreach disk area in region, copy it to transaction file
                foreach (KeyValuePair <long, int> area in region)
                {
                    var logKey = new BackupDataLogKey();
                    logKey.SourceFilename    = f == null ? fFilename : f.Filename;
                    logKey.SourceDataAddress = area.Key;

                    IEnumerable <KeyValuePair <BackupDataLogKey, BackupDataLogValue> > intersectingLogs;
                    long mergedBlockStartAddress, mergedBlockSize;
                    if (GetIntersectingLogs(logKey, area.Value, out intersectingLogs, out mergedBlockStartAddress,
                                            out mergedBlockSize))
                    {
                        BackupDataWithIntersection(intersectingLogs, logKey, area, f, fFilename, readPool, writePool,
                                                   key);
                    }
                    else
                    {
                        BackupDataWithNoIntersection(intersectingLogs, logKey, area, f, fFilename, readPool, writePool,
                                                     key);
                    }
                }

                //** Detect and Merge backed up blocks to minimize growth of Items stored in LogCollection,
                //** impact of not merging is a slower rollback of an unfinished pending transaction in previous run.
                //DetectAndMergeBlocks();
            }
        }
Beispiel #9
0
 protected internal override bool RegisterSave(CollectionOnDisk collection, long blockAddress, int segmentSize,
                                               ConcurrentIOPoolManager readPool, ConcurrentIOPoolManager writePool)
 {
     return(true);
 }
Beispiel #10
0
 /// <summary>
 /// Try to register block for update and back up contents as needed.
 /// </summary>
 /// <param name="collection"></param>
 /// <param name="blockAddress"></param>
 /// <param name="segmentSize"></param>
 /// <param name="readPool"></param>
 /// <param name="writePool"></param>
 /// <returns>true means block was registered and contents backed up,
 /// false means block is either new or recycled and wasn't registered for update and no backup occurred.</returns>
 protected internal abstract bool RegisterSave(CollectionOnDisk collection,
                                               long blockAddress, int segmentSize,
                                               ConcurrentIOPoolManager readPool,
                                               ConcurrentIOPoolManager writePool);
Beispiel #11
0
        /// <summary>
        /// RegisterSave will be called when a block cache faulted from memory
        /// onto Disk. Resolution of Added blocks will be done here and only
        /// those "modified" blocks will be registered & backed up.
        /// </summary>
        /// <param name="collection">Collection that is saving the block</param>
        /// <param name="blockAddress"></param>
        /// <param name="segmentSize"></param>
        /// <param name="readPool"> </param>
        /// <param name="writePool"> </param>
        protected internal override bool RegisterSave(CollectionOnDisk collection, long blockAddress,
                                                      int segmentSize, ConcurrentIOPoolManager readPool, ConcurrentIOPoolManager writePool)
        {
            if (IsTransactionStore(collection))
            {
                return(((TransactionBase)collection.ParentTransactionLogger).RegisterSave(collection, blockAddress,
                                                                                          segmentSize, readPool,
                                                                                          writePool));
            }
            if (LogCollection == null)
            {
                return(false);
            }

            LogTracer.Verbose("Transactin.RegisterSave: Start for Thread {0}.", Thread.CurrentThread.ManagedThreadId);

            //Step 1. Remove Intersections with Added, Growth segments & Recycled Blocks from region as no need to backup
            //         new Blocks
            //Step 2. Copy or backup remaining (Updated) blocks onto the Transaction Log file for restore on Rollback
            RecordKey key = CreateKey(collection, blockAddress);

            // if in file growth segments, don't register for save...
            Region region = RegionLogic.RemoveIntersections(_fileGrowthStore, key, blockAddress, segmentSize);

            if (region == null || region.Count == 0)
            {
                if (_inCommit == 0)
                {
                    TrackModification(collection.GetTopParent());
                }
                return(false);
            }

            #region subtract any region intersecting with recycled and add Stores
            int itemCount = region.Count / 2;
            if (itemCount < 5)
            {
                itemCount = 5;
            }
            var regionsForBackup = new List <KeyValuePair <RecordKey, Region> >(itemCount);

            foreach (KeyValuePair <long, int> area in region)
            {
                // subtract regions intersecting with recycled segments
                key.Address = area.Key;
                Region region2 = RegionLogic.RemoveIntersections(_recycledSegmentsStore,
                                                                 key, area.Key, area.Value);

                LogTracer.Verbose("Transactin.RegisterSave: Thread {0}, _recycledSegmentsStore count {1}.", Thread.CurrentThread.ManagedThreadId, _recycledSegmentsStore.Count);

                if (region2 == null || region2.Count <= 0 ||
                    ((LogCollection is SortedDictionaryOnDisk) &&
                     key.Filename == ((SortedDictionaryOnDisk)LogCollection).File.Filename))
                {
                    continue;
                }
                // subtract regions intersecting with (new) add segments
                foreach (KeyValuePair <long, int> area2 in region2)
                {
                    key.Address = area2.Key;
                    var region3 = RegionLogic.RemoveIntersections(_addBlocksStore, key, area2.Key, area2.Value);

                    LogTracer.Verbose("Transactin.RegisterSave: Thread {0}, _addBlocksStore count {1}.", Thread.CurrentThread.ManagedThreadId, _addBlocksStore.Count);

                    if (region3 == null || region3.Count <= 0)
                    {
                        continue;
                    }
                    foreach (KeyValuePair <long, int> area3 in region3)
                    {
                        key.Address = area3.Key;
                        var region4 = RegionLogic.RemoveIntersections(_recycledBlocksStore, key, area3.Key, area3.Value);

                        LogTracer.Verbose("Transactin.RegisterSave: Thread {0}, _recycledBlocksStore count {1}.", Thread.CurrentThread.ManagedThreadId, _recycledBlocksStore.Count);


                        if (region4 == null || region4.Count <= 0)
                        {
                            continue;
                        }
                        // any remaining portions are marked for backup
                        if (_inCommit == 0)
                        {
                            TrackModification(collection.GetTopParent());
                        }
                        regionsForBackup.Add(new KeyValuePair <RecordKey, Region>(key, region4));
                    }
                }
            }

            #endregion
            if (readPool != null)
            {
                BackupData(regionsForBackup, readPool, writePool);
            }
            else
            {
                BackupData(regionsForBackup);
            }
            return(true);
        }
Beispiel #12
0
        /// <summary>
        /// RegisterSave is the only one we do COW to be able to roll back from text log file
        /// the last transaction action done.
        /// </summary>
        /// <param name="collection"></param>
        /// <param name="blockAddress"></param>
        /// <param name="segmentSize"></param>
        /// <param name="readPool"> </param>
        /// <param name="writePool"> </param>
        protected internal override bool RegisterSave(CollectionOnDisk collection, long blockAddress, int segmentSize,
                                                      ConcurrentIOPoolManager readPool, ConcurrentIOPoolManager writePool)
        {
            if (!string.IsNullOrEmpty(_lastRegisterSaveFilename))
            {
                LoggerTransDetails.Log(string.Format("Successful RegisterSave {0}, {1}, {2}",
                                                     _lastRegisterSaveFilename, _lastRegisterSaveBlockAddress,
                                                     _lastRegisterSaveSegmentSize));
                _lastRegisterSaveFilename     = null;
                _lastRegisterSaveBlockAddress = 0;
                _lastRegisterSaveSegmentSize  = 0;
            }

            /* Step 1. Remove Intersections with added/recycled Blocks from region as no need to backup
             *       new Blocks
             * Step 2. Copy or backup (any) remaining blocks (the Updated blocks)
             *       onto the Transaction Log file for restore on Rollback
             */
            Transaction.RecordKey key = Transaction.CreateKey(collection, blockAddress);

            Region region = RegionLogic.RemoveIntersections(_fileGrowthStore, key,
                                                            blockAddress, segmentSize);

            if (region == null || region.Count == 0)
            {
                return(false);
            }

            bool logOnce = false;

            foreach (KeyValuePair <long, int> area2 in region)
            {
                key.Address = area2.Key;

                Region region2 = RegionLogic.RemoveIntersections(_recycledCollectionStore, key,
                                                                 area2.Key, area2.Value);

                if (region2 != null && region.Count > 0)
                {
                    foreach (KeyValuePair <long, int> area3 in region2)
                    {
                        key.Address = area3.Key;

                        Region region3 = RegionLogic.RemoveIntersections(_addStore, key,
                                                                         area3.Key, area3.Value);

                        //** Step 2: Backup the "modified" portion(s) of data
                        if (region3 != null && region3.Count > 0)
                        {
                            //** foreach disk area in region, copy it to transaction log file
                            foreach (KeyValuePair <long, int> area4 in region3)
                            {
                                BackupData(collection, area4.Key, area4.Value);
                            }
                            if (!logOnce)
                            {
                                logOnce = true;
                                _lastRegisterSaveFilename     = collection.File.Filename;
                                _lastRegisterSaveBlockAddress = blockAddress;
                                _lastRegisterSaveSegmentSize  = segmentSize;
                                LoggerTransDetails.Log(
                                    string.Format("RegisterSave {0}, {1}, {2}", collection.File.Filename, blockAddress,
                                                  segmentSize));
                            }
                        }
                    }
                }
            }
            return(logOnce);
        }
Beispiel #13
0
        /// <summary>
        /// RegisterSave will be called when a block cache faulted from memory
        /// onto Disk. Resolution of Added blocks will be done here and only
        /// those "modified" blocks will be saved. Newly added block(s) will
        /// not be saved.
        /// </summary>
        /// <param name="collection">Collection that is saving the block</param>
        /// <param name="blockAddress"></param>
        /// <param name="segmentSize"></param>
        /// <param name="readPool"> </param>
        /// <param name="writePool"> </param>
        protected internal override bool RegisterSave(CollectionOnDisk collection, long blockAddress,
                                                      int segmentSize, ConcurrentIOPoolManager readPool, ConcurrentIOPoolManager writePool)
        {
            if (IsTransactionStore(collection))
            {
                return(((TransactionBase)collection.ParentTransactionLogger).RegisterSave(collection, blockAddress,
                                                                                          segmentSize, readPool,
                                                                                          writePool));
            }
            if (LogCollection == null)
            {
                return(false);
            }

            /* Step 1. Remove Intersections with Added, Growth segments & Recycled Blocks from region as no need to backup
             *                           new Blocks
             *             Step 2. Copy or backup (any) remaining blocks (the Updated blocks)
             *                           onto the Transaction Log file for restore on Rollback
             */
            RecordKey key = CreateKey(collection, blockAddress);

            //// if in recycled or add store, don't register for save...
            //if (RegionLogic.IsSegmentInStore(_recycledCollectionStore, key, segmentSize) || InAddStore(key, segmentSize))
            //    return false;
            //** if in file growth segments, don't register for save...
            Region region = RegionLogic.RemoveIntersections(_fileGrowthStore, key, blockAddress, segmentSize);

            if (region == null || region.Count == 0)
            {
                if (_inCommit == 0)
                {
                    TrackModification(collection.GetTopParent());
                }
                return(false);
            }
            //**

            int itemCount = region.Count / 2;

            if (itemCount < 5)
            {
                itemCount = 5;
            }
            var regionsForBackup = new List <KeyValuePair <RecordKey, Region> >(itemCount);

            foreach (KeyValuePair <long, int> area in region)
            {
                key.Address = area.Key;
                Region region2 = RegionLogic.RemoveIntersections(_recycledCollectionStore,
                                                                 key, area.Key, area.Value);
                if (region2 == null || region2.Count <= 0 ||
                    ((LogCollection is SortedDictionaryOnDisk) &&
                     key.Filename == ((SortedDictionaryOnDisk)LogCollection).File.Filename))
                {
                    continue;
                }
                foreach (KeyValuePair <long, int> area2 in region2)
                {
                    key.Address = area2.Key;
                    Region region3 = RegionLogic.RemoveIntersections(_addStore,
                                                                     key, area2.Key, area2.Value);
                    //** Step 2: Backup the "modified" portion(s) of data
                    if (region3 == null || region3.Count <= 0)
                    {
                        continue;
                    }
                    if (_inCommit == 0)
                    {
                        TrackModification(collection.GetTopParent());
                    }
                    regionsForBackup.Add(new KeyValuePair <RecordKey, Region>(key, region3));
                }
            }
            if (readPool != null)
            {
                BackupData(regionsForBackup, readPool, writePool);
            }
            else
            {
                BackupData(regionsForBackup);
            }
            return(true);
        }
Beispiel #14
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!");
                }
            }
        }
Beispiel #15
0
        private void BackupDataWithIntersection(
            IEnumerable <KeyValuePair <BackupDataLogKey, BackupDataLogValue> > intersectingLogs,
            BackupDataLogKey logKey, KeyValuePair <long, int> area, OnDisk.File.IFile f, string fFilename,
            ConcurrentIOPoolManager readPool, ConcurrentIOPoolManager writePool,
            RecordKey key
            )
        {
            if (intersectingLogs == null)
            {
                // process conflicts with other trans...
                //ProcessTransactionConflicts(logKey, area.Value);
                // area is within an already backed up area (intersectingLogs == null), do nothing...
                return;
            }
            LogTracer.Verbose("BackupDataWithIntersection: Start for Thread {0}.", Thread.CurrentThread.ManagedThreadId);

            // get area(s) outside each intersecting segment and back it up...
            var newRegion = new Region(area.Key, area.Value);

            #region for future implements... ?
            //bool wasIntersected = false;
            //foreach (KeyValuePair<BackupDataLogKey, BackupDataLogValue> entry in intersectingLogs)
            //{
            //    // process conflicts with other trans...
            //    ProcessTransactionConflicts(entry.Key, entry.Value.DataSize);
            //    if (newRegion.Subtract(entry.Key.SourceDataAddress, entry.Value.DataSize))
            //        wasIntersected = true;
            //}
            //if (!wasIntersected) return;
            #endregion

            // copy modified blocks to the transaction backup file.
            foreach (KeyValuePair <long, int> newArea in newRegion)
            {
                if (readPool.AsyncThreadException != null)
                {
                    throw readPool.AsyncThreadException;
                }
                if (writePool.AsyncThreadException != null)
                {
                    throw writePool.AsyncThreadException;
                }

                var logKey2 = new BackupDataLogKey();
                logKey2.SourceFilename    = logKey.SourceFilename;
                logKey2.SourceDataAddress = newArea.Key;

                var logValue = new BackupDataLogValue();
                logValue.DataSize      = newArea.Value;
                logValue.TransactionId = Id;

                int newSize = newArea.Value;
                key.Address = newArea.Key;
                //if (RegisterAdd(_addBlocksStore, null, null, key, newArea.Value, false))
                //    return;

                logValue.BackupFileHandle = GetLogBackupFileHandle(DataBackupFilename);
                ConcurrentIOData reader = f != null
                                              ? readPool.GetInstance(f, newArea.Value)
                                              : readPool.GetInstance(fFilename, null, newArea.Value);

                if (reader == null)
                {
                    throw new InvalidOperationException("Can't get ConcurrentIOData from ReadPool");
                }
                string           systemBackupFilename = Server.Path + DataBackupFilename;
                ConcurrentIOData writer = writePool.GetInstance(systemBackupFilename, ((TransactionRoot)Root));
                if (writer == null)
                {
                    throw new InvalidOperationException("Can't get ConcurrentIOData from WritePool");
                }

                // return the current backup file size and grow it to make room for data to be backed up...
                logValue.BackupDataAddress = GrowBackupFile(newSize, writer.FileStream);

                // save a record of the backed up data..
                LogCollection.Add(logKey2, logValue);

                // prepare lambda expression to log after data was backed up!!
                Sop.VoidFunc logBackedupData = () =>
                {
                    UpdateLogger.LogLine(
                        "{0}{1}:{2} to {3}:{4} Size={5}", BackupFromToken, logKey2.SourceFilename,
                        logKey2.SourceDataAddress, DataBackupFilename, logValue.BackupDataAddress, newSize);
                };

                writer.FileStream.Seek(logValue.BackupDataAddress, SeekOrigin.Begin, true);
                reader.FileStream.Seek(newArea.Key, SeekOrigin.Begin, true);
                reader.FileStream.BeginRead(
                    reader.Buffer, 0, newSize, ReadCallback,
                    new object[] { new[] { reader, writer }, true, logKey2, logBackedupData });
            }
        }
Beispiel #16
0
        private void BackupDataWithNoIntersection(
            IEnumerable <KeyValuePair <BackupDataLogKey, BackupDataLogValue> > intersectingLogs,
            BackupDataLogKey logKey, KeyValuePair <long, int> area, OnDisk.File.IFile f, string fFilename,
            ConcurrentIOPoolManager readPool, ConcurrentIOPoolManager writePool,
            RecordKey key)
        {
            string systemBackupFilename = Server.Path + DataBackupFilename;
            int    size = area.Value;

            key.Address = area.Key;
            //if (RegisterAdd(_addStore, null, null, key, size, false))
            //{
            //    Logger.LogLine("Extending, skipping Backup...");
            //    return;
            //}

            //** no intersection nor mergeable logs, add new log!
            //** backup and log the data area
            ConcurrentIOData reader = f != null
                                          ? readPool.GetInstance(f, size)
                                          : readPool.GetInstance(fFilename, null, size);

            ConcurrentIOData writer = writePool.GetInstance(systemBackupFilename, (TransactionRoot)Root, size);

            if (reader == null || writer == null)
            {
                return;
            }

            var logValue = new BackupDataLogValue();

            logValue.DataSize      = size;
            logValue.TransactionId = Id;

            //** todo: can we remove this block:
            //long readerFileSize = reader.FileStream.Length;
            //if (area.Key + size > readerFileSize)
            //{
            //    int appendSize = (int)(area.Key + size - readerFileSize);
            //    key.Address = readerFileSize;
            //    RegisterAdd(_addStore, null, null, key, appendSize, false);
            //    size = (int)(readerFileSize - area.Key);
            //    logValue.DataSize = size;
            //    reader.Buffer = new byte[size];
            //}
            //**

            reader.FileStream.Seek(area.Key, SeekOrigin.Begin);

            logValue.BackupFileHandle  = GetLogBackupFileHandle(DataBackupFilename);
            logValue.BackupDataAddress = writer.FileStream.Seek(0, SeekOrigin.End);

            UpdateLogger.LogLine("{0}{1}:{2} to {3}:{4} Size={5}",
                                 BackupFromToken, f != null ? f.Filename : fFilename, area.Key,
                                 DataBackupFilename, logValue.BackupDataAddress, size);

            // resize target file to accomodate data to be copied.
            writer.FileStream.Seek(size, SeekOrigin.End);
            writer.FileStream.Seek(logValue.BackupDataAddress, SeekOrigin.Begin);

            reader.FileStream.BeginRead(
                reader.Buffer, 0, size, ReadCallback,
                new object[] { new[] { reader, writer }, true, logKey }
                );

            //** save a record of the backed up data..
            LogCollection.Add(logKey, logValue);
        }
Beispiel #17
0
        private void BackupDataWithIntersection(
            IEnumerable <KeyValuePair <BackupDataLogKey, BackupDataLogValue> > intersectingLogs,
            BackupDataLogKey logKey, KeyValuePair <long, int> area, OnDisk.File.IFile f, string fFilename,
            ConcurrentIOPoolManager readPool, ConcurrentIOPoolManager writePool,
            RecordKey key
            )
        {
            if (intersectingLogs == null)
            {
                //** process conflicts with other trans...
                ProcessTransactionConflicts(logKey, area.Value);
                //** area is within an already backed up area (intersectingLogs == null), do nothing...
                return;
            }
            //** get area(s) outside each intersecting segment and back it up...
            var  newRegion      = new Region(area.Key, area.Value);
            bool wasIntersected = false;

            foreach (KeyValuePair <BackupDataLogKey, BackupDataLogValue> entry in intersectingLogs)
            {
                //** process conflicts with other trans...
                ProcessTransactionConflicts(entry.Key, entry.Value.DataSize);
                if (newRegion.Subtract(entry.Key.SourceDataAddress, entry.Value.DataSize))
                {
                    wasIntersected = true;
                }
            }
            //** copy
            if (!wasIntersected)
            {
                return;
            }
            foreach (KeyValuePair <long, int> newArea in newRegion)
            {
                var logKey2 = new BackupDataLogKey();
                logKey2.SourceFilename    = logKey.SourceFilename;
                logKey2.SourceDataAddress = newArea.Key;

                var logValue = new BackupDataLogValue();
                logValue.DataSize      = newArea.Value;
                logValue.TransactionId = Id;

                int newSize = newArea.Value;
                key.Address = newArea.Key;
                //if (RegisterAdd(_addStore, null, null, key, newArea.Value, false))
                //    return;

                logValue.BackupFileHandle = GetLogBackupFileHandle(DataBackupFilename);
                ConcurrentIOData reader = f != null
                                              ? readPool.GetInstance(f, newArea.Value)
                                              : readPool.GetInstance(fFilename, null, newArea.Value);

                if (reader == null)
                {
                    throw new InvalidOperationException("Can't get ConcurrentIOData from ReadPool");
                }
                string           systemBackupFilename = Server.Path + DataBackupFilename;
                ConcurrentIOData writer = writePool.GetInstance(systemBackupFilename, ((TransactionRoot)Root),
                                                                newArea.Value);
                if (writer == null)
                {
                    throw new InvalidOperationException("Can't get ConcurrentIOData from WritePool");
                }

                logValue.BackupDataAddress = writer.FileStream.Seek(0, SeekOrigin.End);


                //** todo: can we remove this block:
                //long readerFileSize = reader.FileStream.Length;
                //if (newArea.Key + newArea.Value > readerFileSize)
                //{
                //    int appendSize = (int)(newArea.Key + newArea.Value - readerFileSize);
                //    key.Address = readerFileSize;
                //    RegisterAdd(_addStore, null, null, key, appendSize, false);
                //    newSize = (int)(readerFileSize - newArea.Key);
                //    logValue.DataSize = newSize;
                //    reader.Buffer = new byte[newSize];
                //}
                //**


                reader.FileStream.Seek(newArea.Key, SeekOrigin.Begin);
                UpdateLogger.LogLine(
                    "{0}{1}:{2} to {3}:{4} Size={5}", BackupFromToken, logKey2.SourceFilename,
                    logKey2.SourceDataAddress,
                    DataBackupFilename, logValue.BackupDataAddress, newSize);

                // resize target file to accomodate data to be copied.
                writer.FileStream.Seek(newSize, SeekOrigin.End);
                writer.FileStream.Seek(logValue.BackupDataAddress, SeekOrigin.Begin);

                reader.FileStream.BeginRead(
                    reader.Buffer, 0, newSize, ReadCallback,
                    new object[] { new[] { reader, writer }, true, logKey2 }
                    );

                //** save a record of the backed up data..
                LogCollection.Add(logKey2, logValue);
            }
        }