Merge lp:~cmiller/desktopcouch/mother-forking-threads into lp:desktopcouch

Proposed by Chad Miller
Status: Merged
Approved by: Stuart Colville
Approved revision: 144
Merged at revision: not available
Proposed branch: lp:~cmiller/desktopcouch/mother-forking-threads
Merge into: lp:desktopcouch
Diff against target: 243 lines (+88/-62)
4 files modified
bin/desktopcouch-pair (+2/-0)
bin/desktopcouch-service (+83/-45)
desktopcouch/pair/couchdb_pairing/dbus_io.py (+0/-2)
desktopcouch/replication.py (+3/-15)
To merge this branch: bzr merge lp:~cmiller/desktopcouch/mother-forking-threads
Reviewer Review Type Date Requested Status
Rick McBride (community) Approve
Tim Cole (community) Approve
Review via email: mp+22838@code.launchpad.net

Commit message

Split desktopcouch-service threads into to discrete processes, since they do not depend on each other, and because multithreading breaks with recent changes to libraries. (LP: #524566, #530605)

For places we use DBus function calls, pull the DBus glib mainloop setting close to the place we assign the mainloop to the twisted reactor.

To post a comment you must log in.
Revision history for this message
Tim Cole (tcole) wrote :

Cool, +1 on processes versus threads.

review: Approve
Revision history for this message
Tim Cole (tcole) wrote :

(It may also be worth thinking about having the parent restart the child if it dies.)

Revision history for this message
Rick McBride (rmcbride) wrote :

I like it. I did see mention that Joshua Hoover was going to review this (after I started my review) so I'll defer changing the merge request status pending his review.

review: Approve
Revision history for this message
Joshua Hoover (joshuahoover) wrote :

I tested this yesterday the best I could based on the bug comments. As long as Tim and Rick are cool with it then we should get it released ASAP.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'bin/desktopcouch-pair'
2--- bin/desktopcouch-pair 2009-11-30 12:42:47 +0000
3+++ bin/desktopcouch-pair 2010-04-05 22:05:31 +0000
4@@ -56,6 +56,8 @@
5
6 from twisted.internet import gtk2reactor
7 gtk2reactor.install()
8+from dbus.mainloop.glib import DBusGMainLoop
9+DBusGMainLoop(set_as_default=True)
10 from twisted.internet.reactor import run as run_program
11 from twisted.internet.reactor import stop as stop_program
12
13
14=== modified file 'bin/desktopcouch-service'
15--- bin/desktopcouch-service 2010-02-24 19:46:40 +0000
16+++ bin/desktopcouch-service 2010-04-05 22:05:31 +0000
17@@ -34,15 +34,19 @@
18
19 """
20
21+import os
22+import time
23 import logging
24 import logging.handlers
25-from errno import ENOENT
26+import signal
27
28 from twisted.internet import glib2reactor
29 glib2reactor.install()
30+from dbus.mainloop.glib import DBusGMainLoop
31+DBusGMainLoop(set_as_default=True)
32+
33 from twisted.internet import reactor as mainloop
34-import dbus.service, gobject, os, errno, time
35-from dbus import DBusException
36+import dbus.service
37
38 import desktopcouch
39 from desktopcouch import local_files
40@@ -75,54 +79,18 @@
41 self.death()
42
43
44-def main(ctx=local_files.DEFAULT_CONTEXT):
45- pid = desktopcouch.find_pid(start_if_not_running=False, ctx=ctx)
46-
47- should_shut_down = False
48- if pid is None:
49- logging.warn("Starting up personal couchdb.")
50- pid = desktopcouch.find_pid(start_if_not_running=True, ctx=ctx)
51- should_shut_down = True
52- else:
53- logging.warn("Personal couchdb is already running at PID#%d.", pid)
54-
55- try:
56- port = desktopcouch._direct_access_find_port(pid=pid, ctx=ctx)
57-
58- # Advertise the port
59- replication_runtime = replication.set_up(lambda: port)
60- portAdvertiser = PortAdvertiser(mainloop.stop) # TODO: send port.
61- try:
62- logging.debug("starting main loop")
63- mainloop.run()
64- logging.debug("ending main loop")
65-
66- finally:
67- if replication_runtime:
68- replication.tear_down(*replication_runtime)
69-
70- except:
71- logging.exception("uncaught exception makes us shut down.")
72- finally:
73- logging.info("exiting.")
74- if should_shut_down:
75- logging.warn("shutting down personal couchdb.")
76- stop_local_couchdb.stop_couchdb(ctx=ctx)
77-
78-
79-if __name__ == "__main__":
80+def set_up_logging(name):
81+ """Set logging preferences for this process."""
82 import xdg.BaseDirectory
83- import gobject
84- gobject.set_application_name("desktopcouch service")
85-
86 log_directory = os.path.join(xdg.BaseDirectory.xdg_cache_home,
87 "desktop-couch/log")
88 try:
89 os.makedirs(log_directory)
90 except:
91 pass
92+
93 rotating_log = logging.handlers.TimedRotatingFileHandler(
94- os.path.join(log_directory, "desktop-couch-replication.log"),
95+ os.path.join(log_directory, "desktop-couch-%s.log" % (name,)),
96 "midnight", 1, 14)
97 rotating_log.setLevel(logging.DEBUG)
98 formatter = logging.Formatter('%(asctime)s %(levelname)-8s %(message)s')
99@@ -130,8 +98,78 @@
100 logging.getLogger('').addHandler(rotating_log)
101 console_log = logging.StreamHandler()
102 console_log.setLevel(logging.WARNING)
103- console_log.setFormatter(logging.Formatter("%(asctime)s - %(message)s"))
104+ console_log.setFormatter(logging.Formatter(
105+ "%s %%(asctime)s - %%(message)s" % (name,)))
106 logging.getLogger('').addHandler(console_log)
107 logging.getLogger('').setLevel(logging.DEBUG)
108
109- main()
110+
111+def replicator_main(couchdb_port, ctx=local_files.DEFAULT_CONTEXT):
112+ replication_runtime = replication.set_up(lambda: couchdb_port)
113+ try:
114+ logging.debug("starting replicator main loop")
115+ mainloop.run()
116+ finally:
117+ logging.debug("ending replicator main loop")
118+ if replication_runtime:
119+ replication.tear_down(*replication_runtime)
120+
121+
122+def dbus_server_main(ctx=local_files.DEFAULT_CONTEXT):
123+ portAdvertiser = PortAdvertiser(mainloop.stop)
124+ logging.debug("starting dbus main loop")
125+ try:
126+ mainloop.run()
127+ finally:
128+ logging.debug("ending dbus main loop")
129+
130+
131+def main(ctx=local_files.DEFAULT_CONTEXT):
132+ should_shut_down_couchdb = False
133+ couchdb_pid = desktopcouch.find_pid(start_if_not_running=False, ctx=ctx)
134+ if couchdb_pid is None:
135+ logging.warn("Starting up personal couchdb.")
136+ couchdb_pid = desktopcouch.find_pid(start_if_not_running=True, ctx=ctx)
137+ should_shut_down_couchdb = True
138+ else:
139+ logging.warn("Personal couchdb is already running at PID#%d.",
140+ couchdb_pid)
141+
142+ couchdb_port = desktopcouch._direct_access_find_port(pid=couchdb_pid,
143+ ctx=ctx)
144+ child_pid = os.fork() # Split!
145+ if child_pid != 0:
146+ # Let's be the replicator!
147+ set_up_logging("replication")
148+ #os.nice(10)
149+ replicator_main(couchdb_port)
150+ return
151+ else:
152+ # Let's be the dbus server! This is the main process. When we exit,
153+ # we kill everything.
154+ try:
155+ set_up_logging("dbus")
156+ dbus_server_main()
157+ except:
158+ logging.exception("uncaught exception makes us shut down.")
159+ finally:
160+ logging.info("exiting.")
161+ if should_shut_down_couchdb:
162+ logging.warn("shutting down personal couchdb.")
163+ stop_local_couchdb.stop_couchdb(ctx=ctx)
164+
165+ try:
166+ os.kill(child_pid, signal.SIGTERM)
167+ time.sleep(1)
168+ os.kill(child_pid, signal.SIGKILL)
169+ except OSError:
170+ pass
171+
172+ return
173+
174+
175+if __name__ == "__main__":
176+ import gobject
177+ gobject.set_application_name("desktopcouch service")
178+
179+ main()
180
181=== modified file 'desktopcouch/pair/couchdb_pairing/dbus_io.py'
182--- desktopcouch/pair/couchdb_pairing/dbus_io.py 2010-02-23 16:15:01 +0000
183+++ desktopcouch/pair/couchdb_pairing/dbus_io.py 2010-04-05 22:05:31 +0000
184@@ -20,9 +20,7 @@
185 import logging
186
187 import dbus
188-from dbus.mainloop.glib import DBusGMainLoop
189 import avahi
190-DBusGMainLoop(set_as_default=True)
191
192 from desktopcouch.pair.couchdb_pairing import couchdb_io
193
194
195=== modified file 'desktopcouch/replication.py'
196--- desktopcouch/replication.py 2010-02-23 16:36:20 +0000
197+++ desktopcouch/replication.py 2010-04-05 22:05:31 +0000
198@@ -34,7 +34,6 @@
199
200
201 known_bad_service_names = set()
202-already_replicating = False
203 is_running = True
204
205
206@@ -72,9 +71,6 @@
207 log.debug("started replicating")
208 local_uri = couchdb_io.mkuri("localhost", local_port)
209 try:
210- global already_replicating # Fuzzy, as not really critical,
211- already_replicating = True # just trying to be polite.
212-
213 try:
214 # All machines running desktopcouch must advertise themselves with
215 # zeroconf. We collect those elsewhere and filter out the ones
216@@ -203,16 +199,8 @@
217 log.exception("replication of services aborted")
218 pass
219 finally:
220- already_replicating = False
221- log.debug("finished replicating")
222-
223-
224-def replicate_local_databases_to_paired_hosts(local_port):
225- if already_replicating:
226- log.warn("haven't finished replicating before next time to start.")
227- return False
228-
229- reactor.callInThread(do_all_replication, local_port)
230+ log.debug("finished replicating")
231+
232
233 def set_up(port_getter):
234 port = port_getter()
235@@ -231,7 +219,7 @@
236
237 dbus_io.maintain_discovered_servers()
238
239- t = task.LoopingCall(replicate_local_databases_to_paired_hosts, int(port))
240+ t = task.LoopingCall(do_all_replication, int(port))
241 t.start(600)
242
243 # TODO: port may change, so every so often, check it and

Subscribers

People subscribed via source and target branches