~ubuntu-branches/ubuntu/karmic/bzr/karmic-proposed

« back to all changes in this revision

Viewing changes to doc/developers/tortoise-strategy.txt

  • Committer: Bazaar Package Importer
  • Author(s): Jelmer Vernooij
  • Date: 2008-05-12 00:14:54 UTC
  • mfrom: (1.1.42 upstream)
  • Revision ID: james.westby@ubuntu.com-20080512001454-yjpajuiocykl48p9
Tags: 1.5~rc1-1
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
Bazaar Windows Shell Extension Options
 
2
========================================
 
3
 
 
4
.. contents:: :local:
 
5
 
 
6
Introduction
 
7
------------
 
8
 
 
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
----------------------
 
34
 
 
35
The facts about shell extensions
 
36
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
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
 
92
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
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
 
125
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
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
 
 
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
 
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
 
193
of Python for much of the logic.
 
194
 
 
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
 
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
 
218
~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
219
 
 
220
As discussed above, the model used by Tortoise is that most "interesting"
 
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.
 
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
 
262
~~~~~~~~~~~~
 
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
 
285
~~~~~~~~~~~~~~~~
 
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
 
299
Vista. We can re-evaluate this based on user feedback and more information
 
300
about features of the Vista property system.
 
301
 
 
302
Implementation plan:
 
303
--------------------
 
304
 
 
305
The following is a high-level set of milestones for the implementation:
 
306
 
 
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.
 
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.