Example #1
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();
                }
            }
        }
Example #2
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 });
        }
Example #3
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);
        }
Example #4
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 });
            }
        }