/// <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); }
/// <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); }
/// <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); }