bzr branch
http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
|
3327.1.1
by Mark Hammond
Add document outlining strategies for TortoiseBzr. |
1 |
Bazaar Windows Shell Extension Options |
2 |
======================================== |
|
3 |
||
4 |
.. contents:: :local: |
|
5 |
||
6 |
Introduction |
|
7 |
------------ |
|
8 |
||
|
3327.1.4
by Mark Hammond
based on the suggestions of a few people, make the tone of the document |
9 |
This document details the imlpementation strategy chosen for the |
10 |
Bazaar Windows Shell Extensions, otherwise known as TortoiseBzr, or TBZR. |
|
11 |
As justification for the strategy, it also describes the general architecture |
|
12 |
of Windows Shell Extensions, then looks at the C++ implemented TortoiseSvn |
|
13 |
and the Python implemented TortoiseBzr, and discusses alternative |
|
14 |
implementation strategies, and the reasons they were not chosen. |
|
15 |
||
16 |
The following points summarize the strategy. |
|
17 |
||
18 |
* Main shell extension code will be implemented in C++, and be as thin as |
|
19 |
possible. It will not directly do any VCS work, but instead will perform |
|
20 |
all operations via either external applications or an RPC server. |
|
21 |
||
22 |
* Most VCS operations will be performed by external applications. For |
|
23 |
example, committing changes or viewing history will spawn a child |
|
24 |
process that provides its own UI. |
|
25 |
||
26 |
* For operations where spawning a child process is not practical, an |
|
27 |
external RPC server will be implemented in Python and will directly use |
|
28 |
the VCS library. In the short term, there will be no attempt to create a |
|
29 |
general purpose RPC mechanism, but instead will be focused on keeping the |
|
30 |
C++ RPC client as thin, fast and dumb as possible. |
|
31 |
||
32 |
Background Information |
|
33 |
---------------------- |
|
|
3327.1.1
by Mark Hammond
Add document outlining strategies for TortoiseBzr. |
34 |
|
35 |
The facts about shell extensions |
|
|
3327.1.4
by Mark Hammond
based on the suggestions of a few people, make the tone of the document |
36 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
3327.1.1
by Mark Hammond
Add document outlining strategies for TortoiseBzr. |
37 |
|
38 |
Well - the facts as I understand them :) |
|
39 |
||
40 |
Shell Extensions are COM objects. They are implemented as DLLs which are |
|
41 |
loaded by the Windows shell. There is no facility for shell extensions to |
|
42 |
exist in a separate process - DLLs are the only option, and they are loaded |
|
43 |
into other processes which take advantage of the Windows shell (although |
|
44 |
obviously this DLL is free to do whatever it likes) |
|
45 |
||
46 |
For the sake of this discussion, there are 2 categories of shell extensions: |
|
47 |
||
48 |
* Ones that create a new "namespace". The file-system itself is an example of |
|
49 |
such a namespace, as is the "Recycle Bin". For a user-created example, |
|
50 |
picture a new tree under "My Computer" which allows you to browse a remote |
|
51 |
server - it creates a new, stand-alone tree that doesn't really interact |
|
52 |
with the existing namespaces. |
|
53 |
||
54 |
* Ones that enhance existing namespaces, including the filesystem. An example |
|
55 |
would be an extension which uses Icon Overlays to modify how existing files |
|
56 |
on disk are displayed or add items to their context menu, for example. |
|
57 |
||
58 |
The latter category is the kind of shell extension relevant for TortoiseBzr, |
|
59 |
and it has an important implication - it will be pulled into any process |
|
60 |
which uses the shell to display a list of files. While this is somewhat |
|
61 |
obvious for Windows Explorer (which many people consider the shell), every |
|
62 |
other process that shows a FileOpen/FileSave dialog will have these shell |
|
63 |
extensions loaded into its process space. This may surprise many people - the |
|
64 |
simple fact of allowing the user to select a filename will result in an |
|
65 |
unknown number of DLLs being loaded into your process. For a concrete |
|
66 |
example, when notepad.exe first starts with an empty file it is using around |
|
67 |
3.5MB of RAM. As soon as the FileOpen dialog is loaded, TortoiseSvn loads |
|
68 |
well over 20 additional DLLs, including the MSVC8 runtime, into the Notepad |
|
69 |
process causing its memory usage to more than double - all without doing |
|
70 |
anything tortoise specific at all. |
|
71 |
||
72 |
This has wide-ranging implications. It means that such shell extensions |
|
73 |
should be developed using a tool which can never cause conflict with |
|
74 |
arbitrary processes. For this very reason, MS recommend against using .NET |
|
75 |
to write shell extensions[1], as there is a significant risk of being loaded |
|
76 |
into a process that uses a different version of the .NET runtime, and this |
|
77 |
will kill the process. Similarly, Python implemented shell extension may well |
|
78 |
conflict badly with other Python implemented applications (and will certainly |
|
79 |
kill them in some situations). A similar issue exists with GUI toolkits used |
|
80 |
- using (say) PyGTK directly in the shell extension would need to be avoided |
|
81 |
(which it currently is best I can tell). It should also be obvious the shell |
|
82 |
extension will be in many processes simultaneously, meaning use of a simple |
|
83 |
log-file etc is problematic. |
|
84 |
||
85 |
In practice, there is only 1 truly safe option - a low-level language (such |
|
86 |
as C/C++) which makes use of only the win32 API, and a static version of the |
|
87 |
C runtime library if necessary. Obviously, this sucks from our POV :) |
|
88 |
||
89 |
[1]: http://blogs.msdn.com/oldnewthing/archive/2006/12/18/1317290.aspx |
|
90 |
||
91 |
Analysis of TortoiseSVN code |
|
|
3327.1.4
by Mark Hammond
based on the suggestions of a few people, make the tone of the document |
92 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
3327.1.1
by Mark Hammond
Add document outlining strategies for TortoiseBzr. |
93 |
|
94 |
TortoiseSVN is implemented in C++. It relies on an external process to |
|
95 |
perform most UI (such as diff, log, commit etc commands), but it appears to |
|
96 |
directly embed the SVN C libraries for the purposes of obtaining status for |
|
97 |
icon overlays, context menu, drag&drop, etc. |
|
98 |
||
99 |
The use of an external process to perform commands is fairly simplistic in |
|
100 |
terms of parent and modal windows - for example, when selecting "Commit", a |
|
101 |
new process starts and *usually* ends up as the foreground window, but it may |
|
102 |
occasionally be lost underneath the window which created it, and the user may |
|
103 |
accidently start many processes when they only need 1. Best I can tell, this |
|
104 |
isn't necessarily a limitation of the approach, just the implementation. |
|
105 |
||
106 |
Advantages of using the external process is that it keeps all the UI code |
|
107 |
outside Windows explorer - only the minimum needed to perform operations |
|
108 |
directly needed by the shell are part of the "shell extension" and the rest |
|
109 |
of TortoiseSvn is "just" a fairly large GUI application implementing many |
|
110 |
commands. The command-line to the app has even been documented for people who |
|
111 |
wish to automate tasks using that GUI. This GUI appears to also be |
|
112 |
implemented in C++ using Windows resource files. |
|
113 |
||
114 |
TortoiseSvn appears to cache using a separate process, aptly named |
|
115 |
TSVNCache.exe. It uses a named pipe to accept connections from other |
|
116 |
processes for various operations. At this stage, it's still unclear exactly |
|
117 |
what is fetched from the cache and exactly what the shell extension fetches |
|
118 |
directly via the subversion C libraries. |
|
119 |
||
120 |
There doesn't seem to be a good story for logging or debugging - which is |
|
121 |
what you expect from C++ based apps :( Most of the heavy lifting is done by |
|
122 |
the external application, which might offer better facilities. |
|
123 |
||
124 |
Analysis of existing TortoiseBzr code |
|
|
3327.1.4
by Mark Hammond
based on the suggestions of a few people, make the tone of the document |
125 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
3327.1.1
by Mark Hammond
Add document outlining strategies for TortoiseBzr. |
126 |
|
127 |
The existing code is actually quite cool given its history (SoC student, |
|
128 |
etc), so this should not be taken as criticism of the implementer nor of the |
|
129 |
implementation - indeed, many criticisms are also true of the TortoiseSvn |
|
130 |
implementation - see above. However, I have attempted to list the bad things |
|
131 |
rather than the good things so a clear future strategy can be agreed, with |
|
132 |
all limitations understood. |
|
133 |
||
134 |
The existing TortoiseBzr code has been ported into Python from other tortoise |
|
135 |
implementations (probably svn). This means it is very nice to implement and |
|
136 |
develop, but suffers the problems described above - it is likely to conflict |
|
137 |
with other Python based processes, and it means the entire CPython runtime |
|
138 |
and libraries are pulled into many arbitrary processes. |
|
139 |
||
140 |
The existing TortoiseBzr code pulls in the bzrlib library to determine the |
|
141 |
path of the bzr library, and also to determine the status of files, but uses |
|
142 |
an external process for most GUI commands - ie, very similar to TortoiseSvn |
|
143 |
as described above - and as such, all comments above apply equally here - but |
|
144 |
note that the bzr library *is* pulled into the shell, and therefore every |
|
145 |
application using the shell. The GUI in the external application is written |
|
146 |
in PyGTK, which may not offer the best Windows "look and feel", but that |
|
147 |
discussion is beyond the scope of this document. |
|
148 |
||
149 |
It has a better story for logging and debugging for the developer - but not |
|
150 |
for diagnosing issues in the field - although again, much of the heavy |
|
151 |
lifting remains done by the external application. |
|
152 |
||
153 |
It uses a rudimentary in-memory cache for the status of files and |
|
154 |
directories, the implementation of which isn't really suitable (ie, no |
|
155 |
theoretical upper bound on cache size), and also means that there is no |
|
156 |
sharing of cached information between processes, which is unfortunate (eg, |
|
157 |
imagine a user using Windows explorer, then switching back to their editor) |
|
158 |
and also error prone (it's possible the editor will check the file in, |
|
159 |
meaning Windows explorer will be showing stale data). This may be possible to |
|
160 |
address via file-system notifications, but a shared cache would be preferred |
|
161 |
(although clearly more difficult to implement) |
|
162 |
||
163 |
One tortoise port recently announced a technique for all tortoise ports to |
|
164 |
share the same icon overlays to help work around a limitation in Windows on |
|
165 |
the total number of overlays (its limited to 15, due to the number of bits |
|
166 |
reserved in a 32bit int for overlays). TBZR needs to take advantage of that |
|
167 |
(but to be fair, this overlay sharing technique was probably done after the |
|
168 |
TBZR implementation) |
|
169 |
||
170 |
The current code appears to recursively walk a tree to check if *any* file in |
|
171 |
the tree has changed, so it can reflect this in the parent directory status. |
|
172 |
This is almost certainly an evil thing to do (Shell Extensions are optimized |
|
173 |
so that a folder doesn't even need to look in its direct children for another |
|
174 |
folder, let alone recurse for any reason at all. It may be a network mounted |
|
175 |
drive that doesn't perform at all) |
|
176 |
||
177 |
Although somewhat dependent on bzr itself, we need a strategy for binary |
|
178 |
releases (ie, it assumes python.exe, etc) and integration into an existing |
|
179 |
"blessed" installer. |
|
180 |
||
181 |
Trivially, the code is not PEP8 compliant and was written by someone fairly |
|
182 |
inexperienced with the language. |
|
183 |
||
|
3327.1.4
by Mark Hammond
based on the suggestions of a few people, make the tone of the document |
184 |
Detailed Implementation Strategy |
185 |
--------------------------------- |
|
186 |
||
187 |
We will create a hybrid Python and C++ implementation. In this model, we |
|
188 |
would still use something like TSVNCache.exe (this external |
|
|
3327.1.1
by Mark Hammond
Add document outlining strategies for TortoiseBzr. |
189 |
process doesn't have the same restrictions as the shell extension itself) but |
190 |
go one step further - use this remote process for *all* interactions with |
|
191 |
bzr, including status and other "must be fast" operations. This would allow |
|
192 |
the shell extension itself to be implemented in C++, but still take advantage |
|
|
3327.1.4
by Mark Hammond
based on the suggestions of a few people, make the tone of the document |
193 |
of Python for much of the logic. |
|
3327.1.1
by Mark Hammond
Add document outlining strategies for TortoiseBzr. |
194 |
|
|
3327.1.4
by Mark Hammond
based on the suggestions of a few people, make the tone of the document |
195 |
A pragmatic implementation strategy will be used to work towards the above |
196 |
infrastructure - we will keep the shell extension implemented in Python - but |
|
197 |
without using bzrlib. This would allow us to focus on this |
|
198 |
shared-cache/remote-process infrastructure without immediately |
|
199 |
re-implementing a shell extension in C++. Longer term, once the |
|
|
3327.1.1
by Mark Hammond
Add document outlining strategies for TortoiseBzr. |
200 |
infrastructure is in place and as optimized as possible, we can move to C++ |
201 |
code in the shell calling our remote Python process. This port should try and |
|
202 |
share as much code as possible from TortoiseSvn, including overlay handlers. |
|
203 |
||
204 |
External Command Processor |
|
205 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
206 |
||
207 |
The external command application (ie, the app invoked by the shell extension |
|
208 |
to perform commands) can remain as-is, and remain a "shell" for other |
|
209 |
external commands. The implementation of this application is not particularly |
|
210 |
relevant to the shell extension, just the interface to the application (ie, |
|
211 |
its command-line) is. In the short term this will remain PyGTK and will only |
|
212 |
change if there is compelling reason - cross-platform GUI tools are a better |
|
213 |
for bazaar than Windows specific ones, although native look-and-feel is |
|
214 |
important. Either way, this can change independently from the shell |
|
215 |
extension. |
|
216 |
||
217 |
Performance considerations |
|
|
3327.1.4
by Mark Hammond
based on the suggestions of a few people, make the tone of the document |
218 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
3327.1.1
by Mark Hammond
Add document outlining strategies for TortoiseBzr. |
219 |
|
220 |
As discussed above, the model used by Tortoise is that most "interesting" |
|
|
3327.1.3
by Mark Hammond
Typos spotted by Alexander Belchenko. |
221 |
things are done by external applications. Most Tortoise implementations |
222 |
show read-only columns in the "detail" view, and shows a few read only |
|
223 |
properties in the "Properties" dialog - but most of these properties are |
|
224 |
"state" related (eg, revision number), or editing of others is done by |
|
225 |
launching an external application. This means that the shell extension itself |
|
226 |
really has 2 basic requirements WRT RPC: 1) get the local state of a file and |
|
227 |
2) get some named state-related "properties" for a file. Everything else can |
|
228 |
be built on that. |
|
|
3327.1.1
by Mark Hammond
Add document outlining strategies for TortoiseBzr. |
229 |
|
230 |
There are 2 aspects of the shell integration which are performance critical - |
|
231 |
the "icon overlays" and "column providers" |
|
232 |
||
233 |
The short-story with Icon Overlays is that we need to register 12 global |
|
234 |
"overlay providers" - one for each state we show. Each provider is called for |
|
235 |
every icon ever shown in Windows explorer or in any application's FileOpen |
|
236 |
dialog. While most versions of Windows update icons in the background, we |
|
237 |
still need to perform well. On the positive side, this just needs the simple |
|
238 |
"local state" of a file - information that can probably be carried in a |
|
239 |
single byte. On the negative side, it is the shell which makes a synchronous |
|
240 |
call to us with a single filename as an arg, which makes it difficult to |
|
241 |
"batch" multiple status requests into a single RPC call. |
|
242 |
||
243 |
The story with columns is messier - these have changed significantly for |
|
244 |
Vista and the new system may not work with the VCS model (see below). |
|
245 |
However, if we implement this, it will be fairly critical to have |
|
246 |
high-performance name/value pairs implemented, as described above. |
|
247 |
||
248 |
Note that the nature of the shell implementation means we will have a large |
|
249 |
number of "unrelated" handlers, each called somewhat independently by the |
|
250 |
shell, often for information about the same file (eg, imagine each of our |
|
251 |
overlay providers all called in turn with the same filename, followed by our |
|
252 |
column providers called in turn with the same filename. However, that isn't |
|
253 |
exactly what happens!). This means we will need a kind of cache, geared |
|
254 |
towards reducing the number of status or property requests we make to the RPC |
|
255 |
server. |
|
256 |
||
257 |
We will also allow all of the above to be disabled via user preferences. |
|
258 |
Thus, Icon Overlays could be disabled if it did cause a problem for some |
|
259 |
people, for example. |
|
260 |
||
261 |
RPC options |
|
|
3327.1.4
by Mark Hammond
based on the suggestions of a few people, make the tone of the document |
262 |
~~~~~~~~~~~~ |
|
3327.1.1
by Mark Hammond
Add document outlining strategies for TortoiseBzr. |
263 |
|
264 |
Due to the high number of calls for icon overlays, the RPC overhead must be |
|
265 |
kept as low as possible. Due to the client side being implemented in C++, |
|
266 |
reducing complexity is also a goal. Our requirements are quite simple and no |
|
267 |
existing RPC options exist we can leverage. It does not seen prudent to build |
|
268 |
an XMLRPC solution for tbzr - which is not to preclude the use of such a |
|
269 |
server in the future, but tbzr need not become the "pilot" project for an |
|
270 |
XMLRPC server given these constraints. |
|
271 |
||
272 |
I propose that a custom RPC mechanism, built initially using windows-specific |
|
273 |
named-pipes, be used. A binary format, designed with an eye towards |
|
274 |
implementation speed and C++ simplicity, will be used. If we succeed here, we |
|
275 |
can build on that infrastructure, and even replace it should other more |
|
276 |
general frameworks materialize. |
|
277 |
||
278 |
FWIW, with a Python process at each end, my P4 2.4G machine can achieve |
|
279 |
around 25000 "calls" per-second across an open named pipe. C++ at one end |
|
280 |
should increase this a little, but obviously any real work done by the Python |
|
281 |
side of the process will be the bottle-neck. However, this throughput would |
|
282 |
appear sufficient to implement a prototype. |
|
283 |
||
284 |
Vista versus XP |
|
|
3327.1.4
by Mark Hammond
based on the suggestions of a few people, make the tone of the document |
285 |
~~~~~~~~~~~~~~~~ |
|
3327.1.1
by Mark Hammond
Add document outlining strategies for TortoiseBzr. |
286 |
|
287 |
Let's try and avoid an OS advocacy debate :) But it is probably true that |
|
288 |
TBZR will, over its life, be used by more Vista computers than XP ones. In |
|
289 |
short, Vista has changed a number of shell related interfaces, and while TSVN |
|
290 |
is slowly catching up (http://tortoisesvn.net/vistaproblems) they are a pain. |
|
291 |
||
292 |
XP has IColumnProvider (as implemented by Tortoise), but Vista changes this |
|
293 |
model. The new model is based around "file types" (eg, .jpg files) and it |
|
294 |
appears each file type can only have 1 provider! TSVN also seems to think the |
|
295 |
Vista model isn't going to work (see previous link). It's not clear how much |
|
296 |
effort we should expend on a column system that has already been abandoned by |
|
297 |
MS. I would argue we spend effort on other parts of the system (ie, the |
|
298 |
external GUI apps themselves, etc) and see if a path forward does emerge for |
|
|
3327.1.3
by Mark Hammond
Typos spotted by Alexander Belchenko. |
299 |
Vista. We can re-evaluate this based on user feedback and more information |
|
3327.1.1
by Mark Hammond
Add document outlining strategies for TortoiseBzr. |
300 |
about features of the Vista property system. |
301 |
||
302 |
Implementation plan: |
|
303 |
-------------------- |
|
304 |
||
|
3327.1.4
by Mark Hammond
based on the suggestions of a few people, make the tone of the document |
305 |
The following is a high-level set of milestones for the implementation: |
306 |
||
|
3327.1.1
by Mark Hammond
Add document outlining strategies for TortoiseBzr. |
307 |
* Design the RPC mechanism used for icon overlays (ie, binary format used for |
308 |
communication) |
|
309 |
||
310 |
* Create Python prototype of the C++ "shim": modify the existing TBZR Python |
|
311 |
code so that all references to "bzrlib" are removed. Implement the client |
|
312 |
side of the RPC mechanism and implement icon overlays using this RPC |
|
313 |
mechanism. |
|
314 |
||
315 |
* Create initial implementation of RPC server in Python. This will use |
|
316 |
bzrlib, but will also maintain a local cache to achieve the required |
|
317 |
performance. The initial implementation may even be single-threaded, just |
|
318 |
to keep synchronization issues to a minimum. |
|
319 |
||
320 |
* Analyze performance of prototype. Verify that technique is feasible and |
|
321 |
will offer reasonable performance and user experience. |
|
322 |
||
323 |
* Implement C++ shim: replace the Python prototype with a light-weight C++ |
|
324 |
version. We would work from the current TSVN sources, including its new |
|
325 |
support for sharing icon overlays. Advice on if we should "fork" TSVN, or |
|
326 |
try and manage our own svn based branch in bazaar are invited. |
|
327 |
||
328 |
* Implement property pages and context menus in C++. Expand RPC server as |
|
329 |
necessary. |
|
330 |
||
331 |
* Create binary for alpha releases, then go round-and-round until its baked. |
|
|
3327.1.4
by Mark Hammond
based on the suggestions of a few people, make the tone of the document |
332 |
|
333 |
Alternative Implementation Strategies |
|
334 |
------------------------------------- |
|
335 |
||
336 |
Only one credible alternative strategy was identified, as discussed below. No |
|
337 |
languages other than Python and C++ were considered; Python as the bzr |
|
338 |
library and existing extensions are written in Python and otherwise only C++ |
|
339 |
for reasons outlined in the background on shell extensions above. |
|
340 |
||
341 |
Implement Completely in Python |
|
342 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
343 |
||
344 |
This would keep the basic structure of the existing TBZR code, with the |
|
345 |
shell extension continuing to pull in Python and all libraries used by Bzr |
|
346 |
into various processes. |
|
347 |
||
348 |
Although implementation simplicity is a key benefit to this option, it was |
|
349 |
not chosen for various reasons; The use of Python means that there is a |
|
350 |
larger chance of conflicting with existing applications, or even existing |
|
351 |
Python implemented shell extensions. It will also increase the memory usage |
|
352 |
of all applications which use the shell. While this may create problems for a |
|
353 |
small number of users, it may create a wider perception of instability or |
|
354 |
resource hogging. |