[baobab/wip/vala: 9/39] threaded scanner: document the design



commit b0c1a895f3ccaf61f034276a6209f982f495f724
Author: Ryan Lortie <desrt desrt ca>
Date:   Thu Jan 5 19:54:47 2012 -0500

    threaded scanner: document the design
    
    Add a big comment to baobab-threaded-scanner.vala explaining the design.

 src/baobab-threaded-scanner.vala |   40 +++++++++++++++++++++++++++++++++++++-
 1 files changed, 39 insertions(+), 1 deletions(-)
---
diff --git a/src/baobab-threaded-scanner.vala b/src/baobab-threaded-scanner.vala
index abebf3b..ac0810f 100644
--- a/src/baobab-threaded-scanner.vala
+++ b/src/baobab-threaded-scanner.vala
@@ -2,9 +2,43 @@ namespace Baobab {
 	class ThreadedScanner : Scanner {
 		AsyncQueue<ResultsArray> results_queue;
 		ThreadedScanner? self;
-
 		File directory;
 
+		/* General overview:
+		 *
+		 * We cannot directly modify the treemodel from the worker thread, so we have to have a way to dispatch
+		 * the results back to the main thread.
+		 *
+		 * Each scanned directory gets a 'Results' struct created for it.  If the directory has a parent
+		 * directory, then the 'parent' pointer is set.  The 'display_name' and 'parse_name' fields are filled
+		 * in as soon as the struct is created.  This part is done as soon as the directory is encountered.
+		 *
+		 * In order to determine all of the information for a particular directory (and finish filling in the
+		 * results structure), we must scan it and all of its children.  We must also scan all of the siblings
+		 * of the directory so that we know what percentage of the total size of the parent directory the
+		 * directory in question is responsible for.
+		 *
+		 * After a directory, all of its children and all of its siblings have been scanned, we can do the
+		 * percentage calculation.  We do this from the iteration that takes care of the parent directory: we
+		 * collect an array of all of the child directory result structs and when we have them all, we assign
+		 * the proper percentage to each.  At this point we can report this array of result structs back to the
+		 * main thread to be added to the treemodel.
+		 *
+		 * Back in the main thread, we receive a Results object.  If the results object has not yet had a
+		 * TreeIter assigned to it, we create it one.  We use the parent results object to determine the correct
+		 * place in the tree (assigning the parent an iter if required, recursively).  When we create the iter,
+		 * we fill in the data that existed from the start (ie: display name and parse name) and mark the status
+		 * of the iter as 'scanning'.
+		 *
+		 * For the iter that was actually directly reported (ie: the one that's ready) we record the information
+		 * into the treemodel and free the results structure (or Vala does it for us).
+		 *
+		 * We can be sure that the 'parent' field always points to valid memory because of the nature of the
+		 * recursion and the queue.  At the time we queue a Results struct for dispatch back to the main thread,
+		 * its 'parent' is held on the stack by a higher invocation of add_directory().  This invocation will
+		 * never finish without first pushing its own Results struct onto the queue -- after ours.  It is
+		 * therefore guaranteed that the 'parent' Results object will not be freed before each child.
+		 */
 		[Compact]
 		class ResultsArray {
 			internal Results[] results;
@@ -110,6 +144,10 @@ namespace Baobab {
 				child_results.percent = 100 * ((double) child_results.size) / ((double) results.size);
 			}
 
+			/* No early exit.  In order to avoid a potential crash, we absolutely *must* push this onto the
+			 * queue after having passed it to any recursive invocation of add_directory() above.  See the large
+			 * comment at the top of this class for why.
+			 */
 			results_queue.push ((owned) results_array);
 
 			return results;



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]