Show
Ignore:
Timestamp:
1/13/2010 4:29:25 AM (8 months ago)
Author:
lowjoel
Message:

Merged the SpeedMeter? branch to trunk. Fixes #90: Generic speed meter

Location:
trunk/eraser6
Files:
2 modified

Legend:

Unmodified
Added
Removed
  • trunk/eraser6

  • trunk/eraser6/Eraser.Manager/DirectExecutor.cs

    r1496 r1515  
    251251 
    252252                        //Run the task 
    253                         TaskProgressManager progress = new TaskProgressManager(task); 
    254253                        foreach (ErasureTarget target in task.Targets) 
    255254                            try 
    256255                            { 
    257                                 progress.Event.CurrentTarget = target; 
    258                                 ++progress.Event.CurrentTargetIndex; 
    259  
    260256                                UnusedSpaceTarget unusedSpaceTarget = 
    261257                                    target as UnusedSpaceTarget; 
     
    264260 
    265261                                if (unusedSpaceTarget != null) 
    266                                     EraseUnusedSpace(task, unusedSpaceTarget, progress); 
     262                                    EraseUnusedSpace(task, unusedSpaceTarget); 
    267263                                else if (fileSystemObjectTarget != null) 
    268                                     EraseFilesystemObject(task, fileSystemObjectTarget, progress); 
     264                                    EraseFilesystemObject(task, fileSystemObjectTarget); 
    269265                                else 
    270266                                    throw new ArgumentException(S._("Unknown erasure target.")); 
     
    324320 
    325321        /// <summary> 
    326         /// Manages the progress for any operation. 
    327         /// </summary> 
    328         private class ProgressManager 
    329         { 
    330             /// <summary> 
    331             /// Starts measuring the speed of the task. 
    332             /// </summary> 
    333             public void Start() 
    334             { 
    335                 startTime = DateTime.Now; 
    336             } 
    337  
    338             /// <summary> 
    339             /// Tracks the amount of the operation completed. 
    340             /// </summary> 
    341             public long Completed 
    342             { 
    343                 get 
    344                 { 
    345                     return completed; 
    346                 } 
    347                 set 
    348                 { 
    349                     lastCompleted += value - completed; 
    350                     completed = value; 
    351                 } 
    352             } 
    353  
    354             /// <summary> 
    355             /// The amount to reach before the operation completes. 
    356             /// </summary> 
    357             public long Total 
    358             { 
    359                 get 
    360                 { 
    361                     return total; 
    362                 } 
    363                 set 
    364                 { 
    365                     total = value; 
    366                 } 
    367             } 
    368  
    369             /// <summary> 
    370             /// Gets the percentage of the operation completed. 
    371             /// </summary> 
    372             public float Progress 
    373             { 
    374                 get 
    375                 { 
    376                     return (float)((double)Completed / Total); 
    377                 } 
    378             } 
    379  
    380             /// <summary> 
    381             /// Computes the speed of the erase, in units of completion per second, 
    382             /// based on the information collected in the previous 15 seconds. 
    383             /// </summary> 
    384             public int Speed 
    385             { 
    386                 get 
    387                 { 
    388                     if (DateTime.Now == startTime) 
    389                         return 0; 
    390  
    391                     if ((DateTime.Now - lastSpeedCalc).Seconds < 5 && lastSpeed != 0) 
    392                         return lastSpeed; 
    393  
    394                     //Calculate how much time has passed 
    395                     double timeElapsed = (DateTime.Now - lastSpeedCalc).TotalSeconds; 
    396                     if (timeElapsed == 0.0) 
    397                         return 0; 
    398  
    399                     //Then compute the speed of the calculation 
    400                     lastSpeed = (int)(lastCompleted / timeElapsed); 
    401                     lastSpeedCalc = DateTime.Now; 
    402                     lastCompleted = 0; 
    403                     return lastSpeed; 
    404                 } 
    405             } 
    406  
    407             /// <summary> 
    408             /// Calculates the estimated amount of time left based on the total 
    409             /// amount of information to erase and the current speed of the erase 
    410             /// </summary> 
    411             public TimeSpan TimeLeft 
    412             { 
    413                 get 
    414                 { 
    415                     if (Speed == 0) 
    416                         return new TimeSpan(0, 0, -1); 
    417                     return new TimeSpan(0, 0, (int)((Total - Completed) / Speed)); 
    418                 } 
    419             } 
    420  
    421             /// <summary> 
    422             /// The starting time of the operation, used to determine average speed. 
    423             /// </summary> 
    424             private DateTime startTime; 
    425  
    426             /// <summary> 
    427             /// The last time a speed calculation was computed so that speed is not 
    428             /// computed too often. 
    429             /// </summary> 
    430             private DateTime lastSpeedCalc; 
    431  
    432             /// <summary> 
    433             /// The last calculated speed of the operation. 
    434             /// </summary> 
    435             private int lastSpeed; 
    436  
    437             /// <summary> 
    438             /// The amount of the operation completed since the last speed computation. 
    439             /// </summary> 
    440             private long lastCompleted; 
    441  
    442             /// <summary> 
    443             /// The amount of the operation completed. 
    444             /// </summary> 
    445             private long completed; 
    446  
    447             /// <summary> 
    448             /// The amount to reach before the operation is completed. 
    449             /// </summary> 
    450             private long total; 
    451         } 
    452  
    453         /// <summary> 
    454         /// Provides a common interface to track the progress made by the Erase functions. 
    455         /// </summary> 
    456         private class TaskProgressManager : ProgressManager 
    457         { 
    458             /// <summary> 
    459             /// Constructor. 
    460             /// </summary> 
    461             public TaskProgressManager(Task task) 
    462             { 
    463                 foreach (ErasureTarget target in task.Targets) 
    464                     Total += target.TotalData; 
    465  
    466                 Event = new TaskProgressEventArgs(task); 
    467                 Start(); 
    468             } 
    469  
    470             /// <summary> 
    471             /// The TaskProgressEventArgs object representing the progress of the current 
    472             /// task. 
    473             /// </summary> 
    474             public TaskProgressEventArgs Event 
    475             { 
    476                 get 
    477                 { 
    478                     return evt; 
    479                 } 
    480                 set 
    481                 { 
    482                     evt = value; 
    483                 } 
    484             } 
    485  
    486             private TaskProgressEventArgs evt; 
    487         } 
    488  
    489         /// <summary> 
    490322        /// Executes a unused space erase. 
    491323        /// </summary> 
    492324        /// <param name="task">The task currently being executed</param> 
    493325        /// <param name="target">The target of the unused space erase.</param> 
    494         /// <param name="progress">The progress manager object managing the progress of the task</param> 
    495         private void EraseUnusedSpace(Task task, UnusedSpaceTarget target, TaskProgressManager progress) 
     326        private void EraseUnusedSpace(Task task, UnusedSpaceTarget target) 
    496327        { 
    497328            //Check for sufficient privileges to run the unused space erasure. 
     
    532363            VolumeInfo volInfo = VolumeInfo.FromMountpoint(target.Drive); 
    533364            FileSystem fsManager = FileSystemManager.Get(volInfo); 
    534              
     365 
     366            //Start sampling the speed of the task. 
     367            SteppedProgressManager progress = new SteppedProgressManager(); 
     368            target.Progress = progress; 
     369            task.Progress.Steps.Add(new SteppedProgressManager.Step( 
     370                progress, 1.0f / task.Targets.Count)); 
     371 
    535372            //Erase the cluster tips of every file on the drive. 
    536373            if (target.EraseClusterTips) 
    537374            { 
    538                 progress.Event.CurrentTargetStatus = S._("Searching for files' cluster tips..."); 
    539                 progress.Event.CurrentTargetTotalPasses = method.Passes; 
    540                 progress.Event.CurrentItemProgress = -1.0f; 
    541                 progress.Event.TimeLeft = new TimeSpan(0, 0, -1); 
    542  
    543                 //Start counting statistics 
     375                //Define the callback handlers 
     376                ProgressManager tipSearch = new ProgressManager(); 
     377                progress.Steps.Add(new SteppedProgressManager.Step(tipSearch,  
     378                    0.0f, S._("Searching for files' cluster tips..."))); 
     379                tipSearch.Total = 1; 
     380                ClusterTipsSearchProgress searchProgress = delegate(string path) 
     381                    { 
     382                        if (currentTask.Canceled) 
     383                            throw new OperationCanceledException(S._("The task was cancelled.")); 
     384 
     385                        task.OnProgressChanged(target, 
     386                            new ProgressChangedEventArgs(tipSearch, 
     387                                new TaskProgressChangedEventArgs(path, 0, 0))); 
     388                    }; 
     389 
    544390                ProgressManager tipProgress = new ProgressManager(); 
    545                 tipProgress.Start(); 
    546  
    547                 //Define the callback handlers 
    548                 ClusterTipsSearchProgress searchProgress = delegate(string path) 
    549                     { 
    550                         progress.Event.CurrentItemName = path; 
    551                         task.OnProgressChanged(progress.Event); 
     391                progress.Steps.Add(new SteppedProgressManager.Step(tipProgress, 0.1f, 
     392                    S._("Erasing cluster tips..."))); 
     393                ClusterTipsEraseProgress eraseProgress = 
     394                    delegate(int currentFile, int totalFiles, string currentFilePath) 
     395                    { 
     396                        tipSearch.Completed = tipSearch.Total; 
     397                        tipProgress.Total = totalFiles; 
     398                        tipProgress.Completed = currentFile; 
     399                        task.OnProgressChanged(target, 
     400                            new ProgressChangedEventArgs(tipProgress, 
     401                                new TaskProgressChangedEventArgs(currentFilePath, 0, 0))); 
    552402 
    553403                        if (currentTask.Canceled) 
     
    555405                    }; 
    556406 
    557                 ClusterTipsEraseProgress eraseProgress = 
    558                     delegate(int currentFile, int totalFiles, string currentFilePath) 
    559                     { 
    560                         tipProgress.Total = totalFiles; 
    561                         tipProgress.Completed = currentFile; 
    562  
    563                         progress.Event.CurrentTargetStatus = S._("Erasing cluster tips..."); 
    564                         progress.Event.CurrentItemName = currentFilePath; 
    565                         progress.Event.CurrentItemProgress = tipProgress.Progress; 
    566                         progress.Event.CurrentTargetProgress = progress.Event.CurrentItemProgress / 10; 
    567                         progress.Event.TimeLeft = tipProgress.TimeLeft; 
    568                         task.OnProgressChanged(progress.Event); 
    569  
    570                         if (currentTask.Canceled) 
    571                             throw new OperationCanceledException(S._("The task was cancelled.")); 
    572                     }; 
    573  
     407                //Start counting statistics 
    574408                fsManager.EraseClusterTips(VolumeInfo.FromMountpoint(target.Drive), 
    575409                    method, task.Log, searchProgress, eraseProgress); 
     
    585419                    Eraser.Util.File.SetCompression(info.FullName, false); 
    586420 
     421                ProgressManager mainProgress = new ProgressManager(); 
     422                progress.Steps.Add(new SteppedProgressManager.Step(mainProgress, 
     423                    target.EraseClusterTips ? 0.8f : 0.9f, S._("Erasing unused space..."))); 
     424 
    587425                //Continue creating files while there is free space. 
    588                 progress.Event.CurrentTargetStatus = S._("Erasing unused space..."); 
    589                 progress.Event.CurrentItemName = target.Drive; 
    590                 task.OnProgressChanged(progress.Event); 
    591426                while (volInfo.AvailableFreeSpace > 0) 
    592427                { 
     
    600435                        //Set the length of the file to be the amount of free space left 
    601436                        //or the maximum size of one of these dumps. 
     437                        mainProgress.Total = mainProgress.Completed + volInfo.AvailableFreeSpace; 
    602438                        long streamLength = Math.Min(ErasureMethod.FreeSpaceFileUnit, 
    603                             volInfo.AvailableFreeSpace); 
     439                            mainProgress.Total); 
    604440 
    605441                        //Handle IO exceptions gracefully, because the filesystem 
     
    624460                            delegate(long lastWritten, long totalData, int currentPass) 
    625461                            { 
    626                                 progress.Completed = Math.Min(progress.Total, 
    627                                     progress.Completed + lastWritten); 
    628                                 progress.Event.CurrentItemPass = currentPass; 
    629                                 progress.Event.CurrentItemProgress = progress.Progress; 
    630                                 if (target.EraseClusterTips) 
    631                                     progress.Event.CurrentTargetProgress = (float) 
    632                                         (0.1f + progress.Event.CurrentItemProgress * 0.8f); 
    633                                 else 
    634                                     progress.Event.CurrentTargetProgress = (float) 
    635                                         (progress.Event.CurrentItemProgress * 0.9f); 
    636                                 progress.Event.TimeLeft = progress.TimeLeft; 
    637                                 task.OnProgressChanged(progress.Event); 
     462                                mainProgress.Completed += lastWritten; 
     463                                task.OnProgressChanged(target, 
     464                                    new ProgressChangedEventArgs(mainProgress, 
     465                                        new TaskProgressChangedEventArgs(target.Drive, currentPass, method.Passes))); 
    638466 
    639467                                if (currentTask.Canceled) 
     
    644472                } 
    645473 
     474                //Mark the main bulk of the progress as complete 
     475                mainProgress.Completed = mainProgress.Total; 
     476 
    646477                //Erase old resident file system table files 
    647                 progress.Event.CurrentItemName = S._("Old resident file system table files"); 
    648                 task.OnProgressChanged(progress.Event); 
    649                 ProgressManager residentFilesProgress = new ProgressManager(); 
    650                 residentFilesProgress.Start(); 
     478                ProgressManager residentProgress = new ProgressManager(); 
     479                progress.Steps.Add(new SteppedProgressManager.Step(residentProgress, 
     480                    0.05f, S._("Old resident file system table files"))); 
    651481                fsManager.EraseOldFileSystemResidentFiles(volInfo, info, method, 
    652482                    delegate(int currentFile, int totalFiles) 
    653483                    { 
    654                         residentFilesProgress.Completed = currentFile; 
    655                         residentFilesProgress.Total = totalFiles; 
    656                         progress.Event.CurrentItemProgress = residentFilesProgress.Progress; 
    657                         progress.Event.TimeLeft = residentFilesProgress.TimeLeft; 
    658                         task.OnProgressChanged(progress.Event); 
     484                        residentProgress.Completed = currentFile; 
     485                        residentProgress.Total = totalFiles; 
     486                        task.OnProgressChanged(target, 
     487                            new ProgressChangedEventArgs(residentProgress, 
     488                                new TaskProgressChangedEventArgs(string.Empty, 0, 0))); 
    659489 
    660490                        if (currentTask.Canceled) 
     
    662492                    } 
    663493                ); 
     494 
     495                residentProgress.Completed = residentProgress.Total = 1; 
    664496            } 
    665497            finally 
    666498            { 
    667499                //Remove the folder holding all our temporary files. 
    668                 progress.Event.CurrentTargetStatus = S._("Removing temporary files..."); 
    669                 task.OnProgressChanged(progress.Event); 
     500                ProgressManager tempFiles = new ProgressManager(); 
     501                progress.Steps.Add(new SteppedProgressManager.Step(tempFiles, 
     502                    0.0f, S._("Removing temporary files..."))); 
     503                task.OnProgressChanged(target, new ProgressChangedEventArgs(tempFiles, 
     504                    new TaskProgressChangedEventArgs(string.Empty, 0, 0))); 
    670505                fsManager.DeleteFolder(info); 
     506                tempFiles.Completed = tempFiles.Total = 1; 
    671507            } 
    672508 
    673509            //Then clean the old file system entries 
    674             progress.Event.CurrentTargetStatus = S._("Erasing unused directory structures..."); 
    675             ProgressManager fsEntriesProgress = new ProgressManager(); 
    676             fsEntriesProgress.Start(); 
     510            ProgressManager structureProgress = new ProgressManager(); 
     511            progress.Steps.Add(new SteppedProgressManager.Step(structureProgress, 
     512                0.05f, S._("Erasing unused directory structures..."))); 
    677513            fsManager.EraseDirectoryStructures(volInfo, 
    678514                delegate(int currentFile, int totalFiles) 
     
    682518 
    683519                    //Compute the progress 
    684                     fsEntriesProgress.Total = totalFiles; 
    685                     fsEntriesProgress.Completed = currentFile; 
     520                    structureProgress.Total = totalFiles; 
     521                    structureProgress.Completed = currentFile; 
    686522 
    687523                    //Set the event parameters, then broadcast the progress event. 
    688                     progress.Event.TimeLeft = fsEntriesProgress.TimeLeft; 
    689                     progress.Event.CurrentItemProgress = fsEntriesProgress.Progress; 
    690                     progress.Event.CurrentTargetProgress = (float)( 
    691                         0.9 + progress.Event.CurrentItemProgress / 10); 
    692                     task.OnProgressChanged(progress.Event); 
     524                    task.OnProgressChanged(target, 
     525                        new ProgressChangedEventArgs(structureProgress, 
     526                            new TaskProgressChangedEventArgs(string.Empty, 0, 0))); 
    693527                } 
    694528            ); 
    695         } 
    696  
    697         /// <summary> 
    698         /// Traverses the given folder and deletes it securely only if it is 
    699         /// empty. 
    700         /// </summary> 
    701         /// <param name="info">The folder to check.</param> 
    702         private delegate void FolderEraseDelegate(DirectoryInfo info); 
     529 
     530            structureProgress.Completed = structureProgress.Total; 
     531            target.Progress = null; 
     532        } 
    703533 
    704534        /// <summary> 
     
    708538        /// <param name="target">The target of the erasure.</param> 
    709539        /// <param name="progress">The progress manager for the current task.</param> 
    710         private void EraseFilesystemObject(Task task, FileSystemObjectTarget target, 
    711             TaskProgressManager progress) 
     540        private void EraseFilesystemObject(Task task, FileSystemObjectTarget target) 
    712541        { 
    713542            //Retrieve the list of files to erase. 
     
    719548 
    720549            //Calculate the total amount of data required to finish the wipe. 
    721             dataTotal = method.CalculateEraseDataSize(paths, dataTotal); 
     550            //dataTotal = method.CalculateEraseDataSize(paths, dataTotal); 
    722551 
    723552            //Set the event's current target status. 
    724             progress.Event.CurrentTargetStatus = S._("Erasing files..."); 
     553            TaskEventArgs eventArgs = new TaskEventArgs(task); 
     554            SteppedProgressManager progress = new SteppedProgressManager(); 
     555            target.Progress = progress; 
     556            task.Progress.Steps.Add(new SteppedProgressManager.Step(progress, 1.0f / task.Targets.Count)); 
    725557 
    726558            //Iterate over every path, and erase the path. 
     
    728560            { 
    729561                //Update the task progress 
    730                 progress.Event.CurrentTargetProgress = i / (float)paths.Count; 
    731                 progress.Event.CurrentTarget = target; 
    732                 progress.Event.CurrentItemName = paths[i]; 
    733                 progress.Event.CurrentItemProgress = 0; 
    734                 progress.Event.CurrentTargetTotalPasses = method.Passes; 
    735                 task.OnProgressChanged(progress.Event); 
     562                ProgressManager step = new ProgressManager(); 
     563                progress.Steps.Add(new SteppedProgressManager.Step(step, 
     564                    1.0f / paths.Count, S._("Erasing files..."))); 
     565                task.OnProgressChanged(target, 
     566                    new ProgressChangedEventArgs(step, 
     567                        new TaskProgressChangedEventArgs(paths[i], 0, method.Passes))); 
    736568                 
    737569                //Get the filesystem provider to handle the secure file erasures 
     
    768600                    } 
    769601 
    770                     long itemWritten = 0; 
    771602                    fsManager.EraseFileSystemObject(info, method, 
    772603                        delegate(long lastWritten, long totalData, int currentPass) 
    773604                        { 
    774                             dataTotal -= lastWritten; 
    775                             progress.Completed += lastWritten; 
    776                             progress.Event.CurrentItemPass = currentPass; 
    777                             progress.Event.CurrentItemProgress = (float) 
    778                                 ((itemWritten += lastWritten) / (float)totalData); 
    779                             progress.Event.CurrentTargetProgress = 
    780                                 (i + progress.Event.CurrentItemProgress) / 
    781                                 (float)paths.Count; 
    782                             progress.Event.TimeLeft = progress.TimeLeft; 
    783                             task.OnProgressChanged(progress.Event); 
    784  
    785605                            if (currentTask.Canceled) 
    786606                                throw new OperationCanceledException(S._("The task was cancelled.")); 
     607 
     608                            step.Completed += lastWritten; 
     609                            step.Total = totalData; 
     610                            task.OnProgressChanged(target, 
     611                                new ProgressChangedEventArgs(step, 
     612                                    new TaskProgressChangedEventArgs(info.FullName, currentPass, method.Passes))); 
    787613                        }); 
    788614 
     
    791617                    if (fileInfo != null) 
    792618                        fsManager.DeleteFile(fileInfo); 
     619                    step.Completed = step.Total = 1; 
    793620                } 
    794621                catch (UnauthorizedAccessException) 
     
    828655            if (target is FolderTarget) 
    829656            { 
    830                 progress.Event.CurrentTargetStatus = S._("Removing folders..."); 
     657                ProgressManager step = new ProgressManager(); 
     658                progress.Steps.Add(new SteppedProgressManager.Step(step, 
     659                    0.0f, S._("Removing folders..."))); 
    831660                 
    832661                //Remove all subfolders which are empty. 
    833662                FolderTarget fldr = (FolderTarget)target; 
    834663                FileSystem fsManager = FileSystemManager.Get(VolumeInfo.FromMountpoint(fldr.Path)); 
    835                 FolderEraseDelegate eraseEmptySubFolders = null; 
     664                Action<DirectoryInfo> eraseEmptySubFolders = null; 
    836665                eraseEmptySubFolders = delegate(DirectoryInfo info) 
    837666                { 
    838                     foreach (DirectoryInfo subDir in info.GetDirectories()) 
    839                         eraseEmptySubFolders(subDir); 
    840  
    841                     progress.Event.CurrentItemName = info.FullName; 
    842                     task.OnProgressChanged(progress.Event); 
    843  
    844                     FileSystemInfo[] files = info.GetFileSystemInfos(); 
    845                     if (files.Length == 0) 
    846                         fsManager.DeleteFolder(info); 
     667                     foreach (DirectoryInfo subDir in info.GetDirectories()) 
     668                         eraseEmptySubFolders(subDir); 
     669                     task.OnProgressChanged(target, 
     670                         new ProgressChangedEventArgs(step, 
     671                             new TaskProgressChangedEventArgs(info.FullName, 0, 0))); 
     672 
     673                     FileSystemInfo[] files = info.GetFileSystemInfos(); 
     674                     if (files.Length == 0) 
     675                         fsManager.DeleteFolder(info); 
    847676                }; 
    848677                eraseEmptySubFolders(new DirectoryInfo(fldr.Path)); 
     
    851680                { 
    852681                    DirectoryInfo info = new DirectoryInfo(fldr.Path); 
    853                     progress.Event.CurrentItemName = info.FullName; 
    854                     task.OnProgressChanged(progress.Event); 
     682                    task.OnProgressChanged(target, 
     683                        new ProgressChangedEventArgs(step, 
     684                            new TaskProgressChangedEventArgs(info.FullName, 0, 0))); 
    855685 
    856686                    //See if this is the root of a volume. 
     
    871701            if (target is RecycleBinTarget) 
    872702            { 
    873                 progress.Event.CurrentTargetStatus = S._("Emptying recycle bin..."); 
    874                 task.OnProgressChanged(progress.Event); 
     703                ProgressManager step = new ProgressManager(); 
     704                progress.Steps.Add(new SteppedProgressManager.Step(step, 
     705                    0.0f, S._("Emptying recycle bin..."))); 
     706                task.OnProgressChanged(target, 
     707                    new ProgressChangedEventArgs(step, 
     708                        new TaskProgressChangedEventArgs(string.Empty, 0, 0))); 
    875709 
    876710                ShellApi.EmptyRecycleBin(EmptyRecycleBinOptions.NoConfirmation | 
    877711                    EmptyRecycleBinOptions.NoProgressUI | EmptyRecycleBinOptions.NoSound); 
    878712            } 
     713 
     714            target.Progress = null; 
    879715        } 
    880716