Merge lp:~mhr3/libunity/diff-models into lp:libunity
- diff-models
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Paweł Stołowski |
Approved revision: | 266 |
Merged at revision: | 255 |
Proposed branch: | lp:~mhr3/libunity/diff-models |
Merge into: | lp:libunity |
Diff against target: |
1780 lines (+1156/-278) 16 files modified
configure.ac (+5/-2) debian/changelog (+6/-0) debian/libunity9.symbols (+0/-150) protocol/protocol-scope-interface.vala (+2/-1) src/Makefile.am (+2/-1) src/unity-aggregator-scope-private.vala (+13/-18) src/unity-deprecated-scope-impl.vala (+17/-14) src/unity-models.vala (+200/-0) src/unity-scope-channel.vala (+48/-8) src/unity-scope-dbus-impl.vala (+6/-12) src/unity-scope-interface.vala (+1/-1) src/unity-search.vala (+0/-71) src/unity-utils.vala (+341/-0) test/vala/Makefile.am (+4/-0) test/vala/test-diff.vala (+507/-0) test/vala/test-vala.vala (+4/-0) |
To merge this branch: | bzr merge lp:~mhr3/libunity/diff-models |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot (community) | continuous-integration | Approve | |
Paweł Stołowski (community) | Approve | ||
Review via email: mp+173012@code.launchpad.net |
Commit message
Implement support for models that do diff between the last and current state to minimize the number of additions and removals.
Description of the change
Implement support for models that do diff between the last and current state to minimize the number of additions and removals to be able to provide more visually pleasing experience without the need for the shell to do this itself. This is needed because most scopes always clear the previous result set and re-add appropriate results, even though the results may not change.
PS Jenkins bot (ps-jenkins) wrote : | # |
Michał Sawicz (saviq) wrote : | # |
This will be *awesome* :)
Question: is there a timer by which you batch the changes from the scopes and modify the model or?
Michal Hruby (mhr3) wrote : | # |
It depends on the scope - ie right now they can control it. Most scopes will flush the changes when search finishes, a few do it in stages (files - recent files first, locate search a bit later), and for example home scope uses a timer.
But, we could change this to be managed centrally if needed.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:263
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Paweł Stołowski (stolowski) wrote : | # |
568 + // consider uris the primary key
569 + return get_string (this_iter, ResultColumn.URI) ==
570 + target_
I think we wanted to avoid this assumption in the new Unity shell? How about category + uri + title (+icon)?
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:264
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Paweł Stołowski (stolowski) wrote : | # |
This MP is a great improvement and seems to be working fine (and also unit tests prove it), but it's really hard to understand and judge the code...
Could you please at very least add docs to the main data structures used in the algorithm? Also, would it be feasible to break some bigger chunks of code (e.g. find_diag function) into smaller functions with descriptive names?
893 + int diags = x_set_length + y_set_length + 3;
895 + // allocate one big buffer for the forward and backward vectors
896 + real_diag = new int[diags * 2];
897 + // offset the pointers, cause we're sharing the same mem block,
898 + // plus the indices can be negative
914 + while (diags != 0)
915 + {
916 + diags /= 4;
917 + max_cost *= 2;
918 + }
919 + max_cost = int.max (max_cost, 256);
There are a few magic numbers above - can you add comments describing them?
Also, 896 and the comment in 897-898 look a bit scary, are we certain it's never accessing array out of bounds?
881 + int* f_diag;
882 + int* b_diag;
883 + int max_cost;
884 + uint8[] real_changes;
885 + uint8* x_changes;
886 + uint8* y_changes;
Hmm... I was told by my vala teacher ;) that pointers in vala are evil?...
Michal Hruby (mhr3) wrote : | # |
> Also, would it be feasible to break some bigger chunks of code
> (e.g. find_diag function) into smaller functions with descriptive names?
I do agree that the find_diag function is hard to read, but... I'd rather not split it for 2 reasons:
1) this is the heart of the algorithm and therefore perf-critical
2) although some parts look like they're the same (the inner for loops), they're not, as they are operating on opposite sides of the edit matrix. Therefore IMO moving the parts into separate functions will not actually improve readability (suddenly you have 2 smaller function that look the same), otoh will have perf cost.
> 893 + int diags = x_set_length + y_set_length + 3;
> 895 + // allocate one big buffer for the forward and backward
> vectors
> 896 + real_diag = new int[diags * 2];
> 897 + // offset the pointers, cause we're sharing the same mem
> block,
> 898 + // plus the indices can be negative
> 914 + while (diags != 0)
> 915 + {
> 916 + diags /= 4;
> 917 + max_cost *= 2;
> 918 + }
> 919 + max_cost = int.max (max_cost, 256);
>
> There are a few magic numbers above - can you add comments describing them?
Does `diags = (x_set_length + 1 + y_set_length + 1) + 1;` look more readable?
> Also, 896 and the comment in 897-898 look a bit scary, are we certain it's
> never accessing array out of bounds?
I suppose we'll learn soon :)
>
> 881 + int* f_diag;
> 882 + int* b_diag;
> 883 + int max_cost;
> 884 + uint8[] real_changes;
> 885 + uint8* x_changes;
> 886 + uint8* y_changes;
>
> Hmm... I was told by my vala teacher ;) that pointers in vala are evil?...
They are, but you can't do pointer arithmetic on non-pointer types. FWIW they're not used to alloc and free memory.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:265
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Paweł Stołowski (stolowski) wrote : | # |
Ok, let's get it in! Great work!
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
- 266. By Michal Hruby
-
Use DeeServer in tests which is hopefully less racy
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:266
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Preview Diff
1 | === modified file 'configure.ac' |
2 | --- configure.ac 2013-07-01 09:58:31 +0000 |
3 | +++ configure.ac 2013-07-09 13:37:28 +0000 |
4 | @@ -1,5 +1,5 @@ |
5 | # When releasing also remember to update the soname as instructed below |
6 | -AC_INIT(libunity, 7.0.6) |
7 | +AC_INIT(libunity, 7.0.8) |
8 | |
9 | AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION) |
10 | AM_CONFIG_HEADER(config.h) |
11 | @@ -21,7 +21,10 @@ |
12 | LIBUNITY_LT_REV=2 |
13 | LIBUNITY_LT_AGE=0 |
14 | LIBUNITY_LT_VERSION="$LIBUNITY_LT_CURRENT:$LIBUNITY_LT_REV:$LIBUNITY_LT_AGE" |
15 | -LIBUNITY_LT_LDFLAGS="-version-info $LIBUNITY_LT_VERSION -export-symbols-regex '^unity_.*'" |
16 | +# There's some autoconf weirdness which causes loss of [] characters, |
17 | +# therefore they're doubled, the regex is to exclude unity_internal_.* |
18 | +# symbols, it's so strange cause there's no lookahead support. |
19 | +LIBUNITY_LT_LDFLAGS="-version-info $LIBUNITY_LT_VERSION -export-symbols-regex '^unity_([[^i]]|i[[^n]]|in[[^t]]|int[[^e]]).*'" |
20 | |
21 | AC_SUBST(LIBUNITY_LT_CURRENT) |
22 | AC_SUBST(LIBUNITY_LT_VERSION) |
23 | |
24 | === modified file 'debian/changelog' |
25 | --- debian/changelog 2013-07-03 12:54:16 +0000 |
26 | +++ debian/changelog 2013-07-09 13:37:28 +0000 |
27 | @@ -1,3 +1,9 @@ |
28 | +libunity (7.0.8-0ubuntu1) UNRELEASED; urgency=low |
29 | + |
30 | + * Add support for diff models. |
31 | + |
32 | + -- Michal Hruby <michal.hruby@canonical.com> Thu, 04 Jul 2013 17:40:34 +0100 |
33 | + |
34 | libunity (7.0.7+13.10.20130703.2-0ubuntu1) saucy; urgency=low |
35 | |
36 | [ Didier Roche ] |
37 | |
38 | === modified file 'debian/libunity9.symbols' |
39 | --- debian/libunity9.symbols 2013-07-03 04:02:22 +0000 |
40 | +++ debian/libunity9.symbols 2013-07-09 13:37:28 +0000 |
41 | @@ -189,15 +189,6 @@ |
42 | unity_check_option_filter_get_type@Base 4.0.0 |
43 | unity_check_option_filter_new@Base 4.0.0 |
44 | unity_collect_launcher_entry_properties@Base 3.4.6 |
45 | - unity_dee_result_set_construct@Base 7.0.0daily13.05.31ubuntu.unity.next |
46 | - unity_dee_result_set_construct_with_model@Base 7.0.0daily13.05.31ubuntu.unity.next |
47 | - unity_dee_result_set_get_flush_model@Base 7.0.0daily13.05.31ubuntu.unity.next |
48 | - unity_dee_result_set_get_results_model@Base 7.0.0daily13.05.31ubuntu.unity.next |
49 | - unity_dee_result_set_get_type@Base 7.0.0daily13.05.31ubuntu.unity.next |
50 | - unity_dee_result_set_new@Base 7.0.0daily13.05.31ubuntu.unity.next |
51 | - unity_dee_result_set_new_with_model@Base 7.0.0daily13.05.31ubuntu.unity.next |
52 | - unity_dee_result_set_set_flush_model@Base 7.0.0daily13.05.31ubuntu.unity.next |
53 | - unity_dee_result_set_set_results_model@Base 7.0.0daily13.05.31ubuntu.unity.next |
54 | unity_deprecated_scope_activate_result@Base 7.0.0daily13.05.31ubuntu.unity.next |
55 | unity_deprecated_scope_activate_result_finish@Base 7.0.0daily13.05.31ubuntu.unity.next |
56 | unity_deprecated_scope_base_construct@Base 7.0.0daily13.05.31ubuntu.unity.next |
57 | @@ -299,147 +290,6 @@ |
58 | unity_inspector_get_type@Base 3.4.6 |
59 | unity_inspector_get_unity_bus_name@Base 3.4.6 |
60 | unity_inspector_get_unity_running@Base 3.4.6 |
61 | - unity_internal_aggregator_scope_impl_add_constraint@Base 7.0.0daily13.05.31ubuntu.unity.next |
62 | - unity_internal_aggregator_scope_impl_add_sorter@Base 7.0.0daily13.05.31ubuntu.unity.next |
63 | - unity_internal_aggregator_scope_impl_construct@Base 7.0.0daily13.05.31ubuntu.unity.next |
64 | - unity_internal_aggregator_scope_impl_get_merge_strategy@Base 7.0.0daily13.05.31ubuntu.unity.next |
65 | - unity_internal_aggregator_scope_impl_get_type@Base 7.0.0daily13.05.31ubuntu.unity.next |
66 | - unity_internal_aggregator_scope_impl_get_view_type@Base 7.0.0daily13.05.31ubuntu.unity.next |
67 | - unity_internal_aggregator_scope_impl_invalidate_search@Base 7.0.0daily13.05.31ubuntu.unity.next |
68 | - unity_internal_aggregator_scope_impl_new@Base 7.0.0daily13.05.31ubuntu.unity.next |
69 | - unity_internal_aggregator_scope_impl_push_filter_settings@Base 7.0.0daily13.05.31ubuntu.unity.next |
70 | - unity_internal_aggregator_scope_impl_push_results_to_scope@Base 7.0.0daily13.05.31ubuntu.unity.next |
71 | - unity_internal_aggregator_scope_impl_push_results_to_scope_finish@Base 7.0.0daily13.05.31ubuntu.unity.next |
72 | - unity_internal_aggregator_scope_impl_search_scope@Base 7.0.0daily13.05.31ubuntu.unity.next |
73 | - unity_internal_aggregator_scope_impl_search_scope_finish@Base 7.0.0daily13.05.31ubuntu.unity.next |
74 | - unity_internal_aggregator_scope_impl_set_active_sources@Base 7.0.0daily13.05.31ubuntu.unity.next |
75 | - unity_internal_aggregator_scope_impl_set_active_sources_finish@Base 7.0.0daily13.05.31ubuntu.unity.next |
76 | - unity_internal_aggregator_scope_impl_set_merge_strategy@Base 7.0.0daily13.05.31ubuntu.unity.next |
77 | - unity_internal_aggregator_scope_impl_set_view_type@Base 7.0.0daily13.05.31ubuntu.unity.next |
78 | - unity_internal_aggregator_scope_impl_subscope_ids@Base 7.0.0daily13.05.31ubuntu.unity.next |
79 | - unity_internal_category_column_get_type@Base 7.0.0daily13.05.31ubuntu.unity.next |
80 | - unity_internal_channel_state_get_type@Base 7.0.0daily13.05.31ubuntu.unity.next |
81 | - unity_internal_default_scope_dbus_impl_construct@Base 7.0.0daily13.05.31ubuntu.unity.next |
82 | - unity_internal_default_scope_dbus_impl_get_timeout@Base 7.0.0daily13.05.31ubuntu.unity.next |
83 | - unity_internal_default_scope_dbus_impl_get_type@Base 7.0.0daily13.05.31ubuntu.unity.next |
84 | - unity_internal_default_scope_dbus_impl_get_view_type@Base 7.0.0daily13.05.31ubuntu.unity.next |
85 | - unity_internal_default_scope_dbus_impl_new@Base 7.0.0daily13.05.31ubuntu.unity.next |
86 | - unity_internal_default_scope_dbus_impl_preview_internal@Base 7.0.0daily13.05.31ubuntu.unity.next |
87 | - unity_internal_default_scope_dbus_impl_preview_internal_finish@Base 7.0.0daily13.05.31ubuntu.unity.next |
88 | - unity_internal_default_scope_dbus_impl_set_active_sources@Base 7.0.0daily13.05.31ubuntu.unity.next |
89 | - unity_internal_default_scope_dbus_impl_set_active_sources_finish@Base 7.0.0daily13.05.31ubuntu.unity.next |
90 | - unity_internal_default_scope_dbus_impl_set_categories@Base 7.0.0daily13.05.31ubuntu.unity.next |
91 | - unity_internal_default_scope_dbus_impl_set_filters@Base 7.0.0daily13.05.31ubuntu.unity.next |
92 | - unity_internal_default_scope_dbus_impl_set_timeout@Base 7.0.0daily13.05.31ubuntu.unity.next |
93 | - unity_internal_default_scope_dbus_impl_set_view_type@Base 7.0.0daily13.05.31ubuntu.unity.next |
94 | - unity_internal_deprecated_scope_dbus_impl_get_type@Base 7.0.0daily13.05.31ubuntu.unity.next |
95 | - unity_internal_deprecated_scope_dbus_impl_set_categories@Base 7.0.0daily13.05.31ubuntu.unity.next |
96 | - unity_internal_deprecated_scope_dbus_impl_set_filters@Base 7.0.0daily13.05.31ubuntu.unity.next |
97 | - unity_internal_deprecated_scope_impl_activate_action@Base 7.0.0daily13.05.31ubuntu.unity.next |
98 | - unity_internal_deprecated_scope_impl_construct@Base 7.0.0daily13.05.31ubuntu.unity.next |
99 | - unity_internal_deprecated_scope_impl_get_type@Base 7.0.0daily13.05.31ubuntu.unity.next |
100 | - unity_internal_deprecated_scope_impl_get_view_type@Base 7.0.0daily13.05.31ubuntu.unity.next |
101 | - unity_internal_deprecated_scope_impl_new@Base 7.0.0daily13.05.31ubuntu.unity.next |
102 | - unity_internal_deprecated_scope_impl_set_active_sources@Base 7.0.0daily13.05.31ubuntu.unity.next |
103 | - unity_internal_deprecated_scope_impl_set_active_sources_finish@Base 7.0.0daily13.05.31ubuntu.unity.next |
104 | - unity_internal_deprecated_scope_impl_set_view_type@Base 7.0.0daily13.05.31ubuntu.unity.next |
105 | - unity_internal_filter_column_get_type@Base 7.0.0daily13.05.31ubuntu.unity.next |
106 | - unity_internal_glib_cancellable_construct@Base 7.0.0daily13.05.31ubuntu.unity.next |
107 | - unity_internal_glib_cancellable_get_inner@Base 7.0.0daily13.05.31ubuntu.unity.next |
108 | - unity_internal_glib_cancellable_get_type@Base 7.0.0daily13.05.31ubuntu.unity.next |
109 | - unity_internal_glib_cancellable_new@Base 7.0.0daily13.05.31ubuntu.unity.next |
110 | - unity_internal_io_get_system_data_dirs@Base 7.0.0daily13.05.31ubuntu.unity.next |
111 | - unity_internal_io_open_from_data_dirs@Base 7.0.0daily13.05.31ubuntu.unity.next |
112 | - unity_internal_io_open_from_data_dirs_finish@Base 7.0.0daily13.05.31ubuntu.unity.next |
113 | - unity_internal_io_open_from_dirs@Base 7.0.0daily13.05.31ubuntu.unity.next |
114 | - unity_internal_io_open_from_dirs_finish@Base 7.0.0daily13.05.31ubuntu.unity.next |
115 | - unity_internal_io_read_stream_async@Base 7.0.0daily13.05.31ubuntu.unity.next |
116 | - unity_internal_io_read_stream_finish@Base 7.0.0daily13.05.31ubuntu.unity.next |
117 | - unity_internal_io_system_data_dirs@Base 7.0.0daily13.05.31ubuntu.unity.next |
118 | - unity_internal_io_system_data_dirs_length1@Base 7.0.0daily13.05.31ubuntu.unity.next |
119 | - unity_internal_merge_strategy_get_type@Base 7.0.0daily13.05.31ubuntu.unity.next |
120 | - unity_internal_merge_strategy_merge_result@Base 7.0.0daily13.05.31ubuntu.unity.next |
121 | - unity_internal_owned_name_dup@Base 7.0.4daily13.06.19 |
122 | - unity_internal_owned_name_free@Base 7.0.4daily13.06.19 |
123 | - unity_internal_owned_name_get_type@Base 7.0.4daily13.06.19 |
124 | - unity_internal_result_column_get_type@Base 7.0.0daily13.05.31ubuntu.unity.next |
125 | - unity_internal_results_synchronizer_add_provider@Base 7.0.0daily13.05.31ubuntu.unity.next |
126 | - unity_internal_results_synchronizer_clear@Base 7.0.0daily13.05.31ubuntu.unity.next |
127 | - unity_internal_results_synchronizer_construct@Base 7.0.0daily13.05.31ubuntu.unity.next |
128 | - unity_internal_results_synchronizer_copy_model@Base 7.0.0daily13.05.31ubuntu.unity.next |
129 | - unity_internal_results_synchronizer_disable_all_providers@Base 7.0.0daily13.05.31ubuntu.unity.next |
130 | - unity_internal_results_synchronizer_disable_provider@Base 7.0.0daily13.05.31ubuntu.unity.next |
131 | - unity_internal_results_synchronizer_enable_provider@Base 7.0.0daily13.05.31ubuntu.unity.next |
132 | - unity_internal_results_synchronizer_get_merge_strategy@Base 7.0.0daily13.05.31ubuntu.unity.next |
133 | - unity_internal_results_synchronizer_get_receiver@Base 7.0.0daily13.05.31ubuntu.unity.next |
134 | - unity_internal_results_synchronizer_get_type@Base 7.0.0daily13.05.31ubuntu.unity.next |
135 | - unity_internal_results_synchronizer_new@Base 7.0.0daily13.05.31ubuntu.unity.next |
136 | - unity_internal_results_synchronizer_prepare_row_buf@Base 7.0.0daily13.05.31ubuntu.unity.next |
137 | - unity_internal_results_synchronizer_remove_provider@Base 7.0.0daily13.05.31ubuntu.unity.next |
138 | - unity_internal_results_synchronizer_set_merge_strategy@Base 7.0.0daily13.05.31ubuntu.unity.next |
139 | - unity_internal_scope_channel_construct@Base 7.0.0daily13.05.31ubuntu.unity.next |
140 | - unity_internal_scope_channel_create_channel@Base 7.0.0daily13.05.31ubuntu.unity.next |
141 | - unity_internal_scope_channel_get_filter_by_id@Base 7.0.0daily13.05.31ubuntu.unity.next |
142 | - unity_internal_scope_channel_get_pushed_models@Base 7.0.0daily13.05.31ubuntu.unity.next |
143 | - unity_internal_scope_channel_get_search_type@Base 7.0.0daily13.05.31ubuntu.unity.next |
144 | - unity_internal_scope_channel_get_type@Base 7.0.0daily13.05.31ubuntu.unity.next |
145 | - unity_internal_scope_channel_is_search_running@Base 7.0.0daily13.05.31ubuntu.unity.next |
146 | - unity_internal_scope_channel_new@Base 7.0.0daily13.05.31ubuntu.unity.next |
147 | - unity_internal_scope_channel_register_pushed_model@Base 7.0.0daily13.05.31ubuntu.unity.next |
148 | - unity_internal_scope_channel_set_filter_base@Base 7.0.0daily13.05.31ubuntu.unity.next |
149 | - unity_internal_scope_channel_new@Base 7.0.0daily13.05.31ubuntu.unity.next |
150 | - unity_internal_scope_channel_set_state@Base 7.0.0daily13.05.31ubuntu.unity.next |
151 | - unity_internal_scope_channel_wait_for_search@Base 7.0.0daily13.05.31ubuntu.unity.next |
152 | - unity_internal_scope_channel_wait_for_search_finish@Base 7.0.0daily13.05.31ubuntu.unity.next |
153 | - unity_internal_scope_dbus_impl_export@Base 7.0.0daily13.05.31ubuntu.unity.next |
154 | - unity_internal_scope_dbus_impl_get_categories_model@Base 7.0.0daily13.05.31ubuntu.unity.next |
155 | - unity_internal_scope_dbus_impl_get_filters_model@Base 7.0.0daily13.05.31ubuntu.unity.next |
156 | - unity_internal_scope_dbus_impl_get_type@Base 7.0.0daily13.05.31ubuntu.unity.next |
157 | - unity_internal_scope_dbus_impl_queue_property_notification@Base 7.0.0daily13.05.31ubuntu.unity.next |
158 | - unity_internal_scope_dbus_impl_queue_search_for_type@Base 7.0.0daily13.05.31ubuntu.unity.next |
159 | - unity_internal_scope_dbus_impl_set_categories_model@Base 7.0.0daily13.05.31ubuntu.unity.next |
160 | - unity_internal_scope_dbus_impl_set_filters_model@Base 7.0.0daily13.05.31ubuntu.unity.next |
161 | - unity_internal_scope_dbus_impl_unexport@Base 7.0.0daily13.05.31ubuntu.unity.next |
162 | - unity_internal_scope_dbus_name_manager_acquire_names@Base 7.0.4daily13.06.19 |
163 | - unity_internal_scope_dbus_name_manager_acquire_names_finish@Base 7.0.4daily13.06.19 |
164 | - unity_internal_scope_dbus_name_manager_get_default@Base 7.0.4daily13.06.19 |
165 | - unity_internal_scope_dbus_name_manager_get_type@Base 7.0.4daily13.06.19 |
166 | - unity_internal_scope_dbus_name_manager_own_name@Base 7.0.4daily13.06.19 |
167 | - unity_internal_scope_dbus_name_manager_unown_name@Base 7.0.4daily13.06.19 |
168 | - unity_internal_utils_async_mutex_construct@Base 7.0.0daily13.05.31ubuntu.unity.next |
169 | - unity_internal_utils_async_mutex_get_type@Base 7.0.0daily13.05.31ubuntu.unity.next |
170 | - unity_internal_utils_async_mutex_lock@Base 7.0.0daily13.05.31ubuntu.unity.next |
171 | - unity_internal_utils_async_mutex_lock_finish@Base 7.0.0daily13.05.31ubuntu.unity.next |
172 | - unity_internal_utils_async_mutex_new@Base 7.0.0daily13.05.31ubuntu.unity.next |
173 | - unity_internal_utils_async_mutex_ref@Base 7.0.0daily13.05.31ubuntu.unity.next |
174 | - unity_internal_utils_async_mutex_try_lock@Base 7.0.0daily13.05.31ubuntu.unity.next |
175 | - unity_internal_utils_async_mutex_unlock@Base 7.0.0daily13.05.31ubuntu.unity.next |
176 | - unity_internal_utils_async_mutex_unref@Base 7.0.0daily13.05.31ubuntu.unity.next |
177 | - unity_internal_utils_async_once_construct@Base 7.0.0daily13.05.31ubuntu.unity.next |
178 | - unity_internal_utils_async_once_enter@Base 7.0.0daily13.05.31ubuntu.unity.next |
179 | - unity_internal_utils_async_once_enter_finish@Base 7.0.0daily13.05.31ubuntu.unity.next |
180 | - unity_internal_utils_async_once_get_data@Base 7.0.0daily13.05.31ubuntu.unity.next |
181 | - unity_internal_utils_async_once_get_type@Base 7.0.0daily13.05.31ubuntu.unity.next |
182 | - unity_internal_utils_async_once_is_initialized@Base 7.0.0daily13.05.31ubuntu.unity.next |
183 | - unity_internal_utils_async_once_leave@Base 7.0.0daily13.05.31ubuntu.unity.next |
184 | - unity_internal_utils_async_once_new@Base 7.0.0daily13.05.31ubuntu.unity.next |
185 | - unity_internal_utils_async_once_ref@Base 7.0.0daily13.05.31ubuntu.unity.next |
186 | - unity_internal_utils_async_once_reset@Base 7.0.0daily13.05.31ubuntu.unity.next |
187 | - unity_internal_utils_async_once_unref@Base 7.0.0daily13.05.31ubuntu.unity.next |
188 | - unity_internal_utils_delegate_wrapper_free@Base 7.0.0daily13.05.31ubuntu.unity.next |
189 | - unity_internal_utils_delegate_wrapper_new@Base 7.0.0daily13.05.31ubuntu.unity.next |
190 | - unity_internal_utils_hash_table_to_asv@Base 7.0.0daily13.05.31ubuntu.unity.next |
191 | - unity_internal_utils_icon_to_string@Base 7.0.0daily13.05.31ubuntu.unity.next |
192 | - unity_internal_utils_param_spec_async_mutex@Base 7.0.0daily13.05.31ubuntu.unity.next |
193 | - unity_internal_utils_param_spec_async_once@Base 7.0.0daily13.05.31ubuntu.unity.next |
194 | - unity_internal_utils_value_get_async_mutex@Base 7.0.0daily13.05.31ubuntu.unity.next |
195 | - unity_internal_utils_value_get_async_once@Base 7.0.0daily13.05.31ubuntu.unity.next |
196 | - unity_internal_utils_value_set_async_mutex@Base 7.0.0daily13.05.31ubuntu.unity.next |
197 | - unity_internal_utils_value_set_async_once@Base 7.0.0daily13.05.31ubuntu.unity.next |
198 | - unity_internal_utils_value_take_async_mutex@Base 7.0.0daily13.05.31ubuntu.unity.next |
199 | - unity_internal_utils_value_take_async_once@Base 7.0.0daily13.05.31ubuntu.unity.next |
200 | - unity_internal_utils_wait_for_model_synchronization@Base 7.0.4daily13.06.24 |
201 | - unity_internal_utils_wait_for_model_synchronization_finish@Base 7.0.4daily13.06.24 |
202 | unity_launcher_entry_dbus_impl_construct@Base 3.4.6 |
203 | unity_launcher_entry_dbus_impl_get_type@Base 3.4.6 |
204 | unity_launcher_entry_dbus_impl_new@Base 3.4.6 |
205 | |
206 | === modified file 'protocol/protocol-scope-interface.vala' |
207 | --- protocol/protocol-scope-interface.vala 2013-04-25 13:26:24 +0000 |
208 | +++ protocol/protocol-scope-interface.vala 2013-07-09 13:37:28 +0000 |
209 | @@ -66,7 +66,8 @@ |
210 | { |
211 | NONE = 0, |
212 | PRIVATE, |
213 | - NO_FILTERING |
214 | + NO_FILTERING, |
215 | + DIFF_CHANGES |
216 | } |
217 | |
218 | /* The error types that can be thrown from DBus methods */ |
219 | |
220 | === modified file 'src/Makefile.am' |
221 | --- src/Makefile.am 2013-07-01 07:58:03 +0000 |
222 | +++ src/Makefile.am 2013-07-09 13:37:28 +0000 |
223 | @@ -102,8 +102,9 @@ |
224 | unity-category.vala \ |
225 | unity-filters.vala \ |
226 | unity-preferences-manager.vala \ |
227 | + unity-merge-strategy.vala \ |
228 | + unity-models.vala \ |
229 | unity-search.vala \ |
230 | - unity-merge-strategy.vala \ |
231 | unity-synchronizer.vala \ |
232 | unity-previews.vala \ |
233 | unity-result-activation.vala \ |
234 | |
235 | === modified file 'src/unity-aggregator-scope-private.vala' |
236 | --- src/unity-aggregator-scope-private.vala 2013-06-25 11:19:09 +0000 |
237 | +++ src/unity-aggregator-scope-private.vala 2013-07-09 13:37:28 +0000 |
238 | @@ -1444,7 +1444,7 @@ |
239 | response.insert (key, variant); |
240 | } |
241 | |
242 | - response[SEARCH_SEQNUM_HINT] = new Variant.uint64 (channel.results_model.get_seqnum ()); |
243 | + response[SEARCH_SEQNUM_HINT] = new Variant.uint64 (channel.get_last_seqnum ()); |
244 | return response; |
245 | } |
246 | else |
247 | @@ -1464,9 +1464,9 @@ |
248 | |
249 | var search_cancellable = Unity.Cancellable.create (); |
250 | |
251 | - var result_set = new DeeResultSet.with_model (channel.results_model); |
252 | + var result_set = new DeeResultSet.with_model (channel.backend_model); |
253 | result_set.ttl = -1; |
254 | - result_set.flush_model = synchronizer.receiver as Dee.SerializableModel; |
255 | + result_set.flush_model = channel.transfer_model; |
256 | AggregatedScopeSearch? aggsearch = null; |
257 | |
258 | uint timer_src_id = 0; |
259 | @@ -1506,7 +1506,7 @@ |
260 | search_context.cancellable = search_cancellable; |
261 | |
262 | aggsearch = new AggregatedScopeSearch (owner, channel.id, |
263 | - hints, channel.results_model); |
264 | + hints, channel.backend_model); |
265 | aggsearch.set_search_context (search_context); |
266 | |
267 | ulong sig_id = aggsearch.category_order_changed.connect ((indices) => |
268 | @@ -1621,7 +1621,7 @@ |
269 | |
270 | Unity.Trace.tracepoint ("%s run end: %s", Log.METHOD, owner.id); |
271 | |
272 | - response[SEARCH_SEQNUM_HINT] = new Variant.uint64 (channel.results_model.get_seqnum ()); |
273 | + response[SEARCH_SEQNUM_HINT] = new Variant.uint64 (channel.get_last_seqnum ()); |
274 | if (measure_requests) |
275 | { |
276 | int64 delta_us = search_end_time - search_start_time; |
277 | @@ -1798,14 +1798,13 @@ |
278 | filters_model, |
279 | flags | ChannelFlags.NO_FILTERING); |
280 | |
281 | - if (channel.results_model is Dee.SharedModel) |
282 | + if (channel.transfer_model != null) |
283 | { |
284 | - var sm = channel.results_model as Dee.SharedModel; |
285 | - yield Internal.Utils.wait_for_model_synchronization (sm); |
286 | + yield Internal.Utils.wait_for_model_synchronization (channel.transfer_model); |
287 | } |
288 | |
289 | _channels[channel.id] = channel; |
290 | - _scopes.register_channel (channel.id, channel.results_model, merge_strategy); |
291 | + _scopes.register_channel (channel.id, channel.backend_model, merge_strategy); |
292 | |
293 | out_hints = new HashTable<string, Variant> (str_hash, str_equal); |
294 | out_hints[CHANNEL_SWARM_NAME_HINT] = new Variant.string (model_name); |
295 | @@ -1883,16 +1882,12 @@ |
296 | sync.add_provider (provider, source_scope_id); |
297 | sync.copy_model (provider); |
298 | |
299 | - // FIXME: do we really want to do this? |
300 | - var sm = sync.receiver as Dee.SharedModel; |
301 | - if (sm != null) |
302 | - { |
303 | - sm.flush_revision_queue (); |
304 | - } |
305 | - |
306 | var result = new HashTable<string, Variant> (str_hash, str_equal); |
307 | - var serializable_model = sync.receiver as Dee.SerializableModel; |
308 | - result[SEARCH_SEQNUM_HINT] = new Variant.uint64 (serializable_model.get_seqnum ()); |
309 | + result[SEARCH_SEQNUM_HINT] = new Variant.uint64 (channel.get_last_seqnum ()); |
310 | + if (channel.transfer_model != null) |
311 | + { |
312 | + channel.transfer_model.flush_revision_queue (); |
313 | + } |
314 | |
315 | return result; |
316 | } |
317 | |
318 | === modified file 'src/unity-deprecated-scope-impl.vala' |
319 | --- src/unity-deprecated-scope-impl.vala 2013-06-25 11:19:09 +0000 |
320 | +++ src/unity-deprecated-scope-impl.vala 2013-07-09 13:37:28 +0000 |
321 | @@ -394,8 +394,6 @@ |
322 | this.results_invalidated (channel_type); |
323 | } |
324 | |
325 | - public signal void channel_search_finished (string channel_id); |
326 | - |
327 | private async HashTable<string, Variant> search_internal ( |
328 | string search_string, HashTable<string, Variant> hints, |
329 | ScopeChannel channel) throws ScopeError |
330 | @@ -426,8 +424,9 @@ |
331 | search_context.search_type = channel.get_search_type (); |
332 | search_context.filter_state = channel.filters; |
333 | search_context.search_metadata = SearchMetadata.create (hints); |
334 | - search_context.result_set = new DeeResultSet.with_model (channel.backend_model); |
335 | - search_context.result_set.ttl = -1; |
336 | + var result_set = new DeeResultSet.with_model (channel.backend_model); |
337 | + result_set.ttl = -1; |
338 | + search_context.result_set = result_set; |
339 | search_context.cancellable = cancellable; |
340 | |
341 | // prepare new ScopeSearch instance |
342 | @@ -457,7 +456,7 @@ |
343 | if (SEARCH_NO_RESULTS_HINT in last_hints) |
344 | result[SEARCH_NO_RESULTS_HINT] = last_hints[SEARCH_NO_RESULTS_HINT]; |
345 | } |
346 | - result[SEARCH_SEQNUM_HINT] = new Variant.uint64 (channel.results_model.get_seqnum ()); |
347 | + result[SEARCH_SEQNUM_HINT] = new Variant.uint64 (channel.get_last_seqnum ()); |
348 | return result; |
349 | } |
350 | else |
351 | @@ -476,7 +475,7 @@ |
352 | if (!channel.model_lock.try_lock ()) yield channel.model_lock.lock (); |
353 | channel.set_state (ChannelState.SEARCH_ACTIVE); |
354 | // don't clear the model, the deprecated scopes do that themselves |
355 | - //channel.results_model.clear (); |
356 | + //channel.backend_model.clear (); |
357 | |
358 | // wait for idle, so requests that came after this one can cancel this |
359 | // before we even run it |
360 | @@ -489,6 +488,8 @@ |
361 | normalized_query); |
362 | } |
363 | |
364 | + result_set.flush_model = channel.transfer_model; |
365 | + |
366 | int64 search_start_time = 0; |
367 | if (measure_requests) search_start_time = get_monotonic_time (); |
368 | int64 search_end_time = search_start_time; |
369 | @@ -502,10 +503,7 @@ |
370 | }); |
371 | yield; |
372 | |
373 | - // resume any suspended searches |
374 | - channel_search_finished (channel.id); |
375 | - |
376 | - result[SEARCH_SEQNUM_HINT] = new Variant.uint64 (channel.results_model.get_seqnum ()); |
377 | + result[SEARCH_SEQNUM_HINT] = new Variant.uint64 (channel.get_last_seqnum ()); |
378 | |
379 | Unity.Trace.tracepoint ("%s run end: %s", Log.METHOD, owner.id); |
380 | if (measure_requests) |
381 | @@ -515,6 +513,11 @@ |
382 | result[SEARCH_TIME_HINT] = new Variant.double (delta); |
383 | } |
384 | |
385 | + if (!cancellable.is_cancelled ()) |
386 | + { |
387 | + result_set.flush (); |
388 | + } |
389 | + |
390 | // handle hints |
391 | var reply_hints = new_search.get_reply_hints (); |
392 | if (reply_hints != null) |
393 | @@ -630,13 +633,13 @@ |
394 | optional_schema, |
395 | filters_model, |
396 | flags); |
397 | - var sm = channel.results_model as Dee.SharedModel; |
398 | - if (sm != null) |
399 | + |
400 | + if (channel.transfer_model != null) |
401 | { |
402 | // force AUTOMATIC flushing for the deprecated scopes as they don't |
403 | // expect the ResultSet to have a separate flush() method |
404 | - sm.flush_mode = Dee.SharedModelFlushMode.AUTOMATIC; |
405 | - yield Internal.Utils.wait_for_model_synchronization (sm); |
406 | + channel.transfer_model.flush_mode = Dee.SharedModelFlushMode.AUTOMATIC; |
407 | + yield Internal.Utils.wait_for_model_synchronization (channel.transfer_model); |
408 | } |
409 | |
410 | _channels[channel.id] = channel; |
411 | |
412 | === added file 'src/unity-models.vala' |
413 | --- src/unity-models.vala 1970-01-01 00:00:00 +0000 |
414 | +++ src/unity-models.vala 2013-07-09 13:37:28 +0000 |
415 | @@ -0,0 +1,200 @@ |
416 | +/* |
417 | + * Copyright (C) 2013 Canonical, Ltd. |
418 | + * |
419 | + * This library is free software; you can redistribute it and/or modify |
420 | + * it under the terms of the GNU Lesser General Public License |
421 | + * version 3.0 as published by the Free Software Foundation. |
422 | + * |
423 | + * This library is distributed in the hope that it will be useful, |
424 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
425 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
426 | + * GNU Lesser General Public License version 3.0 for more details. |
427 | + * |
428 | + * You should have received a copy of the GNU Lesser General Public |
429 | + * License along with this library. If not, see |
430 | + * <http://www.gnu.org/licenses/>. |
431 | + * |
432 | + * Authored by Michal Hruby <michal.hruby@canonical.com> |
433 | + * |
434 | + */ |
435 | + |
436 | +using GLib; |
437 | +using Dee; |
438 | + |
439 | +namespace Unity.Internal { |
440 | + |
441 | +internal class DeeResultSet: ResultSet |
442 | +{ |
443 | + public DeeResultSet () |
444 | + { |
445 | + Object (); |
446 | + } |
447 | + |
448 | + public DeeResultSet.with_model (Dee.SerializableModel model) |
449 | + { |
450 | + Object (results_model: model); |
451 | + } |
452 | + |
453 | + public override void constructed () |
454 | + { |
455 | + if (results_model == null) |
456 | + { |
457 | + results_model = new Dee.SequenceModel (); |
458 | + results_model.set_schema_full (Internal.RESULTS_SCHEMA); |
459 | + results_model.set_column_names_full (Internal.RESULTS_COLUMN_NAMES); |
460 | + } |
461 | + } |
462 | + |
463 | + public Dee.SerializableModel results_model { get; construct set; } |
464 | + |
465 | + public override void add_result (ScopeResult result) |
466 | + { |
467 | + // ensure this matches the schema! |
468 | + Variant metadata_v; |
469 | + if (result.metadata != null) |
470 | + { |
471 | + metadata_v = result.metadata; |
472 | + } |
473 | + else |
474 | + { |
475 | + metadata_v = new Variant.array (VariantType.VARDICT.element (), {}); |
476 | + } |
477 | + results_model.append (result.uri, result.icon_hint, result.category, |
478 | + result.result_type, result.mimetype, result.title, |
479 | + result.comment, result.dnd_uri, metadata_v); |
480 | + } |
481 | + |
482 | + public override void add_result_from_variant (Variant variant) |
483 | + { |
484 | + if (variant.get_type_string () != "(ssuussssa{sv})") |
485 | + { |
486 | + warning ("Incorrect signature for %s", Log.METHOD); |
487 | + return; |
488 | + } |
489 | + |
490 | + Variant row_buf[9]; |
491 | + variant.get ("(@s@s@u@u@s@s@s@s@a{sv})", |
492 | + out row_buf[0], out row_buf[1], |
493 | + out row_buf[2], out row_buf[3], |
494 | + out row_buf[4], out row_buf[5], |
495 | + out row_buf[6], out row_buf[7], |
496 | + out row_buf[8]); |
497 | + results_model.append_row (row_buf); |
498 | + } |
499 | + |
500 | + public Dee.SerializableModel flush_model { get; set; } |
501 | + |
502 | + public override void flush () |
503 | + { |
504 | + var diff_model = flush_model as DiffModel; |
505 | + if (diff_model != null) |
506 | + { |
507 | + diff_model.commit_changes (); |
508 | + } |
509 | + var sm = flush_model as Dee.SharedModel; |
510 | + if (sm != null) |
511 | + { |
512 | + sm.flush_revision_queue (); |
513 | + } |
514 | + } |
515 | +} |
516 | + |
517 | +internal class DiffModel: Dee.SharedModel |
518 | +{ |
519 | + public DiffModel (Dee.Peer peer, Dee.Model target) |
520 | + { |
521 | + var model = new Dee.SequenceModel (); |
522 | + Object (peer: peer, back_end: model, target_model: target); |
523 | + } |
524 | + |
525 | + public Dee.Model target_model { get; construct set; } |
526 | + |
527 | + public void commit_changes () |
528 | + { |
529 | + uint this_rows = this.get_n_rows (); |
530 | + uint target_rows = target_model.get_n_rows (); |
531 | + |
532 | + // a few short-circuits |
533 | + if (target_rows == 0) |
534 | + { |
535 | + clear (); |
536 | + return; |
537 | + } |
538 | + else if (this_rows == 0) |
539 | + { |
540 | + // diff model is empty, copy everything from target_model |
541 | + Variant row_buf[9]; |
542 | + var iter = target_model.get_first_iter (); |
543 | + var end_iter = target_model.get_last_iter (); |
544 | + while (iter != end_iter) |
545 | + { |
546 | + // vala doesn't know we're changing the array, so need to clear it |
547 | + for (int i = 0; i < row_buf.length; i++) row_buf[i] = null; |
548 | + target_model.get_row_static (iter, row_buf); |
549 | + this.append_row (row_buf); |
550 | + iter = target_model.next (iter); |
551 | + } |
552 | + return; |
553 | + } |
554 | + |
555 | + var script = Utils.Diff.run ((int) this_rows, (int) target_rows, |
556 | + (index_a, index_b) => |
557 | + { |
558 | + var this_iter = this.get_iter_at_row (index_a); |
559 | + var target_iter = target_model.get_iter_at_row (index_b); |
560 | + |
561 | + // check categories first |
562 | + if (get_uint32 (this_iter, ResultColumn.CATEGORY) != |
563 | + target_model.get_uint32 (target_iter, ResultColumn.CATEGORY)) |
564 | + { |
565 | + return false; |
566 | + } |
567 | + |
568 | + // consider uris + metadata primary key |
569 | + if (this.get_string (this_iter, ResultColumn.URI) != |
570 | + target_model.get_string (target_iter, ResultColumn.URI)) |
571 | + { |
572 | + return false; |
573 | + } |
574 | + |
575 | + Variant om = target_model.get_value (target_iter, ResultColumn.METADATA); |
576 | + return this.get_value (this_iter, ResultColumn.METADATA).equal (om); |
577 | + }); |
578 | + |
579 | + // the script is reversed, so no need to worry about decrementing indices |
580 | + // after a deletion |
581 | + foreach (unowned Utils.Diff.Change? change in script) |
582 | + { |
583 | + int to_delete = change.deleted; |
584 | + var iter = this.get_iter_at_row (change.x_offset); |
585 | + while (to_delete > 0) |
586 | + { |
587 | + var rm_iter = iter; |
588 | + iter = this.next (iter); |
589 | + this.remove (rm_iter); |
590 | + to_delete--; |
591 | + } |
592 | + if (change.inserted > 0) |
593 | + { |
594 | + Variant row_buf[9]; |
595 | + int to_insert = change.inserted; |
596 | + int inserted = 0; |
597 | + var target_iter = target_model.get_iter_at_row (change.y_offset); |
598 | + while (inserted < to_insert) |
599 | + { |
600 | + for (int i = 0; i < row_buf.length; i++) row_buf[i] = null; |
601 | + target_model.get_row_static (target_iter, row_buf); |
602 | + this.insert_row (change.x_offset + inserted, row_buf); |
603 | + // advance positions |
604 | + target_iter = target_model.next (target_iter); |
605 | + inserted++; |
606 | + } |
607 | + } |
608 | + } |
609 | + |
610 | + assert (get_n_rows () == target_model.get_n_rows ()); |
611 | + } |
612 | +} |
613 | + |
614 | +} /* namespace Unity.Internal */ |
615 | + |
616 | |
617 | === modified file 'src/unity-scope-channel.vala' |
618 | --- src/unity-scope-channel.vala 2013-05-01 20:56:04 +0000 |
619 | +++ src/unity-scope-channel.vala 2013-07-09 13:37:28 +0000 |
620 | @@ -37,9 +37,9 @@ |
621 | private const uint METADATA_COLUMN = 8; |
622 | |
623 | public Utils.AsyncMutex model_lock; |
624 | - /* results_model is usually a Dee.SharedModel */ |
625 | - public Dee.SerializableModel results_model; |
626 | - /* backing model for the results_model (ie SequenceModel or FilterModel) */ |
627 | + /* transfer_model must be a Dee.SharedModel */ |
628 | + public Dee.SharedModel? transfer_model; |
629 | + /* backing model for the transfer_model (ie SequenceModel or FilterModel) */ |
630 | public Dee.SerializableModel backend_model; |
631 | |
632 | public FilterSet filters; |
633 | @@ -138,15 +138,41 @@ |
634 | Dee.Peer peer = ChannelFlags.PRIVATE in flags ? |
635 | new Dee.Server (swarm_name) : new Dee.Peer (swarm_name); |
636 | |
637 | + /* If NO_FILTERING is not specified, create_backend_model () will return |
638 | + * a FilterModel which will ensure that all required fields |
639 | + * from the schema are present, otherwise the row will be ignored. |
640 | + * |
641 | + * backend_model will then point to a simple SequenceModel which is used |
642 | + * as a backend for the FilterModel. |
643 | + */ |
644 | Dee.Model backend = create_backend_model ( |
645 | metadata_schema, ChannelFlags.NO_FILTERING in flags, |
646 | out backend_model); |
647 | |
648 | - var sm = Object.new (typeof (Dee.SharedModel), |
649 | - "peer", peer, |
650 | - "back-end", backend) as Dee.SharedModel; |
651 | - sm.flush_mode = Dee.SharedModelFlushMode.MANUAL; |
652 | - results_model = sm; |
653 | + /* Careful about using DiffModel, the ResultsSynchronizer doesn't play |
654 | + * nice with it, as the synchronized model gets cleared and listens |
655 | + * only to additions, if the provider model for the synchronizer only |
656 | + * removes a couple of results, and leaves the rest there, |
657 | + * the synchronizer will think that there are no results (cause there |
658 | + * were no additions). |
659 | + * Therefore AggregatorScopes can't use DiffModels. */ |
660 | + if (ChannelFlags.DIFF_CHANGES in flags) |
661 | + { |
662 | + var sm = new DiffModel (peer, backend); |
663 | + sm.flush_mode = Dee.SharedModelFlushMode.MANUAL; |
664 | + sm.set_schema_full (RESULTS_SCHEMA); |
665 | + sm.set_column_names_full (RESULTS_COLUMN_NAMES); |
666 | + sm.register_vardict_schema (METADATA_COLUMN, vardict_schema); |
667 | + transfer_model = sm; |
668 | + } |
669 | + else |
670 | + { |
671 | + var sm = Object.new (typeof (Dee.SharedModel), |
672 | + "peer", peer, |
673 | + "back-end", backend) as Dee.SharedModel; |
674 | + sm.flush_mode = Dee.SharedModelFlushMode.MANUAL; |
675 | + transfer_model = sm; |
676 | + } |
677 | |
678 | backend_model.set_schema_full (RESULTS_SCHEMA); |
679 | backend_model.set_column_names_full (RESULTS_COLUMN_NAMES); |
680 | @@ -211,6 +237,20 @@ |
681 | return state == ChannelState.SEARCH_ACTIVE; |
682 | } |
683 | |
684 | + public uint64 get_last_seqnum () |
685 | + { |
686 | + if (transfer_model != null) |
687 | + { |
688 | + if (transfer_model is DiffModel) |
689 | + { |
690 | + (transfer_model as DiffModel).commit_changes (); |
691 | + } |
692 | + return transfer_model.get_seqnum (); |
693 | + } |
694 | + |
695 | + return backend_model.get_seqnum (); |
696 | + } |
697 | + |
698 | public void register_pushed_model (string search_string, |
699 | Dee.SerializableModel model) |
700 | { |
701 | |
702 | === modified file 'src/unity-scope-dbus-impl.vala' |
703 | --- src/unity-scope-dbus-impl.vala 2013-06-25 11:19:09 +0000 |
704 | +++ src/unity-scope-dbus-impl.vala 2013-07-09 13:37:28 +0000 |
705 | @@ -424,8 +424,6 @@ |
706 | } |
707 | } |
708 | |
709 | - public signal void channel_search_finished (string channel_id); |
710 | - |
711 | private async HashTable<string, Variant> search_internal ( |
712 | string search_string, HashTable<string, Variant> hints, |
713 | ScopeChannel channel) throws ScopeError |
714 | @@ -465,7 +463,7 @@ |
715 | // wait for the previous search to finish and then return |
716 | yield channel.wait_for_search (); |
717 | } |
718 | - result[SEARCH_SEQNUM_HINT] = new Variant.uint64 (channel.results_model.get_seqnum ()); |
719 | + result[SEARCH_SEQNUM_HINT] = new Variant.uint64 (channel.get_last_seqnum ()); |
720 | return result; |
721 | } |
722 | else |
723 | @@ -506,7 +504,7 @@ |
724 | { |
725 | if (!channel.model_lock.try_lock ()) yield channel.model_lock.lock (); |
726 | channel.set_state (ChannelState.SEARCH_ACTIVE); |
727 | - channel.results_model.clear (); |
728 | + channel.backend_model.clear (); |
729 | |
730 | // wait for idle, so requests that came after this one can cancel this |
731 | // before we even run it |
732 | @@ -519,7 +517,7 @@ |
733 | normalized_query); |
734 | } |
735 | |
736 | - result_set.flush_model = channel.results_model; |
737 | + result_set.flush_model = channel.transfer_model; |
738 | |
739 | int64 search_start_time = 0; |
740 | if (measure_requests) search_start_time = get_monotonic_time (); |
741 | @@ -549,12 +547,9 @@ |
742 | yield; |
743 | } |
744 | |
745 | - // resume any suspended searches |
746 | - channel_search_finished (channel.id); |
747 | - |
748 | Unity.Trace.tracepoint ("%s run end: %s", Log.METHOD, _dbus_name); |
749 | |
750 | - result[SEARCH_SEQNUM_HINT] = new Variant.uint64 (channel.results_model.get_seqnum ()); |
751 | + result[SEARCH_SEQNUM_HINT] = new Variant.uint64 (channel.get_last_seqnum ()); |
752 | if (measure_requests) |
753 | { |
754 | int64 delta_us = search_end_time - search_start_time; |
755 | @@ -699,10 +694,9 @@ |
756 | filters_model, |
757 | flags); |
758 | |
759 | - if (channel.results_model is Dee.SharedModel) |
760 | + if (channel.transfer_model != null) |
761 | { |
762 | - var sm = channel.results_model as Dee.SharedModel; |
763 | - yield Internal.Utils.wait_for_model_synchronization (sm); |
764 | + yield Internal.Utils.wait_for_model_synchronization (channel.transfer_model); |
765 | } |
766 | |
767 | _channels[channel.id] = channel; |
768 | |
769 | === modified file 'src/unity-scope-interface.vala' |
770 | --- src/unity-scope-interface.vala 2013-06-25 09:00:37 +0000 |
771 | +++ src/unity-scope-interface.vala 2013-07-09 13:37:28 +0000 |
772 | @@ -182,7 +182,7 @@ |
773 | * Abstract method where the search is performed |
774 | * |
775 | * Scopes need to implement this method and add results to the ResultSet |
776 | - * which was passed to the Unity.AbstractScope.create_search_for_query(). |
777 | + * which was passed to the {@link Unity.AbstractScope.create_search_for_query}. |
778 | * By the time this method returns, the ResultSet is considered complete. |
779 | */ |
780 | public abstract void run (); |
781 | |
782 | === modified file 'src/unity-search.vala' |
783 | --- src/unity-search.vala 2013-06-18 14:17:57 +0000 |
784 | +++ src/unity-search.vala 2013-07-09 13:37:28 +0000 |
785 | @@ -37,77 +37,6 @@ |
786 | |
787 | } /* namespace Unity.Internal */ |
788 | |
789 | -public class DeeResultSet: ResultSet |
790 | -{ |
791 | - public class DeeResultSet () |
792 | - { |
793 | - Object (); |
794 | - } |
795 | - |
796 | - public class DeeResultSet.with_model (Dee.SerializableModel model) |
797 | - { |
798 | - Object (results_model: model); |
799 | - } |
800 | - |
801 | - public override void constructed () |
802 | - { |
803 | - if (results_model == null) |
804 | - { |
805 | - results_model = new Dee.SequenceModel (); |
806 | - results_model.set_schema_full (Internal.RESULTS_SCHEMA); |
807 | - results_model.set_column_names_full (Internal.RESULTS_COLUMN_NAMES); |
808 | - } |
809 | - } |
810 | - |
811 | - public Dee.SerializableModel results_model { get; construct set; } |
812 | - |
813 | - public override void add_result (ScopeResult result) |
814 | - { |
815 | - // ensure this matches the schema! |
816 | - Variant metadata_v; |
817 | - if (result.metadata != null) |
818 | - { |
819 | - metadata_v = result.metadata; |
820 | - } |
821 | - else |
822 | - { |
823 | - metadata_v = new Variant.array (VariantType.VARDICT.element (), {}); |
824 | - } |
825 | - results_model.append (result.uri, result.icon_hint, result.category, |
826 | - result.result_type, result.mimetype, result.title, |
827 | - result.comment, result.dnd_uri, metadata_v); |
828 | - } |
829 | - |
830 | - public override void add_result_from_variant (Variant variant) |
831 | - { |
832 | - if (variant.get_type_string () != "(ssuussssa{sv})") |
833 | - { |
834 | - warning ("Incorrect signature for %s", Log.METHOD); |
835 | - return; |
836 | - } |
837 | - |
838 | - Variant row_buf[9]; |
839 | - variant.get ("(@s@s@u@u@s@s@s@s@a{sv})", |
840 | - out row_buf[0], out row_buf[1], |
841 | - out row_buf[2], out row_buf[3], |
842 | - out row_buf[4], out row_buf[5], |
843 | - out row_buf[6], out row_buf[7], |
844 | - out row_buf[8]); |
845 | - results_model.append_row (row_buf); |
846 | - } |
847 | - |
848 | - public Dee.SerializableModel flush_model { get; set; } |
849 | - |
850 | - public override void flush () |
851 | - { |
852 | - var sm = flush_model as Dee.SharedModel; |
853 | - if (sm != null) |
854 | - { |
855 | - sm.flush_revision_queue (); |
856 | - } |
857 | - } |
858 | -} |
859 | - |
860 | /** |
861 | * Internal transitioning class, note that it will disappear from the public |
862 | * API as soon as possible and therefore shouldn't be used. |
863 | |
864 | === modified file 'src/unity-utils.vala' |
865 | --- src/unity-utils.vala 2013-06-24 16:05:00 +0000 |
866 | +++ src/unity-utils.vala 2013-07-09 13:37:28 +0000 |
867 | @@ -305,6 +305,347 @@ |
868 | { |
869 | return icon != null ? icon.to_string () : ""; |
870 | } |
871 | + |
872 | + namespace Diff |
873 | + { |
874 | + internal delegate bool ResultSetCompareFunc (int index_a, int index_b); |
875 | + |
876 | + private struct Context |
877 | + { |
878 | + // Lengths of the analyzed sets |
879 | + int x_length; |
880 | + int y_length; |
881 | + // Buffer for finding the minimal edit path, contains space for both |
882 | + // forwards and backwards paths |
883 | + int[] real_diag; |
884 | + // Buffer for finding forwards edit path, indexed from (-y_length-1) |
885 | + // to (x_length+1) |
886 | + int* f_diag; |
887 | + // Buffer for finding backwards edit path, indexed from (-y_length-1) |
888 | + // to (x_length+1) |
889 | + int* b_diag; |
890 | + // Maximum cost, finding the optimal one is often too costly |
891 | + int max_cost; |
892 | + // Buffer combining the x and y change buffers |
893 | + uint8[] real_changes; |
894 | + // Buffer for recording which items in the original set were removed |
895 | + uint8* x_changes; |
896 | + // Buffer for recording which items in the target set were added |
897 | + uint8* y_changes; |
898 | + |
899 | + Context (int x_set_length, int y_set_length) |
900 | + { |
901 | + x_length = x_set_length; |
902 | + y_length = y_set_length; |
903 | + int diags = (x_set_length + 1 + y_set_length + 1) + 1; |
904 | + |
905 | + // allocate one big buffer for the forward and backward vectors |
906 | + real_diag = new int[diags * 2]; |
907 | + // offset the pointers, cause we're sharing the same mem block, |
908 | + // plus the indices can be negative |
909 | + f_diag = real_diag; |
910 | + f_diag += y_set_length + 1; |
911 | + b_diag = real_diag; |
912 | + b_diag += diags; |
913 | + b_diag += y_set_length + 1; |
914 | + |
915 | + // another one big buffer to record the changes |
916 | + real_changes = new uint8[diags]; |
917 | + x_changes = real_changes; |
918 | + y_changes = real_changes; |
919 | + y_changes += x_set_length + 1; |
920 | + |
921 | + // finding the optimal solution could be too expensive, use suboptimal |
922 | + // if the cost is getting too high |
923 | + max_cost = 1; |
924 | + // fast sqrt(diags) approximation |
925 | + while (diags != 0) |
926 | + { |
927 | + diags /= 4; |
928 | + max_cost *= 2; |
929 | + } |
930 | + max_cost = int.max (max_cost, 256); |
931 | + } |
932 | + } |
933 | + |
934 | + private struct Partition |
935 | + { |
936 | + // find the midpoints where we need to split the two sets |
937 | + int x_mid; |
938 | + int y_mid; |
939 | + // is the upper and lower part of the edit path optimal? |
940 | + bool lo_minimal; |
941 | + bool hi_minimal; |
942 | + } |
943 | + |
944 | + internal struct Change |
945 | + { |
946 | + int x_offset; |
947 | + int y_offset; |
948 | + int inserted; |
949 | + int deleted; |
950 | + } |
951 | + |
952 | + internal static SList<Change?> run (int x_set_length, int y_set_length, |
953 | + ResultSetCompareFunc cmp_func) |
954 | + { |
955 | + Context ctx = Context (x_set_length, y_set_length); |
956 | + |
957 | + compare_sequences (0, x_set_length, 0, y_set_length, |
958 | + false, ref ctx, cmp_func); |
959 | + |
960 | + return build_edit_script (ref ctx); |
961 | + } |
962 | + |
963 | + // Note that this produces changeset in reversed order |
964 | + private static SList<Change?> build_edit_script (ref Context ctx) |
965 | + { |
966 | + SList<Change?> script = new SList<Change?> (); |
967 | + int x_length = ctx.x_length; |
968 | + int y_length = ctx.y_length; |
969 | + uint8* x_changes = ctx.x_changes; |
970 | + uint8* y_changes = ctx.y_changes; |
971 | + int x = 0; |
972 | + int y = 0; |
973 | + // find continous change sets and record them, so we're able |
974 | + // to transform the first set into the second |
975 | + while (x < x_length || y < y_length) |
976 | + { |
977 | + if ((x_changes[x] | y_changes[y]) != 0) |
978 | + { |
979 | + int xx = x; |
980 | + int yy = y; |
981 | + while (x_changes[x] != 0) x++; |
982 | + while (y_changes[y] != 0) y++; |
983 | + |
984 | + script.prepend ({xx, yy, y - yy, x - xx}); |
985 | + } |
986 | + |
987 | + x++; |
988 | + y++; |
989 | + } |
990 | + |
991 | + return script; |
992 | + } |
993 | + |
994 | + /* Find the midpoint of the shortest edit script for a given subset |
995 | + of the two vectors */ |
996 | + private static void find_diag (int x_offset, int x_limit, |
997 | + int y_offset, int y_limit, |
998 | + ResultSetCompareFunc equal_func, |
999 | + ref Context ctx, |
1000 | + ref Partition partition) |
1001 | + { |
1002 | + int d_min = x_offset - y_limit; |
1003 | + int d_max = x_limit - y_offset; |
1004 | + int f_mid = x_offset - y_offset; |
1005 | + int b_mid = x_limit - y_limit; |
1006 | + |
1007 | + int f_min = f_mid; |
1008 | + int f_max = f_mid; |
1009 | + int b_min = b_mid; |
1010 | + int b_max = b_mid; |
1011 | + |
1012 | + int cost; |
1013 | + bool is_odd = ((f_mid - b_mid) & 1) != 0; |
1014 | + |
1015 | + int* f_diag = ctx.f_diag; |
1016 | + int* b_diag = ctx.b_diag; |
1017 | + f_diag[f_mid] = x_offset; |
1018 | + b_diag[b_mid] = x_limit; |
1019 | + |
1020 | + for (cost = 1; ; cost++) |
1021 | + { |
1022 | + int d; |
1023 | + |
1024 | + // extend the forwards search by an edit step in each diagonal |
1025 | + if (f_min > d_min) f_diag[--f_min - 1] = -1; |
1026 | + else ++f_min; |
1027 | + |
1028 | + if (f_max < d_max) f_diag[++f_max + 1] = -1; |
1029 | + else --f_max; |
1030 | + |
1031 | + for (d = f_max; d >= f_min; d -= 2) |
1032 | + { |
1033 | + int x, y; |
1034 | + int t_lo = f_diag[d - 1]; |
1035 | + int t_hi = f_diag[d + 1]; |
1036 | + int x0 = t_lo < t_hi ? t_hi : t_lo + 1; |
1037 | + |
1038 | + for (x = x0, y = x0 - d; |
1039 | + x < x_limit && y < y_limit && equal_func (x, y); |
1040 | + x++, y++) |
1041 | + { |
1042 | + continue; |
1043 | + } |
1044 | + |
1045 | + f_diag[d] = x; |
1046 | + if (is_odd && b_min <= d && d <= b_max && b_diag[d] <= x) |
1047 | + { |
1048 | + partition.x_mid = x; |
1049 | + partition.y_mid = y; |
1050 | + partition.lo_minimal = partition.hi_minimal = true; |
1051 | + return; |
1052 | + } |
1053 | + } |
1054 | + |
1055 | + // and extend the backwards search |
1056 | + if (b_min > d_min) b_diag[--b_min - 1] = int.MAX; |
1057 | + else ++b_min; |
1058 | + |
1059 | + if (b_max < d_max) b_diag[++b_max + 1] = int.MAX; |
1060 | + else --b_max; |
1061 | + |
1062 | + for (d = b_max; d >= b_min; d -= 2) |
1063 | + { |
1064 | + int x, y; |
1065 | + int t_lo = b_diag[d - 1]; |
1066 | + int t_hi = b_diag[d + 1]; |
1067 | + int x0 = t_lo < t_hi ? t_lo : t_hi - 1; |
1068 | + |
1069 | + for (x = x0, y = x0 - d; |
1070 | + x_offset < x && y_offset < y && equal_func (x-1, y-1); |
1071 | + x--, y--) |
1072 | + { |
1073 | + continue; |
1074 | + } |
1075 | + |
1076 | + b_diag[d] = x; |
1077 | + if (!is_odd && f_min <= d && d <= f_max && x <= f_diag[d]) |
1078 | + { |
1079 | + partition.x_mid = x; |
1080 | + partition.y_mid = y; |
1081 | + partition.lo_minimal = partition.hi_minimal = true; |
1082 | + return; |
1083 | + } |
1084 | + } |
1085 | + // Chance to implement heuristic to speed things up at the cost |
1086 | + // of loosing optimal path |
1087 | + |
1088 | + // If cost is too high, give up and report halfway between best results |
1089 | + if (cost >= ctx.max_cost) |
1090 | + { |
1091 | + int fxy_best, bxy_best; |
1092 | + int fx_best = 0; |
1093 | + int bx_best = 0; |
1094 | + |
1095 | + fxy_best = -1; |
1096 | + for (d = f_max; d >= f_min; d -= 2) |
1097 | + { |
1098 | + int x = int.min (f_diag[d], x_limit); |
1099 | + int y = x - d; |
1100 | + if (y_limit < y) |
1101 | + { |
1102 | + x = y_limit + d; |
1103 | + y = y_limit; |
1104 | + } |
1105 | + if (fxy_best < x + y) |
1106 | + { |
1107 | + fxy_best = x + y; |
1108 | + fx_best = x; |
1109 | + } |
1110 | + } |
1111 | + |
1112 | + bxy_best = int.MAX; |
1113 | + for (d = b_max; d >= b_min; d -= 2) |
1114 | + { |
1115 | + int x = int.max (x_offset, b_diag[d]); |
1116 | + int y = x - d; |
1117 | + if (y < y_offset) |
1118 | + { |
1119 | + x = y_offset + d; |
1120 | + y = y_offset; |
1121 | + } |
1122 | + if (x + y < bxy_best) |
1123 | + { |
1124 | + bxy_best = x + y; |
1125 | + bx_best = x; |
1126 | + } |
1127 | + } |
1128 | + |
1129 | + if ((x_limit + y_limit) - bxy_best < fxy_best - (x_offset + y_offset)) |
1130 | + { |
1131 | + partition.x_mid = fx_best; |
1132 | + partition.y_mid = fxy_best - fx_best; |
1133 | + partition.lo_minimal = true; |
1134 | + partition.hi_minimal = false; |
1135 | + } |
1136 | + else |
1137 | + { |
1138 | + partition.x_mid = bx_best; |
1139 | + partition.y_mid = bxy_best - bx_best; |
1140 | + partition.lo_minimal = false; |
1141 | + partition.hi_minimal = true; |
1142 | + } |
1143 | + return; |
1144 | + } |
1145 | + } |
1146 | + } |
1147 | + |
1148 | + /* Compare contigous sequences of two sets. |
1149 | + * |
1150 | + * Return true if terminated through early abort, false otherwise. |
1151 | + */ |
1152 | + private static bool compare_sequences (int x_offset, int x_limit, |
1153 | + int y_offset, int y_limit, |
1154 | + bool find_minimal, ref Context ctx, |
1155 | + ResultSetCompareFunc equal_func) |
1156 | + { |
1157 | + // slide down the bottom diagonal in the forwards path |
1158 | + while (x_offset < x_limit && y_offset < y_limit && equal_func (x_offset, y_offset)) |
1159 | + { |
1160 | + x_offset++; |
1161 | + y_offset++; |
1162 | + } |
1163 | + |
1164 | + // and slide up the top diagonal in the backwards path |
1165 | + while (x_offset < x_limit && y_offset < y_limit && equal_func (x_limit-1, y_limit-1)) |
1166 | + { |
1167 | + x_limit--; |
1168 | + y_limit--; |
1169 | + } |
1170 | + |
1171 | + if (x_offset == x_limit) |
1172 | + { |
1173 | + // these items were added to the target set |
1174 | + while (y_offset < y_limit) |
1175 | + { |
1176 | + ctx.y_changes[y_offset] = 1; |
1177 | + y_offset++; |
1178 | + } |
1179 | + } |
1180 | + else if (y_offset == y_limit) |
1181 | + { |
1182 | + // these items were removed from the original set |
1183 | + while (x_offset < x_limit) |
1184 | + { |
1185 | + ctx.x_changes[x_offset] = 1; |
1186 | + x_offset++; |
1187 | + } |
1188 | + } |
1189 | + else |
1190 | + { |
1191 | + Partition partition = { 0, 0, false, false }; |
1192 | + |
1193 | + // split into two subproblems |
1194 | + find_diag (x_offset, x_limit, y_offset, y_limit, |
1195 | + equal_func, ref ctx, ref partition); |
1196 | + |
1197 | + if (compare_sequences (x_offset, partition.x_mid, |
1198 | + y_offset, partition.y_mid, |
1199 | + partition.lo_minimal, |
1200 | + ref ctx, equal_func)) |
1201 | + return true; |
1202 | + if (compare_sequences (partition.x_mid, x_limit, |
1203 | + partition.y_mid, y_limit, |
1204 | + partition.hi_minimal, |
1205 | + ref ctx, equal_func)) |
1206 | + return true; |
1207 | + } |
1208 | + |
1209 | + return false; |
1210 | + } |
1211 | + } /* namespace Unity.Internal.Utils.Diff */ |
1212 | } |
1213 | |
1214 | } /* namespace Unity.Internal */ |
1215 | |
1216 | === modified file 'test/vala/Makefile.am' |
1217 | --- test/vala/Makefile.am 2013-07-02 18:42:23 +0000 |
1218 | +++ test/vala/Makefile.am 2013-07-09 13:37:28 +0000 |
1219 | @@ -13,6 +13,7 @@ |
1220 | -DTESTDIR=\"$(top_srcdir)/test\" \ |
1221 | -DTESTVALADIR=\"$(top_srcdir)/test/vala\" \ |
1222 | -DG_SETTINGS_ENABLE_BACKEND \ |
1223 | + -ggdb \ |
1224 | $(LIBUNITY_CFLAGS) \ |
1225 | $(LIBUNITY_LIBS) |
1226 | |
1227 | @@ -56,10 +57,12 @@ |
1228 | TEST_PROGS += test-vala test-scope test-blacklist-crash test-extras |
1229 | |
1230 | test_vala_LDADD = $(test_libs) |
1231 | +test_vala_LDFLAGS = -static |
1232 | |
1233 | test_vala_VALASOURCES = \ |
1234 | common.vala \ |
1235 | test-appinfo-manager.vala \ |
1236 | + test-diff.vala \ |
1237 | test-filters.vala \ |
1238 | test-io.vala \ |
1239 | test-launcher.vala \ |
1240 | @@ -74,6 +77,7 @@ |
1241 | nodist_test_vala_SOURCES = $(test_vala_VALASOURCES:.vala=.c) |
1242 | |
1243 | test_scope_LDADD = $(test_libs) |
1244 | +test_scope_LDFLAGS = -static |
1245 | test_scope_VALASOURCES = common.vala test-scope.vala |
1246 | nodist_test_scope_SOURCES = $(test_scope_VALASOURCES:.vala=.c) |
1247 | |
1248 | |
1249 | === added file 'test/vala/test-diff.vala' |
1250 | --- test/vala/test-diff.vala 1970-01-01 00:00:00 +0000 |
1251 | +++ test/vala/test-diff.vala 2013-07-09 13:37:28 +0000 |
1252 | @@ -0,0 +1,507 @@ |
1253 | +/* -*- Mode: vala; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2 -*- */ |
1254 | +/* |
1255 | + * Copyright (C) 2011 Canonical Ltd |
1256 | + * |
1257 | + * This program is free software: you can redistribute it and/or modify |
1258 | + * it under the terms of the GNU General Public License version 3 as |
1259 | + * published by the Free Software Foundation. |
1260 | + * |
1261 | + * This program is distributed in the hope that it will be useful, |
1262 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1263 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1264 | + * GNU General Public License for more details. |
1265 | + * |
1266 | + * You should have received a copy of the GNU General Public License |
1267 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1268 | + * |
1269 | + * Authored by Michal Hruby <michal.hruby@canonical.com> |
1270 | + * |
1271 | + */ |
1272 | +using Unity.Internal; |
1273 | +using Unity.Internal.Utils.Diff; |
1274 | + |
1275 | +namespace Unity.Test |
1276 | +{ |
1277 | + public class DiffSuite |
1278 | + { |
1279 | + public DiffSuite () |
1280 | + { |
1281 | + GLib.Test.add_data_func ("/Unit/Diff/Empty", |
1282 | + Fixture.create<DiffTester> (DiffTester.test_empty_diff)); |
1283 | + GLib.Test.add_data_func ("/Unit/Diff/Populate", |
1284 | + Fixture.create<DiffTester> (DiffTester.test_populate)); |
1285 | + GLib.Test.add_data_func ("/Unit/Diff/Identical", |
1286 | + Fixture.create<DiffTester> (DiffTester.test_identical)); |
1287 | + GLib.Test.add_data_func ("/Unit/Diff/Appends", |
1288 | + Fixture.create<DiffTester> (DiffTester.test_appends)); |
1289 | + GLib.Test.add_data_func ("/Unit/Diff/Prepends", |
1290 | + Fixture.create<DiffTester> (DiffTester.test_prepends)); |
1291 | + GLib.Test.add_data_func ("/Unit/Diff/Inserts", |
1292 | + Fixture.create<DiffTester> (DiffTester.test_inserts)); |
1293 | + GLib.Test.add_data_func ("/Unit/Diff/MoveToMiddle", |
1294 | + Fixture.create<DiffTester> (DiffTester.test_move_to_middle)); |
1295 | + GLib.Test.add_data_func ("/Unit/Diff/RemoveBegin", |
1296 | + Fixture.create<DiffTester> (DiffTester.test_remove_begin)); |
1297 | + GLib.Test.add_data_func ("/Unit/Diff/RemoveEnd", |
1298 | + Fixture.create<DiffTester> (DiffTester.test_remove_end)); |
1299 | + GLib.Test.add_data_func ("/Unit/Diff/RemoveMid", |
1300 | + Fixture.create<DiffTester> (DiffTester.test_remove_mid)); |
1301 | + GLib.Test.add_data_func ("/Unit/Diff/Mixed", |
1302 | + Fixture.create<DiffTester> (DiffTester.test_mixed)); |
1303 | + |
1304 | + GLib.Test.add_data_func ("/Unit/DiffModel/Populate", |
1305 | + Fixture.create<DiffModelTester> (DiffModelTester.test_populate)); |
1306 | + GLib.Test.add_data_func ("/Unit/DiffModel/Clear", |
1307 | + Fixture.create<DiffModelTester> (DiffModelTester.test_clear)); |
1308 | + GLib.Test.add_data_func ("/Unit/DiffModel/Mixed", |
1309 | + Fixture.create<DiffModelTester> (DiffModelTester.test_mixed)); |
1310 | + GLib.Test.add_data_func ("/Unit/DiffModel/ChangedMetadata", |
1311 | + Fixture.create<DiffModelTester> (DiffModelTester.test_metadata)); |
1312 | + } |
1313 | + |
1314 | + class DiffTester: Object, Fixture |
1315 | + { |
1316 | + private void setup () |
1317 | + { |
1318 | + } |
1319 | + |
1320 | + private void teardown () |
1321 | + { |
1322 | + } |
1323 | + |
1324 | + private SList<Change?> run_diff (string[] x, string[] y) |
1325 | + { |
1326 | + var script = run (x.length, y.length, (a, b) => |
1327 | + { |
1328 | + return x[a] == y[b]; |
1329 | + }); |
1330 | + script.reverse (); |
1331 | + return script; |
1332 | + } |
1333 | + |
1334 | + public void test_empty_diff () |
1335 | + { |
1336 | + string[] x_results = {}; |
1337 | + string[] y_results = {}; |
1338 | + |
1339 | + var script = run_diff (x_results, y_results); |
1340 | + |
1341 | + assert (script.length () == 0); |
1342 | + } |
1343 | + |
1344 | + public void test_populate () |
1345 | + { |
1346 | + string[] x_results = {}; |
1347 | + string[] y_results = {}; |
1348 | + y_results += "Line #1"; |
1349 | + y_results += "Line #2"; |
1350 | + y_results += "Line #3"; |
1351 | + y_results += "Line #4"; |
1352 | + |
1353 | + var script = run_diff (x_results, y_results); |
1354 | + |
1355 | + assert (script.length () == 1); |
1356 | + var change = script.nth_data (0); |
1357 | + assert (change.x_offset == 0); |
1358 | + assert (change.y_offset == 0); |
1359 | + assert (change.inserted == 4); |
1360 | + assert (change.deleted == 0); |
1361 | + } |
1362 | + |
1363 | + public void test_identical () |
1364 | + { |
1365 | + string[] x_results = {}; |
1366 | + x_results += "Line #1"; |
1367 | + x_results += "Line #2"; |
1368 | + x_results += "Line #3"; |
1369 | + x_results += "Line #4"; |
1370 | + string[] y_results = {}; |
1371 | + y_results += "Line #1"; |
1372 | + y_results += "Line #2"; |
1373 | + y_results += "Line #3"; |
1374 | + y_results += "Line #4"; |
1375 | + |
1376 | + var script = run_diff (x_results, y_results); |
1377 | + |
1378 | + assert (script.length () == 0); |
1379 | + } |
1380 | + |
1381 | + public void test_appends () |
1382 | + { |
1383 | + string[] x_results = {}; |
1384 | + x_results += "Line #1"; |
1385 | + x_results += "Line #2"; |
1386 | + x_results += "Line #3"; |
1387 | + x_results += "Line #4"; |
1388 | + string[] y_results = {}; |
1389 | + y_results += "Line #1"; |
1390 | + y_results += "Line #2"; |
1391 | + y_results += "Line #3"; |
1392 | + y_results += "Line #4"; |
1393 | + y_results += "Line #5"; |
1394 | + y_results += "Line #6"; |
1395 | + y_results += "Line #7"; |
1396 | + |
1397 | + var script = run_diff (x_results, y_results); |
1398 | + |
1399 | + assert (script.length () == 1); |
1400 | + var change = script.nth_data (0); |
1401 | + assert (change.x_offset == 4); |
1402 | + assert (change.y_offset == 4); |
1403 | + assert (change.inserted == 3); |
1404 | + assert (change.deleted == 0); |
1405 | + } |
1406 | + |
1407 | + public void test_prepends () |
1408 | + { |
1409 | + string[] x_results = {}; |
1410 | + x_results += "Line #1"; |
1411 | + x_results += "Line #2"; |
1412 | + x_results += "Line #3"; |
1413 | + x_results += "Line #4"; |
1414 | + string[] y_results = {}; |
1415 | + y_results += "Line #5"; |
1416 | + y_results += "Line #6"; |
1417 | + y_results += "Line #7"; |
1418 | + y_results += "Line #1"; |
1419 | + y_results += "Line #2"; |
1420 | + y_results += "Line #3"; |
1421 | + y_results += "Line #4"; |
1422 | + |
1423 | + var script = run_diff (x_results, y_results); |
1424 | + |
1425 | + assert (script.length () == 1); |
1426 | + var change = script.nth_data (0); |
1427 | + assert (change.x_offset == 0); |
1428 | + assert (change.y_offset == 0); |
1429 | + assert (change.inserted == 3); |
1430 | + assert (change.deleted == 0); |
1431 | + } |
1432 | + |
1433 | + public void test_inserts () |
1434 | + { |
1435 | + string[] x_results = {}; |
1436 | + x_results += "Line #2"; |
1437 | + x_results += "Line #4"; |
1438 | + string[] y_results = {}; |
1439 | + y_results += "Line #1"; |
1440 | + y_results += "Line #2"; |
1441 | + y_results += "Line #3"; |
1442 | + y_results += "Line #4"; |
1443 | + y_results += "Line #5"; |
1444 | + |
1445 | + var script = run_diff (x_results, y_results); |
1446 | + |
1447 | + assert (script.length () == 3); |
1448 | + var change = script.nth_data (0); |
1449 | + assert (change.x_offset == 0); |
1450 | + assert (change.y_offset == 0); |
1451 | + assert (change.inserted == 1); |
1452 | + assert (change.deleted == 0); |
1453 | + change = script.nth_data (1); |
1454 | + assert (change.x_offset == 1); |
1455 | + assert (change.y_offset == 2); |
1456 | + assert (change.inserted == 1); |
1457 | + assert (change.deleted == 0); |
1458 | + change = script.nth_data (2); |
1459 | + assert (change.x_offset == 2); |
1460 | + assert (change.y_offset == 4); |
1461 | + assert (change.inserted == 1); |
1462 | + assert (change.deleted == 0); |
1463 | + } |
1464 | + |
1465 | + public void test_move_to_middle () |
1466 | + { |
1467 | + string[] x_results = {}; |
1468 | + x_results += "Original"; |
1469 | + string[] y_results = {}; |
1470 | + for (int i = 0; i < 86; i++) |
1471 | + { |
1472 | + if (i == 40) y_results += "Original"; |
1473 | + else y_results += "Line #%d".printf (i); |
1474 | + } |
1475 | + |
1476 | + var script = run_diff (x_results, y_results); |
1477 | + |
1478 | + assert (script.length () == 2); |
1479 | + var change = script.nth_data (0); |
1480 | + assert (change.inserted == 40); |
1481 | + change = script.nth_data (1); |
1482 | + assert (change.inserted == 45); |
1483 | + } |
1484 | + |
1485 | + public void test_remove_begin () |
1486 | + { |
1487 | + string[] x_results = {}; |
1488 | + x_results += "Line #1"; |
1489 | + x_results += "Line #2"; |
1490 | + x_results += "Line #3"; |
1491 | + x_results += "Line #4"; |
1492 | + string[] y_results = {}; |
1493 | + y_results += "Line #3"; |
1494 | + y_results += "Line #4"; |
1495 | + |
1496 | + var script = run_diff (x_results, y_results); |
1497 | + |
1498 | + assert (script.length () == 1); |
1499 | + var change = script.nth_data (0); |
1500 | + assert (change.x_offset == 0); |
1501 | + assert (change.y_offset == 0); |
1502 | + assert (change.inserted == 0); |
1503 | + assert (change.deleted == 2); |
1504 | + } |
1505 | + |
1506 | + public void test_remove_end () |
1507 | + { |
1508 | + string[] x_results = {}; |
1509 | + x_results += "Line #1"; |
1510 | + x_results += "Line #2"; |
1511 | + x_results += "Line #3"; |
1512 | + x_results += "Line #4"; |
1513 | + string[] y_results = {}; |
1514 | + y_results += "Line #1"; |
1515 | + y_results += "Line #2"; |
1516 | + |
1517 | + var script = run_diff (x_results, y_results); |
1518 | + |
1519 | + assert (script.length () == 1); |
1520 | + var change = script.nth_data (0); |
1521 | + assert (change.x_offset == 2); |
1522 | + assert (change.y_offset == 2); |
1523 | + assert (change.inserted == 0); |
1524 | + assert (change.deleted == 2); |
1525 | + } |
1526 | + |
1527 | + public void test_remove_mid () |
1528 | + { |
1529 | + string[] x_results = {}; |
1530 | + x_results += "Line #1"; |
1531 | + x_results += "Line #2"; |
1532 | + x_results += "Line #3"; |
1533 | + x_results += "Line #4"; |
1534 | + string[] y_results = {}; |
1535 | + y_results += "Line #1"; |
1536 | + y_results += "Line #4"; |
1537 | + |
1538 | + var script = run_diff (x_results, y_results); |
1539 | + |
1540 | + assert (script.length () == 1); |
1541 | + var change = script.nth_data (0); |
1542 | + assert (change.x_offset == 1); |
1543 | + assert (change.y_offset == 1); |
1544 | + assert (change.inserted == 0); |
1545 | + assert (change.deleted == 2); |
1546 | + } |
1547 | + |
1548 | + public void test_mixed () |
1549 | + { |
1550 | + string[] x_results = {}; |
1551 | + x_results += "Line #1"; |
1552 | + x_results += "Line #2"; |
1553 | + x_results += "Line #3"; |
1554 | + x_results += "Line #4"; |
1555 | + x_results += "Line #5"; |
1556 | + x_results += "Line #6"; |
1557 | + x_results += "Line #7"; |
1558 | + x_results += "Line #8"; |
1559 | + x_results += "Line #9"; |
1560 | + x_results += "Line #10"; |
1561 | + string[] y_results = {}; |
1562 | + y_results += "Line #3"; |
1563 | + y_results += "Line #4"; |
1564 | + y_results += "Line #5"; |
1565 | + y_results += "Line #6"; |
1566 | + y_results += "Line #7"; |
1567 | + y_results += "Added #1"; |
1568 | + y_results += "Added #2"; |
1569 | + y_results += "Line #8"; |
1570 | + y_results += "Line #9"; |
1571 | + y_results += "Line #12"; |
1572 | + y_results += "Line #14"; |
1573 | + |
1574 | + var script = run_diff (x_results, y_results); |
1575 | + |
1576 | + assert (script.length () == 3); |
1577 | + var change = script.nth_data (0); |
1578 | + assert (change.x_offset == 0); |
1579 | + assert (change.y_offset == 0); |
1580 | + assert (change.inserted == 0); |
1581 | + assert (change.deleted == 2); |
1582 | + change = script.nth_data (1); |
1583 | + assert (change.x_offset == 7); |
1584 | + assert (change.y_offset == 5); |
1585 | + assert (change.inserted == 2); |
1586 | + assert (change.deleted == 0); |
1587 | + change = script.nth_data (2); |
1588 | + assert (change.x_offset == 9); |
1589 | + assert (change.y_offset == 9); |
1590 | + assert (change.inserted == 2); |
1591 | + assert (change.deleted == 1); |
1592 | + } |
1593 | + } |
1594 | + |
1595 | + class DiffModelTester: Object, Fixture |
1596 | + { |
1597 | + private Unity.Internal.DiffModel? model; |
1598 | + private Dee.SequenceModel? backend_model; |
1599 | + private uint rows_added; |
1600 | + private uint rows_removed; |
1601 | + |
1602 | + private void setup () |
1603 | + { |
1604 | + backend_model = new Dee.SequenceModel (); |
1605 | + backend_model.set_schema_full (RESULTS_SCHEMA); |
1606 | + backend_model.set_column_names_full (RESULTS_COLUMN_NAMES); |
1607 | + |
1608 | + var peer = new Dee.Server ("com.canonical.Libunity.Test"); |
1609 | + model = new Unity.Internal.DiffModel (peer, backend_model); |
1610 | + model.set_schema_full (RESULTS_SCHEMA); |
1611 | + model.set_column_names_full (RESULTS_COLUMN_NAMES); |
1612 | + model.row_added.connect (() => { rows_added++; }); |
1613 | + model.row_removed.connect (() => { rows_removed++; }); |
1614 | + |
1615 | + var ml = new MainLoop (); |
1616 | + Utils.wait_for_model_synchronization (model, (obj, res) => |
1617 | + { |
1618 | + ml.quit (); |
1619 | + }); |
1620 | + assert (run_with_timeout (ml)); |
1621 | + } |
1622 | + |
1623 | + private void teardown () |
1624 | + { |
1625 | + model = null; |
1626 | + backend_model = null; |
1627 | + } |
1628 | + |
1629 | + private void add_sample_result ( |
1630 | + string uri, |
1631 | + uint category, |
1632 | + HashTable<string, Variant>? metadata = null) |
1633 | + { |
1634 | + Variant metadata_v = metadata != null ? |
1635 | + metadata : new Variant.array (VariantType.VARDICT.element (), {}); |
1636 | + backend_model.append (uri, "icon", category, 0, "text/plain", |
1637 | + Path.get_basename (uri), "", uri, metadata_v); |
1638 | + } |
1639 | + |
1640 | + public void test_populate () |
1641 | + { |
1642 | + assert (backend_model.get_n_rows () == 0); |
1643 | + assert (model.get_n_rows () == 0); |
1644 | + assert (model.target_model.get_n_rows () == 0); |
1645 | + |
1646 | + add_sample_result ("file:///test1", 0); |
1647 | + add_sample_result ("file:///test2", 0); |
1648 | + add_sample_result ("file:///test9", 1); |
1649 | + add_sample_result ("file:///test2", 1); |
1650 | + |
1651 | + assert (backend_model.get_n_rows () == 4); |
1652 | + assert (model.target_model.get_n_rows () == 4); |
1653 | + assert (model.get_n_rows () == 0); |
1654 | + assert (rows_added == 0); |
1655 | + assert (rows_removed == 0); |
1656 | + |
1657 | + model.commit_changes (); |
1658 | + assert (model.get_n_rows () == 4); |
1659 | + assert (rows_added == 4); |
1660 | + assert (rows_removed == 0); |
1661 | + } |
1662 | + |
1663 | + public void test_clear () |
1664 | + { |
1665 | + add_sample_result ("file:///test1", 0); |
1666 | + add_sample_result ("file:///test2", 0); |
1667 | + add_sample_result ("file:///test3", 0); |
1668 | + add_sample_result ("file:///test9", 1); |
1669 | + add_sample_result ("file:///test2", 1); |
1670 | + add_sample_result ("file:///test5", 4); |
1671 | + |
1672 | + model.commit_changes (); |
1673 | + assert (model.get_n_rows () == backend_model.get_n_rows ()); |
1674 | + assert (rows_added == backend_model.get_n_rows ()); |
1675 | + assert (rows_removed == 0); |
1676 | + |
1677 | + backend_model.clear (); |
1678 | + |
1679 | + rows_added = 0; |
1680 | + rows_removed = 0; |
1681 | + model.commit_changes (); |
1682 | + assert (model.get_n_rows () == backend_model.get_n_rows ()); |
1683 | + assert (rows_added == 0); |
1684 | + assert (rows_removed == 6); |
1685 | + } |
1686 | + |
1687 | + public void test_mixed () |
1688 | + { |
1689 | + add_sample_result ("file:///test1", 0); |
1690 | + add_sample_result ("file:///test2", 0); |
1691 | + add_sample_result ("file:///test3", 0); |
1692 | + add_sample_result ("file:///test9", 1); |
1693 | + add_sample_result ("file:///test2", 1); |
1694 | + add_sample_result ("file:///test5", 4); |
1695 | + |
1696 | + model.commit_changes (); |
1697 | + assert (model.get_n_rows () == backend_model.get_n_rows ()); |
1698 | + assert (rows_added == backend_model.get_n_rows ()); |
1699 | + assert (rows_removed == 0); |
1700 | + |
1701 | + backend_model.clear (); |
1702 | + add_sample_result ("file:///test1", 0); |
1703 | + add_sample_result ("file:///test3", 0); |
1704 | + add_sample_result ("file:///test9", 1); |
1705 | + add_sample_result ("file:///test2", 1); |
1706 | + add_sample_result ("file:///test5", 4); |
1707 | + add_sample_result ("file:///test2", 4); |
1708 | + add_sample_result ("file:///test1", 4); |
1709 | + |
1710 | + rows_added = 0; |
1711 | + rows_removed = 0; |
1712 | + model.commit_changes (); |
1713 | + assert (model.get_n_rows () == backend_model.get_n_rows ()); |
1714 | + assert (rows_added == 2); |
1715 | + assert (rows_removed == 1); |
1716 | + // compare the actual values and their ordering |
1717 | + for (uint i = 0; i < model.get_n_rows (); i++) |
1718 | + { |
1719 | + var row = model.get_row (model.get_iter_at_row (i)); |
1720 | + var orig_row = backend_model.get_row (backend_model.get_iter_at_row (i)); |
1721 | + assert (row[ResultColumn.URI].equal (orig_row[ResultColumn.URI])); |
1722 | + assert (row[ResultColumn.CATEGORY].equal (orig_row[ResultColumn.CATEGORY])); |
1723 | + } |
1724 | + } |
1725 | + |
1726 | + public void test_metadata () |
1727 | + { |
1728 | + var metadata = new HashTable<string, Variant> (str_hash, str_equal); |
1729 | + add_sample_result ("file:///test1", 0, metadata); |
1730 | + |
1731 | + model.commit_changes (); |
1732 | + assert (model.get_n_rows () == backend_model.get_n_rows ()); |
1733 | + assert (rows_added == backend_model.get_n_rows ()); |
1734 | + assert (rows_removed == 0); |
1735 | + |
1736 | + backend_model.clear (); |
1737 | + // change in metadata will count as completely different result |
1738 | + metadata["test"] = new Variant.int32 (43); |
1739 | + add_sample_result ("file:///test1", 0, metadata); |
1740 | + |
1741 | + rows_added = 0; |
1742 | + rows_removed = 0; |
1743 | + model.commit_changes (); |
1744 | + assert (model.get_n_rows () == backend_model.get_n_rows ()); |
1745 | + assert (rows_added == 1); |
1746 | + assert (rows_removed == 1); |
1747 | + // compare the actual values and their ordering |
1748 | + for (uint i = 0; i < model.get_n_rows (); i++) |
1749 | + { |
1750 | + var row = model.get_row (model.get_iter_at_row (i)); |
1751 | + var orig_row = backend_model.get_row (backend_model.get_iter_at_row (i)); |
1752 | + assert (row[ResultColumn.URI].equal (orig_row[ResultColumn.URI])); |
1753 | + assert (row[ResultColumn.CATEGORY].equal (orig_row[ResultColumn.CATEGORY])); |
1754 | + assert (row[ResultColumn.METADATA].equal (orig_row[ResultColumn.METADATA])); |
1755 | + } |
1756 | + } |
1757 | + } |
1758 | + } |
1759 | +} |
1760 | |
1761 | === modified file 'test/vala/test-vala.vala' |
1762 | --- test/vala/test-vala.vala 2013-06-27 11:13:00 +0000 |
1763 | +++ test/vala/test-vala.vala 2013-07-09 13:37:28 +0000 |
1764 | @@ -30,6 +30,7 @@ |
1765 | PreferencesSuite preferences_suite; |
1766 | PreviewSuite preview_suite; |
1767 | ScopeSuite scope_suite; |
1768 | + DiffSuite diff_suite; |
1769 | ScopeDiscoveryTestSuite scope_discovery; |
1770 | ResultsSynchronizerTestSuite synchronizer_suite; |
1771 | ScopeGroupTestSuite scope_group; |
1772 | @@ -65,6 +66,9 @@ |
1773 | /* Scope test suite */ |
1774 | scope_suite = new ScopeSuite (); |
1775 | |
1776 | + /* Diff test suite */ |
1777 | + diff_suite = new DiffSuite (); |
1778 | + |
1779 | /* Scope discovery test suite */ |
1780 | scope_discovery = new ScopeDiscoveryTestSuite (); |
1781 |
PASSED: Continuous integration, rev:262 jenkins. qa.ubuntu. com/job/ libunity- ci/54/ jenkins. qa.ubuntu. com/job/ libunity- saucy-amd64- ci/39 jenkins. qa.ubuntu. com/job/ libunity- saucy-armhf- ci/39 jenkins. qa.ubuntu. com/job/ libunity- saucy-i386- ci/39
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins: 8080/job/ libunity- ci/54/rebuild
http://