[baobab/wip/vala: 10/45] Introduce threaded scanner
- From: Paolo Borelli <pborelli src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [baobab/wip/vala: 10/45] Introduce threaded scanner
- Date: Sun, 29 Jan 2012 14:44:25 +0000 (UTC)
commit ad9002dc93b582bc493c49fc13493991ef2bc9f1
Author: Ryan Lortie <desrt desrt ca>
Date: Thu Jan 5 17:54:58 2012 -0500
Introduce threaded scanner
src/Makefile.am | 2 +
src/baobab-threaded-scanner.vala | 208 ++++++++++++++++++++++++++++++++++++++
src/baobab-window.vala | 2 +-
3 files changed, 211 insertions(+), 1 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 5b0a300..a3ac182 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -20,6 +20,7 @@ baobab_SOURCES = \
baobab-chart.c \
baobab-treemap.c \
baobab-ringschart.c \
+ baobab-threaded-scanner.vala \
baobab-sync-scanner.vala \
baobab-scanner.vala \
baobab-cellrenderers.vala \
@@ -42,6 +43,7 @@ baobab_LDADD = \
MAINTAINERCLEANFILES = \
baobab-application.c \
+ baobab-threaded-scanner.c \
baobab-sync-scanner.c \
baobab-scanner.c \
baobab-cellrenderers.c \
diff --git a/src/baobab-threaded-scanner.vala b/src/baobab-threaded-scanner.vala
new file mode 100644
index 0000000..70bfd46
--- /dev/null
+++ b/src/baobab-threaded-scanner.vala
@@ -0,0 +1,208 @@
+namespace Baobab {
+ class ThreadedScanner : Scanner {
+ Queue<ResultsArray> results_queue;
+ ThreadedScanner? self;
+ Mutex mutex;
+
+ File directory;
+
+ [Compact]
+ class ResultsArray {
+ internal Results[] results;
+ }
+
+ [Compact]
+ class Results {
+ // written in the worker thread on creation
+ // read from the main thread at any time
+ internal unowned Results? parent;
+ internal string display_name;
+ internal string parse_name;
+
+ // written in the worker thread before dispatch
+ // read from the main thread only after dispatch
+ internal uint64 size;
+ internal uint64 alloc_size;
+ internal uint64 elements;
+ internal double percent;
+ internal int max_depth;
+
+ // accessed only by the main thread
+ internal Gtk.TreeIter iter;
+ internal bool iter_is_set;
+ }
+
+ Results? add_directory (File directory, FileInfo info, Results? parent = null) {
+ var results_array = new ResultsArray ();
+
+ if (Application.is_excluded_location (directory)) {
+ return null;
+ }
+
+ var results = new Results ();
+ results.display_name = info.get_display_name ();
+ results.parse_name = directory.get_parse_name ();
+ results.parent = parent;
+
+ if (info.has_attribute (FILE_ATTRIBUTE_STANDARD_SIZE)) {
+ results.size = info.get_size ();
+ }
+
+ if (info.has_attribute (FILE_ATTRIBUTE_UNIX_BLOCKS)) {
+ results.alloc_size = 512 * info.get_attribute_uint64 (FILE_ATTRIBUTE_UNIX_BLOCKS);
+ }
+
+ results.elements = 1;
+
+ try {
+ var children = directory.enumerate_children (ATTRIBUTES, FileQueryInfoFlags.NOFOLLOW_SYMLINKS, cancellable);
+ FileInfo? child_info;
+ while ((child_info = children.next_file (cancellable)) != null) {
+ if (cancellable.is_cancelled ()) {
+ break;
+ }
+
+ switch (child_info.get_file_type ()) {
+ case FileType.DIRECTORY:
+ var child = directory.get_child (child_info.get_name ());
+ var child_results = add_directory (child, child_info, results);
+
+ if (child_results != null) {
+ results.size += child_results.size;
+ results.alloc_size += child_results.size;
+ results.elements += child_results.elements;
+ results.max_depth = int.max (results.max_depth, child_results.max_depth + 1);
+ results_array.results += (owned) child_results;
+ }
+ break;
+
+ case FileType.REGULAR:
+ if (child_info.has_attribute (FILE_ATTRIBUTE_UNIX_NLINK)) {
+ if (child_info.get_attribute_uint32 (FILE_ATTRIBUTE_UNIX_NLINK) > 1) {
+ var hl = HardLink (child_info);
+
+ // check if we've already encountered this file
+ if (hl in hardlinks) {
+ continue;
+ }
+
+ hardlinks += hl;
+ }
+ }
+
+ if (child_info.has_attribute (FILE_ATTRIBUTE_UNIX_BLOCKS)) {
+ results.alloc_size += 512 * child_info.get_attribute_uint64 (FILE_ATTRIBUTE_UNIX_BLOCKS);
+ }
+ results.size += child_info.get_size ();
+ results.elements++;
+ break;
+
+ default:
+ // ignore other types (symlinks, sockets, devices, etc)
+ break;
+ }
+ }
+ } catch (IOError.PERMISSION_DENIED e) {
+ } catch (Error e) {
+ warning ("couldn't iterate %s: %s", results.parse_name, e.message);
+ }
+
+ foreach (unowned Results child_results in results_array.results) {
+ child_results.percent = 100 * ((double) child_results.size) / ((double) results.size);
+ }
+
+ mutex.lock ();
+ results_queue.push_tail ((owned) results_array);
+ mutex.unlock ();
+
+ return results;
+ }
+
+ void* scan_in_thread () {
+ try {
+ var array = new ResultsArray ();
+
+ var info = directory.query_info (ATTRIBUTES, 0, cancellable);
+ var results = add_directory (directory, info);
+ results.percent = 100.0;
+ array.results += (owned) results;
+ //max_depth = results.max_depth;
+ } catch { }
+
+ // drop the thread's reference on the Scanner object
+ this.self = null;
+ return null;
+ }
+
+ void ensure_iter_exists (Results results) {
+ Gtk.TreeIter? parent_iter;
+
+ if (results.iter_is_set) {
+ return;
+ }
+
+ if (results.parent != null) {
+ ensure_iter_exists (results.parent);
+ parent_iter = results.parent.iter;
+ } else {
+ parent_iter = null;
+ }
+
+ append (out results.iter, parent_iter);
+ set (results.iter,
+ Columns.STATE, State.SCANNING,
+ Columns.DISPLAY_NAME, results.display_name,
+ Columns.PARSE_NAME, results.parse_name);
+ results.iter_is_set = true;
+ }
+
+ bool process_results () {
+ while (true) {
+ mutex.lock ();
+ var results_array = results_queue.pop_head ();
+ mutex.unlock ();
+
+ if (results_array == null) {
+ break;
+ }
+
+ foreach (unowned Results results in results_array.results) {
+ ensure_iter_exists (results);
+
+ set (results.iter,
+ Columns.SIZE, results.size,
+ Columns.ALLOC_SIZE, results.alloc_size,
+ Columns.PERCENT, results.percent,
+ Columns.ELEMENTS, results.elements,
+ Columns.STATE, State.DONE);
+
+ if (results.max_depth > max_depth) {
+ max_depth = results.max_depth;
+ }
+ }
+
+ }
+
+ return this.self != null;
+ }
+
+ protected override void scan (File directory) {
+ this.directory = directory;
+
+ // the thread owns a reference on the Scanner object
+ this.self = this;
+
+ try {
+ Thread.create<void*> (scan_in_thread, false);
+ } catch {
+ }
+
+ Timeout.add (100, process_results);
+ }
+
+ public ThreadedScanner () {
+ results_queue = new Queue<ResultsArray> ();
+ mutex = new Mutex ();
+ }
+ }
+}
diff --git a/src/baobab-window.vala b/src/baobab-window.vala
index 5204fe1..7fd6337 100644
--- a/src/baobab-window.vala
+++ b/src/baobab-window.vala
@@ -66,7 +66,7 @@ namespace Baobab {
return;
}
- var scanner = new SyncScanner ();
+ var scanner = new ThreadedScanner ();
scanner.scan (directory);
model = scanner;
var rings_chart = builder.get_object ("rings-chart") as Chart;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]