Merge lp:~mhr3/libunity/shared-models-only-on-main-thread into lp:libunity

Proposed by Michal Hruby
Status: Merged
Approved by: James Henstridge
Approved revision: 261
Merged at revision: 260
Proposed branch: lp:~mhr3/libunity/shared-models-only-on-main-thread
Merge into: lp:libunity
Diff against target: 300 lines (+117/-43)
6 files modified
configure.ac (+1/-1)
src/unity-aggregator-scope-private.vala (+1/-2)
src/unity-deprecated-scope-impl.vala (+5/-6)
src/unity-models.vala (+71/-14)
src/unity-scope-dbus-impl.vala (+6/-6)
test/vala/test-scope.vala (+33/-14)
To merge this branch: bzr merge lp:~mhr3/libunity/shared-models-only-on-main-thread
Reviewer Review Type Date Requested Status
James Henstridge Approve
PS Jenkins bot (community) continuous-integration Approve
Review via email: mp+175317@code.launchpad.net

Commit message

Fix a threading issue where shared model could have been serialized (in response to a standard Clone() request defined by the dee protocol) while a search was running in a separate thread and adding more rows to the model.

Description of the change

Fix a threading issue where shared model could have been serialized (in response to a standard Clone() request defined by the dee protocol) while a search was running in a separate thread add adding more rows to the model.

DeeSharedModels are no longer pushed to directly from the search thread, instead a IdleSource is used to add the rows from the main thread. This only fixes the non-deprecated scopes, but the deprecated ones don't perform searches in a separate thread in the first place.

To post a comment you must log in.
260. By Michal Hruby

Use more appropriate name in the tests

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
261. By Michal Hruby

Bump valac requirement

Revision history for this message
Marco Trevisan (TreviƱo) (3v1n0) wrote :

Probably changing also build-dep for valac?

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
James Henstridge (jamesh) wrote :

Looks good. I notice that it slightly changes the search time metric, but it probably won't make a substantial difference.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'configure.ac'
--- configure.ac 2013-07-11 10:42:15 +0000
+++ configure.ac 2013-07-17 17:22:24 +0000
@@ -63,7 +63,7 @@
63AM_PROG_CC_STDC63AM_PROG_CC_STDC
64AC_HEADER_STDC64AC_HEADER_STDC
65AM_PROG_LIBTOOL65AM_PROG_LIBTOOL
66AM_PROG_VALAC([0.16.0])66AM_PROG_VALAC([0.18.0])
67AS_IF([test -z "$VALAC"], [AC_MSG_ERROR(["Can't find suitable vala compiler."])])67AS_IF([test -z "$VALAC"], [AC_MSG_ERROR(["Can't find suitable vala compiler."])])
6868
69###################################################################69###################################################################
7070
=== modified file 'src/unity-aggregator-scope-private.vala'
--- src/unity-aggregator-scope-private.vala 2013-07-16 17:23:39 +0000
+++ src/unity-aggregator-scope-private.vala 2013-07-17 17:22:24 +0000
@@ -1621,6 +1621,7 @@
16211621
1622 Unity.Trace.tracepoint ("%s run end: %s", Log.METHOD, owner.id);1622 Unity.Trace.tracepoint ("%s run end: %s", Log.METHOD, owner.id);
16231623
1624 result_set.flush ();
1624 response[SEARCH_SEQNUM_HINT] = new Variant.uint64 (channel.get_last_seqnum ());1625 response[SEARCH_SEQNUM_HINT] = new Variant.uint64 (channel.get_last_seqnum ());
1625 if (measure_requests)1626 if (measure_requests)
1626 {1627 {
@@ -1629,8 +1630,6 @@
1629 response[SEARCH_TIME_HINT] = new Variant.double (delta);1630 response[SEARCH_TIME_HINT] = new Variant.double (delta);
1630 }1631 }
16311632
1632 result_set.flush ();
1633
1634 if (cancellable != null) cancellable.set_error_if_cancelled ();1633 if (cancellable != null) cancellable.set_error_if_cancelled ();
1635 return response;1634 return response;
1636 }1635 }
16371636
=== modified file 'src/unity-deprecated-scope-impl.vala'
--- src/unity-deprecated-scope-impl.vala 2013-07-16 17:23:39 +0000
+++ src/unity-deprecated-scope-impl.vala 2013-07-17 17:22:24 +0000
@@ -503,7 +503,11 @@
503 });503 });
504 yield;504 yield;
505505
506 result[SEARCH_SEQNUM_HINT] = new Variant.uint64 (channel.get_last_seqnum ());506 if (!cancellable.is_cancelled ())
507 {
508 result_set.flush ();
509 result[SEARCH_SEQNUM_HINT] = new Variant.uint64 (channel.get_last_seqnum ());
510 }
507511
508 Unity.Trace.tracepoint ("%s run end: %s", Log.METHOD, owner.id);512 Unity.Trace.tracepoint ("%s run end: %s", Log.METHOD, owner.id);
509 if (measure_requests)513 if (measure_requests)
@@ -513,11 +517,6 @@
513 result[SEARCH_TIME_HINT] = new Variant.double (delta);517 result[SEARCH_TIME_HINT] = new Variant.double (delta);
514 }518 }
515519
516 if (!cancellable.is_cancelled ())
517 {
518 result_set.flush ();
519 }
520
521 // handle hints520 // handle hints
522 var reply_hints = new_search.get_reply_hints ();521 var reply_hints = new_search.get_reply_hints ();
523 if (reply_hints != null)522 if (reply_hints != null)
524523
=== modified file 'src/unity-models.vala'
--- src/unity-models.vala 2013-07-15 09:56:14 +0000
+++ src/unity-models.vala 2013-07-17 17:22:24 +0000
@@ -35,6 +35,18 @@
35 Object (results_model: model);35 Object (results_model: model);
36 }36 }
3737
38 private unowned Thread<void*> origin_thread;
39 private unowned MainContext origin_context;
40 private GenericArray<Variant> results;
41
42 construct
43 {
44 origin_thread = Thread.self<void*> ();
45 origin_context = MainContext.get_thread_default ();
46 if (origin_context == null) origin_context = MainContext.default ();
47 results = new GenericArray<Variant> ();
48 }
49
38 public override void constructed ()50 public override void constructed ()
39 {51 {
40 if (results_model == null)52 if (results_model == null)
@@ -59,33 +71,46 @@
59 {71 {
60 metadata_v = new Variant.array (VariantType.VARDICT.element (), {});72 metadata_v = new Variant.array (VariantType.VARDICT.element (), {});
61 }73 }
62 results_model.append (result.uri, result.icon_hint, result.category,74
63 result.result_type, result.mimetype, result.title,75 Variant v = new Variant ("(ssuussss@a{sv})", result.uri, result.icon_hint,
64 result.comment, result.dnd_uri, metadata_v);76 result.category, result.result_type, result.mimetype, result.title,
77 result.comment, result.dnd_uri, metadata_v);
78 results.add ((owned) v);
65 }79 }
6680
67 public override void add_result_from_variant (Variant variant)81 public override void add_result_from_variant (Variant variant)
68 {82 {
69 if (variant.get_type_string () != "(ssuussssa{sv})")83 const string EXPECTED_TYPE_STRING = "(ssuussssa{sv})";
84 if (variant.get_type_string () != EXPECTED_TYPE_STRING)
70 {85 {
71 warning ("Incorrect signature for %s", Log.METHOD);86 warning ("Incorrect signature for %s, expected %s, but got %s",
87 Log.METHOD, EXPECTED_TYPE_STRING, variant.get_type_string ());
72 return;88 return;
73 }89 }
7490
75 Variant row_buf[9];91 results.add (variant);
76 variant.get ("(@s@s@u@u@s@s@s@s@a{sv})",
77 out row_buf[0], out row_buf[1],
78 out row_buf[2], out row_buf[3],
79 out row_buf[4], out row_buf[5],
80 out row_buf[6], out row_buf[7],
81 out row_buf[8]);
82 results_model.append_row (row_buf);
83 }92 }
8493
85 public Dee.SerializableModel flush_model { get; set; }94 public Dee.SerializableModel flush_model { get; set; }
8695
87 public override void flush ()96 private void do_flush_locked ()
88 {97 {
98 uint results_len = (uint) results.length;
99 for (uint i = 0; i < results_len; i++)
100 {
101 Variant variant = (owned) results.data[i];
102 Variant row_buf[9];
103 variant.get ("(@s@s@u@u@s@s@s@s@a{sv})",
104 out row_buf[0], out row_buf[1],
105 out row_buf[2], out row_buf[3],
106 out row_buf[4], out row_buf[5],
107 out row_buf[6], out row_buf[7],
108 out row_buf[8]);
109 results_model.append_row (row_buf);
110 }
111 // clear the results array
112 results.length = 0;
113
89 var diff_model = flush_model as DiffModel;114 var diff_model = flush_model as DiffModel;
90 if (diff_model != null)115 if (diff_model != null)
91 {116 {
@@ -97,6 +122,38 @@
97 sm.flush_revision_queue ();122 sm.flush_revision_queue ();
98 }123 }
99 }124 }
125
126 /* Note that this method can either be called from inside the search thread
127 * (while the search is in progress), or from the main thread BUT only after
128 * the search finished (if search is run in main thread it's safe always). */
129 public override void flush ()
130 {
131 // check which thread is this running in
132 unowned Thread<void*> current_thread = Thread.self<void*> ();
133 if (current_thread == origin_thread)
134 {
135 // no locking needed
136 do_flush_locked ();
137 }
138 else
139 {
140 // can't use Mutex and Cond directly, vala does scary copying of structs
141 var queue = new AsyncQueue<bool> ();
142 var idle = new IdleSource ();
143 idle.set_callback (() =>
144 {
145 do_flush_locked ();
146
147 queue.push (true);
148
149 return false;
150 });
151 idle.attach (origin_context);
152
153 // wait for the idle to get processed
154 queue.pop ();
155 }
156 }
100}157}
101158
102internal class DiffModel: Dee.SharedModel159internal class DiffModel: Dee.SharedModel
103160
=== modified file 'src/unity-scope-dbus-impl.vala'
--- src/unity-scope-dbus-impl.vala 2013-07-16 17:23:39 +0000
+++ src/unity-scope-dbus-impl.vala 2013-07-17 17:22:24 +0000
@@ -549,18 +549,18 @@
549549
550 Unity.Trace.tracepoint ("%s run end: %s", Log.METHOD, _dbus_name);550 Unity.Trace.tracepoint ("%s run end: %s", Log.METHOD, _dbus_name);
551551
552 result[SEARCH_SEQNUM_HINT] = new Variant.uint64 (channel.get_last_seqnum ());552 // FIXME: handle no-reply-hint etc!
553 if (!cancellable.is_cancelled ())
554 {
555 result_set.flush ();
556 result[SEARCH_SEQNUM_HINT] = new Variant.uint64 (channel.get_last_seqnum ());
557 }
553 if (measure_requests)558 if (measure_requests)
554 {559 {
555 int64 delta_us = search_end_time - search_start_time;560 int64 delta_us = search_end_time - search_start_time;
556 double delta = delta_us / 1000000.0;561 double delta = delta_us / 1000000.0;
557 result[SEARCH_TIME_HINT] = new Variant.double (delta);562 result[SEARCH_TIME_HINT] = new Variant.double (delta);
558 }563 }
559 // FIXME: handle no-reply-hint etc!
560 if (!cancellable.is_cancelled ())
561 {
562 result_set.flush ();
563 }
564 }564 }
565 finally565 finally
566 {566 {
567567
=== modified file 'test/vala/test-scope.vala'
--- test/vala/test-scope.vala 2013-07-16 17:24:10 +0000
+++ test/vala/test-scope.vala 2013-07-17 17:22:24 +0000
@@ -76,6 +76,8 @@
76 Fixture.create<SimpleScopeTester> (SimpleScopeTester.test_simple_search));76 Fixture.create<SimpleScopeTester> (SimpleScopeTester.test_simple_search));
77 Test.add_data_func ("/Unit/SimpleScope/SearchAsync",77 Test.add_data_func ("/Unit/SimpleScope/SearchAsync",
78 Fixture.create<SimpleScopeTester> (SimpleScopeTester.test_simple_search_async));78 Fixture.create<SimpleScopeTester> (SimpleScopeTester.test_simple_search_async));
79 Test.add_data_func ("/Unit/SimpleScope/SearchWithFlush",
80 Fixture.create<SimpleScopeTester> (SimpleScopeTester.test_simple_search_with_flush));
79 Test.add_data_func ("/Unit/SimpleScope/DiffSearch",81 Test.add_data_func ("/Unit/SimpleScope/DiffSearch",
80 Fixture.create<SimpleScopeTester> (SimpleScopeTester.test_simple_diff_search));82 Fixture.create<SimpleScopeTester> (SimpleScopeTester.test_simple_diff_search));
81 Test.add_data_func ("/Unit/SimpleScope/NoDiffSearch",83 Test.add_data_func ("/Unit/SimpleScope/NoDiffSearch",
@@ -1015,7 +1017,31 @@
1015 assert (model.get_string (iter, 0) == "test:uri");1017 assert (model.get_string (iter, 0) == "test:uri");
1016 }1018 }
10171019
1018 public static void search_func (Unity.ScopeSearchBase search, int state = 0)1020 public void test_simple_search_with_flush ()
1021 {
1022 int search_invoked = 0;
1023 // invoked in separate thread
1024 simple.set_search_func ((search) =>
1025 {
1026 search_invoked++;
1027
1028 for (int i = 0; i <= 1; i++)
1029 {
1030 add_search_result (search, i);
1031 search.search_context.result_set.flush ();
1032 }
1033 });
1034
1035 var reply_dict = perform_search ("");
1036 assert (reply_dict != null);
1037
1038 assert (search_invoked == 1);
1039 assert (model.get_n_rows () == 2);
1040 var iter = model.get_first_iter ();
1041 assert (model.get_string (iter, 0) == "test:uri");
1042 }
1043
1044 public static void add_search_result (Unity.ScopeSearchBase search, int state = 0)
1019 {1045 {
1020 Unity.ScopeResult result = Unity.ScopeResult ();1046 Unity.ScopeResult result = Unity.ScopeResult ();
1021 switch (state)1047 switch (state)
@@ -1033,17 +1059,6 @@
1033 search.search_context.result_set.add_result (result);1059 search.search_context.result_set.add_result (result);
1034 break;1060 break;
1035 case 1:1061 case 1:
1036 result.uri = "test:uri";
1037 result.icon_hint = "";
1038 result.category = 0;
1039 result.result_type = Unity.ResultType.DEFAULT;
1040 result.mimetype = "inode/folder";
1041 result.title = "Title";
1042 result.comment = "";
1043 result.dnd_uri = "test::uri";
1044 result.metadata = null;
1045 search.search_context.result_set.add_result (result);
1046
1047 result.uri = "test:uri2";1062 result.uri = "test:uri2";
1048 result.icon_hint = "";1063 result.icon_hint = "";
1049 result.category = 0;1064 result.category = 0;
@@ -1064,7 +1079,9 @@
1064 int search_state = 1;1079 int search_state = 1;
1065 simple.set_search_func ((search) =>1080 simple.set_search_func ((search) =>
1066 {1081 {
1067 search_func (search, search_state);1082 add_search_result (search, 0);
1083 if (search_state == 1)
1084 add_search_result (search, 1);
1068 });1085 });
10691086
1070 var reply_dict = perform_search ("foo", ChannelFlags.DIFF_CHANGES);1087 var reply_dict = perform_search ("foo", ChannelFlags.DIFF_CHANGES);
@@ -1089,7 +1106,9 @@
1089 int search_state = 1;1106 int search_state = 1;
1090 simple.set_search_func ((search) =>1107 simple.set_search_func ((search) =>
1091 {1108 {
1092 search_func (search, search_state);1109 add_search_result (search, 0);
1110 if (search_state == 1)
1111 add_search_result (search, 1);
1093 });1112 });
10941113
1095 var reply_dict = perform_search ("foo");1114 var reply_dict = perform_search ("foo");

Subscribers

People subscribed via source and target branches